jajuk-1.9.6.orig/0000755000175000017500000000000011720500104013454 5ustar drazzibdrazzibjajuk-1.9.6.orig/infinitest.args0000644000175000017500000000003011720500104016477 0ustar drazzibdrazzib-Djava.awt.headless=truejajuk-1.9.6.orig/.fbprefs0000644000175000017500000001607511720500104015115 0ustar drazzibdrazzib#FindBugs User Preferences #Thu Aug 27 16:25:50 CEST 2009 detectorAppendingToAnObjectOutputStream=AppendingToAnObjectOutputStream|true detectorBadAppletConstructor=BadAppletConstructor|true detectorBadResultSetAccess=BadResultSetAccess|true detectorBadSyntaxForRegularExpression=BadSyntaxForRegularExpression|true detectorBadUseOfReturnValue=BadUseOfReturnValue|true detectorBadlyOverriddenAdapter=BadlyOverriddenAdapter|true detectorBooleanReturnNull=BooleanReturnNull|true detectorCallToUnsupportedMethod=CallToUnsupportedMethod|true detectorCheckImmutableAnnotation=CheckImmutableAnnotation|true detectorCheckTypeQualifiers=CheckTypeQualifiers|true detectorCloneIdiom=CloneIdiom|true detectorComparatorIdiom=ComparatorIdiom|true detectorConfusedInheritance=ConfusedInheritance|true detectorConfusionBetweenInheritedAndOuterMethod=ConfusionBetweenInheritedAndOuterMethod|true detectorCrossSiteScripting=CrossSiteScripting|true detectorDoInsideDoPrivileged=DoInsideDoPrivileged|true detectorDontCatchIllegalMonitorStateException=DontCatchIllegalMonitorStateException|true detectorDontIgnoreResultOfPutIfAbsent=DontIgnoreResultOfPutIfAbsent|true detectorDontUseEnum=DontUseEnum|true detectorDroppedException=DroppedException|true detectorDumbMethodInvocations=DumbMethodInvocations|true detectorDumbMethods=DumbMethods|true detectorDuplicateBranches=DuplicateBranches|true detectorEmptyZipFileEntry=EmptyZipFileEntry|true detectorEqualsOperandShouldHaveClassCompatibleWithThis=EqualsOperandShouldHaveClassCompatibleWithThis|true detectorFinalizerNullsFields=FinalizerNullsFields|true detectorFindBadCast2=FindBadCast2|true detectorFindBadForLoop=FindBadForLoop|true detectorFindCircularDependencies=FindCircularDependencies|true detectorFindDeadLocalStores=FindDeadLocalStores|true detectorFindDoubleCheck=FindDoubleCheck|true detectorFindEmptySynchronizedBlock=FindEmptySynchronizedBlock|true detectorFindFieldSelfAssignment=FindFieldSelfAssignment|true detectorFindFinalizeInvocations=FindFinalizeInvocations|true detectorFindFloatEquality=FindFloatEquality|true detectorFindHEmismatch=FindHEmismatch|true detectorFindInconsistentSync2=FindInconsistentSync2|true detectorFindJSR166LockMonitorenter=FindJSR166LockMonitorenter|true detectorFindLocalSelfAssignment2=FindLocalSelfAssignment2|true detectorFindMaskedFields=FindMaskedFields|true detectorFindMismatchedWaitOrNotify=FindMismatchedWaitOrNotify|true detectorFindNakedNotify=FindNakedNotify|true detectorFindNonSerializableStoreIntoSession=FindNonSerializableStoreIntoSession|true detectorFindNonSerializableValuePassedToWriteObject=FindNonSerializableValuePassedToWriteObject|true detectorFindNonShortCircuit=FindNonShortCircuit|true detectorFindNullDeref=FindNullDeref|true detectorFindNullDerefsInvolvingNonShortCircuitEvaluation=FindNullDerefsInvolvingNonShortCircuitEvaluation|true detectorFindOpenStream=FindOpenStream|true detectorFindPuzzlers=FindPuzzlers|true detectorFindRefComparison=FindRefComparison|true detectorFindReturnRef=FindReturnRef|true detectorFindRunInvocations=FindRunInvocations|true detectorFindSelfComparison=FindSelfComparison|true detectorFindSelfComparison2=FindSelfComparison2|true detectorFindSleepWithLockHeld=FindSleepWithLockHeld|true detectorFindSpinLoop=FindSpinLoop|true detectorFindSqlInjection=FindSqlInjection|true detectorFindTwoLockWait=FindTwoLockWait|true detectorFindUncalledPrivateMethods=FindUncalledPrivateMethods|true detectorFindUnconditionalWait=FindUnconditionalWait|true detectorFindUninitializedGet=FindUninitializedGet|true detectorFindUnrelatedTypesInGenericContainer=FindUnrelatedTypesInGenericContainer|true detectorFindUnreleasedLock=FindUnreleasedLock|true detectorFindUnsatisfiedObligation=FindUnsatisfiedObligation|true detectorFindUnsyncGet=FindUnsyncGet|true detectorFindUselessControlFlow=FindUselessControlFlow|true detectorFormatStringChecker=FormatStringChecker|true detectorHugeSharedStringConstants=HugeSharedStringConstants|true detectorIDivResultCastToDouble=IDivResultCastToDouble|true detectorIncompatMask=IncompatMask|true detectorInconsistentAnnotations=InconsistentAnnotations|true detectorInefficientMemberAccess=InefficientMemberAccess|true detectorInefficientToArray=InefficientToArray|true detectorInfiniteLoop=InfiniteLoop|true detectorInfiniteRecursiveLoop=InfiniteRecursiveLoop|true detectorInfiniteRecursiveLoop2=InfiniteRecursiveLoop2|true detectorInheritanceUnsafeGetResource=InheritanceUnsafeGetResource|true detectorInitializationChain=InitializationChain|true detectorInstantiateStaticClass=InstantiateStaticClass|true detectorInvalidJUnitTest=InvalidJUnitTest|true detectorIteratorIdioms=IteratorIdioms|true detectorLazyInit=LazyInit|true detectorLoadOfKnownNullValue=LoadOfKnownNullValue|true detectorLostLoggerDueToWeakReference=LostLoggerDueToWeakReference|true detectorMethodReturnCheck=MethodReturnCheck|true detectorMultithreadedInstanceAccess=MultithreadedInstanceAccess|true detectorMutableLock=MutableLock|true detectorMutableStaticFields=MutableStaticFields|true detectorNaming=Naming|true detectorNumberConstructor=NumberConstructor|true detectorOverridingEqualsNotSymmetrical=OverridingEqualsNotSymmetrical|true detectorPreferZeroLengthArrays=PreferZeroLengthArrays|true detectorPublicSemaphores=PublicSemaphores|true detectorQuestionableBooleanAssignment=QuestionableBooleanAssignment|true detectorReadOfInstanceFieldInMethodInvokedByConstructorInSuperclass=ReadOfInstanceFieldInMethodInvokedByConstructorInSuperclass|true detectorReadReturnShouldBeChecked=ReadReturnShouldBeChecked|true detectorRedundantInterfaces=RedundantInterfaces|true detectorRepeatedConditionals=RepeatedConditionals|true detectorRuntimeExceptionCapture=RuntimeExceptionCapture|true detectorSerializableIdiom=SerializableIdiom|true detectorStartInConstructor=StartInConstructor|true detectorStaticCalendarDetector=StaticCalendarDetector|true detectorStringConcatenation=StringConcatenation|true detectorSuperfluousInstanceOf=SuperfluousInstanceOf|true detectorSuspiciousThreadInterrupted=SuspiciousThreadInterrupted|true detectorSwitchFallthrough=SwitchFallthrough|true detectorSynchronizeAndNullCheckField=SynchronizeAndNullCheckField|true detectorSynchronizeOnClassLiteralNotGetClass=SynchronizeOnClassLiteralNotGetClass|true detectorSynchronizingOnContentsOfFieldToProtectField=SynchronizingOnContentsOfFieldToProtectField|true detectorURLProblems=URLProblems|true detectorUncallableMethodOfAnonymousClass=UncallableMethodOfAnonymousClass|true detectorUnnecessaryMath=UnnecessaryMath|true detectorUnreadFields=UnreadFields|true detectorUseObjectEquals=UseObjectEquals|true detectorUselessSubclassMethod=UselessSubclassMethod|true detectorVarArgsProblems=VarArgsProblems|true detectorVolatileUsage=VolatileUsage|true detectorWaitInLoop=WaitInLoop|true detectorWrongMapIterator=WrongMapIterator|true detectorXMLFactoryBypass=XMLFactoryBypass|true detector_threshold=2 effort=default filter_settings=Medium|BAD_PRACTICE,CORRECTNESS,MT_CORRECTNESS,PERFORMANCE,STYLE|false filter_settings_neg=MALICIOUS_CODE,NOISE,I18N,SECURITY,EXPERIMENTAL| run_at_full_build=false jajuk-1.9.6.orig/pom.xml0000644000175000017500000002155611720500104015002 0ustar drazzibdrazzib 4.0.0 org.jajuk jajuk Jajuk 1.9.6 Jajuk is a Java music organizer for all platforms. The main goal of this project is to provide a fully-featured application to advanced users with large or scattered music collections. http://jajuk.info http://trac.jajuk.info 2003 Jajuk Developers http://lists.sourceforge.net/lists/listinfo/jajuk-developers http://lists.sourceforge.net/lists/listinfo/jajuk-developers http://sourceforge.net/mailarchive/forum.php?forum=jajuk-developers Jajuk Internalionalization http://lists.sourceforge.net/lists/listinfo/jajuk-i18n http://lists.sourceforge.net/lists/listinfo/jajuk-i18n http://sourceforge.net/mailarchive/forum.php?forum=jajuk-i18n GPL http://jajuk.sourceforge.net/LICENSE.txt manual scm:git:git://gitorious.org/jajuk/jajuk.git http://gitorious.org/jajuk/jajuk/ Jajuk team http://jajuk.info maven-compiler-plugin 1.6 1.6 UTF-8 org.apache.maven.plugins maven-surefire-plugin 2.4.2 src/main/resources src/main/java java.awt.headless true jfree jcommon 1.0.2 com.google.guava guava 11.0.1 commons-collections commons-collections 3.2 system ${basedir}/lib/commons-collections-3.2.jar com.melloware jintellitype 1.3 JLayer jlayer 1.0 system ${basedir}/lib/jlayer-1.0.jar Substance substance 4.2dev system ${basedir}/lib/substance-5.3.jar Swingx swingx 1.6 system ${basedir}/lib/swingx-1.6.jar commons-codec commons-codec 1.3 FreeDB entagged-freedb 0.04 system ${basedir}/lib/entagged-freedb-0.04.jar VLDocking vldocking 2.1.4 system ${basedir}/lib/vldocking-2.1.5.jar BasicPlayer basicplayer 3.0 system ${basedir}/lib/basicplayer-3.0.jar JGoodies animation 1.2.0 system ${basedir}/lib/animation-1.2.0.jar Cobra cobra 0.96.5R2 system ${basedir}/lib/cobra-0.98.4.jar JS js 0.96.5R2 system ${basedir}/lib/js-0.98.4.jar log4j log4j 1.2.6 jfree jfreechart 1.0.13 system ${basedir}/lib/jfreechart-1.0.13.jar com.jhlabs filters 2.0.235 org.jaudiotagger jaudiotagger 2.0.2 system ${basedir}/lib/jaudiotagger-2.0.2.jar junit junit 4.5 DBus-Java dbusjava 2.6 system ${basedir}/lib/libdbus-java-2.6.jar libmatthew-java-32 libmatthewjava32 0.7.1 system ${basedir}/lib/lib32/libunix-java.so libmatthew-java-64 libmatthewjava64 0.7.1 system ${basedir}/lib/lib64/libunix-java.so libmatthew-java unixjar 0.5 system ${basedir}/lib/unix-0.5.jar libmatthew-hexdump hexdump 0.2 system ${basedir}/lib/hexdump-0.2.jar com.miglayout miglayout-swing 3.7 system ${basedir}/lib/miglayout-swing-3.7.jar commons-io commons-io 1.4 commons-lang commons-lang 2.4 com.thoughtworks.xstream xstream 1.3.1 last.fm-bindings last.fm-bindings 7.3 system ${basedir}/lib/last.fm-bindings-7.3.jar netbeans simple_validation 0.4 system ${basedir}/lib/simple_validation-0.4.jar maven-pmd-plugin UTF-8 100 1.6 org.codehaus.mojo taglist-maven-plugin org.apache.maven.plugins maven-surefire-plugin src/main/resources ide true jajuk-1.9.6.orig/infinitest.filters0000644000175000017500000000005211720500104017217 0ustar drazzibdrazzib# Disable Infinitest globally in 1.9.x .*jajuk-1.9.6.orig/lib/0000755000175000017500000000000011720500104014222 5ustar drazzibdrazzibjajuk-1.9.6.orig/README.txt0000644000175000017500000000072711720500104015160 0ustar drazzibdrazzibThis is the full Jajuk SVN repository --- USING MAVEN --- To build Jajuk (Maven2 is required, download it from http://maven.apache.org/) , from the source folder containing the pom.xml file: $ mvn jar:jar --- USING ANT --- To compile Jajuk : (Ant is required, download it on http://ant.apache.org/ ) $ cd src/scripts $ ant ---------------- -> jajuk.jar is built in target directory All legals information are in the 'src/legals' directory jajuk-1.9.6.orig/.classpath0000644000175000017500000000564211720500104015446 0ustar drazzibdrazzib jajuk-1.9.6.orig/.project0000644000175000017500000000055411720500104015127 0ustar drazzibdrazzib jajuk org.eclipse.jdt.core.javabuilder org.eclipse.jdt.core.javanature jajuk-1.9.6.orig/.gitignore0000644000175000017500000000007311720500104015444 0ustar drazzibdrazzib # Ignore classes bin/ # maven built directories target/ jajuk-1.9.6.orig/src/0000755000175000017500000000000011720500104014243 5ustar drazzibdrazzibjajuk-1.9.6.orig/src/tools/0000755000175000017500000000000011720500104015403 5ustar drazzibdrazzibjajuk-1.9.6.orig/src/tools/jautodoc_templates.xml0000644000175000017500000001174611720500104022024 0ustar drazzibdrazzib jajuk-1.9.6.orig/src/main/0000755000175000017500000000000011720500104015167 5ustar drazzibdrazzibjajuk-1.9.6.orig/src/main/resources/0000755000175000017500000000000011720500104017201 5ustar drazzibdrazzibjajuk-1.9.6.orig/src/main/resources/perspectives/0000755000175000017500000000000011720500104021715 5ustar drazzibdrazzibjajuk-1.9.6.orig/src/main/resources/perspectives/AlbumsPerspective.xml0000644000175000017500000000113011720500104026067 0ustar drazzibdrazzib jajuk-1.9.6.orig/src/main/resources/perspectives/ConfigurationPerspective.xml0000644000175000017500000000105011720500104027454 0ustar drazzibdrazzib jajuk-1.9.6.orig/src/main/resources/perspectives/PlaylistsPerspective.xml0000644000175000017500000000062411720500104026637 0ustar drazzibdrazzib jajuk-1.9.6.orig/src/main/resources/perspectives/InfoPerspective.xml0000644000175000017500000000054311720500104025546 0ustar drazzibdrazzib jajuk-1.9.6.orig/src/main/resources/perspectives/FilesPerspective.xml0000644000175000017500000000124711720500104025717 0ustar drazzibdrazzib jajuk-1.9.6.orig/src/main/resources/perspectives/SimplePerspective.xml0000644000175000017500000000063011720500104026101 0ustar drazzibdrazzib jajuk-1.9.6.orig/src/main/resources/perspectives/DisplayPerspective.xml0000644000175000017500000000130111720500104026251 0ustar drazzibdrazzib jajuk-1.9.6.orig/src/main/resources/perspectives/StatPerspective.xml0000644000175000017500000000037411720500104025570 0ustar drazzibdrazzib jajuk-1.9.6.orig/src/main/resources/perspectives/TracksPerspective.xml0000644000175000017500000000126611720500104026105 0ustar drazzibdrazzib jajuk-1.9.6.orig/src/main/resources/icons/0000755000175000017500000000000011720500104020314 5ustar drazzibdrazzibjajuk-1.9.6.orig/src/main/resources/icons/22x22/0000755000175000017500000000000011720500104021073 5ustar drazzibdrazzibjajuk-1.9.6.orig/src/main/resources/icons/22x22/ext_dd_mount_22x22.png0000644000175000017500000000402211720500104025127 0ustar drazzibdrazzibPNG  IHDRĴl; pHYs B(xtIME IDAT8YnpkgwnpkSQV+#"% npk0# &N_J-npk0 npk0& &_f.%%%110 .!!! vtyxw|  !' ,UWSV.g,nV/.n9%$RY d 07; Sh\^IENDB`jajuk-1.9.6.orig/src/main/resources/icons/22x22/player_mount_22x22.png0000644000175000017500000000402211720500104025154 0ustar drazzibdrazzibPNG  IHDRĴl; pHYs B(xtIME AIDAT8YRTP]_]XWX^_#$# 8<  0/0R c   646878 "     224?>?mok33   dC j 879768gfghfh  ڄ   lkm212..-9<;  ++*+$$$fdg574b134fdg&=  9;8 ece~ FHE M}ܺyIENDB`jajuk-1.9.6.orig/src/main/resources/icons/22x22/folder_unmount_22x22.png0000644000175000017500000000125011720500104025476 0ustar drazzibdrazzibPNG  IHDRĴl;bKGDC pHYs B(xtIME &m^5IDAT8ՕkAԦZ+车'QgxU)D/~IQO"Xų7 Z"i{ڴMd!M~xp7;oޝ(<Ӹ9X091vg52w) ?nGk~uPz.dFovAc`Z[kXœoRL&S԰ ;a>Z]AJ8I.q o=|sh,,ki qMjkGoUJekW[xee(^ccW#SC7u  DA5(a{ͯ%W{2Cp29;Pt`i E׀m1;v&\pDܦKz ?a/Mtд4-f>;-R-7 m:9hblw;ssZ,HqtUU*}"P:i14"2+@/6OIENDB`jajuk-1.9.6.orig/src/main/resources/icons/22x22/cdrom_mount_22x22.png0000644000175000017500000000402211720500104024764 0ustar drazzibdrazzibPNG  IHDRĴl; pHYs B(xtIME 7IDAT8Ynpkgwnpkxzu+npk0#&N1/2;9<-J|npk0 npk0&&-*)+#"#9.  N&&&(((cRPUFFG""#BAC ,,- DBE 989BAB! "   !!!UWSV %%%IkliYYZM98:$$$񽾼ʅD\ N h̵ E  ÝaH_(*ḁ ! ۡ_ 2\-)k=)$ [\Z; ^A;Y m3+FMZ7; lHDs]IENDB`jajuk-1.9.6.orig/src/main/resources/icons/22x22/jajuk-icon_22x22.png0000644000175000017500000000164511720500104024500 0ustar drazzibdrazzibPNG  IHDRĴl;bKGD pHYs  tIME /R7Ҥ2IDAT8k]Es=sM/m"P.tQ~DB4HE mq!e(Zh!(J)hۍ+)MP$7>9gf\$Jnk}vow'ڔxwON86P,-/?Iu_ǿj=6xbJ(J|@iD$cv.ygffrfV&.hm-t! -Tɓo_؊a_;eʐzAzvR0Pؗ`˭_>>|tvvݮ/^$UnMUJ!dn ~MΥ#/P,Y`PKM" ϡhm-Gsc͠2`gFN)%Z)ܔɜ@) 1{d(ƺV+COJNH)QjY@Gc)d'fǾ2j0Cr3klxiA+l0an xi l#%*/Ñ$2 ¶/#t8veuur7 lly 7c9@p=yN+b]:w叩tPV.dq-6B!tJL}UR[ܽ^ѻ^y~ޞMMYI ض`P&NK!Eг>2+0pֶ6m! V1{ ~vow9z%c ²6n+3?s;6_mX^Sr)?O_vyIENDB`jajuk-1.9.6.orig/src/main/resources/icons/22x22/player_unmount_22x22.png0000644000175000017500000000210411720500104025516 0ustar drazzibdrazzibPNG  IHDRĴl;bKGD pHYs B(xtIME  O~IDAT8˵k\UdnIt&͓&!IQlE_)}Mb-R[ H(" qҨACIt:$M:9s9go&9Mڊ}Xg>iO>qr@mϟY{w\GRvԭS4]O7r9٬iMq5MC4 `kV4MM ,=I,iض%MLR&4%aǽ;8QLf>H$hE * (U@r[.R^`@he\>53W2,..DY/^)CUtsUw sR)eYhxͮVCjWLDJm; RJZ6YU^P(L$ % A F.Å@`Y&lvc |w?]5ɋE C!u GI}~;YXX`k ewGq#m[Dce^/8Ꮇl@ aπз1?Ёf. SA.QNj(@PX A   ;Wfk(`0@a r&` þ4f0@a5* ǰ_[KWB^290W:FȆ2|o3@1Ja 66EEpR<Ǝ=ď_30|33(?Ɗi8@1.Ca>ȥ C1/"`B"  \*h7נd1܆AleFP)EL⇆~e&#nhb8(S@?G_c /AYqo|Dv,ޟ]lef08%] d?-@fJS`K)  ԥ3 0&Py DWM@`.EyH 4IENDB`jajuk-1.9.6.orig/src/main/resources/icons/22x22/ok_22x22.png0000644000175000017500000000140111720500104023045 0ustar drazzibdrazzibPNG  IHDRĴl;gAMA7tEXtSoftwareAdobe ImageReadyqe<IDATxb?-@11  FFFƷA! 2s!CMϠ4h ffGbd,!Dg ddJ./ | 3Lf0 I@0``萠"4oC %2x#33~< ez_X3#ԃʍ+ n^:t#C&Rb`b``]e@{64[3gg/xD zy:!$I41gev`RgbsM?0?0dF9 #P ?~_Pǐ`b?6_u -`af@>s B@DB ..z>C+ bv$+@Q \/~;-á*o 0&N g eg``\h((O!.phx#Aa: P `RF/8r@^g`x 4i0 ?`H30|@AI7Ln.eK tc4J# #&Y @43 䭛pEIENDB`jajuk-1.9.6.orig/src/main/resources/icons/22x22/nfs_unmount_22x22.png0000644000175000017500000000152111720500104025012 0ustar drazzibdrazzibPNG  IHDRĴl;bKGDC pHYs B(xtIME %IDAT8˭KhTYs&&!4f r`p@tQ\Q D2n>V:=֑ADwB_qc&1;{jӉdM Pŭԭ~=q5̲|>quo0pc6gQtꍧ ^/ Y3ADCγsg[~ܼs3r5@+.joo?DR_)&on#2g GC~͡=:w^`OI rit,P Lޝ .UP(d,qt!91+,e10F0Fp=/x:C?UrA!AM}T m;MOZX}hrb(j4>'Ύ, (yee ɑ"t'TZȗk>(*ͬ DkÔ|) $LMi{{y93w @ P(߾cۉ͛uׯ8 ^y3@jmmm5J`RA)\)Ud0 x9"0*"cOwVgggۼSX,ꀪh4b1jkk IHXpy('H`6mKWW/P7K_7BYav9OIENDB`jajuk-1.9.6.orig/src/main/resources/icons/22x22/cdrom_unmount_22x22.png0000644000175000017500000000200411720500104025325 0ustar drazzibdrazzibPNG  IHDRĴl;bKGD4(I pHYs B(xtIME gh<IDAT8˽O\U?潡3 ?'hҺmMLlLM5Tƅ ac4ƅhݘ [?VV "A)̛=.:†rr?Ls8{gh O)ˈHԾ>w}"K$y bmm|\.G"`l|t`7pw2@k2a瑃_)2> HkhD{.-˞|73--nO@m-^ADUGL" EloTDēL2Sx2*  kdl|t2MIJ첪kEk.C%5B@4@c{{[iXMו\ڒnAX,>L&,KU "^:rJDvS2vlx_WWw6G(T`mm}D"Ε7sC=Z`7̙mq'7 nn2XXgxI5`>,dvvvFGX,N8\O$rWEOhj""ޘ b!jWWW%J֖Nvl&'`ii] ӴFdgHwʊJR!Fc|e o@.(e eb(ɚ;S##k a? զRZeqɉ__IC_IENDB`jajuk-1.9.6.orig/src/main/resources/icons/22x22/folder_mount_22x22.png0000644000175000017500000000402211720500104025133 0ustar drazzibdrazzibPNG  IHDRĴl; pHYs B(xtIME $DIDAT8Ypqo~Xmokcae4mok97:v**+iiigie?=@Ǡo},,-{b?|} ,,-,,-,,-  ,,-3 $  7F * 9"eߤЛ?   pJ0D]:*W!jQP 0 7; ߆4.IENDB`jajuk-1.9.6.orig/src/main/resources/icons/22x22/ext_dd_unmount_22x22.png0000644000175000017500000000114411720500104025474 0ustar drazzibdrazzibPNG  IHDRĴl;bKGD pHYs B(xtIME ;/AIDAT8ՔMkQ4IB&3k$[ Auٝ.! ]BAno&4$KLg:.L> 3nzr99nPgyG'ǧjgPUueꗯ30ponZ4˱R-NOł%#q6S#4+' Vvnuup y{y VKڭ$D۶W۶M<GOJ\Rb*h4uH}}MJF7MqN$5-LQ֔B"#_pAB>Ԓ4MyDz,i=<2vzP(]bB.ȟs!q>||O|7 K`^M&~8.z$6hZ~)v=W,h_Dt:aMhZ> ee?!j} KC?R>-sh&Eo}IENDB`jajuk-1.9.6.orig/src/main/resources/icons/22x22/undo_22x22.png0000644000175000017500000000125311720500104023406 0ustar drazzibdrazzibPNG  IHDRĴl;bKGD pHYs  ~tIME 7"8IDATx=hawIsicZ$"MѡAD.{GRqs9(%.nP\[cl.܇CJҦZy}^<#D)= .`J%TˉrbP'Og |WJc\85l;Fs ĘS*s`#w\ aqL'ĽKGu$lN'ήmUB8W%sU-8pq1}O n|+c%_|+ -R.* P6dff?ñ={HbD@(MZyHvQ71W2l2BO8$w}OIEo3’efd(pi£4m'Zw"P^96h Vd #7;Fi9n%E.A{w+khUr_+`0"{㙦KHf0Lv)Vm+EȮɭSO1̾KhXxl/^5t0A"S!/IENDB`jajuk-1.9.6.orig/src/main/resources/icons/22x22/nfs_mount_22x22.png0000644000175000017500000000402211720500104024446 0ustar drazzibdrazzibPNG  IHDRĴl; pHYs B(xtIME IDAT8Ypqo~Xmokcae4mok97:v**+iiigie?=@Ǡo},,-{b?|} ,,-,,-,,-  ,,-3   * eߤЛ㻩6, * UVSKJM~ #\KBjRRR"#+"!" '''&7+vvv  #&#*$ ()8\P7; Ʈ|-PQ%IENDB`jajuk-1.9.6.orig/src/main/resources/icons/40x40/0000755000175000017500000000000011720500104021073 5ustar drazzibdrazzibjajuk-1.9.6.orig/src/main/resources/icons/40x40/perspective_logic_40x40.png0000644000175000017500000000510711720500104026151 0ustar drazzibdrazzibPNG  IHDR((msBIT|d pHYs B(xtEXtSoftwarewww.inkscape.org< IDATXiUy;w;mH3v- l! 5XA?4h A0( P".@KBLgt{g,<~x:-SI{{9Te7U "+:F*2 R*^#}BG~w/{7oɏ_{J$|U0"MUyS5H/;n;zsG̋0>>FGR&Jv8cIRc5| W[_-[ti(dbZATb0u[u;y0ǜI*>>Ueh{<$>cC;g]4`"5dZ244Lo_?}G筞>a!LΏ#VƏOxqFİw/b} 翰9@_?c#s0K3fX Id!LPbݍZ%ӚcliS'"OOK߽Gx@UA tXˊSLT*rHvى3S :>$( 332$/C2,C#%Ƨlݵ5Ov&k _j/0"(S`:?Atuu~d;qT2w> >Sǒn8߽c| jv1xz~v6^]ҵՄaxB_cLuBcHdsqνsԃ  d0"oi"?kNSHd" 2@ݰDDڂF+1fqPxc 0=kii PN0Ae:xATk;ma@,Ub:DB Da=!r,qZ~[n>xUU/V{ B1*9\g~j\{JAp48@< # 1+cU1N)e{YZ(.<Ol^+_$V-.ea ٶ6aSyWD~ޘIX,8Ɯ}3cD$2)^?cCį RZZh(5۳jO{*Uٽg/?wٙs=z{a@qhL&u :9a'hk44z&M:yR_w=ѣNm0735ZKe"P(r-f"_d/_`lZ97Td(4*Tc^]{Z(g`<] to{]Ͼ@غȴOCf1ҒFUϗnemGUeO(S!Rь17U5׊J&:b?!*D5;wrUqͭ3?0đ1fʶ[crr#=:&gफ़1v*MΦLJq_on\6owz|/31g>¯{wp0@43 K=T6(MOf(y!ql #=x_<ϧ~}riᦒM*vW kn(|5fV  /1ش :s%ܣoބ1پK<{. qY>}%W_u9tɴɪʢEmo-8 A~I? lGg2;׳OgsG?O6ZE%N㶵8u]ū{^? @X9h'J@5UXCd3n?p?0F0NAq 7iFX0#"e#cpup<׭(X+Qdz챲ACWW'w؎i V-*\ƪF+DAT8rl#'ݚ{{؁־aA1z>61 b*jǁ*SHLtKSGS]e\:^i"k~y7RUWMˡ:d*ݽ8CKD,z>nA2U*~s-t&_ox#kVxѬ:<."_rXϤ~(}@ŦUz;9@%S* jJ|k/L9:Y?ӎK__e\-*m˖-#}EPPo6k_%}qk ji4xqz{hAc]Žom?=;CDځV*H?Z>sO.[l=2^IGCL: 0cwQ[lyzTƻ银76)[k   zjŽ'^>s,E" "rzrrb}Kˋťz(Z圫md=~dxsZ0wg\-^zsffjE)ncs`#uXzN8y\)}V> ( s3kvNv^JYu%?i蜋{⹃@$~+{G)ק9p jqD䌈0`QyahO-k7{"eY &8Jir)QAHҨ)Lƭ6Vv/㥟\CP'&(%?ugshќ>foվmQTCShnK(] h#^m,]a|svr5>Y =(G# <2?IEp!F*AgI> E9ˡQO. 8w*(TU82,q"e%R~n/?~[ 1I059Vw~{ݤepNpN{0 C=!3 <+=S7Mܸ~^^A"TH p pR!8kqaˏٳpd8ι2VmkX+K^A1aQu nY?aLc'8kf}}16I@P! AƀC:8Ο=CK6~[6EPEVYe8Lp4S3Xk~JYGk/5ւLL4H{co'~( }\ۧ`C[;? 4 ~W?3 2%M3*rlur8HZh}P\mPg` q1v8^WZr k0~kݑ Fk Z~n)8,GDĢoS6 :Yn9((-.$""t];7pCPJaYR Ҭj!DŘ6J%hq(B /Yy~٩I|XV&`iM+۷J?R) D yyBG2p`IB J$a'$⯞y?yxqxdR79G.~h!*%r`| Qc,:jDnMzp ā?ceMx`ڂ$N>3K6EK}'Zu#|&)C z)ap,Ɇu XEKS =.yE%C9Φ-'o.ZW olb-5rV(Q"&,@5!ZrđF8@-^z!;Gݗ^z~ۼr"BEILR8H*48)3,lV*yu힀 [+#7> Sá$IVT$Dt*h!"Ppl |CWt=L JEw5bSBJ%s2 N~ɋ,W]k_Q_ʷ?>Sg`{͛km!'O10υ˗8p$`[]}(l$YZ- *.8/ZK)g1l\[yXwzdc3VZH,GVIs$ӳ>$zK^}l!0`,zXgxgRt;ZDsxzVU ;;ۻ76=9\LJKvLR4ˣQ=̔}m`m9'"=.K ww@ ()awd] >F`a_sSP`ЁOIENDB`jajuk-1.9.6.orig/src/main/resources/icons/40x40/tip_40x40.png0000644000175000017500000000501611720500104023236 0ustar drazzibdrazzibPNG  IHDR($sBIT|d pHYs  5VtEXtSoftwarewww.inkscape.org< IDATXkh3j%˲dK55Ď$vZHB&MhQ B *%4Q#h4bsQ`;˲dvuǎ-˲I>xa3;9{fIJժO ^~?#%t0tw!NWW,(Z MBOMtKgEiH9gF⼿\9ږ7Ÿ_JО޾0D{y$P%B06y HdSao Sřҵ蟺ehOo_]7oܩ̘.6iHF9b @+Iwom%RoWЫ?|#71ӷOm|ŽN z+¼ܲAە/=BR>8П]e<Wжy&?Le{hmTKˈFp@Th[r%آL+О޾]hEf6mIDp%CTfD6#92QWUxmtTbIw]~}C()vC9wn@t@K(p89͈dTq5j!Kۧ^c"6p!c}\+q[fYCPVR./ΕnK!<߃# 6cd1"3W9ZH0CUX6j]+@dӆhհ|I"xazXMd Ȳ*P7*Fw5TxC:fDW:v$KrU1Da{p𤃢@d@zcdz'T$0[})URd]1N=4Di)lDVJ͙]!$*T7,U0 #_+8i=К]VFzl"ŗ:Z_W9RDXMKewOV|iav)~Ű)}~PmIG;Zbdbe Ust0+,َ_aٰQ}xh?RyMɈ^|=}tp}ꗿ,ekL4I\ إ](^U݅Lty\=3pRZ *P(*,>Rhu>ڻ>Vr Z:;}=Dx8#3rswut4‰KM.vf~2 fRrIZxO?ufggW@ae=x^z70#x󌤫! fVNOdlǽ(88';?횮wp߼%(OR:'"PӁ{G̺|i$)! #8FHg3/xC@](kf@ -QUjՂZ*,?X1HcD^XQ:s# pU./Ӹm9)d)63uP@<51 ##ܐv#G{>b~%G~7?dDDm[A!JD\nPEwRBQÃՠ{}msCY1 8N ZR Z(xD'.\+^4Mf:Cm*;vE2Վ;Xs<7FF>>tUR"_)W/0t| ɔXG,"D|°@$  \?E!&'lf?ǩ1ޙ :st:U$" tҧ=z3#I?9s⽀RN(`9u8޽+W{$Il? Xc1qA'ڏ~gNd s'q4@^{hv7u&1>!o왂n7A%a]0edx ?SJ!ZYY YIhV`aa~~f s`f03V˪,A>(EV/}1g~FDj ADŋ6ɲ Y `fN>}/Za="Bh6wΝ;JzF vcL NOMӴĸI0 "q ZDAHVJ|ԩjբ(EDJR۷O...~4(c5KPA@ Bn~_sC@ZkZ-y>d=`nn.Zk cˬW :" 3j D(\.4<JDjѣr]x}LRm}k}M[Z~*"2(tк<AUj5"sR R qImq-ՌED0E=l3:Ƙ`Ae} ޒ:<( ReB? /s6f!`"Vd3+XY B(Rxg,XY)mIt@f69E4MQlwĢm6( 봂M+Hqܻfbfgze( %fY:iMd?EQQ9rJE`ͩ"c*x6XkYXS!7nlGV`:6 LɨvLnl8(R*{ ##,QLFQ x+e<2 R"-;CׯWYkr<뀭mbl@DU3D1*CzF-xJ:Bh#m\'0:<0 }`IU9fac;bǃPDG*>| ڱ w"x6כ2. 5b`@@όY =Y@@[FQU(PPtl-ZI )Fe:nIENDB`jajuk-1.9.6.orig/src/main/resources/icons/40x40/perspective_simple_40x40.png0000644000175000017500000000422511720500104026345 0ustar drazzibdrazzibPNG  IHDR((msBIT|d pHYs B(xtEXtSoftwarewww.inkscape.org<IDATX͘[l=3ऍCD@DRIJ'"UTA#w AP@*y j p8v0qsޫ}89,=k #"|&}l'd~!?c}Dܿ<vMkIyvFsңiN oxׅrJ{6O"" H !?i(m6B$ImD$"۶FDXdIQccc d"Mbiߌ@$`:70 MzJZzm"g_[f4Mc?Q7GABv!fL5&ɸY< ?FZy`BpΙ<9g+#y*Hr8:<̌,K2 3ZIW/k8/T@tgԵ,QHAӴ(9B̮TQ+(js^r"be10 شLضlۖs S MID4Mf3\4LȲ,WZU|TLfFAV\ݼysiۛTr"BYY|ȑ(l``2 ]A4Ml߾ ˗//nll,쌹\YUV^=pw2kmܸd׮]oxJa<ks/ 񎏏[gϞ} r1&߿PH%"y޽!Z ϟD"lذXeVQkkkZ5{ι VO93t=app0588ݸq#sNRUTTxcҊ+|]]]j$1׭[}FQ[a=PHTN8D;v,ucņa~zni&6>.n̋/T*%m0СC*ڵkɾ>'O&lŞ&/ ˙th144$<ӧJU(ffϠi֭[K4M댈aY~d۶q^YY)>|8PZZ*W\1 ΢c1`0(l2YQd0tlٲd۶mdRttt$?~l h?zjii񍎎K.ipX.^jtwwkBI6mRCS*))aɴIlivZu={Ds%ܹcݺu˼xKzݻwm׫=z4uuuʙ3gDWWΙ@4b1ܻwOknnPN5$'`0(A TUlۖ<ܛۗ""V^^.~$!.4aYH$\ ׯ "bUUURCCixhR Dx$2j%Ir,'OιD.zz?~pׯ_cμUN__zJD"E*xgb#K ;BwԩSvS|y&Y 5?ʩsΠ0MS✻:o[8E\Q%˲9ks J֒&PuX%q];Urq>_544ڍ ٳ€-1]׳ O˜COO+ݼ 2˲Vsq*P(M]EAuu,I3 1@C1 2m:Ks\~JɿD?\IENDB`jajuk-1.9.6.orig/src/main/resources/icons/40x40/perspective_player_40x40.png0000644000175000017500000000423511720500104026351 0ustar drazzibdrazzibPNG  IHDR((msBIT|d pHYs B(xtEXtSoftwarewww.inkscape.org<IDATX͘ɏG]ޛy3 I$v% R?8 YJ!" !q@Y0(l D_=ުCo6; KJjuwuu}Z^.F_.\.ٳm|<|0{ULݥRk(`DUŋ"]/xAz_x<3 AyG2HBU].HƃAbXg̀kHmh|Q`c[S`6s9~םb "/&IeYb/TRjSQ- Qؘ깁i pg9=qA"$IlL`+IU9gceSwޱ7Ůf$My?7G=1dyƭ}u8NX`VҠyؼ$[cc0jmTZS˂Vuf\z>rx8nY`EVDpA`(J۵Y;A&6U B_Q oHӌO܅!@E XQ,^ Y* }I+*Zi4hdE<ϙgYQ%Y1(BDV\"\`p[p*,Ւu4ګҳ55G^a:_fh k-*\Q VH7ZK!MWkW˒k4bfG lΝǎR0Ee-&Hr) #F)d omOٚ 0Zw,Q(YG^p#"֖f]C_>!su}tm \,am~rh-(3R(Bɣ⾓ۮWQ~s/"/!|ߊsQ\tcKZLHryK<}% UT#K+ű9^;Hi4`>S4 CT4H˘B?9ŋ(Re^nMw*m"K6~*nDDDdlϞ=cH$. !QXM*2M Zٳ, dkk€ȉ/pUuŪ8IBEg9r@o9I9 &\=bϲ #lЈ؊8#/R( & C[VS8xiWYA hIӔnaRJRE)I.|Gx3>U9\|><mZ,kkD<0P+"$N{ ~{166/=zYQUZ26u4( Uw շ>XD~{3>N>ፍieٲsnXHDsk0 lʕ+W^Z@`jZ_c &O[-[4l } v^J`^^3;Um*/@Tc5Wõ V ]RTHIENDB`jajuk-1.9.6.orig/src/main/resources/icons/40x40/perspective_configuration_40x40.png0000644000175000017500000000621311720500104027722 0ustar drazzibdrazzibPNG  IHDR((msBIT|d pHYs B(xtEXtSoftwarewww.inkscape.org< IDATXyl}ǿofvf w(%R&e(GG!%rFI] HPܢ"=iS Jbɵ+6[܋^s\RK;U`{|oo *@0/p$WܽV޹Kty94 -` ]8`˽,>+̛<.  {+?tDrVOe!i^@_׃@pH.1N4Ӳ!i:5dt@AD¡L)+Xxo> DBv7 tIW&+:@Q>o88HSEN[]Is:BRou_8C H`y,3&'s*mEeIV/<3܌vC{N.${iê{8-|"]/T?IcQfܺ P0b oc;o_'YPLLKe|n;<68w&ͳC7#<+G˴E!}]@ H8uz:5K/XU4^7j& x,e!`C#:N]@9/R/)kli4Q]ߖ<B@7(rdCZ65E( &Hdd\)C̰a4Yѱ); +_*S&T]駔BіS,̖<|wIVW(p ASU.|zq;p(TL)6uԍ6i,@ӌO Zr^>O ]ץC*/2Ϯư,Z|Vn3U"jVp8ћ*m Ԅ>+96V Cˆ[pY(R8LJݺYA,S٢oѱh٭?/, ޖf 64C`9l-t>qlL+)$UoQn-S gW܆<ֹg]O~۽0 {c g{w6j Qs%8r,[,ô:RTò*=Yyr{.34~\AsX`RkwXaSi Si ,C`+Qc|i=a,Ot9pVIQrͨU,Cb n}]$ҲyuT$x*+U5n4lfW "#k81!Zy4=pTIX9m9n9‚en3weH8D wngRnR|8Ó_U^v`c|@ vб`C;ݣ0)r;1Aț._=O>ȸ32O,q&xM}MJNaa8Ӌ_'e/'J). 9=Ll) *ŕI4VU2w?&!le hx=!VaE#7Dz68;F!;}bRYbqJJbV4ÄfeWvY^=mtx}2&Gb+e:I',?( =Ct!Tta^4XV]fcmg(]tCUqim 6Eʀ;vmx]px) rX@ }O2ϪϪϪϪ*i5C)涺&d6 gϞqrZo#[ [8B<^#TzPbL n<ԩSv5 6/zOnl80*_.3LFGy>^Xu͵kۂhjp <#L6kh"޿|>OWWR:- q;D2G%@(mT*#X\\]52ZzWWWʔ%xWw 06{k7 }c>fPhbSSSk033C>L(G7}r7{!5~@>QŻyT*eg7ꀮJ|)eF  P +E @kM8&Nвq˲o?Ep$JaYvƍIFaaOn.!R~d Ìo?Ij:r{mLn\-LFBA@gg'd鎵XEWWccc; H$iyo `ƀiP( hjj¶m,ڒc)LMMqB!ioo51RQXZZ<E –Aww7J)*ʎ( L!gΜܫmfggD"H)1zvk%y[&>a0==]rWM]4ޡCɤ]vjNj'nTfkܺu+x .ﮬ577H$[VZZU[^^^ӥK~6==-СzvV[Of V!Dh]WW\bu_U:Xw/B9V }7gruIENDB`jajuk-1.9.6.orig/src/main/resources/icons/40x40/perspective_stat_40x40.png0000644000175000017500000000500211720500104026021 0ustar drazzibdrazzibPNG  IHDR((msBIT|d pHYs B(xtEXtSoftwarewww.inkscape.org< IDATX[%EU>眙3:Chh4XI4ĄD}Ј!q61J0 B]efwg/a/gfwfa.{.]U>3}ffa}SZ/r>Kc"0n(GhLDu҇K\mUo"RrRKsxZZA@i~,pDuXu\G1X'!xNR ()B  Bꭀ%jKD}|ُ8Vx+WR, 贑d]D]Jݯכ~ks8<k: ~%%PR8G)GuR+)Q4!҄( 8JM[]nin=TJ=4MH%s)iuI!v>darU@ ɳ8s-polZ[FF؍RJ}rYw_aKˮgBF.C+NmNܹ#rfpY(LԵn+Ժ6)ibvq%8s~qewCĵSL#q譝i4a=[?ZJ"x.%M%/SuMVJyb>ARJ6NDk=譬 Hn u6Jhq7CΜ[ʍ `g~`tRQ2=;X{k-GOi꧘ϢB*_[Z`Bk3REJxV8852tޠJcX'|`f︳'߮Wv D֑\zSgx_֛ R)I\RKymR A>2T*~ }9v:}NʻH))e._@1{jz߼"y 7wLFw&ykĖ6b|` ߍ!sA^֬XR48 &(˖aPL 1۪3.!D.&6g j  덝<9Ӹʫ1&ck|vF7S404'_?A<ԶcԎAbX|ccdYβQZw#.A:Y|Gs\VmB{l Ck1$ǖ_84mDifdz \Sh@AI*Ys_NN6)|++&s9Ь[\7X I i:TR:CliLdz 3UP_1̘NlŽ.jn>p J[ JkSZ~`$0`zWk|+iڌv}4եZX,p"u/LC\\ @ҔkWqyX6xLUF@ JG:.=w/q|9/u)ʊ%OF`QXOZU8 AhBQіHol粯^ӏ?ʍ%g2k6 GJG3iW$hXЪgV5s<^u>w^E_ LGY5 {wv0G#]g .j/:q1طo?6| _:u14 G4ۖf_ (iA8>NXϬ8nuZ|rPZO{TiӶɶ;>9m.9V bߴs=}?>VRZ,&o~Bf YGCH 0gk\u7׹cu#;Vd^Y4C#0Ȥk…lfskʛڶZ122CX']->ܺV;>Wߥ Ef#2#yFQGK> 4 Dm#k.gY#y,È Szmʎwwg'Fb]aˁM d`:}4|>RM1&]_T7}5r܀(<ף/1]R&;UncY RUH p,plܿ2nX6u db lJDx/vm@nb0r1::]? }}}C=YWQKU3@kO;j3X,H\=ȣX+&0UUgwJO `uZ`LdjIENDB`jajuk-1.9.6.orig/src/main/resources/icons/64x64/0000755000175000017500000000000011720500104021107 5ustar drazzibdrazzibjajuk-1.9.6.orig/src/main/resources/icons/64x64/player_mount_64x64.png0000644000175000017500000003630611720500104025216 0ustar drazzibdrazzibPNG  IHDR@<։dbKGD pHYsGtIME :(qy IDATh<</57D+/57t632 k/-*QNL'&985g~/570 764420d~   0    ]       |055    HL5   5444! , 2 5qd %# */57h  $#%##$   !!"  ('*A?C436  LKO ><@>,䩾B#kUUU=== &&& ΎH.% 23b л:'''{\YYY### Ҽ{N  8888&***!!!Ӓ    W:::'520.dSؚ1IENDB`jajuk-1.9.6.orig/src/main/resources/icons/64x64/player_unmount_64x64.png0000644000175000017500000001103411720500104025550 0ustar drazzibdrazzibPNG  IHDR@<։dsBIT|d pHYsGtEXtSoftwarewww.inkscape.org<IDATh՛{\}?;3;0kc0;MJ%mT*?HqR(U#T_6J+BPDQ&oqa!,,.S(x-c_'1:([ڄQ a-LIQJ)e5YT\cc?Uc@j/0(B`A(.Zs.B6`&ߑ˹H%m"a!0heCEJ>NPJ&bcFz{43c$|6CƱ o{$1qr Yc RImӧ/p}c؎pOJ}QUŘPl)m@Agg:Z'!Qǂ$2NLHcLC;UHtR2Dخ]CEW@BJ( X\7&$:@IE H1!Ib':ID$Iy81fmc+D0Unj\cB4 @IRQӹU0PnxvyB6p;Q$eLJoB"zIaT}؎` iV!t6Aˆuuu jyfjBHX7RV&ت6Ɨ*Jvm[O7_i_>auFpUϡj}]o14P&3 c'_yTzZ`b8 Ԥս_'uLRV1,V" ?hW △GA(FW*K%Y%_nW ~TIJbJH8p`mV7SDI0P,|DY|KW8 II.G)U*(bQBw ChG1tqfk㭞o T)U:zKTT,&yJBX" ClۦP͸AцBGёaqqfݚB@YuqV0s tuvsYJ[ŋ(0…i6mou;IA$1\BeaeYa1u[OVT|27]\ЖB q,..q~]w䙜<}= ]| >y{bqa]w掏’XZIE<}~uq3X"ef w^>5>AWg7.K"[6T JO*~uxtRFk3?;v| 6zqvpXw'͒rmrz뺍uIFU;L/<@BФ.f$ً HiuDF2IXhSvRiA8&c13󌌌W Lf9sv*ꕗFjtd2(.HRɸ$:\e@5RD]=] W;8q&mfsKerzT||Bm?!Nb ,zrnƮZFk#h}@y=%Ibk)K˥5`DtF=W֡%?j_Ik.31un_NzqLX\*d ftStCֺ*hˀVh9{Voaa~͛73>>N6mYֲ,`LMM/2;YMhldr\tc=?wO(;цOp -ٶ h ^CMOo`ֵm1qܹ۶ DIKŃ ]afe< WS#[co~oݶOr9$iZR8z([n󼺲2G]lEAP?N!ApY/CT];ATJ!?ox twwctC O痖ClK/Fr\,+dYiZy @`d M:vN`o###?y1::XpdcTl6KWWQ裏&/^P-UaXS|s͡;w=00u۶;x5>>`jQ>q.l(xSO=%/lB&iAַ7&''ZUd(7= mMV: zK4pw޽]]]h /ھ}ڴiBpԩȑ#*ÇcaaaKʷӽ@a+AK!۷Ͷ1!e,vcREaz\>r%^,)aU_cMk G@A0TŹIENDB`jajuk-1.9.6.orig/src/main/resources/icons/64x64/new_64x64.png0000644000175000017500000000357111720500104023267 0ustar drazzibdrazzibPNG  IHDR@@iqsBIT|d pHYs^tEXtSoftwarewww.inkscape.org<IDATxn$IY_ۻޙzXܐ 2/0Yi^$ށWn02c=nw+93=5e{Gr%Q*k-׹WmUzڀn6Լ@/t9ȴ| ܻw@e?LEa>/=4o77o (L$B0XlO #=fEQ,<ϗIeÇ0X*-:1o`ߔ[A[L*D]uQ*u5ʌ Y-Ϣe$z{3jGf f]L[zLo:K{n`2EWb @Լ;s-/ukU1 l} {"ZFcBG p_>7 54[`}%CMfc1Z;b]!ɇš-F{{{Gg.ǀBonښ͍nںxhפ?j?'Nź hMXqRcpv VWW=^7"t)( H_ +f`LSt*_ Q&(bppcux>\yϿ(Cu VıGF p?Bd|+$9jo|I2#s.c?V_Lx;V^ٶCBP"g3'Q?IVDo>l*X`ev0\4vڃIv~IӶ\%NKzANtnJo2# 'OSCl^!wiX4Kt:t J5n)&f;NtW*,Y>[#| 0hF*ƩۣGŠvGOcW7n ]1#Ũ~3ؽ*}5ʌ4Mx|VHCrOrR7o,c\RHZ_bJO2Zc= @ϋe/r,q-¥Jn:Orq\2_iz:W{V8>B0Or~vZm~1=}t :jUy`>-oDgg {Ye}g JF@$I ϪQ dùV8u4wyաGxX_%W#(\ǀQ UNw+|:*z@ez/`X~Ob§==T8PfXk'isJݫY,YKos/<нd㟴[{~s{c_?3]9Gdw7SSS#$<999^@xQ7QVm+c x7ySSSW:ѥcL0#J7+Y\!T x7oOMM%VJNcccrXZZy V)ٮ< \|y16I2i/NLLmxג? FgfYt]g-j`f *JGB>Lbm inKڷS.;wPV74n&nUUݻa^N/1i?vjdL?lms>}~_'p!0o˲OiO'i={¶rq w›,BWW9$0N)M2l i ש[ 0Bu]+4c<<¡Cյaq7fC¶ma:7h8d2 9Lyzttt˭ߪoNÀsuSOo<ّdحo›]:qyr(?`M[7*cPUCCC'!A +A\.+W@ӴiAyxW)7nsKy|'0nww7!`pa\E.khurv킪j5pa,jPTUUh!رcTU a*y4XF*t],oPp'c ann. `yyy!$I(fgpj6X"DY100XXXmrDQ d! 'N۷#"I8N#WU56RJQTzaPK!;`ΝbѐśA4 eNqaq`U4 L!ed2&MTU|W!s7@8RXAcdd$2diZZiYcpR|+r$I*S$}0(4!{rAc;v Hжm0??7n R EQ r , *J?XD)fi\׍l'@Q nXZsE8M]WF7ź7(r333?={9oH "$cl۶ `yjJ)t]8p]cmm-v.JRd2G)Yܾ}HRḿs*>pPR!@@zeUUy u]tww㥗^j)dc>2<σR Y4E,xwP*`6$Ij؛pQ*Jr5jT@*J>|!$989- {z7m?gamm-PH$Ȳe|X\\gݔ$K!R)>!1ƊoXRP~$ K\.Ν#===U,%f嫯իWۗ.]^8]\jb(sΝ05*E1Perr£>B@FGGZ=x0SJ׾>>Į_۷z!eza";u l%ι D*KQ h:rB@8c, ZU[cXVVVp R4/X )VcuE9W4 Jȯ3|{ ###?88(͇)|mm u+Ogff{..,ԯ"znoT| 2ebbb^4 5zEaR)MӠ( AVmۨT*o{>e⟮^ׯSWȏ朷w7JE]G{Ǐtuu1 8ƘJ)8E۶VWW?w޿]/~]a~ݺ# ~ @HMKx$zXz=[ @0:Q A$3Q,*;a h H@f]=VƇ is|+,GmIENDB`jajuk-1.9.6.orig/src/main/resources/icons/64x64/folder_mount_64x64.png0000644000175000017500000003267711720500104025204 0ustar drazzibdrazzibPNG  IHDR@5bKGD pHYsII"6tIME 9b IDATh55wwwm qwww o'''g&sss  36 vooo(qqq888  ߌhhh !    36hʚ\ ll5e˛[|WG. Y|             Р`  bq@IDAT    4]Yu  $YNy- 10  $:;#CB  #CB     #>;    q  /0 $>,̚0360 $!23b Ͷn^ ^  aSn7hHtIENDB`jajuk-1.9.6.orig/src/main/resources/icons/64x64/cdrom_mount_64x64.png0000644000175000017500000003265511720500104025031 0ustar drazzibdrazzibPNG  IHDR@5 pHYsNJtIME  U IDATh55TTTJTTT!!!Aeee[TTT>  &`>>> 666$?TTT UIII<<<dT !!!<<<STTT`QQQ [TTT!?:::FFFc_&&&3331TTT2TTT^PPP000c?!+++???[TTT aCCC%%% STTT SCCCAAAdU 666?TTT$`PPP###cTTT#>666???_TTT_...+++JTTT_KKK999dB'''666JTTT`FFF`TTTR>>>???bTTTV ...$?`KKK 000cTTT%;111777STTTJ*** &&& P'444$$$# !!! :@IDAT&&&  MMM ]]] $$$    ===%%%RRR /// >>/&&&XXX !# ; ///C= 6661 NNN@(57<Ⱥ eeew;QQQⱠs BD  eee_f666111Ѝ JQLA AAA|0666))) JQM   \\\B&&&q*"""***͔VMB   ־B#III U^ ųVA5  $>,ݷ999(((005 \/!23b \u  dS^FIENDB`jajuk-1.9.6.orig/src/main/resources/icons/64x64/nfs_unmount_64x64.png0000644000175000017500000000650311720500104025047 0ustar drazzibdrazzibPNG  IHDR:@KdsBIT|d pHYs#tEXtSoftwarewww.inkscape.org< IDATh[KlGzy2eJFr$$ 0b;NX# SN2c}>䐃u^%AF `rl/ ̵bJERh8ϡyp(6(ԣkQWЛo{DBD䍷~cAoͥǟ~i@˓&AD@Dc}}{^zwv%G.\'|y#203DdjU[AgyF]z1Or\, "Cu҇=`=_[[éSly'MTDr\3IܹsgHtيDKgqq1t:/ }(fάahx*Ozh`_y7HCh0ƀǤ9MԷy sBjT'wj@F*Z+qݻvQQ#I`BDFa983'[m|mx(~K8hO?!"Z0:XkcPgF؎>”[cX4EE󛻭뛝C~['s+=b0nrˡ} ov0  <7V3D<>]sVxԂR%$I Fdg} &{Op!MS03lhE?I+D.t,"ۆ<ϕ1VsssAh5 #&z|/*g C'ۃdЊ !;gAwp[1s;E摱Qςs A H2QI( hj{IB@GP Vr*",0끙O17W8$N2 Bz0s;hm`PKT$AaZ!mUݗ03QV!J6$åJ40 n\3YZ?7WB %kD$Fh4F!fgS`Tex(QfRZkQ!ZC= 2U0H,.6gG4 52{DgX/cgV,9p(uFV, C;&Zũ,?ܫMpd-&Q02|>A~L}E@P)m,<*"8/$Ed(R rq`=[lsQ%^o(Ep,ęJf9lP(tt\Ryh*T7N-$\3XkQ@E&"Eg!Hi`k6Jy#u ̀y:A38À(2s."\̸&,ߗ;IĵHi"c( Y^`O%t?JHn^b {DcN{2fFY@qF]'8$S&ιb{XZ23î"re=#-(G3F=#;?fcF1ţR版L\h8"b\/+SE./31f`2G:v111T']v !'ƈd@JD9 IF(`Μ9ԩS~( Agbuuu1^?ձ&"!"β_r `#x( 3zs=wDeTv ݋:*aVWW?1&HsNØF"/1'XYYw.5uLcR ^_~%D?GڡWֈ }"/_F(9Ξ=;v*O;V[[[zLk}3 "Zt}mٸrJV3T8̿40@33;whZڬMEֿͦTBs6lj iZh4@q=F^a "GDDSf~Zh]dE~QDulll~D+Xk.^VmD4ZZQJu10 ;a p76#q.]Z0<J%\LM\{ 5W_=0Qy3g)ĉ1&Z/AbI 4MmDn7GDƘ1FYk\qifz=ȘDhܬeu^{A0GQ-ܮ>oH?h9U:eY\E"u]]7\`KDvlN޹MDUK/4hkgYv{IDޟ_Hד˶9DA(9ki>ՋSJ}RsO1Dwww֟1sWJ! ?Z__׫T"~P숵R?βllң 7h`0^~%zj \vaՕZIENDB`jajuk-1.9.6.orig/src/main/resources/icons/64x64/folder_unmount_64x64.png0000644000175000017500000000465511720500104025542 0ustar drazzibdrazzibPNG  IHDR@5sBIT|d pHYsII"6tEXtSoftwarewww.inkscape.org< *IDATh՚K\GU3N"# a"|>Bl^YV$a$K$bC, ,$#L?^Ž{}{SիWJDD ` 4ydJ^{~ X`Y}sKyQq…9ǹsZ/-W7oK~x*Bs. V 8&GGG}>Q̀ז(^,ƍ p:Dgc iRx{ ~:pxx0KDwRB{Oeoof`z *^Ekc'(1T,Kʲ$0 NHxPZkHYpaCQpC1Q_zӿO׵IIӈ(_V }\K9,cww5!*'p~eW/xic_o~_|myY (Ep8d8B``bo|\;ֶ \_֦?;g|m~bͧC3Ssm#ju/JAG >[F@i8T9W@ lbD%gwRƹ Ĉ1ZFqt||1!{h$1ͿҺ̨0>[CCsN8"˲z%I1.<^W&(d~s"|kCLfKo qM4VKQF#!,;{ ɰHb>V41$zTU;5<.P@h|?4G6Z@F~=ZB륍 l74DN<{O5nJ$EUd{$1~v IV 6Zm,k 8Ub[jK_}xnZ@2v:)o:q$REfKc;.n^ǨV%AƅQ Hfb(Ѩ;6~]h x8N&:I: |J hG(“"4=u! އ-[yaW"͒U14C|I"D<4XhwuP/G8 X+ c rOL@Ӡfmg-e%I#$}N!Ah8VN@@s ',_2 uz܂&Q(*Ka0 ǔ!""\`}:Ӣe},~% .f!ƏSE=s6Xk,8|PIİp=M @^+AHXOG׌}X! 7/>A uz]#mNVwuQDV1/-~ ~+EidjUԷ*5vL_dVҡ[ @[= Jk2 0ow;h3"^0ADR5wρOL)eD$t:HYMp\VFpvBQ']`R8"ߡ>cF QRi,=1u[sHM@Dm襈&f AH38ٺHtʲ  A)eOi!MSan8P$RrޖըX?ܥg>ΟV;oKQ6Lyus?n??@qZp ,S|Ծ{o~e57^QVmI?|x7~X"'_*b3i-Q۳#^" `Me9LAqJ{mpVBe, 9PL~[ F'%*f*j#f\ܳdU84N9Kk-IENDB`jajuk-1.9.6.orig/src/main/resources/icons/64x64/jajuk-icon-shortcut_64x64.png0000644000175000017500000002137311720500104026401 0ustar drazzibdrazzibPNG  IHDR@@iqbKGD pHYs  tIME9%$ IDATx͛yg]?{:ӝr3M4LQH(XBq(QQPkY.RDCZj)J]DB{g;?Sx ˳ֹw=WzXVգNDD蚎eb6ж-{{EAۋ[[[/]/9y׋_cLJ򕯹Zkuͫy_:/ͩшi9::$ryn|ౝw_yomm+7h nںjٴJm kP}dZ1uj‡T4m۲\p2O88:hڦdi*<,FGdyQqc-};ϛ^7_pBHVEJ7Xk!dZ4-Co3?:jjPW+]!ZUt]O ]ߡ,K$J)d]ۢ'>';|;?5wf/}O^D"EAL;t]G?ᝧ:Hq֥  !SK!Js ƀu<#l?onmu-R]/{?p 7|;Μ{ES?^ya d Ȳ '!QJR&CJv3)KstuL>P96!B {dYF]lomrlgw頻jw d~g "!D*ef)J8 Hut]G4 Z!]߲ASsucX̗4m,3,+BJR VF#)ZI|y+_^ۯˌA IQd-u`EA]7 C À@`nRM/~ږ#EQ1Pkú.W+1{G+U_.ffp9<: #eY"80FQ5yt:hMQhsuSF[`%4|Eцb)B?ww~s_ַ>mΟ)Dehڠ:KwF|>Y0۞3W Y@pp0sK0uGsB(qα;9P j*"NfSqcX>qӀ7\X/0?hgv,O}Z4m"-XsU]S uд-}Ӷ }9K>b$D"1U@D@"I 8giVz<`==vw vzx$57~7}mOPJ`kAƌf:S1,KrÍDcƑKkGȨ&)G#~ASw=I^@ jC AF `ɉ=}:lA<s~eWM')9j /%{B=l<'.`cd١ NG-f U,y ]QU+b%g,W+TŔlPsx8QlIdޡƆgwJܤil 14M^;Vomm>"갧8AR<DO1uYѯ_H2 : K7bv;e;zJSe](}+$վ<ȓHHD (% jtqGM%~'cL)TȂvW`;O!v%3Th4B =`Tۅ@*?5R1u@hUz<Q\<2Nؘgy.=O>4A$J|39ݮ&DҤ8t H0UD&F7o$ AF* tH\Z7"Vf1 @E2S;L\'Cڈ~wKJPPu#i `2Sn ^ϲb*gAw"F#DGצ 9vp0:-pXD(cTaYBm#6wY 'k%FMLPw("FbKcO㱽'l_ bŘtٟ9quo>xsiwD$2KnK%z0"ٲ( 2wD"`H;[yIvFe$XȏV'|ݡӌN M}#?" KM|#FѠGS8Fp]2HJl%]oLsӗxVRWUGn_jEkL.DeHu71@ȀP& @.2< s 34~V5b]:'"SS[@w4(lQsr]z.}?ݽߴ8yHD:▚ .~[&.@b܄bS."J|"5XDE-A1nl"Lm' 6`kIP:-דvLNx&p=sux{.b뻞wϯo"Ҳ}eK6.=M)3A22=WJ[$BFymL!џ]-<w3\#m$X07:5*R!xDpEy FرtsENdtSL/1:A9-ͷ~C#:Z%ŋtmYz<i 04HTCm&b&)sG/1ST ߲%a=qd.%Eنc ~MJ]zV(ԧ~/}讻woՏ9ʼnk5'qjͱk9/(O8Btb$pDff)m:4'XWb&n}}7 f DH(6SJt4ɩd Q #ؿgs@p z#oG?/?{̳"l,wǦPX_:S'aTFQ !QZ` ֐#]H>I@ Xb&:2IhC[xmXw58m!c!Jjt 8F [c)R[?uJ 3˚KXyQx_ydrBdY"C|jx.]CHDkn2D5;0.KrL^$kuã9jlFuEA^TsUWK^7}:obkOǿqN=00xM_zCnrI4,sm65m[um*Wkpbh z֞q3uR U]\Xt]K]Ukehd:e<08<<ĉc|>c$/,%Z)99WȵPZw}Q5]!(%(VUkehTU 1bM!٤ | 4 ENQL&!麎O?囪_|.b"ӚkOOy5=e:-+F18:T"WJu&qJuRA$ e $JBPER 5hij9 yRr?g>Ϻ3KgQB)وޯ, O57>!$}@6-'c ahaT"D = ])[_0d:E));"/h@'g 5]`a\%."3I&.ˤNgɔZ!HƣǾ;>w|&.(ם~';65޹}:=Hn9:VyuI&婔8"(G%Z m8Kq:\..a9_(Jh/?|7{?SL*zxR^ރ p۸u ecc3%))4m:Պr0[b<BB&IkbR-Mu-U"xIJI4he/ǿOxOu1W=Rr#?J|IDATP C"=ӵ->)eY"S$޻Hu-m]ѮUg1:Vъ`6deY2pku۵f۟~|K^l,b%?_ƿys+)w޵<n?z\ͭ. BMCTxXkɋ,/O̦5l1ΘL)<1Yvft5\'=|_C }˯Bn'W?;;|pTRqM_?'7>M_CIENDB`jajuk-1.9.6.orig/src/main/resources/icons/64x64/ext_dd_unmount_64x64.png0000644000175000017500000000373711720500104025536 0ustar drazzibdrazzibPNG  IHDR@.sBIT|d pHYse9tEXtSoftwarewww.inkscape.org<\IDAThݚoLC(E|0D|"TS@9M ћ !Un(TԫBqAEpLIԎzza]pJg<;J)rGg@2o2̟vAR ohSJa*7'jWJiu]޽{|dosPfn"8"\5Mc޽q73oR@kvsddN>|Ғ'mAH* +Wd ̥Ցt]oIŎp9Hˎ~<~&YerG,*n\v 4y/6BU_{f$ < xppqLM>bgff( 9s, pĉttt͛&UU,hvDJM@J~y%XXXh)r}{@7&X,ַo>޾}|қ-Jn_wM+WB011Icn$H\߰-!rax Y,,RӧO`:p@l6|sHR?Rߨ7/_LP`vv֕vn&oY.C4E0@JyRqM7V*ץmqEѨc\٦hkk#Lv2RpٳNTr$[0x,/yOOOw*rtJ׷[ZEu+RիW)J>(g/1]Bp!8aO[1={*.%oY:&A&Y v"a ѣG@?)Y6e._ 'O{RtvvvK`3pmnn={pQ ݾnyyJ4 {:yJB4JhبVOhƄa"\`Ǫ6B4333tt8)V`<ȫDT1WE?FRU[[oo6H? !sIp;VU^655p[VvAOE܄%=_(wHd2o@85]H&Ygo"HiKwm R)'ogq:Y^^&ֶk/< G><\V'ϯnmU?41 !p1{{QT-:)~N-;vSNiZJiFQ ^f 6/ȸI$ X4@%B@Q r:A <P(DR!iJ)VVVW` !*V S0|IR,//x{m6߻a~ϪcX#<=`oŷ9L<}Htww{X8Mէo~5?¶rqqW^a/wP B.\jΝ43 \.O (Sq$&Q!^t:t*B5IRJSJiBSaEr=W)e:Gx=E)BmàOˬVVTCQQ{SZ P*@ ()*v秲1TOZ}i;0 ,8IENDB`jajuk-1.9.6.orig/src/main/resources/icons/64x64/jajuk-icon_64x64.png0000644000175000017500000002141011720500104024520 0ustar drazzibdrazzibPNG  IHDR@@iqgAMAOX2tEXtSoftwareAdobe ImageReadyqe<"IDATx{yeu޹}{;#f , 1*$"v% 8SeNJ\J%"d" ,0,~o=BaI޼~;ws~ZEGǓ1f$/b./D-؎5-  %XV!aX \g?q-[<'۶WCiO@/,$mnGA6Džy;==E*y#b}g8n_$:+Fk?k/j DFNF`!RP*- BZ8DxY-+|U6e`erp|*J7T:t3/+^~+ov8kfDL?eX1l +fN.m zQQt\c$USSbâ(V5>Æ*u`0Af@Giyϯ.=ڏs]w1R׾0?anm#w-:PT!]o\\] dAVWd' cY1D(zO*B=*ź)ZJp_T4x\Vllll۾\F/7[1Y]k{wй8Ok4sXL&=z iz(0o{*1T(sH ܞ֐BC^[>O/Ȳ (Ҹzns8 I,ZqGȱ6yaqU.ig-EU-Ge` v5`M@TGHYkuN35$ l ŏd3##b<ۺu˓90 Yl~ʘ"W/>hgPJ-칯xg'A"i=j_2ؠT`41iAƗ ;_Z\.J0wKwKK5[楾yPav} yß=xޯTFslZjzqU ME)Vԅ.9(p}XxMXw_klG%8JX!FL![^8JwmC&@9 ^#>gί\qbRАzv7AjəQ~啼7)(3p[y'.Dvc.gr-*<ѬBCTj5鰐h"v[HgcJi+QXz](:c%w(^T\P2$م8>@4nÚHH7~I{5'S,)}os)u Di_C2mx.J2xY"Uf@ k@)uL /XtΟ{+?|M/p),?m dO]GΟIVUD6.ERa!Mabml]MˋPǸyajf"_0Q =rYXJ!#/2-7Ic] $=/>wޯH^?xڡ-2i8--)J_ G\';nd Q{ Z!9ˆi4&|TW @,8De&pe 4t Pzae_q$-@& 6MeP7woʷ}GKK*?uzgTlFt]Pƥ5=mډҮ](e] R 85\@Q8D&"Ez*E3$x+9u_4t(@ \=J hQGaGjx0'uz{.?l{ŗnq_3@ĕ)Ek^7zJVHBu 4% : @nw(j8@w GSQ'j(,usJ}T=kXH}C ot͂A+4(TR d;ZrePbɓnymss3\vR7N `u[ο 0$3 mqqj.mEХHR##+s"Æq^v(xe9m1h!MDž1[ FI5I`ۗ!t;r-J,t8t>zyyᥗnEq^j 92įYa'BH&r.O'F kx^(!%daP{̂rhՖ8L6x-ttyLX t vN1]2""eԋe}q*;SUJ N {gMTu>Xk, s``pXf Ń$~TܸTanOabqdi<+3V0%]`ʱ ҳt3 dJזj>{ }=+<ߧM? c*XE*g%3W,D\\^RRM(CV&Ѭ+4ւ|b/o3[*LֲaĬcCN_R…edx pk(0[LG Ot;5(@t­bbM /2ȃ3̅B㞵iBE S6S茮m^S(+"7o}(B d?Ɯ䅦df$G"܉0k/bm=ܹgwLnXE8DSew,%s/TL'NMLFq1+)󸗩+ G$XecowO:]u\&/2Õ~):ȗ/dSt r.yZ12vk{FJ.,-*8࿊ \(5c &幁Cu8įkvGC}V6Vcú>*@\@9KNe87ɾU7هzr\'l68 B%+UXNdi 3-R݅\HJJw H*CPX6TAXHtSZR>tB=3 X?Dzx~;F Om7}=p&"+*\zZ;6kTwurk( $6ߌ}V))TViim2n,C yjk yFW:&[oЗ;Xgs݇rG|4L|T:@2GXkܡv/^\)]UY$U֩LضX.4{g ܴSm" {r0Huw`YFpƖk{ФDkk#\$/L,Ty 4 Mܿ[Yahin UG݈(`Ya('PyiئGx?Hm) : zOI٥ E-YI+ӅR񡋚871{,)r=xS*֙ e\3 $r 4 FhlgxiB0~-5u3n! P E\ ,R/ tQ,b:2%&pˁ %b^vR KM)[cf<u4 Rej(ڍT:br CM7PݞeϝYp_`0^ZZm$:zWȭ͉F*.Ϊ_, 5*Q m7??њ Ґc˴Q*^5$i4f‹$SjNu7`B]]l"@`B5h"uE}wۏ^3H+рe-3 v0%ԶưL$#73ica; On}5bZ .r07;:t'=VN^?*}.s6@έyDӜUb!A;64 vh,;DG%i(KsTR su(z6RωW\nh&=WF#X=>mNΖb d QQ^F[ls2ub[aY:lۣ߱05+jp%ZuB넇FչɻHZ[q2l 3[?w6MQւI(1 pKNٻTL PYX7;LupD9Pa a: ӝ;iCW^䃭?yfeyhLm^غZ"tVV]va#3mM7&7$F!`AN?uLN i`I`,LD$aJFHRgC:t*83_|eEٹg]uՓF8#< krl} 9S 2L_ 3f5hJ m YLULHL/J&>1c\ !p8gdI `8 E}[Pih>y!hMp_np wW!+#CaFE~F#эka֭_5=-Jl k(5OTOulRb{FFq cW4u] [i&K-32H5E0Ԝe-S%{ l$,C&nL^z4j&]W^}U3le]Wvq'~)ˁkAWVe+sWغ;> ,S$(eOtW(3 l䘽G=B L/>mLJ*Y{ՒSY}e*˧c9wfM=jW__dnn: {_xnrCfR";jeoKP4KRӗ18^ȭn!Z.uXnNT1(YL VLǾzY_$kD92Vf7e@Tܗ奮]֯K]soXYE[/8ymYXPaǓ, {@^9uYOڒ7ClN9tO]@$NfBdK6P7^8BX%L(G]x8U6>%d lEŷ:m#Ff9P6=9rپ} y圡g~3/|ѿݛN%ѓ@J 6jk{~Flq@c3Ǒ>dK9יrR-^Ut0˫@Ӎj>,R?sw| NȏYgZ48nҲ:B?]vihL;.ܖ^C2%内*F /y' L)>[cy{NmV6*dLA,KRl pew1:Viq^ZM.$sPC_^vC |_ם ?1<c}Kw177-Ie#nYfsr2}i9\<W%}ޤ0 -Yf*,NS?2McLRހG7gUAf{~qV7|yi\lx睷uۃp7,;pD^w9(A)m4.*80,5THgz>yF1:' \T9I>z6TY]:HgS33׿o](WGtpYE8لdYTy::i͏<ӓgo5s:q¡WAcl4y>EbWeE9P7>k9r2>,^wC(A 8]h|*$'; r간ycї 9sٶʩPG/XCl#t qS+mRa(!xݟMU?6 ߘ'o\N09ǔJ7D^sNI+9;G[,3Y-7i節EѴҺCXPq["g.mCfֈ0Gs)] TgfR¹w w?lZ/v-}l m'_/S77j0ZYCi&*3$0 =&rTQk4i\>-y {\F v-۝γ<Ӑ>% |jZ 2ߛ̓f $QbN&j7k7{,oQ} AUC}yyp_߯ǻ݂d`qlf0P4|qr???;N=>>]*^Ds?Z3Mގ9F 얼sog:_;xTefXSЕo;СCjy@0wǓ0-}!I"s%HRxv۶tFk52===.f]LABGGG GGG0DDDpGGG+HHHAG(LL 0/(%  ($7 FJ  ;;; +++ ?J   ,,," :::  ,3   $>,  23b  '    ,,'#I     ^Z !DDDKu?dSlPeIENDB`jajuk-1.9.6.orig/src/main/resources/icons/64x64/ext_dd_mount_64x64.png0000644000175000017500000002727011720500104025171 0ustar drazzibdrazzibPNG  IHDR@.bKGD pHYse9tIME  5CU IDATh..TTTK TTT'''A^^^\TTTA#bDDD'''!DTTTRDDD>>>dW )))PTTTaXXX ^TTT(9///<<<da111)TTT:TTT]LLL555eH )))VTTTbQQQ  ZTTTM555;;;d["""3TTT0bPPP///eTTT2.$$$(((ZTTT aFFF TTTTZ===666eO=TTT'aRRR&&&cTTT⍍***_666!!! N`222+++eTTT;ď!<000 M$666(((   TTTG O2j9IDATM&B   "  H   !! ...88812  <@?E 8@@@>F    ^***8=    }k3&1  $>,****^_8 ' 23b r8     WeɃIENDB`jajuk-1.9.6.orig/src/main/resources/icons/32x32/0000755000175000017500000000000011720500104021075 5ustar drazzibdrazzibjajuk-1.9.6.orig/src/main/resources/icons/32x32/player_play_32x32.png0000644000175000017500000000206711720500104024772 0ustar drazzibdrazzibPNG  IHDR szzsRGBbKGD pHYs  tIME 3 7IDATXOh\Eǿ&MYfw4Cbƞm%5 [$j4-,Z`( ^Z(BfKnm43!JԷ6|an3o><`W}k5siɴ8NDs4ǟh].5.Ԏ{2}rj ҒzjqqX sBYqd!ROa]R#`]v~~a@CCp]JIwtC ȞV[Ux! d'rpsRmۨ-BD2 {g fX*o8c?2@:CGQe0"R $ iT7A\^[S(L|`}6br`37xZ{Iu]wifff#@<ߠ%98 RR+{+%HU{p]7RTrddjh4 PJ²-؎۶<ρe)q @ 8X_eFQmr@"nAWm\T%u@.7qqϟ?D0gX,Ӳjx<C7@D1b ~)qQ*099ݞJ=p8퀮 c`ZZpի棍S'NյowСH%A !7_?;o7||ԙb,3_*RPӑs/|*/_=xggg@|7'D0Bҥ^6g@D+6#s |wf2ró*Ҏ:`><֛\D"Hc^&DTڊ'^WIRe-yRJWJv"vv|9>IENDB`jajuk-1.9.6.orig/src/main/resources/icons/32x32/playlist_new_32x32.png0000644000175000017500000001005311720500104025155 0ustar drazzibdrazzibPNG  IHDR ꂣAsRGBbKGD pHYs WtIME ? MIDATH _  $!   z)))1ɐ !"""O& &/$#"&-    #     $  .^b &   444B  0g _IENDB`jajuk-1.9.6.orig/src/main/resources/icons/32x32/ddj_32x32.png0000644000175000017500000000265211720500104023212 0ustar drazzibdrazzibPNG  IHDR szzbKGD pHYs B(xtIME  ^j7IDATXGkW?wfvl&`MD-DtbK h yhc)PAi>R*&i lEG6;>fvؗws{9/~k?O>Z­[O_bB(W1 L&UU6!;w- x׾}ׯ8vq-s%69yԛJ" (*h˲0 OŨEQTTUX4pI099ʽ{wQU.dž2ݙֽJ<?&all|>/C8{ "hiğۀl6[x:G ?;v0.]fuu5!=ڃ;1/q:;W ׬u_ ~R(r\p.Ο]/>_I{f\2L$L~ؠ)tU`ll .Fgz:p rlCCiHe58innԩQEwb~~>8r3LLLp qL@UUN08%333XE"h0 cÇ~.d2:pTWWL&BیN.ɓ',..",D{ؽ{7^`vvqW~?yƍW}r bO===uhpw:;;={ZHRH)4H$8DQLIJ,lFA>.Ve! N/..fٟ! o%U^CJX^Y^îg6R)f*Ԕ Ìͷm^fR+sʢ?O@aFzH)1M (R,iVHMPU۷\g^#M4!E keaY_Ls-TjBJ)pDտR>lƶmpՀQτ( R:P P=zd:t2r!@Tg $:;;OiiiAJQY!wL~Lp@pG|5h4J<8NJ)5WEe{o B` !lBB}ii>0`ik[noDp;ᓗ_@(yfE@775 nr9p <("xAk"lJmVqɗ<-4<.;W3<\_}["B 'RpwOY ' J ~ ¶% Z62I@@A0 "xgo?NF6fؔ0,2IENDB`jajuk-1.9.6.orig/src/main/resources/icons/32x32/volume1.png0000644000175000017500000000326011720500104023174 0ustar drazzibdrazzibPNG  IHDR szzsBIT|dgIDATX_lG?3w;ʱc7F@jSJ *TPR%@}@*-P!JUAj$OBB8g&/gߝvgxH\򕾚YHO;ۺy;x _Hla6t*7FByXZPUrgg1Bѓ>0,} G.#n3gZ'}>4D6my'ZSӷ BJ=}+l#Z4M=|Ip$VX)lVPZ#0uaHk@_~H}vەj7se}NNR[CQeKH8 , !%9KJ%f|Q͊7={e ]{x^vmz\ʖ8yxN:nngtTKcj[⣏nNΏl۪Nq%b8 97ta6  @&N^'Fl3aK}ڹ/^=_~+=k8k&?֚l6C[[;33y Za CCC w0\ W I(j2Bo`7Re"m8KZ%J),]Z6b, !jF$>($7J8@kT*e*KKDQD5qBي8i!Jc{ض1f[G1qZHRF˶+wRqmb-E\z(|C)1Fe5!"KnK9-,˺XÒ+rZCk$+Jp@ޥK#}[6z.5eQ.GSJ9wkL+iy97=]@)T%2RA, n{&L8 |\G T+U0CX/R'NRɀDŶ-N6 19u籦 !uU۶8C!P,i"f-^8thR]zzJ }}}Li Rd2j0ǚ0 RnwW-Okm$ɶz˲PJa 1 sT5j JWg.LN'3~T^xΩ5J.7}Mxwp?ixl5`r%VX3W(QXnjg^ $ wZ:2O?@&R,248@[:h)-\ܹI͈ Hq)Xyllw#@j5\ j[gW-B}kx#l)%yr,濻'ݳz/,Yp.\dEv"_}E\x& lUDod͕b~EИyjDcb^) uq"^EJ/8;93  ݿ=7tǍ*b`_wCbQuQDy4F5v3ΈĶ.o(x~OVp v7mtc nF|:|mgw fL%8v^ݒ&JLB H6d%(m u!7܌6~pm_x<>dVA~,b||H$2`vh4͙f)ehOviLNNloorI*ʁyPz'N  pҥGFF&mkKD J144tP(i/^V8ήZrVhp)MJ.EMӴϳ,j)~ձm\.a ѣs)!f{H)㌏z>؂+gϞ:"NհmӧO t:M^*n[VVűcPJ{H$ѣGmN/-۶V+8{ۂvT*nܸC_u&''w<BB)^SÇ>iJ)z{{㻪qMP866H)}(۶FA&appZCHӻi8B,"Hw0@.ٳgH)9|0ia`Y4LbY_FA" Rׯ^b #1FIܹsai0 v:RbH\FJix˲hZeVVVCut]$5ԟ<d2 "\p0,Hgl6B`rwL&b~?8O^PR黥ou]O{$I޼yC>gttԷ7wkMӐRcVWWy J]׉D"!Rmll|;G~v^ v=f6pff\6SӃiAU)EVX,/nիW ; TI ؑORԔiК*Wէkkkݿ׍-7T:@(d4 ;+HwW%-TBx-2\}wxq濡Q-˲ IENDB`jajuk-1.9.6.orig/src/main/resources/icons/32x32/player_stop_32x32.png0000644000175000017500000000107311720500104025006 0ustar drazzibdrazzibPNG  IHDR szzsBIT|dIDATX@Iۓ "DAo XdyۢF/ !s}28餓wE=}/ dO?$O۶xѡ9Gʲ2OӔg/RH3~n:;;@ˑlkM_snDOGS0$IQ"ks7ԶVfAEQ$8&vǦ -ZE1 kh4ڦB!wBhiCCK!MSem E [nQ<";HIY b/DqDDW$FKwX,v*M"H1ؘtG`6aeY&)c; ̘L&LfFAwgP]#ZToja54 I'm3ia;̦z_d6%G$rVۺoƟtI\?;:`oIENDB`jajuk-1.9.6.orig/src/main/resources/icons/32x32/dropdown_32x32.png0000644000175000017500000000310711720500104024301 0ustar drazzibdrazzibPNG  IHDR ǂbKGD pHYs  tIME ! OntEXtCommentCreated with The GIMPd%nIDAT8_ + ,44rrw'#؆F1IENDB`jajuk-1.9.6.orig/src/main/resources/icons/32x32/finish_album_32x32.png0000644000175000017500000000356111720500104025111 0ustar drazzibdrazzibPNG  IHDR szzbKGD pHYs B(xtIME .JAIDATXGW{l[?۱c7zB Hڀ& @ J$4 ش lS5UڪHTHDa t@!-mShhqI48N;g;3zkܔt"%Ȋw}hK) [,,mcQ@Qb:74M*+*$YցL<v2\mo]|bXln +ǵ0 A0wv`'{WUeaUc{MQG rS pco. .ZXaXY&CgD,h<qP㭴ܳnك?r{*fŲ7' A Ӊh2LeApm=3߿¶ ϕ:aշq%5utg4jJ*uu5/twk[fNW6#AV}rhYInXZBW4F dMIpű/g~[˲ Jtzh, =λb7{]k- EK},5K#z4'OL̉;/w|*]%J%%4zv˳D4v7-AcՔ.N\D,uODf_==cx 1;O:lq ߭ߟժqC, 4i$`th7c grQO Y{}tبhVuvߝ1W ?z(n= VˑnژVB`V[Eu =ً`9LsϦ7yRBhWIF@A[:a 53]-46EH`DّEJsK/imX"jU$32 h7^k(xڲ^$ni^]*ċ= C5~|ץTzk54|E,D8SAMf^g'.r.qHg 8P#F5%RRXGQk#Ho.Fx4Q@ytTub*h(݀62rD⻨b6f ճ_Ĭ2Hc̓Jf2H 1hD}l- M}ɪ DPWF}+toX'%8OSairjN¹~?eN_]E/ԐkLx2y@C}0:CB}U__ӳݶ˗R ֓\W47a;;]}Bqȕ< ;Ou2wr\:O496lwplxlH Xg@^Q\0|Km,z*bO1Wщ3pP^?\}nϽ#M_z֓y/ sCmUv$ ypy3L߸w&#g?/?|0p'4c4k2@:ނyBn]wy8)HoJ['/<8ӈ&b%/[ 腮/;|7/|68P'~B8l?<( jCDDc+ڤ mbd, htzCӹ?Eg1wM8mIB' HO8_ uZ82ᎌyxm\'M~YZyyH-W*j\j@ym%n^ӘZzѮKn"ql2[ӋͿubă Xq5=O!IENDB`jajuk-1.9.6.orig/src/main/resources/icons/32x32/volume2.png0000644000175000017500000000347611720500104023206 0ustar drazzibdrazzibPNG  IHDR szzsBIT|dIDATXmTW{;/23˲ah6TشQRc/1Q11i~~0M&BLmԚl R ]fwٷٙrvP<朜yN%߆.`>m u}_-&h͵شi#uu)Ky CCc"!O}CGOO\cw|?ξq5D];۶8BVkuyVruGʷw(֑kkO~ *5m458PWŗ^OuD3Ǿ}d*8BV˕1# sW$D +iOc`ǣBġܟxaaνown{ b ۓ ̇zpU{댎r{.S^(#?QeK91, !%x & spH|{Ͼt]{~<gjRlģ[:{rQ'ղeT+U([8=8DbӺ,[IR(BOƼ2W-Νb]f~~Hk֮Yv8Wtb6M"@:@R0 f޶->;;Ga--.i]嫗:čhL7Τ$T( 1={(m!):ă5X@kM&TRm[i:;;dyrd4R UG)U.;@" D RjC_9-QJdhiicu;FR-B[LGh4BJBŒp'a5@SsSEiCFS*-vGqnJ9XV#hjab) B eYss+-x*Je8NI$F1F`+{݄8N c BJؖER^Qʹ[cJDdM c~ЮBJI204T [YdY:Va$ 'FRpTu+\}d"E,bLk;rєmFvȥm uq R0>9I6J8 9adG3hyk+RZ,P$)Ƙc Q}0 Z0>1?HKWNhA'~z{fMq:&i/+BM'˕/hdd|}C ॗy\nR@qDRauden9Q:gk`"4F\{zGv!^2xkYV{XqᭋtsF3;3ϥKA[7t5 l>^8,yVsX%L=bKVڜmneYrEn9w]C&FJ|+hB[Nxvf n1w,nݰA/}Ėv&zShBs;~7$cZ271@b*@u]_݊-榸%39IENDB`jajuk-1.9.6.orig/src/main/resources/icons/32x32/player_fwd_32x32.png0000644000175000017500000000226511720500104024605 0ustar drazzibdrazzibPNG  IHDR szzsBIT|dlIDATX[lUg.;;3.wK`I A XR%"*&xA@kv)Xn۹aie›'|/NU,<{W ݼusL)۶G?-O+Z=<7^.HrdpثZ㝷w7+c-QE,udYV3KG?=oinrbj4q;iڶm$H$bԢcGOp[ʹmɆB; Xrٚ+H$bֱxgv3qҀ,˞R)5*3kkT}5ݓe ,[,jkxek#YʴV4'6 XL+ifɲ,BBm0^S StIekddī%@&w?8V!C8p#s_ݦb<=s, lpݖ444( z>\ׁivl[soaIlnmme[ C:Ku=7ooT*$BQHX,ˁc€Rlƅ_DLfE+WƦ_!EQ4m.|e󣗗L.P[=7[y.x}v%EQfA¸s/tIR-I|QџLSg+fgm$=iYId29gke%(b E#>JTTDq_BY(}"gIENDB`jajuk-1.9.6.orig/src/main/resources/icons/32x32/player_previous_32x32.png0000644000175000017500000000206211720500104025674 0ustar drazzibdrazzibPNG  IHDR szzsBIT|dIDATX]L[U{{o[J[m1)l8B0q0I!B/<%t!!X:RJoYZe Ȃ&/ܗ9wrq,+ @ Yaym/~ғ1x]]];=}~wog\.^p{ikgXl[Ŗw\w&TU}~@]E{{[P5H4I@(~uEElm(2!`8cY8⪩zl7}f 6ӛ407(Ks: ͗{onj VA4 g| NAt:}0d2577t z/aڑX[A&% C0 ΎꋅO=W>y7 KTVV*v[jXf#e2B`Yvt7GmE|x"Q$IXLN'nom~+FNtWr&34h'#ݷeyk1qyjwV۷bZ2<rcFyDp14±܌wvQes,Ą86h$ HJ=o,g䏏}(Y@@EYJĮg/?9%(J(~PbTR1*tQB u9$AЀ]~vUUR0ƼOx>tn`+ 8=S#BH:o;l$!ӿby}g@o5 .m x孶 81 *tS0SLPL$ DGc;F|o_؞JIM 1qz%pQxd!G5US jqi`w.ܡk:9|;#lgB<߂HL1o|&#'=دut]Gə&g3Z;ZoHF (vH% |>pkn={O<9pDY0ump$/ !,"$TṄ_ e1̳F52Nz)u>;0 ntBq6H%dWMз֥>oC/[HuBt~f} HH()j_0͇d@M~(UD+ڋ?fggga4ASht5ѝ9?5{ɓ+HIXT& C=☾8X͛V0`LTn5RJq! U! a(?{ #cZ7!q뉥)%B R*ToվjU=쳛˟=ʌvT|>aB)!~52 Jo'>Ԕڿ`+ξ?\qzwG|׽5aiGкUVmY0@oޣK/z{O1>1JZcFjxDDQDE LMy?յtsÎ頸'e'|>7Fشi#W$uˋ7whA;Gյk+GW6|s=k')$0v3;;ݏ!M6l޸BR%surӧ5Jl:KZpZ~kA; /sz1[fnp[`]>RLC}:OvkߛGcj|`]3\\lwOB; }Qr*˾4[s!~GkA(c|4ՙ.jkC4}!LW//رp/|pq3P6DZ <7/+<_:vN?&388(..m_lZ J,ό2>hY`}@ƪ|OTgܺ쑕 [0x+Y@.ZzΟl2..!d: g/9pzᖞN'ZXټ#e<|@2 qLĵ--~{g70VOYl6>婝Bk33zIENDB`jajuk-1.9.6.orig/src/main/resources/icons/32x32/shuffle_global_32x32.png0000644000175000017500000001023611720500104025422 0ustar drazzibdrazzibPNG  IHDR szzbKGD pHYs  tIME  .'+IDATX  HHH)###THHHWa---8'''EIII?aR>>> ::: &EJJJ ^_999"???%%%EJJJ Pb'''ABBB888ccbhheELLL4dW???BBB $$- $$$sss%EMMM)]]]111E%%%}}@@Bhhh"""rrr#222  """qqq$444 '''f NNJ333XXT885'''N--(  +-&EED" N***uuy&&& LLLCC=DD@DD@fh^ oqjWW[cbcbwuw`CE<   33.88;+++ zsrQOa ddYf  //* qo~zw#X"""|g886?((( 34/-.(WYRޛM000_aX "'(%زckkkoqhק000;@@@hhh  ``` ضDZ kVWR߿ T׳ 999nط=r8IENDB`jajuk-1.9.6.orig/src/main/resources/icons/32x32/playlist_bookmark_32x32.png0000644000175000017500000000274611720500104026203 0ustar drazzibdrazzibPNG  IHDR ꂣAsBIT|d pHYs Q Q^߿tEXtSoftwarewww.inkscape.org<cIDATHo\W?񼱃in!UihJihFvE%+6e+ 6,X2MS'ĨS7$=?ޛw/̛+qy{{ތxfO0RGA|{?N94 ?Oz~道Nx7lٓ`ASȷIW,.\0'N1мїV}WWc;Gq9sSl0QxG]=@.$!ۅFϟ]XXzzΝ}l#%zEѧΝ;wo_/c`&]瑙]HZzAnNCe8d=^k< sdY~ot W{k"z UjqS~7ձ[|"FƕADFX5[9f A i$OOIL @D~o>lh4p~ C"$p A/1H\R/;Z}($hwo]d{)؞J>,xĻ1r!TUj92c6D{m{26! 4M1a00BŀIC`=ƽ6Y*y!9|@\BF)V C!I:N?Lvã=!э:>ɟ 7Vs0GQ%}%ɞ!u? Єsӫqf>:E5JTC&*XqLc~,=&[]DP5Xk5 szf<VU'7Fj:v8rSgBݔܹtSVU=ᴕҮXCh_'V* F Ge~~<ڸuaq鍿gWxWVl?:j(7+SQR;wx8kO_>"B%lk6߽sz( 2bggg XUYZZ* J>|OVFo=#?P}~٘8^ъ_X{NC"SgNnKd'5HdY6|y|oZLqA0H`M2c aN$TR)>I͝sȲVu`ڭ{UG_ 1zHu?Q+M}0ko߾y.uat9gDd{["٥%a$ 54M6""MwIǏ?&;yM ]$IGQD*@ 98Y-ǧIENDB`jajuk-1.9.6.orig/src/main/resources/icons/32x32/player_next_32x32.png0000644000175000017500000000226511720500104025003 0ustar drazzibdrazzibPNG  IHDR szzsBIT|dlIDATX[lUg.;;3.wK`I A XR%"*&xA@kv)Xn۹aie›'|/NU,<{W ݼusL)۶G?-O+Z=<7^.HrdpثZ㝷w7+c-QE,udYV3KG?=oinrbj4q;iڶm$H$bԢcGOp[ʹmɆB; Xrٚ+H$bֱxgv3qҀ,˞R)5*3kkT}5ݓe ,[,jkxek#YʴV4'6 XL+ifɲ,BBm0^S StIekddī%@&w?8V!C8p#s_ݦb<=s, lpݖ444( z>\ׁivl[soaIlnmme[ C:Ku=7ooT*$BQHX,ˁc€Rlƅ_DLfE+WƦ_!EQ4m.|e󣗗L.P[=7[y.x}v%EQfA¸s/tIR-I|QџLSg+fgm$=iYId29gke%(b E#>JTTDq_BY(}"gIENDB`jajuk-1.9.6.orig/src/main/resources/icons/32x32/webradio_32x32.png0000644000175000017500000000440311720500104024241 0ustar drazzibdrazzibPNG  IHDR szzsBIT|d pHYs B(xtEXtSoftwarewww.inkscape.org<IDATXklwξl^?#&u0@E&ʫAR5_JQ4*6*ڪ)MԼ\ص cݝ | qnݲ9®-߻Gkaƞ l(VJq?7*@J|{ D<g2@ݻw>x#/!!Dd"br.9vɶcmmZK5v%7r;c^[[kw*FMuM)ݰlɪ"O<~u!ay[/9UUW:yj*xR^AVO]%A #4m 9d纾0Қkz,BXG^q]4]O@ݱ<8X}M Be N.9ߎ/;{c_8`cc8 77`bD{{tDOgv"qR4)[Wy/e T2 RV:#6K.%,}+` ܳ~eWe oٴrEiC)uo<B]qM&$%%}=DCÐk%J9rWgU,{iׇ\E"~T<>CZć&&@)99d䕕LGrr@Jvn޸Qkj9}`0/}䑠o )0Sy4onr]3UG}r #,\tL,;/23JJPCCmڔr6`l"_ [ӊ"KS)BS7l g5qrtsxYY((b|py9_ R $46</*DhdIR, %52G{2$t](2 T4wBZ H yyyhD*23qO@ uNv6 (XdOwh?quf)@zWlB${{Lt&qQiVW52ksi~< THiv$8ͳB裣ddM#iĆ `jdF0DuQJ.D_ IML̤i5 b -"69Ӥ, O0/GYmω ?igHOOiFa!vg'ZVJB3gHvtiQMF0H֢Eyy99(C%Lvt`_Xf&+EEXgbut%(@#60QzёGl!TQ>N8bc1-(mInOo ;Q_Yc#B)+*"#3,`%)uD9M+Wde%b|N<Ț_iB/<%t!!X:RJoYZe Ȃ&/ܗ9wrq,+ @ Yaym/~ғ1x]]];=}~wog\.^p{ikgXl[Ŗw\w&TU}~@]E{{[P5H4I@(~uEElm(2!`8cY8⪩zl7}f 6ӛ407(Ks: ͗{onj VA4 g| NAt:}0d2577t z/aڑX[A&% C0 ΎꋅO=W>y7 KTVV*v[jXf#e2B`Yvt7GmE|x"Q$IXLN'nom~+FNtWr&34h'#ݷeyk1qyjwV۷bZ2<rcFyDp14±܌wvQes,Ą86h$ HJ=o,g䏏}(Y@@EYJĮg/?9%(J(~PbTR1*tQB u9$AЀ]~vUUR0qts[:N)eQ?b 1hLLH_&h@P S ҊPhowft^}~wjC'?Y9+k^k}vc^HLxL{?1zR$pZBtܹ& "r\.G~j u(x[ ~|b^{/?j=I ȹ_h%O>O"l[co<Tꖇ~Z-Xo}U{DHu㱟})n뺻{ǰ{L'ٔdKO7 ^}45%xhmm1e /%BR;o8=) = `9~D-۶?#JW˷8e eZqTJp~>qu=zg꜊zwmh澢1bdȚk[tя|Ӧϝ;ǡG8R`[˔XEĎ`Y&a $2sn% {=5Z.jJh퟽g`Gp.jY,Sb6F](XFlSY*w( CqlP%뮝}5cP(*-[' Lq\ǹK,V'LPVinj"Z^ =T/X ݈uwd]:~ysstuvp p"Z-$SI )D"~D"' hhRB] `gAoYB@ܔNqRRIZȓH$(˘A-I__}}}^O]D"Fa[U.{A m/ Dit@Ѷ,VVVftR 5ҔXE*bݺz7КlE6 Q\^@+);+f"ղF$LT*P\]X(Ac[i!5ϣX,*TQ4Z>NLa)P=hN(\!ePTL!ꚴRC0 VVVOY_`yy˶.eyXaj" +Kuegw@WB"aӫ+ YWRR ێ0?@<Ƕ-iWql;!%Z)LàXce_%V` bq.e!$295M5I< RmmnaˉbvhulBi(Kxa)6x@TBO]6> V?x,A$`T۶;Cuio@qdLql-,("RJ G -hBN-Gsgs.4%N3>Ոb 5a< [V27 e!%=Ti+#/;8281;;hk#-Ve݅i(?;漺}McORJo%ã/yP6o/ e#q'$ ;E/{J2IENDB`jajuk-1.9.6.orig/src/main/resources/icons/32x32/mute_32x32.png0000644000175000017500000000337511720500104023426 0ustar drazzibdrazzibPNG  IHDR szzsBIT|dIDATXlUg?9=sRnQ:Dnj?dmbLLX3d11Ѱ2m uDI+a26,嶽?{9m`sϾɓ''}?K䮮]>* ,J" Ou>Mh %hmK~4b EJLkh}!g={vLF5:Nƺ:V],KYons?~nNc-TH;ײìj[Κ˚MOEyWhjj xX {Dض[R+Tu]'#&i -1I$7 i:T{4sydMhSoOyo[H@ڒ@J 48399_xW vnкuO`dd7T*d2WmCAQr[Yg&?c=ڼIKBk׬v_x{XE0$  9!'D88x#sss4bZ=ZoP@]N>?C0-~r9Z'r JyqL 8 hКMuٖj3(H$b eFe,$VVPVkEh4LRŖRXcKI>S/P,ZcXRJ--I%b|bq0Ms=aJE^.TZQ*() xR"-TU"|E aYZk\%X.{>QƼ% ÛI(QgnB0LY&'F'BJ?g~D23J>_cK \а LӼ>34K2J)l;Hۖ#ׯXO0ĶL꥽)N˧>08\Jtt(1Kkjfpp_WA,$h澵\! 9b1ZXI0D+0 ",Gw@X|a0^:vbX>Wb&c1RVDQֵ5Vo87SXӳ'Oz,맺--ɤ7REkqRyTQR_^kNrϞ]@OWUKo;Ag}i뺼ʟm%b\X(Vtk ۻxCCn M oڶѱOl{Ko](O,],d>_>s?|4UBJukאH1 I2,W||#4m~P/hV.,V@Wnn6t1LiڳLt0*] ,\.u8e8N&Y`X HY~N&Y`e o-A,Ḁ<8u]*(p $z—xlfao,K̎#$ }/*p=!*W,,u]^\Y@3$ (3Cf5kcG2MȬW'fM(my~i~$ H:;ιfΜ9H '0IENDB`jajuk-1.9.6.orig/src/main/resources/icons/16x16/0000755000175000017500000000000011720500104021101 5ustar drazzibdrazzibjajuk-1.9.6.orig/src/main/resources/icons/16x16/update_manager_16x16.png0000644000175000017500000000134411720500104025432 0ustar drazzibdrazzibPNG  IHDRasBIT|d pHYs B(xtEXtSoftwarewww.inkscape.org<aIDAT8MhgUP)X+a^bzR=xQ{X,-x\-".QVVkMYkCs7<1u5lvT4Akw?ͺ|k-DZO&g:YzY Ra!>qQIn|Pg}T^hpͅQ6>}h%(v{Jst^ndv\"=3LQ\](NƒHTEa2A\ʜw?5@n焈ۺ=ܴ͉gH~> ␱mh?fKrS=V0Œ>6wM3s ^lu =a.L%5Y[iݼjڿjǵ>H`r0_WV? M-^YJEМU/D Q)wL5IfycPB'9C'h8pCZ4M>3uŅ,ic Zt]5XkM8$(c c EQཧn_INs0Ix2EUUE <VUR @ :l6^HsDZ Cq'yx)ιFE+qղwL,IENDB`jajuk-1.9.6.orig/src/main/resources/icons/16x16/type_mp2_16x16.png0000644000175000017500000000221611720500104024214 0ustar drazzibdrazzibPNG  IHDRabKGD pHYs  tIME 2}IDAT8:)kN L{FWWh4<_(,l!8՟ ]#[ho]T@X 7HME)BF zb}jQA54KinW7cm0H hCb ~W4]Թg"jIqy}_݄5ffж7d>~eKEQu7`g9J=6` 4&`Fk-{ˏww`T"1Zn@ Dp@L$obc3nVt&Y;"<6?c_xń aq9GLn@=IENDB`jajuk-1.9.6.orig/src/main/resources/icons/16x16/genre_16x16.png0000644000175000017500000000106311720500104023554 0ustar drazzibdrazzibPNG  IHDRagAMA abKGD pHYs  ~tIME ;IDATx=oPƵcb>J Jl##ԍ  4C;' !&1?NI8X1m8Ցy}ՔR\TceR-^ƅsضmBሺ_QwAaꅰk׷/Xf1<g كu 7oH}ŰMiwC-,x8{'$iJ6Ȳ }*|xy> 8|{y#Rt6/ho^Pa9xxB2IHҔ41rhmT']_?C[6UE*IՖi HeSU! ӅK^RfK+Nm4;!՚O<}~>t^ǂ+3cme >"IENDB`jajuk-1.9.6.orig/src/main/resources/icons/16x16/novelties_16x16.png0000644000175000017500000000103411720500104024462 0ustar drazzibdrazzibPNG  IHDRabKGDC pHYs B(xtIME IDAT8˭1hTAww=b A I#MR (X( ;H) h,Ebl"*Q]۱x9#xQفٙ4h0lڑВF4ѳWc[6#H>/bJi"/3sV,1;ZEsSpZ8vKo[G-Cb 4ET }W(Pٲ ٰ|r@ UPmҏHV?1(>9! d Bj}Xk`<h~pb+@zP$3_F0׌Q3_Aszy]❇{ 3Al'2=֮G%J=.]q{ klf_o҇)IENDB`jajuk-1.9.6.orig/src/main/resources/icons/16x16/complex_search_16x16.png0000644000175000017500000000047611720500104025457 0ustar drazzibdrazzibPNG  IHDRagAMA a pHYs  IDATx1nC! ?^SUݲAn)ޑ l Kcxm rCl~ W(96_fA8#xY0v~?`?V(lYZC!u]dzghLe>* h_`HŋiEkD C凗8LA(㊤FKtn-ZB]ZIENDB`jajuk-1.9.6.orig/src/main/resources/icons/16x16/webradio_16x16.png0000644000175000017500000000221611720500104024251 0ustar drazzibdrazzibPNG  IHDRabKGD pHYs  tIMEWIDAT8I^|VNA0㯬ҭM`8Ru< ):g]jWD  Z Oct'(2:   1ܲcT@L8&7+'&36J 1 !4:1! >1.U$7).)W'  Ᾰ&%+.*@+ ,  ű$' * ԯݳ8ЦŨ""& @Y}&''AQGֹA# "- $!" VYZ 43yIENDB`jajuk-1.9.6.orig/src/main/resources/icons/16x16/test_16x16.png0000644000175000017500000000121511720500104023432 0ustar drazzibdrazzibPNG  IHDRabKGD pHYs  #utIME  ;,IDATxOHq?sgmͦ a`4N B+iCa;䵓dl ph,xs:nE5]y>(!*bty 3{{<*3h1:$@!G綮xHLʒNiOMd^W뀪pgOœ@֓y @#=1//n&u:!+ !x.*Ji9dk$20靛T" o{ 7s9J y^e,*wo_=a0ky_Ns]oC*,ռH$"bE$PSIrvRScV:c$( s@ḏt]'B40)F+%(CL$n 7_YATUEEj5ZEyq!?:2bl.ڶ >Whnj~s:sӱ,0plۀ~11>!dY{tMVIENDB`jajuk-1.9.6.orig/src/main/resources/icons/16x16/donate_16x16.png0000644000175000017500000000230011720500104023721 0ustar drazzibdrazzibPNG  IHDRasRGBbKGD pHYs  tIME5tEXtCommentCreated with GIMPWIDAT81nD nϑ%-*9o 4_Ū )& >`.` Ҽ!$ Ȍ k !!/)% )T@пkK %*2 '%K - !* - ºB<UEd۸   6%D  E/Qnkx  ZVdþ zd}!& 83FUN^hhZ۴s{`<3Ft 81@kajt1ṋ$!"LDQZFco *1nD&߀ңIENDB`jajuk-1.9.6.orig/src/main/resources/icons/16x16/flag_pt.png0000644000175000017500000000142511720500104023225 0ustar drazzibdrazzibPNG  IHDRaIDATxڥS[HTQ];3w>|c0Sh=L@>¯4## 21¢2e&+'_`޹ kùܻ]gfXo:[;le 0d.FMZ3ZRZUUW|u˘87Bdv.ɋP^1 Y0 .I28n%nz⡀:e1V %!GhS=`t Iv`ٛB/ê ߛUSpY4 Hչ`.LN! cfUe=c!(Yj?3Ѱ fr N97䦪sˉAC1n>'d\N,[va ?KL@h-Lԭ~0&pe6V,^Ah2n|y7TvĄ= Mh#T,U|0F%up7RJF%Di3L5(RpdxYB@Ubq:Ԉژ FZ&0*$P^1$"$P}M+a"!bZN }0N .eޜ\eI]v ȼˆ_爫K,st =e8x<B -Z9N= (oG_Q^%mxHIENDB`jajuk-1.9.6.orig/src/main/resources/icons/16x16/ban_16x16.png0000644000175000017500000000121511720500104023213 0ustar drazzibdrazzibPNG  IHDRabKGDC pHYs  tIME 2SIDAT8˝OQm 壾Mh ĔD2iҁ";2tf#@XD0hc$-M[(=}KOrs9nTR<ƽ,e`z!~; -L&a|*3ef39x7Lr{UE XCwOMRSWt2^,F{sm4@UAEAi|?öj2CX[C*zbŅ1S)>olPkf-`~2rguPqTqy<`>?>|DE+OoA5?JDQ`zpT?P&×AĽQ7<7UD (Y "":'V][x%u7:NCPcG" lZlg w(CO4Fz`VW*H$p }0vrjܺLv_“QEEpM::_΋nOGfXvwIENDB`jajuk-1.9.6.orig/src/main/resources/icons/16x16/type_mp3_16x16.png0000644000175000017500000000114111720500104024211 0ustar drazzibdrazzibPNG  IHDRabKGDC pHYs B(xtIME :IDAT8˥=hSQ{{iiRFMZ'gnA]:?vEEإ(iO" $i|M3}sυ ld.lut8qLS]yh8&}-J;?1K{j Fl#4#[nnQ(L.5JdzCogo bY6DNH 7і:72eCT8Oc X5dm7Jvk'0' %cp3ĮL1Z]ElƷsjv7mDj1R <=z8ۛ|^?>B>@5やb鑃^`JƘ. mEJ_1ψ %F)վx+%S^|ADmt@k6!w>z7)̄t}pmb;Q.}xZd86'zT_d#l^IENDB`jajuk-1.9.6.orig/src/main/resources/icons/16x16/remove_16x16.png0000644000175000017500000000036711720500104023757 0ustar drazzibdrazzibPNG  IHDRabKGDC pHYs B(xtIME ;"\IDAT8푱 Pi:+#mF stԶ"DO!ʳ3w&H6暺`?S-FIENDB`jajuk-1.9.6.orig/src/main/resources/icons/16x16/explorer_16x16.png0000644000175000017500000000057211720500104024320 0ustar drazzibdrazzibPNG  IHDRabKGDC pHYs B(xtIME)0,C]ZIDAT8˽JAEI,|h%"h pNxZh{k%^R8; }IgN.I{Z!$Q }ӗ0ƙ17:#;֔v/Fٷ՗R^;Zא FrS(ҿs痔#\Q4<˕ZGڂOG,@0!`+c{R>8'Z;k LT_Ze҆IENDB`jajuk-1.9.6.orig/src/main/resources/icons/16x16/preference-hate_16x16.png0000644000175000017500000000160211720500104025510 0ustar drazzibdrazzibPNG  IHDRabKGD pHYs B(xtIME ;@IDAT8uKhe?sI2L.S%46b mS*MJuS ,т`/ZcBBIu;3ęf2sZkλy,ZkĀ8.Fe}B_>s- G*lcbW[gUY N77'+oGvOt_cKLzUD&h<8a\kzps;_PrVUوkH 1WM/ .J`Μ:K}fk_dHgl۱|1 [0|%v3jÞK:*Rװgo_ E}݀*'ha<` (hU`YJ/y@u{04G(>:o!&JHYFtڮc46%'I}b}1:i{QS4ufMh `I e3VTu+ݽ*dYe/&:r ԖE;`m;3͟|ƼsHG[u^. u/_|1#ғxH?~`?h(N17}J@KS.6"M^F;.͂@H Z碝 "8->=m?6~:mU]* 8nȐu-LW+cF44fC]̲8vO [r^Q 6 xX,XzkDk8dw؊2nIENDB`jajuk-1.9.6.orig/src/main/resources/icons/16x16/stop_16x16.png0000644000175000017500000000161311720500104023442 0ustar drazzibdrazzibPNG  IHDRabKGD pHYs ,tIME FIDATxmkh[4KKKomfD NNDPG *! * (E bQK6Hbd49iҜsQn~?svۨ˲a llŲN'N0neG`ö*MƕNS4!|YoДzfhD㢵=Ch~?jOE̪U[?@q:Yi:B=3~\wz$– ƹ 'GU^VOo]`f.*( C_.>O8W RU"} j:r+pFDs)%(6hJ- @`fwk+m ԭ&5RiDQ$>[ //0݂rQ0ŠNI>a'ˊPz鍛K^p/1v&XVv$- x h6z6XF&#z,Fef'?tv<~)ߎ6Sxv"7m*Shdd2Y ;Q{v?83B}ȩHH|2,oj#~וlgo!g(5Š.-d2 *2kIENDB`jajuk-1.9.6.orig/src/main/resources/icons/16x16/type_aac_16x16.png0000644000175000017500000000156711720500104024252 0ustar drazzibdrazzibPNG  IHDRabKGD pHYs  tIME!(IDAT8m[Lu?˿J(hXWDpRE`jv&LM4>7\4f&hᜂFQ6X)R(fu|Or#f8%C+jiq;iҵ+yob*V]-xv,ml2NGzZ8?7Ϟ>&'#{4*fs_+!尡b,㏹ jbߩo w1|xz`|},NMc ;e,%9csÁ<`F6,&&:JS*qU*|,ū=)^޽p Τ87b_k3;Ů+e)YgB͙70e(%R y{kɥ S%C+IV ZKhіBiVC~RVe^z ?\`Z Ht`s=WyN:[!<`>s9P/@kV,W?l|x38Ğ ~6N^F x"g>8;B2x-"I я#&Ӂ(2];<*}gqI,aSl\f Zίxq} $r6IENDB`jajuk-1.9.6.orig/src/main/resources/icons/16x16/type_ogg_16x16.png0000644000175000017500000000124611720500104024274 0ustar drazzibdrazzibPNG  IHDRabKGD pHYs  tIME%3IDAT8˵MHTa}3 cDELX4DtmFʘ-%h%$\T h?`HZ`MfhLvgtzHPЁ;9=1.7⒆Lv11 B`rJ]m/(p"kV6qΜIv+Kp, ae36Cf2j|6FUyi kad ^>K_|@=WnR޸F!ʹ2RA:YdB%7O~LJlݟQ1I[I>z\COP~]9*⩓9P}R vGGAGi)U8iJfirr2)Ο6<8kWC`eJ1܄]W.B?d9Hߗe4#To7 Ua8s`F-IUƴ?c'8F,/]%Fz6jm{+ @zl_&valbݎ?}c0;o NG*6IENDB`jajuk-1.9.6.orig/src/main/resources/icons/16x16/jajuk-icon_16x16.png0000644000175000017500000000166011720500104024511 0ustar drazzibdrazzibPNG  IHDRagAMAOX2tEXtSoftwareAdobe ImageReadyqe<BIDATx$SoE}3mnjTHДP*8T *zA|Dp\9DU9U*4$w3v{7om!4#HӬG~Jvxb;a<(J;/,4uض 4+(Y Ƙ:8- iFϫ ,}O߂5MS$x(ǹ(HBJ"`Ja gӇ\㱏0Kqö-dYc2QIZF$SSK^Ul[r/ؽ;qbtqq=BHL[Y]`&|?Xm6׳_A.3F'> ܙ sйGkpFa Fc$IBX*2Pn"%q.j̓Q(pb R s$Q% Ko.IJس9ԂfJ8reri9$ ґ(XpF E8sb%/o.^]xuFﵚyf LHR2z&3޵7*x4ZoeXh24}3Ï}o )JBvz X`~9lIENDB`jajuk-1.9.6.orig/src/main/resources/icons/16x16/dir_desynchro_16x16.png0000644000175000017500000000221611720500104025311 0ustar drazzibdrazzibPNG  IHDRabKGD pHYs B(xtIME +/-pIDAT8]h^v)E[}Znv)@Nfnq  PNRpqVfr VWy'    * (#F0ϫ{nM!?Ʉ8yk=UIENDB`jajuk-1.9.6.orig/src/main/resources/icons/16x16/type_ram_16x16.png0000644000175000017500000000157411720500104024303 0ustar drazzibdrazzibPNG  IHDRh6 pHYs  tIME 9%{'IDAT(ӽ 6&P  ./!  $6"1   %.)7 BEF " BBA`a_WSb !/06  E?8 643"#נß-=3a    ٵ¡1,1      2 Ҿų;4G 5.C79Ӽ׽3 笾       !    "( N}1$IENDB`jajuk-1.9.6.orig/src/main/resources/icons/16x16/launch_16x16.png0000644000175000017500000000147411720500104023734 0ustar drazzibdrazzibPNG  IHDRagAMA7tEXtSoftwareAdobe ImageReadyqe<IDATxb` c`hxg<$ֿ͗Nwn h@8|ᲄ  s"JG?ݽ'[eC} Ⴕ @Jgf`W9;+8ݗ fq%3049Z101p r1p8 3|?vA ?>3L4BR\Su9$ t_d`+ οfx^s1@ }"e 3~g````ϣ W6df`WaX/A .g`(ñL/(?=k>031(1Qd8Hgdo8 j Ò4Xt=>1d`I \:3LZAC7ǯ `bb LA@טOFn1< Ë @`tK=9tE@/K.@?=^b:` ß jL /w1Z omx!C27ç ?ޱ0pͭNkԀA X~aȿꅏ>p0&gxi~/" G>IENDB`jajuk-1.9.6.orig/src/main/resources/icons/16x16/tree-table-sync_16x16.png0000644000175000017500000000110011720500104025442 0ustar drazzibdrazzibPNG  IHDRasRGBbKGD pHYs B(xtIME  BmIDAT8˵KHQ>)Qf"UDQܹ.* q%V .BŅ5 ;]8jb2c\{={^e^-9Ƿ+bLρ@YW6rco;Եw'?G<[^۲Ll?a/sChmibjηh `X-y?\5CD[3s-6Z*l4:;\:@ }# 6Oo}K*x~v\U4U%ۛ8pĚ 6m܊659ď_Dܙ.;E 0E=4m_-B78;Vk]Jv6>6 1Ѝ^~YOQ( =?uL]T7[YZxe+(K6Eˌ>ϷqZ +Vy\yz|qcj;'Nl8WPq2"hL&8#/ *w_0LߺRWM^O3S"WB*k9B<c֚26i3Y]%BsUIENDB`jajuk-1.9.6.orig/src/main/resources/icons/16x16/mute_16x16.png0000644000175000017500000000150711720500104023431 0ustar drazzibdrazzibPNG  IHDR&N:gAMA abKGDC pHYs  IDAT(U=oW{Όgf|1x@ADHt(\!~_GCrhi@Nwe]Ν*9s+U?",qL$O8 EYkE)9f#.i sYX(Z8FD0!$ApRj֚p̥K%.^chS5pCE!B`cg5,C֠8FDУјVD&s"NS"οzIn>Vh8&*L}TxS.3u=+澹Ks!ZKhx}zJOp%ͻ?pU9$lʋ%o5[2o a'JL̡B)Ms}8$s49E"ru]P\ \@I17ȴ;gsȀx݀/|zyxpG@uOHRZXXОRZ VC 0a/ zbwLIt8l,z>ϓ-e !v{^aR Z v "8=bc.| f̙\xrg\uݑ[Ra&#lח=8`^K=@Dn=|C>y' f"/t 4}IENDB`jajuk-1.9.6.orig/src/main/resources/icons/16x16/player_rew_16x16.png0000644000175000017500000000137411720500104024632 0ustar drazzibdrazzibPNG  IHDRabKGDC pHYs  tIME ' IDAT8˽KTaƟ;3x;glf:fJ:AmEe!-]l҅Z" iUfBRr%,J%iE"ġ%ԤlbpaE1EM%It&JJ͊4Lqtwo5~s~s8T\L)%) 1ek^v}STޔ0bmeZqU7S{z?\!&,zIW׈%ooߓc,RFg}ZUYEӣm%Y{[n=v_0kEI珖D N Jhs;u&%srm'$=Wn/@ ,C-f PPn(.*rraB+YWUH43 sW߽%::6ilZN̾24PU}z YXXx(7VL6^|IENDB`jajuk-1.9.6.orig/src/main/resources/icons/16x16/cddb_16x16.png0000644000175000017500000000154011720500104023350 0ustar drazzibdrazzibPNG  IHDRabKGD pHYs B(xtIME ;=ClIDAT8˥;l[uׯ85v$"U " NB "10x@( * i}@gt~:t>%^4G(ʺi; 1\;bZu!eqa)癙ܩߥ\NKo}?bOӹ̟L dA#kgn?u- ɗ?xY|'w^)rdz S&D 2h7ZY~ߟ?l_Avoyh;kmcAv&I*ca)'Pz\^ u MB#+GңLYj1`lx,\dHr6y=hnpi1^hTŘءc5|6G3y4DU&ĵllAh{h8#L2L9lQ>^]ff&~>!տwfC;Zd#4:Ɩ66I'U2ST\(Vw [GدZOP$gxHR3NfW薷Z{108a[vgbۜN1 u +l|R뇲'뇃X<*S$VrnW=&z[,rg`ҡՓPÖ1ΰw6+&rssNs! { `t>_%?TK_IENDB`jajuk-1.9.6.orig/src/main/resources/icons/16x16/thumbnail_16x16.png0000644000175000017500000000105611720500104024441 0ustar drazzibdrazzibPNG  IHDRabKGD pHYs B(xtIME 6IDAT8˝MkA4ݘॅ\ĢSɃ@g(1 z @ ՞TD*C"&nٙab !{fgDQ[3ZyBQ3ZjQ31nKVWpf,µM4(HakM0؂33sZ$(l~{?CR@4yò,.1SrzoD'S@)_@JNh'-\̟.@:} b}x{_ʧ|=({hmh9%_}z=oj%1@usIo?GN7.nքaQN&x3iv$ĉqǨLdk&|[Z? Ƚk^CrB0EJXᖋBIENDB`jajuk-1.9.6.orig/src/main/resources/icons/16x16/flag_fr.png0000644000175000017500000000025411720500104023210 0ustar drazzibdrazzibPNG  IHDR 2I pHYs t tb?^IDATѡ @ѷE%\/CP {;GMRuh5*>n0mEA' +8>\9v2IENDB`jajuk-1.9.6.orig/src/main/resources/icons/16x16/star0_16x16.png0000644000175000017500000000213211720500104023503 0ustar drazzibdrazzibPNG  IHDRsO/sRGBbKGD pHYs  tIME"&IDAT(0JJJGGGIII !p...///p_SSSTTT_FFF`$$$  !!! MMMZZZ @ gggXXX%%%`TTTܠPPPp ]]]qGGG` <<<a555HQ? @@ 0)))?IIIq֠!!!`333 p!WEIENDB`jajuk-1.9.6.orig/src/main/resources/icons/16x16/editcut_16x16.png0000644000175000017500000000144711720500104024123 0ustar drazzibdrazzibPNG  IHDRabKGDC pHYs  tIME 1hAd^IDAT8˅]HQǟsw}lhxUtaIWEd"hiXi}J$ 0m36c6uu_vMaZ? <}rG$d F`Jiym7TDb$[ccbَ$w"V"rzM\T*( ,KRbȅvHx<"" '@ h4f儿P5N۶Ry =we;7\?2#w=CIENDB`jajuk-1.9.6.orig/src/main/resources/icons/16x16/configure_16x16.png0000644000175000017500000000114311720500104024434 0ustar drazzibdrazzibPNG  IHDRabKGD pHYs  tIME  9cHIDAT8˥KhaLM JƅE.4bfBp!T-RCBkAte@‰bW6IUiӗ DD:3nf1³{?'#Q X"M4QlRTlb4u#Q ZêEtFZdfx>XBr"2>06א:%Z,1`o %nFa~N(/;+tHRa %Nʿ4J'{( LA0: ԬN Gl6y75 irtI4Mk @ҾB0L8;77TIENDB`jajuk-1.9.6.orig/src/main/resources/icons/16x16/properties_16x16.png0000644000175000017500000000072011720500104024647 0ustar drazzibdrazzibPNG  IHDRabKGD pHYs  tIME  +T]IDAT8˭jP l"ނfuء-8(q%.]tiQpNDdМ)v1}qAG%rE"糈d0M3%Q~¥Dz׍j5z^u:JR r}Vv5Zk`:bfneYXVjWwpθX,<A$v{sN-fb1FA0$ C!Zm6& B\.|>RJ;pza4$h\..v-4))? ``0x}+ڶm1$IENDB`jajuk-1.9.6.orig/src/main/resources/icons/16x16/type_ape_16x16.png0000644000175000017500000000131311720500104024260 0ustar drazzibdrazzibPNG  IHDR&/bKGD pHYs  tIME;kbAtEXtCommentCREATOR: gd-jpeg v1.0 (using IJG JPEG v62), quality = 50 _ IDAT(͑Ka_&ӌiZiW#QQ"C:u/A :$R AFbAg Nm !Yb-!}4Nx?|7@}N  Ƀ~cɇ>Fgk#ˌ"':1M_*;ՎI~kȬ  @d.F8ɿPNIQ~.v'Oܺ'k%lͬ)?1k| 'H|ݾ'r,ui@ns :مybM&irK,Аέn.B2 &#VBСϿbIENDB`jajuk-1.9.6.orig/src/main/resources/icons/16x16/volume4.png0000644000175000017500000000150311720500104023201 0ustar drazzibdrazzibPNG  IHDR&N:gAMA abKGDC pHYs  IDAT(=NWΝMZ6@"AiԬQh=<} ^+T)RJ7IQ.Za d@{L0ܹ]|9Gt~B`a>VOt:c>1YfZ#E9D)s~H2PDQM^ɓ-*y~ׯ7TZR\__e9ի=^c4thi4Rh<Zeig0ln` K]/(Ţ1"k1qqΑ P|ÇVm!I׻c:-yt98^FQ~f&M-X qyya_DQHYDdiNDQRV[[[L&<,K$(Zϰ60f3\P0k~'A!\\\lV""@666TDdE^ŵ' C?o^=9(Qgg%4;_c4rsӡӹ{zL `s;4˧Ǐxn޽{ "h6mq6pΡZ` n&zTXtCommentxs.JM,IMQ(,PHUp R#epIENDB`jajuk-1.9.6.orig/src/main/resources/icons/16x16/dir_synchro_16x16.png0000644000175000017500000000076211720500104025004 0ustar drazzibdrazzibPNG  IHDRabKGDC pHYs B(xtIME 9 pPIDAT8˥MRQc*@ZA ,b lf]P3*DeIPlF"( {Gfq ͗/Q.6S2Bԝ{3x^wZ=>Lxx3}Z=B)pS @0y.?iv2̥gn:RHaf'us1RC}X?<5_8 &3 \ _KM`e "(DZah}H,C+ \t]D#1Y~uڜ>{_w"a/_8hyʛ,‡ʧIENDB`jajuk-1.9.6.orig/src/main/resources/icons/16x16/star4_16x16.png0000644000175000017500000000124211720500104023510 0ustar drazzibdrazzibPNG  IHDRCPrd pHYs  tIME6%6@/AIDATHݖOA;/F΂tAA6466&vp(ڈ6`L9becbQH DE yrޙp;3k!ًby;B"SA 14sSo6\jkqU@HGN5='L)H45>{80x чt7ՌuCm_BK,벬廇G2v 24uTX*ьt!q,dQ8B4RJS^Jb${pˎc}ˣ ?Ga#@09a?~kޭOl`hUSh,vZ2 ]bWj?0ØL\dś:9/TTk&vN :(=hMkŖ]xgx״ӌTWU`FPqdFxpjh$<-h0@l`ODufJ62_Vެp.W f43=gOk40ĭCձž _M^l8l?3]X1/23ǕgƧg^hڷuS( wD-HU/<A2e^ۏ^,}?,az  ,Hc$UgnSui&vn{'v>Eq4Akw_?߼''k'W%߼[0j>AX-/?ԩT=eYcJ奎Go@W!'$_ԓSln\{&?3 DV%r=?JeFmXv@x\qqah=Ѿ2;}З|9r-k5tT2>hMA҄ǡ̖MD, z=*];[x 8wyIuI1MN<-I7, #?[FՕD(̗ˣRmcer-0{ W1oR ]!PՑl.UvjeIENDB`jajuk-1.9.6.orig/src/main/resources/icons/16x16/clear_16x16.png0000644000175000017500000000140511720500104023542 0ustar drazzibdrazzibPNG  IHDRasBIT|dtEXtSoftwarewww.inkscape.org<IDAT8KhgLHBHը+& ҂JKvэ" ]Rƅ`Ku 1-i411qFIe?O+Ec!pQG`s8Ʋ @4߯mڰ1zt^`qET*-XHs~SIՙJV|Rt}#ה]K뙋Lɧʕ7M/JDڧNWrUsK;=rT%'_A*vitsGWvjUC3F%њdS}k9$j&]toeQP5~Pν_ ` )RI(r;͵:.iB `dA϶Ր wj2[ԯVI8RwU{#e`g!^̌#^UVJo5RLZ[P">WXPFDJOz'yMwqcLL˥ep)DX6 EЃ18o #z)u=<p ݘܺy%oLe‘ߤYQ{/'e52 CC}Y‘wҀ1t =v咆?jӣkr ;8TR-S>L8xK~C(IENDB`jajuk-1.9.6.orig/src/main/resources/icons/16x16/slim_window_16x16.png0000644000175000017500000000633011720500104025011 0ustar drazzibdrazzibPNG  IHDRa pHYs   OiCCPPhotoshop ICC profilexڝSgTS=BKKoR RB&*! J!QEEȠQ, !{kּ> H3Q5 B.@ $pd!s#~<<+"x M0B\t8K@zB@F&S`cbP-`'{[! eDh;VEX0fK9-0IWfH  0Q){`##xFW<+*x<$9E[-qWW.(I+6aa@.y24x6_-"bbϫp@t~,/;m%h^ uf@Wp~<5j>{-]cK'Xto(hw?G%fIq^D$.Tʳ?D*A, `6B$BB dr`)B(Ͱ*`/@4Qhp.U=pa( Aa!ڈbX#!H$ ɈQ"K5H1RT UH=r9\F;2G1Q= C7F dt1r=6Ыhڏ>C03l0.B8, c˱" VcϱwE 6wB aAHXLXNH $4 7 Q'"K&b21XH,#/{C7$C2'ITFnR#,4H#dk9, +ȅ3![ b@qS(RjJ4e2AURݨT5ZBRQ4u9̓IKhhitݕNWGw Ljg(gwLӋT071oUX**| J&*/Tު UUT^S}FU3S ԖUPSSg;goT?~YYLOCQ_ cx,!k u5&|v*=9C3J3WRf?qtN (~))4L1e\kXHQG6EYAJ'\'GgSSݧ M=:.kDwn^Loy}/TmG X $ <5qo</QC]@Caaᄑ.ȽJtq]zۯ6iܟ4)Y3sCQ? 0k߬~OCOg#/c/Wװwa>>r><72Y_7ȷOo_C#dz%gA[z|!?:eAAA!h쐭!ΑiP~aa~ 'W?pX15wCsDDDޛg1O9-J5*>.j<74?.fYXXIlK9.*6nl {/]py.,:@LN8A*%w% yg"/6шC\*NH*Mz쑼5y$3,幄'L Lݛ:v m2=:1qB!Mggfvˬen/kY- BTZ(*geWf͉9+̳ې7ᒶKW-X潬j9(xoʿܔĹdff-[n ڴ VE/(ۻCɾUUMfeI?m]Nmq#׹=TR+Gw- 6 U#pDy  :v{vg/jBFS[b[O>zG499?rCd&ˮ/~јѡ򗓿m|x31^VwwO| (hSЧc3-gAMA|Q cHRMz%u0`:o_FIDATxڤIha_`RrP[44PZ=X(U!`'Z\p9آ xPoZp- blmIlk65Eso}g>sڥ@=>uO$-M^'m@1\.`00`f/w c,Ib!hETcTAUQןeb: !:d2QPa٧esQz0mx"MK±=~OOi> _DgSnۄ-@Pv#'_пQ?ѽU)K5 @D\D~D5W<nѶKK1~8(UDp?'DzΑ =΅ej7,CGp9jU;|=xD;1X۰V(3 Z} }=;P"}GdH{| C(U|* ڶQ)nCf4[{۶}b9+es~ w̏7IENDB`jajuk-1.9.6.orig/src/main/resources/icons/16x16/contents_16x16.png0000644000175000017500000000067311720500104024317 0ustar drazzibdrazzibPNG  IHDRabKGDC pHYs  ~tIME 3HIDAT8˥AKQowKx",AAPo}$E)]A5&l Tv؝${3OS| $2[V$VDvE题4Ny4ິ} F,.!cjah_|LaAPxX  ȩx|xQL =[PXoaxVD ({9$~@_o0ϭOMPո:ߛHh4Fe9=e+gT.vw}ubCu8{%srz R|V6frʕٌӜx;#IENDB`jajuk-1.9.6.orig/src/main/resources/icons/16x16/player_stop_16x16.png0000644000175000017500000000065511720500104025023 0ustar drazzibdrazzibPNG  IHDRabKGD pHYs  tIME (.:IDAT8͒_J1줯 f,ćOd2_7ez/so`o4ui2.qu``NOMJDM`)"wWUH8<:v$":@;IԣPTB* )luEIENDB`jajuk-1.9.6.orig/src/main/resources/icons/16x16/history_16x16.png0000644000175000017500000000071311720500104024156 0ustar drazzibdrazzibPNG  IHDRabKGD pHYs B(xtIME  &y.XIDAT8˥=N[Q36 \ o!Q@U@g#*P Lm,f(.6v8#hs>pfft{\ԺNVc~O[V)(iHH $$qs{mO_ "b@;mdƟsHb0xQL11E k1wܝ`Uu=`n4iqRq3 7WxhMH䜜lVDY&`oHꗚ:j`*g0E=5@$3B Jaiq(㙰jf/^}!?IENDB`jajuk-1.9.6.orig/src/main/resources/icons/16x16/traces_16x16.png0000644000175000017500000000051511720500104023736 0ustar drazzibdrazzibPNG  IHDRabKGD pHYs  tIME8`&BIDAT8˭=n0H[!!l"A!QsL$^Xj,{|3m1 Z;騬8xt/5ǒ4MW(w=ιURW/P&AH৞"9JIENDB`jajuk-1.9.6.orig/src/main/resources/icons/16x16/star3_16x16.png0000644000175000017500000000123711720500104023513 0ustar drazzibdrazzibPNG  IHDR2ۜ pHYs  tIME*/>IDATH͕OSQ{q[F@Zb ď 7,..&n.. c\J\L. a0hh"T(Rz[S F1l'9yy?*"SAXbh^&l,8T׷:Zad^%:y 0 H6)>z80p  d)p@g[B.Ŗt%w*5efh.HHd4lX3ҁճyD+6WK`DByV &Iǻ06e in  s+vcb;}ghUS`,rZ_ w.L17cŒdb#_ҩ _|E^19Rߚvc-{?^^ϿWbk* U֠ꗾ&j(UŨR}ꏆ FB%ܢ1Q#D+uYeE CZo[<R_/~1vRSf5W*mT)IIizS XbIm0 -#RqiN̤r"IENDB`jajuk-1.9.6.orig/src/main/resources/icons/16x16/star1_16x16.png0000644000175000017500000000126211720500104023507 0ustar drazzibdrazzibPNG  IHDRsO/gAMA7tEXtSoftwareAdobe ImageReadyqe<DIDATxb`>U1_0b%A T:be lzZ0R@8 ``cgscrRfK@a5mC#cF  OD- u1A/Я9q3 "/cx>߿ _|d`` @= ƿ '0;Y%A}"@{N2~}Fo#P3Õi>[ha@}C|n+>L?ڼçmw2, J:x?Y"X Çw0l  JJ ~}'DR<?@(zȞ 1#ïMP f0=bO_93 oB :L @5pO4\`hՋv_  x NdP>05 :+Pρ'^&(seٗ:::tː$ ,dwX.4}d2itvvBbss[[[H&LfRp8ɲ` ]{1rfs~7 ͏>]0=;P[5*Ǫc88MB## C *)eccOѪJ۶dp8,2p7sjrʘ}yWOQvi7˜fuwd]&mKۖeYI'KIENDB`jajuk-1.9.6.orig/src/main/resources/icons/16x16/flag_it.png0000644000175000017500000000030711720500104023214 0ustar drazzibdrazzibPNG  IHDR 2I pHYs t tb?yIDATѱ @А81V$ 0 CBݕl1?xh ~hTy,@B IwӨE@T~Z p~\|6X+Om$zIENDB`jajuk-1.9.6.orig/src/main/resources/icons/16x16/save_16x16.png0000644000175000017500000000161711720500104023417 0ustar drazzibdrazzibPNG  IHDRabKGDC pHYs  tIME 7*ؿtEXtCommentMenu-sized icon ========== (c) 2003 Jakub 'jimmac' Steiner, http://jimmac.musichall.cz created with the GIMP, http://www.gimp.orggGIDAT8˝MHTaL1͑QlQQ4&E.B(,V-*ETR( "((j["DETjܛN al6<=_'?[ظ3 T[&Ÿ?ͻϝ 4wt퍭Uk:#km'-Q7˺; <}۝;ƨf(ce#+s >b$y,%_FDDdsZzD/Hϫ/.wY%<r$qDxXBAA(W'n۱wp=/x|vl_PPP#wҘX̌M4єXi^"2"0e1.XͻǪ Q_ͭ{h\Î,4M9H*|!mkص)i8(m41MCRO-hm aPYYޚ <۶qy!<]s?D30DQ,@.x]:R,Fs4_;3L"bmIENDB`jajuk-1.9.6.orig/src/main/resources/icons/16x16/playlist_queue_16x16.png0000644000175000017500000000111411720500104025516 0ustar drazzibdrazzibPNG  IHDRabKGD pHYs  tIME q_ZtEXtCommentCreated with The GIMPd%nIDAT8œJQXNm%0Ţ@2:O(y!:\&8&-3(-vtbM7.zVs9?߅[FbT0n''L"b,* \axCWy9uo)JIENDB`jajuk-1.9.6.orig/src/main/resources/icons/16x16/ddj_16x16.png0000644000175000017500000000223311720500104023215 0ustar drazzibdrazzibPNG  IHDRasRGBbKGD pHYs B(xtIME7~tQIDAT8Sqqq###< .OOPFAAAsuullmDAAAJJJyyx::9!999[<<=j...SSR665 $$& {{{6  &+   W JUIENDB`jajuk-1.9.6.orig/src/main/resources/icons/16x16/flag_cs.png0000644000175000017500000000045011720500104023204 0ustar drazzibdrazzibPNG  IHDR ޜ pHYs+IDAT(c.CfӤaŎ l Z" l F & J D2Iҭy Ò^`+B Ё,?CK?^pZ]13n>'ߜbH}?x#?G O61h~@\B !>w"R+W`$0|yF%IENDB`jajuk-1.9.6.orig/src/main/resources/icons/16x16/bestof_16x16.png0000644000175000017500000000142411720500104023737 0ustar drazzibdrazzibPNG  IHDRasBIT|d pHYs B(xtEXtSoftwarewww.inkscape.org<IDAT8KHQofKA a%=ADb(Z&Z-(&*͖-M$ l!e=373{Z[kӁg913'EnK^H,bP)^ fAGIֵɲrܔc&q2xċ fb0 (c9hׇ"|f~bfIF]R30f Q: 6?Zb%`,Io3ӫ+t 1Z]lAB;OW!"J CnQ5e/d/?"L{`efñJ1x^Qw[2щW#ӑj HYm5`~UXnWWͯظ!^~y3p2 a39bI1 Ruӎp7z_,z]q( D>S;Iْ-'}1GfoAߒ"ڏS.o< 4 NJ*HyIENDB`jajuk-1.9.6.orig/src/main/resources/icons/16x16/star2_16x16.png0000644000175000017500000000123011720500104023503 0ustar drazzibdrazzibPNG  IHDR!jB) pHYs  tIME /7IDAT8˥OAFH=$1p0G /^L82| G|AƁی;Zt-B'=8>Ԭah!iHHd4lX+ҁ͋DO`Dr ˃3$e]8c/rg49 ҳVnbhTK`2rZwç',[Wf cDKcbFұK-l- |C%1_FM(=nO9նo`~_m֡HOH0JoZ~5h`kT.\mh3@,`KFBV,#"39E.cZW< R0T/~{JY/bg/ҶKnr%_3&gHt$ JJ16o-L)H Tt]gy_oPT2FIENDB`jajuk-1.9.6.orig/src/main/resources/icons/16x16/continue_16x16.png0000644000175000017500000000036711720500104024306 0ustar drazzibdrazzibPNG  IHDRRgAMA aPLTEGGG ^^^ɨytRNS@fbKGDH pHYs  tIME 7AفBIDATxc`@LJJ @H0E%P@r D pA+IENDB`jajuk-1.9.6.orig/src/main/resources/icons/16x16/shuffle_16x16.png0000644000175000017500000000127511720500104024115 0ustar drazzibdrazzibPNG  IHDR;֕JbKGD pHYs  tIME#60$JIDAT(]AHaϷe۾澩0HH -A :Kt. &82@x< xU0MsaI&D^wn0^LOOf6I@DCC7@8i&_zOO< fggǗOoH/Q4]Ŵ^9- on& ɰ3? 4@Y>B׽x:.2{{{\.![4M#J}D⍦i5' =sss1Pj]'הX[[[y֓p81 ݊D"uN/~u4vP(|^7vwwzBP~]""qy$"{kRnMӨjlcprrr#R(JF:vvvGGGi5G] E8 ^c0gVd3C}0R*pj@"£=d1(?d!zN(y ԇ8-V 8[`ՇJRn}cЗv;&Кg14L8DtIENDB`jajuk-1.9.6.orig/src/main/resources/icons/16x16/empty_16x16.png0000644000175000017500000000025611720500104023615 0ustar drazzibdrazzibPNG  IHDRabKGD pHYs  tIME +>tEXtCommentCreated with The GIMPd%nIDAT8c``?rIENDB`jajuk-1.9.6.orig/src/main/resources/icons/16x16/type_wav_16x16.png0000644000175000017500000000202311720500104024307 0ustar drazzibdrazzibPNG  IHDRagAMA7tEXtSoftwareAdobe ImageReadyqe<IDATxȱ @{ Ia+CљJ"Ǖ)AgЛFQ R;Ś;^ +1b1{  M K0|Q .P y8`İ! 1-$< M **(*ʱ3^t鉠jll;Z@`ݹ)d ӧO ecf`z֝{<6`bD×o_|?63 3mfbKII1kVNnkV8!={,/`͌ rrr  bbb {NNNVVVi5)n;{\{lGXEDD Iׯ c.e˗@`]vDWWl#ofx f&&&e z { aR$..^TT ,a`cc33 ~O:7& @ЄgffKYY|}}p ܠgfx%ƍ[O]~e߿v_b+))5+**F-$$t!cN^wL<0s8?<$IENDB`jajuk-1.9.6.orig/src/main/resources/icons/16x16/preference-love_16x16.png0000644000175000017500000000161111720500104025534 0ustar drazzibdrazzibPNG  IHDRabKGD pHYs  tIME 3OTM5tEXtComment(c) 2004 Jakub Steiner Created with The GIMPًoIDAT8˭Mhwv5V(`S%b0"[)䔃ibA%!E#zQK)(ukKBf1 S> !I)I۶ɝlA:3Q">G BIee%a`uU:ӇȐȃDacߺ-;Yt] `Yw<@b]v"dz޶-kU;1QUC$P';Ɍ|L)ݖjPJZbܗE?4),}?twTͪCQ(Pz;3YR/̓ߩ[C7m =k{y߼"AXIENDB`jajuk-1.9.6.orig/src/main/resources/icons/16x16/refresh_all_16x16.png0000644000175000017500000000223611720500104024745 0ustar drazzibdrazzibPNG  IHDRagAMA abKGD pHYs  tIME $XWIDAT8j6 ?\j6ym6PC5#! h\m7fj6) bS(      7s:B5b  0% :; 7ְ$8|X,=(K^1  ,Z( 92\\Y3kvt 1$-j6diU(&nI>a;j6d\j6O0\Ȅ\j6 L;!5  ?,o9j66_r<\޴ az4 gU(4(k7   ) Va)  (X  Zmj6T؋ɚ/ 0/  f\j6_\j6N k+ z\2pǠ&BQIENDB`jajuk-1.9.6.orig/src/main/resources/icons/16x16/finish_album_16x16.png0000644000175000017500000000173111720500104025116 0ustar drazzibdrazzibPNG  IHDRabKGDC pHYs oyyIDAT8}SKh\U=&$I&IMMZ-BRt\7#jp# +Dj*Q+_;d0余yB#Ҳn815O?S*!h7/Vݛ3=Ckv7ȶoJaiOI;h|<+JnѴV:ܨ:P3Td ՘Z_h8_,,4*! nl,(iڞX4.6$6@DMtɪcDy=6 \?.cGnY?VflKIENDB`jajuk-1.9.6.orig/src/main/resources/icons/16x16/disc_number_16x16.png0000644000175000017500000000111411720500104024743 0ustar drazzibdrazzibPNG  IHDRabKGD pHYs  tIME q_ZtEXtCommentCreated with The GIMPd%nIDAT8œJQXNm%0Ţ@2:O(y!:\&8&-3(-vtbM7.zVs9?߅[FbT0nhDDQ\&JTU!,B ڸ%ECtTpG|@Lx`zq- Qa3~_>3}?Hf.   [*xqRBAy$q vX,fj P_Pmȫۺ[d\eR]TwEmUUUUUi;"1z<ϟ 3Se|㑖r9#]]U^9ZrԂStO[ϙǎF(zW竼WpM/ ou[JČD";─ aއ—U OAL|XBPh!˲[g!Ib lSuQ6|JRJvG~6H~HIENDB`jajuk-1.9.6.orig/src/main/resources/icons/16x16/void_16x16.png0000644000175000017500000000025611720500104023420 0ustar drazzibdrazzibPNG  IHDRabKGD pHYs  tIME -:=uitEXtCommentCreated with The GIMPd%nIDATc``)8ġIENDB`jajuk-1.9.6.orig/src/main/resources/icons/16x16/popup_16x16.png0000644000175000017500000000116411720500104023621 0ustar drazzibdrazzibPNG  IHDRabKGD pHYs B(xtIME  ©KIDAT8˥OHTQSތfcfNJDhڴLTUڷ hem]B֢Dڴ) 2a ɱ f^9-}s;kLG㽦IěQ-8TN=VlԄolmLMdV:k\'qR1M!79dVF;YL) 4cR3#V2;>3ޝmjGUu(1soÜ;JnrGIR8bv7EpoNa-}_:R?a!|FDf$IOCؤ=dii U@D ^%'ui+>;/fn1FTm;(x&&(rC~9EmmmPwW{ﳱ- jQ,FUD"j1A`6uDXV`a"U* "> 3"TIENDB`jajuk-1.9.6.orig/src/main/resources/icons/16x16/unmute_16x16.png0000644000175000017500000000150311720500104023770 0ustar drazzibdrazzibPNG  IHDR&N:gAMA abKGDC pHYs  IDAT(=NWΝMZ6@"AiԬQh=<} ^+T)RJ7IQ.Za d@{L0ܹ]|9Gt~B`a\Z<&6hv;i6k-9-QGĔ B޼1ݐI8|cZhxhҊB=|w&zTXtCommentxs.JM,IMQ(,PHUp R#epIENDB`jajuk-1.9.6.orig/src/main/resources/icons/16x16/search_16x16.png0000644000175000017500000000164711720500104023731 0ustar drazzibdrazzibPNG  IHDRabKGD pHYs B(xtIMElx4IDAT8˥[hTwgn646>|P4B5M5TZ4DThk&/}/Hh@[d޷=9%Z 3Ïo>W~7ߊ*qBfyxE |ͲQE&NgRg2{v[c ;֦[aHR,(ĥ\6J>iTw=6DrQcJK6 hDčآŃCro::毫<MqIʥ"3d"rIP\fU[,X6n0y}V34ݑApw־D$I v(x/7br]Hė4ʀ+m$yZ$QO&ژ LhbN80@D<ޙw2>s79(" q0ȭXt}rL&zee` DQJx+V5`rGArPpylxo#Eԉ} 6.@o{`rO^Z&`lZ[[[TCz ;fhOIENDB`jajuk-1.9.6.orig/src/main/resources/icons/16x16/dropdown_16x16.png0000644000175000017500000000030011720500104024301 0ustar drazzibdrazzibPNG  IHDRځebKGD pHYs  tIME 4hg|tEXtCommentCreated with The GIMPd%n$IDATc`J?>I 8hB,yEuIENDB`jajuk-1.9.6.orig/src/main/resources/icons/16x16/flag_ko.png0000644000175000017500000000073611720500104023217 0ustar drazzibdrazzibPNG  IHDR 2I pHYs t tb?IDATmMKQϽ38Q1b3U!"8 5 *SoJ]n)](" QZdLd^V³~ρâh8&"Y.f?}W#Z7#t8DB5 #pc3`| @(/mY1~Gdȥ[/>T?ƠPvhtXK(0HFP$ nE,I`:'HRR/Bx] 8B` 0 Dž/%ĝupc֋/ڼjH%A`Q J)#w'?1KN6g|`mmD)8-3p,-xe8`aa^G?I)wY}=T[󨭔D~W.H5ԂUX-*&ZǀP(L9-SyC]WJ,zWCzv=^I}N8Rf?0d[*!{R84|#c&PJbӦ()!Bk"B_6&ӳj,Õ9 3 Hjb@kjbo(p4<F)OJa6A)lu딌g***m)!}<Q%Bk])~B6zzfg8\^p$Pjt79OlDEZk%{wM^N^ZV$/sݻt>)%֒,N !}!sSW?sz5J !s/!Ws)K,k ;J%@|'`hL^x,q?12:$ y8? G_X-x^xZ]f+IENDB`jajuk-1.9.6.orig/src/main/resources/icons/16x16/unmount_16x16.png0000644000175000017500000000073311720500104024164 0ustar drazzibdrazzibPNG  IHDRagAMA abKGDb_ pHYs  d_tIME  H_XIDATx1j0?@7p/2tKr@C;eB K F ^9utбA'8q!C]VEA>2n) *x`e2p8\APoC@4Z1k-{!Z&MSsy1z1<u}6 a%I(((f5 ps~R "xl-J)TI=Պh@e(X,-@8p::a^[3>KsDZLSqε3ܽB|YPKϧt%Ӹ 0˹IENDB`jajuk-1.9.6.orig/src/main/resources/icons/16x16/player_pause_16x16.png0000644000175000017500000000072011720500104025144 0ustar drazzibdrazzibPNG  IHDRabKGD pHYs  tIME  +J`D]IDAT8͒KnA *(؊8@r HHp(;DgH0ia/J\~?_Gڻ=;-"#:kΟ=y/Y C>f_ywnyfWfps_L-{>}`t]7#7Svw)@T0sEDkv(?$д;AT@v7Zq4mC"!yt0FU_,n>&C *fO,e`n; ﻩ_dQxh 6N1-F$j\BB|9Q*Ώ몞l7D"ic#)HsJtV:mJ8IENDB`jajuk-1.9.6.orig/src/main/resources/icons/16x16/up_16x16.png0000644000175000017500000000121411720500104023076 0ustar drazzibdrazzibPNG  IHDRasBIT|dtEXtSoftwarewww.inkscape.org<IDAT8OhAƿ73ٍzhLт@*ՊhDbE-rkJIbREOBM*^DPC)*4&Q!|ߛ!5ɛ|fvn<IuL:.O <WLFfG ฼ʼns֖ǖ% Ep74HK: ]"GJ a2Wk =<؎Ql*eh :}6.N_ +XR"K(u@AVqE؟~ԋ+U?cjJZۆ25|I=/b1 lܺ?n%&Fs'0۶К"IENDB`jajuk-1.9.6.orig/src/main/resources/icons/16x16/repeat_all_16x16.png0000644000175000017500000000641511720500104024572 0ustar drazzibdrazzibPNG  IHDR;֕J pHYs  ~ OiCCPPhotoshop ICC profilexڝSgTS=BKKoR RB&*! J!QEEȠQ, !{kּ> H3Q5 B.@ $pd!s#~<<+"x M0B\t8K@zB@F&S`cbP-`'{[! eDh;VEX0fK9-0IWfH  0Q){`##xFW<+*x<$9E[-qWW.(I+6aa@.y24x6_-"bbϫp@t~,/;m%h^ uf@Wp~<5j>{-]cK'Xto(hw?G%fIq^D$.Tʳ?D*A, `6B$BB dr`)B(Ͱ*`/@4Qhp.U=pa( Aa!ڈbX#!H$ ɈQ"K5H1RT UH=r9\F;2G1Q= C7F dt1r=6Ыhڏ>C03l0.B8, c˱" VcϱwE 6wB aAHXLXNH $4 7 Q'"K&b21XH,#/{C7$C2'ITFnR#,4H#dk9, +ȅ3![ b@qS(RjJ4e2AURݨT5ZBRQ4u9̓IKhhitݕNWGw Ljg(gwLӋT071oUX**| J&*/Tު UUT^S}FU3S ԖUPSSg;goT?~YYLOCQ_ cx,!k u5&|v*=9C3J3WRf?qtN (~))4L1e\kXHQG6EYAJ'\'GgSSݧ M=:.kDwn^Loy}/TmG X $ <5qo</QC]@Caaᄑ.ȽJtq]zۯ6iܟ4)Y3sCQ? 0k߬~OCOg#/c/Wװwa>>r><72Y_7ȷOo_C#dz%gA[z|!?:eAAA!h쐭!ΑiP~aa~ 'W?pX15wCsDDDޛg1O9-J5*>.j<74?.fYXXIlK9.*6nl {/]py.,:@LN8A*%w% yg"/6шC\*NH*Mz쑼5y$3,幄'L Lݛ:v m2=:1qB!Mggfvˬen/kY- BTZ(*geWf͉9+̳ې7ᒶKW-X潬j9(xoʿܔĹdff-[n ڴ VE/(ۻCɾUUMfeI?m]Nmq#׹=TR+Gw- 6 U#pDy  :v{vg/jBFS[b[O>zG499?rCd&ˮ/~јѡ򗓿m|x31^VwwO| (hSЧc3-gAMA|Q cHRMz%u0`:o_F(IDATx|RkSQM"|h4zX8zczzZѤO)QsDdacw}aa(4M{("u"3t@D,쐬٧0Bi6HF0GDp8&dd f!̌z~&l' "*lSbX&zD"q!^O$j{uC#ccvh6ԤNDBnTTUlTdfG.%Rn*\W~nd2yIZމ|{,@IENDB`jajuk-1.9.6.orig/src/main/resources/icons/16x16/fileopen_16x16.png0000644000175000017500000000103111720500104024250 0ustar drazzibdrazzibPNG  IHDRabKGD pHYs B(xtIME 2 P IDAT8˥OSQ?/} ML7`sB#F$  6~0AG lhL&mm8iyM1~r{O=ZfS*k`M>d,,R({)0tL9<:nHiD.}9djZ8.[%ŘPCͷ=?s$[[𼋺Ů\9a8SI']5 D:ť t{rA`z~kމ% >\kWbLVg#p|vѰXkCݭqJ"eY"`DFPB-%ͤO\=XBA, ES8͜q]ORw0"Wn Z5i.~6o7fʋoqIENDB`jajuk-1.9.6.orig/src/main/resources/icons/16x16/flag_de.png0000644000175000017500000000022111720500104023163 0ustar drazzibdrazzibPNG  IHDR 2I pHYs t tb?CIDAT 0  RLIY)/ +wLy0v'*iX4 'W@^cbIENDB`jajuk-1.9.6.orig/src/main/resources/icons/16x16/full_window_16x16.png0000644000175000017500000000121211720500104025001 0ustar drazzibdrazzibPNG  IHDRabKGD pHYs  tIME 5wߚ5tEXtComment(c) 2004 Jakub Steiner Created with The GIMPًoIDAT8˝;hQ5i%Hq *v*_P*AppH`APVQtPq -%-EjMSMLuؼrsϹȉEo4g Xm֜XԵ%'ýHp".qSK$~QM :yCυoePO9/hYk>H0=@{g<wdvBV))`\ 8tIdjЊ{1R5Ea.ۢ$N@7fn+ CZ{O[h뚦yM<:h99"}Vpx|~b߳Z(2 #0Ο sg̴Ʀ(TZ*cKt H1a}CY^Eqi )J U œ % 0KsREzTe>}N IA)OJc@oYyoK˷$XV- :g;6Mo!ڮޒb>3;&ܯ^IENDB`jajuk-1.9.6.orig/src/main/resources/icons/16x16/down_16x16.png0000644000175000017500000000125311720500104023424 0ustar drazzibdrazzibPNG  IHDRasBIT|dtEXtSoftwarewww.inkscape.org<=IDAT8MhAߙk`C"I"/*AU*mك١E&MADEt>S8zVO޼)c>. Q51Qw&zgO/Dk00(nCȽ{[a~5鈴@bLQ= &$dY[AOXZloxz.Ҽ6?_h8|E7sJ*hIENDB`jajuk-1.9.6.orig/src/main/resources/icons/16x16/preference-poor_16x16.png0000644000175000017500000000162611720500104025554 0ustar drazzibdrazzibPNG  IHDRabKGDC pHYs  tIME6(h+5tEXtComment(c) 2004 Jakub Steiner Created with The GIMPًoIDAT8˥OhgL!ݘ &.TZ-ѢD) "T(i= BR,6CBc?B\dKcJ4)QKM6&qw33;}=Hc}/dv68`2- ]1DkfQ*j@V?]_{R'0 0Aȋ΋Q;Rz#0Ah߇IYF=Ua#qWš@M~ Ax=bF(` Z@tоzj]E3Ig}:L3\ QNr e];iLI1Na: !B @ xEm3B$F=[v|=--ϥĂDU@fAвg7-{']:TBO;vs(D&3-{YP@PA,800u%?9(=g" !{M%ٹv]!C_EA'r ܾqGqwytaWȥ!BFGr>&0Fz=~ N!=вذ?.)v<d>bzi8v&jW[AZil<EVD>9mԜ6J$Z1M; , $;N˕2ROvrphcH8"dto2/6zIENDB`jajuk-1.9.6.orig/src/main/resources/icons/16x16/netsearch_16x16.png0000644000175000017500000000165611720500104024440 0ustar drazzibdrazzibPNG  IHDRabKGD pHYs  tIME %-;IDATxmoHu_wwy;NNcm,&H?`1RbTV "z'T`(RFQ,e67 w?ww}=p+Ňafl}H7 J@eF:=.q3()8i@/],PJi<?wVcJa ^mUD;Z2+t^8tkmnuvSpֲIJr[ww@!p\ ׇwQIvoMRŽUE<Mjy u( 3 ֞}m+BJY)$_݂5ٟHIIvBpϞGJb:b5ɔ u9Bo@,T\`K ]6Æsd2O?0aBB nZ@`+zSi/ZT\z QЯ8',}'JWG&sy[_&7:zb_'![Z|^#3NVYnO^׵y}~=1JٶRWٟ_NLG Ow|3|tp[0990X;onk+#;cj`.K:6?}npwɡC'xξ'B;tdz x;B-/=윊p=FO0kJxƵO@m {0tr߇.R:˖0$i`Yi {FR<ځc[2<ID2x޾]'9# zvZOd轱k [[H\_`aӻs907+fH.IENDB`jajuk-1.9.6.orig/src/main/resources/icons/16x16/bookmark_16x16.png0000644000175000017500000000125611720500104024265 0ustar drazzibdrazzibPNG  IHDRabKGD pHYs  tIME 4A1=;IDAT8˕AHa}ݻr[#k-,/BE¨ A{СvCt%((+ЦA!xqS DZmv+]?k:s؈ "ݧ"&&.ݫr= ]5AV> P}T] [|䘜S01>8z}C:7KPYZ^f~a[p+E ]ܚ:2(g))jJJPrV(;+TVܲxP-1;eiPM0Kwց1FFM:c,;߄iѦlLv Ob`gn rU݁a( C R&q@ eY Ɨ0B fx`ϫ#MfDd{n'B||3yy2?@mp)\hDDQ\&JTU!,B ڸ%ECtTpG|@Lx`zq- Qa3~_>3}?Hf.   [*xqRBAy$q vX,fj P_Pmȫۺ[d\eR]TwEmUUUUUi;"1z<ϟ 3Se|㑖r9#]]U^9ZrԂStO[ϙǎF(zW竼WpM/ ou[JČD";─ aއ—U OAL|XBPh!˲[g!Ib lSuQ6|JRJvG~6H~HIENDB`jajuk-1.9.6.orig/src/main/resources/icons/16x16/calendar_16x16.png0000644000175000017500000000113411720500104024224 0ustar drazzibdrazzibPNG  IHDRabKGDC pHYs B(xtIME 2MIDAT8˕OkQ3o1 af! o .RH#*"L FPh&H_jUiV pj'ӒE1BgX=7^p\Uv\[fnTWf@h6u%wmǵRJ9޼}B8*R*)ez?<<`i9[[ߨjF?7^izd2Oo4I2dc+ R)opi|2eaYi" x]ױg](!87gx8_@)RjgAsdx8WgrAӿj;d.σ{w dWhpYiεA˾uheg"IENDB`jajuk-1.9.6.orig/src/main/resources/icons/16x16/editpaste_16x16.png0000644000175000017500000000106111720500104024434 0ustar drazzibdrazzibPNG  IHDRa pHYs  tIME IDAT8˕kSQ4$1Ԕ "\\jbpv!8EmA84K.8)RHB^olF91/m ~=?T*{ϝ~I\.konΚ+*+v< |`_)h/Y2g .9.Ҵ0f LD9̤γ׫VTS yf,y_ϲxAPTB"Jqm.f!1 ނD"03sl08[y=j(߼ )>\qKa{UEEȝ<9DAU21 (mnh>A_4!5纀VҨ)onP^CDz\Z14I3XpcZ7l/D#팦$1fSU;`\13TKOxiIENDB`jajuk-1.9.6.orig/src/main/resources/icons/16x16/shuffle_global_16x16.png0000644000175000017500000000166511720500104025440 0ustar drazzibdrazzibPNG  IHDRabKGDC pHYs  UIDAT8uML#uƟt-ih+lŲ;1Gz$nQ75-Uii4t=&rI}(@4Dal6NR"HD"p8((J}599 Y*677.]D"×&]ŵ%W`aOT*ucjj˨T*ObP( !̀R>bapB666,Bzp1 .Fѡ~PJnC,5qg7fggm~~~i$Iz_E$I8n78\sqqzʏPc2t]͛#/@$H`C#*=N 8$Q| )b1eN`o``G&snAb& C#}b'kJs\.009xrbD["[-$mx\9XwV2@@PiAkeRjt&Rȿ&ROXNOӅ43kgO=TrK wIENDB`jajuk-1.9.6.orig/src/main/resources/icons/16x16/autoscroll.png0000644000175000017500000000066311720500104024003 0ustar drazzibdrazzibPNG  IHDRabKGDG pHYs  tIME  ^ @IDAT8˕JA >Iԏz ?YD>T#$œ~-+{ϙsw X, owσrUKB`HqU@@@R?+y}hUܥ?~h /8!ͫ>pG Yu }h碅Jn @@TH@AAmė0D1& R??Jn v ,WoI@@l^n|h0Ѧb :?1/\@ڹ Jn @7 ěxVmuIENDB`jajuk-1.9.6.orig/src/main/resources/icons/16x16/preference-adore_16x16.png0000644000175000017500000000162711720500104025670 0ustar drazzibdrazzibPNG  IHDRabKGDC pHYs  tIME $:{5tEXtComment(c) 2004 Jakub Steiner Created with The GIMPًoIDAT8˭kusf6<4CY!C X!pH3(/%RQs$H@w\-]Ӛ-rמ?^O_x O4 cPEX ϑx^{U*/3luxkS_l1q6NϷ)61d{EUA9 ָmc*e_”JhTbIZm 5-3%:!{;l8F,5``&\Įmh3 ܼExm ˗4Z `jxKhM.Q7B8alۭE @5EEim;91B8^H6w0efAYeh1}|uwϟr,Lj|5dK9̸]>M v;+T1v$jqU 6QӴ=v=.Uc+-uV/T mJ:̎Pgq"QTS.-"}TQ\ccZE-b[#Z__35ˋ~IENDB`jajuk-1.9.6.orig/src/main/resources/icons/16x16/ext_drive_16x16.png0000644000175000017500000000132011720500104024441 0ustar drazzibdrazzibPNG  IHDRabKGDC pHYs  tIMEsʥtEXtCommentMenu-sized icon ========== (c) 2003 Jakub 'jimmac' Steiner, http://jimmac.musichall.cz created with the GIMP, http://www.gimp.orggGIDAT8˝MkQ3fd`S,Eԍ(n "Z]H?ЂPDXhEADJhI&f!ЄŤ"=ù>{=R8ZQ(\) `-$wj5 A*2=L }ՌUIAЃN,`߅FH4TSUETQWDCFpˇ`0`804 By^ 0!.^Ib v OL&F!ݿ]č7jA@E?~DS!_YY9O^.a'u]r/~]St:.E>!I߻gUqe/,oT7elnݾsk{nYݹW}-"[o?'IENDB`jajuk-1.9.6.orig/src/main/resources/icons/16x16/intro_16x16.png0000644000175000017500000000100011720500104023576 0ustar drazzibdrazzibPNG  IHDR7bKGD̿ pHYs  ~tIME (*tIDATxm?HSNcQbPtZA E2 K8炃C"B:`*DC1HIxIx]6ov) w/A*"GX[Xg;Ym\|V)]gOv6B$IENDB`jajuk-1.9.6.orig/src/main/resources/icons/16x16/new_16x16.png0000644000175000017500000000073511720500104023252 0ustar drazzibdrazzibPNG  IHDRabKGDO4ױ pHYs  tIME&Ӷ)jIDAT8˭OK[QsV$}%[\f qYE޲w#ĂM7*RJRJIZEbwDž&Tz63 s3R.kZ\go˟oϾdRIxS/Oh缠'+⮶23l6 ! "=c~!"f L&jǷ[SW{jky`1*F_^^o: L8 n4Y:OPEi@дޛzƦ织'Z_YD)]Cu4_"hKw4{`_he߯ގx[J<:in|>nv{DjjFw̱(b]Q{NۺUH}cff>T6Ic]Qש3۹#~2ʪJKfKP4+W>s}zE:P԰yE O?hs]UP]G"WH`IENDB`jajuk-1.9.6.orig/src/main/resources/icons/16x16/player_previous_16x16.png0000644000175000017500000000137411720500104025711 0ustar drazzibdrazzibPNG  IHDRabKGDC pHYs  tIME ' IDAT8˽KTaƟ;3x;glf:fJ:AmEe!-]l҅Z" iUfBRr%,J%iMі֚nޤs'?Ct>($}}Rt گ[X](`sZqLѠ5?"XDP| o^bXD! .MuJe6JV`r77ܰ,.,Rj!l~\D$//񺺞~a`hbb ˗XֿץZ6>c0QzS†> ϣ&jYٻw@`xGV%Y\`Mxs-곀|mk,+#Za7u9 ?=]eIENDB`jajuk-1.9.6.orig/src/main/resources/icons/16x16/flag_es.png0000644000175000017500000000043111720500104023205 0ustar drazzibdrazzibPNG  IHDR 2I pHYs t tb?IDATӍѱJBqE P QMC>HDoAn:UoC pI2"nC Lg8ss#&r9 $ Qb\nAt% 2+^o*{4Ǖ\ĵd{{ՃYdw8eknW?yy 90^{.7_=cr/11}fo;3}gGhA 6.;u2*FIENDB`jajuk-1.9.6.orig/src/main/resources/icons/16x16/position_16x16.png0000644000175000017500000000125511720500104024323 0ustar drazzibdrazzibPNG  IHDRasBIT|dtEXtSoftwarewww.inkscape.org<?IDAT8MHQ{?Ѣ`,(HD-EBhcPFZM\Ti""3b)aJ滷ijc wsk-KUߪp=_KјN5UVlј._,TS{]"x BTS{U8b('ͩhNbY($ycMhd)Ցz4YߢXKsß;l[sGHB!_l\U'~1kL#0 xZKu]!?=fN]YQ]D.ۃFH2 MAd3ô2zHɦsyf)r8P'cd BMNҋL)H#R (A8>0A5 sγ ^8 Sq%Ml)`(Huݺ(F?s|H*ɶ^ʽ NeGX3c4g[s{;rd2c{f|;]6œ#S&1)6,Fo&' dfzs AsIENDB`jajuk-1.9.6.orig/src/main/resources/icons/16x16/report_16x16.png0000644000175000017500000000051211720500104023765 0ustar drazzibdrazzibPNG  IHDRasBIT|dtEXtSoftwarewww.inkscape.org<IDAT8S[ @=ZPKIIB-!,i ,9}ȈSf#]80$krňpnvHpsl$I>#tf0\kAF.X,iyG fqi{ 򼀔o$eBJ9@ !:U vH,KmܶI4|x_Iothn&X^Q@dct| UsEΟ0 M ҽ \y7}7FdY~C;>Yz=iv4nK!?y%;nL&q]7\OPV<G;+H%H`YeExA,CkMVCk5Bl:ud})0oZy IENDB`jajuk-1.9.6.orig/src/main/resources/icons/16x16/player_play_16x16.png0000644000175000017500000000122411720500104024774 0ustar drazzibdrazzibPNG  IHDRabKGD pHYs  tIME $!٭^!IDAT8˝Kk<2$M&1ibZI0#JHRlgt'XB\H/r . BMXlJФ3M23.Ħb)wus9@wx`]: z`0,>0LDz/nZϵZMB4>7ԤʥOSL4-kuhpf.^x06 Îx""@0Sx}LQ*̝d t 6x=>褃bxuhEFo͎0,kf,BoZ;5e>Y& x' FK %ɐ,vunQKyS<Z`&aQ8sXTU&pa% JUUz=/ڤf$IeYh'(LUIENDB`jajuk-1.9.6.orig/src/main/resources/icons/16x16/saveas_16x16.png0000644000175000017500000000154211720500104023740 0ustar drazzibdrazzibPNG  IHDRabKGD pHYs  tIME 8ptEXtCommentMenu-sized icon ========== (c) 2003 Jakub 'jimmac' Steiner, http://jimmac.musichall.cz created with the GIMP, http://www.gimp.orggGWIDAT8˝OHa?3skZH"4 iD!"Xy`a ! E E"fy(hYpna-y/χQu\8W @PLQeٖ[VZJ+A4vn~YЀ9qRwgx:{cqQ54~ɒBc>m  x"W%0<-=OJånrF$K`k`0,`(#/~[X1S0L[k:M txq$Iǎq!ϦR鮠5ŘvF~k@wX] 26gat]ǙWxvQF4VrʍD-iDu]=oz2@UUBH͖>W*" ?~2" 6/).f|| AASp8x>,%[4M#=Ϻ]W[~-j{hcc?{IENDB`jajuk-1.9.6.orig/src/main/resources/icons/16x16/accuracy_low_16x16.png0000644000175000017500000000144011720500104025126 0ustar drazzibdrazzibPNG  IHDRabKGD pHYs  tIME-"IDATxڕKHTa;g(=$ljRڗ % E( Zhe.Zhː,ҞcƩqfw9F:9n@Hֶ쉂a\.x2 ENO^)  |6*=s^[c==Vv4-,(Wl%P*C(Q\`g.s*h+B $ƠPU>776AqTYbFP9WUpp}Uj`N)EPķG$2.@IDTVm! P@DFAȢ.ˀ4K٪)cрذlq@)$࢈ODU\"y9BA p]T2ϰ[jKBζpȫ*@ A"GT(քӱwZ=9ۻx]CMk!O+R*V cQ<5/η2B[U7GN9/ιo슬L_8i!d%ܝ~2^ zvټ#Oimw|ŷX<)={hn S)_[*^;9QVi}샾<.nm3mwFg?:Rl\k:? M[IENDB`jajuk-1.9.6.orig/src/main/resources/icons/16x16/preference-unknown_16x16.png0000644000175000017500000000157611720500104026300 0ustar drazzibdrazzibPNG  IHDRabKGD pHYs  tIME!\5tEXtComment(c) 2004 Jakub Steiner Created with The GIMPًoIDAT8˥MhTW3f$Nm:NԊBE7]D:MZP ݴA-R  -$!ANd1ܟ9Edw>*ɫHJ "I)K#'~b] #g%umԸ/{'qʵΦT3 hВßpOJ&O | Ni0x!$7 g`kyб,j|Ƕwr&pMHc%qxi~ͣ:THoێ}aiи]⏷&ǖ~#݋](ڻ" w@b~c˿t7l3Td#: JvDZfHhfmh Xtb ( Q~T. hfm̌V~|~]z/׈D3Sظip×vw"XSOyd!#3ʐGrX ')X Q jZ$_!ƽo7V7| y,j0yX@P/$l|??QR^?r{|PHwȵe]B83Ey {?&1oȫ5Ex#2#cDB~Ez- zW#/ӼOX f](ZKGcȦŊC;V,T T`7-c̘ڄ-ߋ? N]~hu[ șҰ4IIx¯\7Q jR=`XIENDB`jajuk-1.9.6.orig/src/main/resources/icons/16x16/undo_16x16.png0000644000175000017500000000121211720500104023415 0ustar drazzibdrazzibPNG  IHDRabKGD pHYs B(xtIME #!IDAT8˕Ohaǿ҈ABCxbDP];<Aui%+$IENDB`jajuk-1.9.6.orig/src/main/resources/icons/16x16/preference-like_16x16.png0000644000175000017500000000162711720500104025522 0ustar drazzibdrazzibPNG  IHDRabKGDC pHYs  tIME7W<5tEXtComment(c) 2004 Jakub Steiner Created with The GIMPًoIDAT8˥Ohe?>ymM׬ku ؒv9lYZ Se`w C$F4L@"sm&՛`x?OuF!0UejB[EMXǦwec:wh(r>sy L21\f񫱙lG)R=\gN# ^ @?M?ȶ6ް3z/&S}IT2: WY=OeqfFE-l܍5DssP4ec\"nM}/f*| j2UIENDB`jajuk-1.9.6.orig/src/main/resources/icons/16x16/album_16x16.png0000644000175000017500000000164311720500104023560 0ustar drazzibdrazzibPNG  IHDRabKGD pHYs B(xtIME55*})K0IDAT8mO\ew8g@R(e. Mim5֔Ru+[(ӈؤlبEع@$,`(0snJb˳xGpↆ/}@L_/NcD۷?xղfz^|21M_~y^.,,R)\\\ rXVCٙcN;v/﹑#@aH)i4"u'mV,hCÃǷ.//K9PP?G5Bt03yyҧw|v7Uq]]7hnn!NkkDJu&ՄO-..n@γJR sͬ/޸αR^&Oygt$3MS)0M! /<#}b1 8a@N?S)E躎mH)?4Lq<! @H`hxJ)R:h;ץRꙮo]{[Ty>t: Оjgwog_$=D"vvwCRrJոi躎eZU/TZS!RŽ{ԏhBi =cXG+"@J ]7Fv)%GGGdYO޿;:P,XMێd2q0 ,L&#_g4Bhs$;;;Kڕi˲'''W ʼne߰_Rt !Dd9 QnJ:IENDB`jajuk-1.9.6.orig/src/main/resources/icons/16x16/filter_16x16.png0000644000175000017500000000160311720500104023741 0ustar drazzibdrazzibPNG  IHDRVΎWgAMA abKGD pHYs  #utIME 4)uIDATxMoT;Ni;MA*B]aҨbl.F?MQYCb uC"6 mݴS+TmIq6 49{U\t:TU}7Q(i宊Ϯ~oY֯n4R ]]]=l۟ai( ,311AP 766+uݯ677abvvL&i]בeYd2ha87׀n?3My0! BeY&Ht}RD(Z ArȲyA@Ap88},](²|>i$Ix뺤R).p||mۿ/0==0R鉮8CC$4dhZakfs;瀓ᰬ>77" $IB4:Z ۶,Nqh+jZz533HRuakk+,kR|.!  ~(ŢTT(r^V# D#-,,+++iOܨ_׊ à3 =r  !f~6w].^EQ :(Ll6D=鮍ZoA$NNN>K% Q;'?ǯ]ϑar~IENDB`jajuk-1.9.6.orig/src/main/resources/icons/16x16/editcopy_16x16.png0000644000175000017500000000076211720500104024301 0ustar drazzibdrazzibPNG  IHDRabKGDC pHYs  tIME /4IDAT8˕KKQ#3cڀ ZuBEvDDD616e007itFGoy;$3,F(Ͻmwa(z&vj5BЄ'sj^wcfnyu$IBTGE@QNV9TlGr(( ,˞H$?dYv pPRšz-,EA08vaSiJ%K дc,61Ӷ(XY^ePT䮳6֣yyrl;KUUn(zi.y}*($bBYIENDB`jajuk-1.9.6.orig/src/main/resources/icons/16x16/delete_16x16.png0000644000175000017500000000125011720500104023714 0ustar drazzibdrazzibPNG  IHDRabKGD!~ pHYs  tIME HtEXtCommentid logowIDAT8˥OqƟw-Z* nnP(8ijMM`RB4F7'u11d08rWzwrCQ|y>| ;YqڍLhs(lEat 岵M$A.f$IBy@f.Ql64EQ ("INyΊт h4`j"úDnKL!Vg"gc8LYd :~E @`P Z_4wqR\}T.)S{&Ъ MiZ7+˲QyGk~C^]7!Ztpi8#Hy~$6 #F ('t)mG^(,+"}߱o_}d$I{= XvT,>L q3s_^y)nr:]ͬ8 +Ϟ:өٶQKKEǏ$d"ݧ( ^zCQtJ\Xҕ}Rws8~ q#iqI^g]xn/2#z9\ߌol<{/,+bbhnтxgEQۥRiO @D@ B6%"z@&"B{J}ę4M[$^шQQ$ ) 4MDd"qczsbU=KiC]T.^ݮKOONNj3AN\{j|V 3;{gg[Z^^ٷ,kg5 _3fOL̩.43#f|U\IENDB`jajuk-1.9.6.orig/src/main/resources/icons/16x16/flag_en.png0000644000175000017500000000167411720500104023212 0ustar drazzibdrazzibPNG  IHDR k=sRGBbKGD pHYs  tIME2I/tEXtCommentCreated with GIMPWIDAT( &d3e4E+jv   pտ!$R\@-5;vO |_ { ms##zz%)29 'E1w grgr\`}}}vv[ް \b)C%n(cu ȩ.IENDB`jajuk-1.9.6.orig/src/main/resources/icons/16x16/reorganize_16x16.png0000644000175000017500000000137511720500104024627 0ustar drazzibdrazzibPNG  IHDRabKGDC pHYs B(xtIME )IDAT8˭MlunP^G IxhDK `J⁃ƣ=`LAX"F%%)vݙ9agyFx(f p݆Dd.~nj?7Cw@>9rb1 1[ro/ޝuL> \|l@+4Cs,Ȟ#oR&Y&@.Np!x] = BLz3Y@05n%)=H H:N1v ~ Oh["MA,miMSݢet@`;GiEoA´`2F]NLRdVtJĬuAp p0kpkҭXYY4=T6mo:#nm>YObju rrY=9nW{ x'_msLVVv=sw!$cᯨTu[=iu@oE35soݢ̯ a ҵ>0-^/f8 sg?bɓxb:6U>ϝw Z߽|J_3}o*gw<[:Uu]tm?([JIENDB`jajuk-1.9.6.orig/src/main/resources/icons/16x16/alarm_16x16.png0000644000175000017500000000076111720500104023554 0ustar drazzibdrazzibPNG  IHDRagAMA abKGD pHYs  ~tIME"ClD#nIDATxKBQǿ/ \j)BQ0h\DjH]°Ahi ' 9۠}l2{y( <]$kc60^{yńؼ77A&!V(X$jRҵqMu"03f"H XOVޤX뉫*;[fo@x:3A6,M; ϴ@@kt`fb!'fft:H9{,uJ%$E[h4"^ HGsщ@'NdQ|ޟDϴ"YnH6pja{'> s/gR,be@IENDB`jajuk-1.9.6.orig/src/main/resources/icons/16x16/push_16x16.png0000644000175000017500000000132311720500104023432 0ustar drazzibdrazzibPNG  IHDRasBIT|dtEXtSoftwarewww.inkscape.org<eIDAT8}Ka\K iF&J -DDR˨m_("EH&- Di͌:_3iǬgs8JDQ \( "tl}fv%:UQN6nV$'>'{clf ѱ_3;ҺGUW0}[r)2E!pڷKL*1 jj7Ұ{՟|`ZpMC,AHJl6{o@de&\=AoTVUc X hcdc;g?K1Ȥsxn'WByrlSi.K2/;xܘ[tl)sgrvlR@f21GpY@Eǣ9Pv6VUk( xML.MU(:X+L ̽ wύm(9G`ҒaCzZU~^e^l0htG{ GZCqTKӃ< "uP|apx.U(vgqxA;S͍͕7=sп]I>>8<`X+Phִ-nkwoh. ȧy};vG[W#-[DJ3CDt4Y.gimmHg}w?K*^'rx{‘0B)gQv,F^چsm9lBûѡ()9DbLLLBkae+Z+U::کTPJQ,ïrUjRJRh H4 SrX;R ?5W=A:bRAkM 4M_My輷kna6c\!m[!7ʐ٥Lr:7Wf45Ģm-xEJ~r̭-.߮v@NlJ=gSu)]wB:pXv(@(_$d6IENDB`jajuk-1.9.6.orig/src/main/resources/icons/16x16/karaoke_16x16.png0000644000175000017500000000127711720500104024100 0ustar drazzibdrazzibPNG  IHDRabKGD: pHYs B(xtIME *!wLIDAT8}_HSaͶSH,ȴ ٔX^v%AtMiwAԍ 7u jFЋmHM]ډlzl8y8"why{3qO#јR(|zT!._oUtհ"[#/ܓBWv_R+bh* 󬭮C̕C 3Z' Vh(n^~k_u|333(@ƁBi;u|=[YYA4, `6Y^^FccB!f}7&tHDhgΞJ%t0 :| ȲL&RI2_0aj H$j.J)5Ӄ$IdYDQdrr GcQ[ &P+](l;H":?)j 3xgNt]\.:kgR$sP4twpFl5rz)y€_"N\1TOyO46IENDB`jajuk-1.9.6.orig/src/main/resources/icons/16x16/volume3.png0000644000175000017500000000150311720500104023200 0ustar drazzibdrazzibPNG  IHDR&N:gAMA abKGDC pHYs  IDAT(=nUGϝ;_;nWu۔m ]K/Ol>n7-EQɝ A)" g;-7BD Nq_ݻhIGJyVFAz=fryyjiUO?lz$X,8DQ$Zk}ɊRy)_|/YFd,r{FKr||,""E.?֓dIerzz&x<ZjǗw۽`_z>1 G`ٝw._3g}|'PY'5,k/԰?+UA\9^fn߶J2}a#e9.ngnP|ުuX ߥ柇Foܸ?z SKNJB,IENDB`jajuk-1.9.6.orig/src/main/resources/icons/16x16/flag_nl.png0000644000175000017500000000027511720500104023215 0ustar drazzibdrazzibPNG  IHDR 2I pHYs t tb?oIDATӕѱ0D'A .8 n }xo^zp;'R</(Az@*%hҲl0ʭm;2JŽIMibIENDB`jajuk-1.9.6.orig/src/main/resources/icons/16x16/preference-average_16x16.png0000644000175000017500000000161011720500104026200 0ustar drazzibdrazzibPNG  IHDRabKGD pHYs  tIME  : 05tEXtComment(c) 2004 Jakub Steiner Created with The GIMPًoIDAT8˥Mh\u{ofRg3Q bRmv"vBEhw#Jqn袖@;?P R`*jk]DPqH!*͢N$޼_CKsnQ~a+% )k a<{u^e|ݕ9NWX X\09m\/!#U}t4,DlP 8_p鳃Ed#Y r$ x(G y$&F?_d/qu/JK6ȏ0|COu?5"w"NH @ڨbV!v?3Q21j2ع9y$|11۟MY{I>Zc,2^:ի82+.#!Ow|oeVJD<:95-JrdUHB9;8653+#mqbSG@8:67531/*~}obSFA:<69433,/(!|ugXNC?8:4832-2*,eznbTLC@;;8:3B@/.#-Ax~xocZKF?<9945,^<*) *_nx}~}wmiEA<::9662QJ))$#:mhlpllg]`AA<;:9:6/FS$'#*A~Zbda][PX9;98896?_'(-$$'8oHMRPMMFR9=;:9879e!Sb#14_EIIL9O4;8685:6k%"Gl*11K6=>D2M4;;:96:1o7u$&8a8;D2M2?>5;/sMrq"#3j.2>-J0=;16)s\s"2c-|0L4@>4oWq!/c'&D)68.lYp!(&{}<3vyl$+"},"{c*"sutr}[!!_}yJ)@2(*>UiztiXI5$/#$+/15688730+(-$ "" "  )!"" !!  (0""" "! ! /*#" "!  )* "#" ""(# !"!!" #&""& 0GLE?72,.#"Ow|ofVIE=:86-JrfUHB:;8654+#nrcTH@8;78651/*~}paTGB;=894,0(!}uhYOD?8:6831,2*,f|oaUMDA<<8:2JK1.$-AyzobZMG?=:956(~G() *\mz~~wmlEA<;::56/d\')#"9}empnmh\f?@=;:9<7-Uo ("*=Ubfb][N`8<987:6H$(2'$'6ENSQMND[8><;999>v#14sCIHO׼5X3;7676?9ܙ" ^)13X2>=J/X3<=<:6@3ܡH$%:{59K-Y0B@4B0ӥh""7+0D'V-@>0<(֩ܬ!"5'*X1BA2ءz̩"2#M"6;-ݟ̥!'&Һ̰?2#*!+Ǻ)!}ԣ˄!ʾg'VA%/NvŮbB&/#&06;?CDED?:4."-$!"" !!)!"" !!  (0" """!   /)#" "!   ))"#"! ""(#!""!!" " %"!& 3KPKC=703&$S{tj\OKBA>:1Lwj[NH@A>;:9.&qvhZMF>@<=;:63.thZLHAA9976./ith[SIFAA>@;>952&0D~~ui`RLEB@@;;7BJ81-#- eu}|tlkdLIBAA@==:BK<1,&%@aporurrmebc^HGBAA@>:8=I;,*'-K]gdgjgebXWZVAB??>>MJ;=JA/,*$'*BWVSTXWUTNQWTADBAA>MK:9I>)%48&4?=MK<9JB,*3=,56OBABEETS?IPQ>A@@A>NK:5H@&"*=&*:PPKADERR>HPQ=BOOB>NL;5IA&5>=%'5LOG9<@NN9DMO:@NM?:KI7.F? 6D95/*"! 2 %""!&%)*+. --*)&& !/&"%$#&"#"!"!! !!!!!"#+#$%"#!#" "!!*3%"$$"$!#" "! !!2,&!%"$ # "" ""! "+,!"$"&"$#"$ % " *"&"#"$""%!""&! )$!"!!$(l8mkKвL(* ~ #&,1!% ~%*JOֳLP(, $)15'* -0OָOich#HIU+[wȕUkk}"*UU(EWWwoQUҔK+GՊݫժuc߳n][mձcfܺileVYՇsqZGҊ,KǝGMJDT!,RODH$HRO A$ (MQED ov߻~~vv߿m~~????ich4^}^_Yݝ}]Yޞ^՝ݽێޝX핽Xю틾ޝYю]۽덾Ջޞѽ][ێݽݻۻݽٯXݽݽсͼ۽۽ݱˏѽѽݽݽ۽ݼۻ݌ظich8 ବVVVVVUUVVVVUVVUVUUVVVVVVVUUUVUVU\zVVVVVVVVVVVVVUVVVUVUVVVVVVWQЬUUUUUVUUWKvVVVV-KPWRQU'KQ]Ku,QPKP{(Q'Q-QQQQQ{'Q,{K'QRKRLK|]KKQQQ-'K-RWKPQ-KQQKRRQ{RWQKKQ{'KQQQK'.X|QR-K{.KWQKRLKR{uQ{W'QQ'QuQQQQQ'QQ{||||K.KR(K|(KQ.K.RK(LLRKRWQ'-QKQQKQu'-'QQKЫQ-|vRvvQLQQWRQKKuQK{-QQQKLQvQRQQ{RQQKQKW'QKKQ{KKQKKKQQKQ'QQ.|vRvRQLKRQ(KRK|(KQ.KRRKRQRQRKR{R{u'QQQQQ'QQQQWuWQ-uu{{Q-QQ-QuQuQuu|vXRR|Q(KRK(K(KRKRK(QLKQK(QRKRRKRQQQKLuLQRuR{QQQQ'QKQ'Q'QKQ'KQ-K-'KKQQ'QKuQvQRvXvX|(KRQRQRQLKQQQQQQQQLQQQQ{{{RQRQRQRR|RuRuR'-'QKQK-KK'-KQKQQQKQ'QQQK-Q-QQLuRRRvRvRRRQLQRQRKLKLK(QRKRK(QRKRK(KLKLQQQQR|R{R{RQ-KQKQ'QQQQQQuQQQQQ{QQQQQuQQQuQWRRRvRvR||{QRK(KRKRK(QRKRKLQRKLKRQLLLRQRQRQRW||vuuQQKQKK'-'QKKK-KQ'-QvRX|ih32 1;:571,+#$0Mj{tycdYMSAI<;- Euy~egZMV@HB>B<8'.~jh[PXFKKDI:D;<$"Y~zecWJQ@AEG@?B:@62$#7{xacVHOA9C<:-'#7xafXJXICRBEH=B7:6<54'%0tskT^P?N>7J89B5>:9?=<1($' r}|tci_S\RKWGFN=?6.4*862('O~hk_KVJ;KA7I=;G=A|Y4:.1'&(z#|tckaQ\RDRI>L?8C74z,427/'#+c[O[RESPGSIEOHC21+))+.+3h|y}werG>MD6EA4C>4@:2t96810* "Mfiyr~xvqwsfuPKWPEPNBNG:C@3h6(.#-*+&%N[fxtz{~pwm_rFBQI>JJ?HH?aK68'+$ %1Nkz`j`o`dgUcWJf:7IB5CC4;>.QI*5(Gi2$#>AucOZReW_^P^YQlHHVPFPPCFH6NR$-CA):HM>CMGCSBSACi@API>IO@BL4?e"*+q&">C|UP[K\EFmCBSSDFQ;Bn1=ibt(*"68B:H5M24d34GE34H+3j2~$!38C>G3L8;h9:LK:;F(/l2 #$:>H@DFlFGVTEFl(8|(+ +.9.13e44GD22h.  8:=.-0`//CE34d2u).(%*~TEE\p&-+)?.0g#-)+y6%'Y$$(eqmmF%*)O8$'#2x!)%%%!Nkt[A#+)%# *6KdytiU?/$!$)+)-+%!"+#+85@DDLNMRSNQJCE<35$# ''$))($.),(-$.#"(#%&#&"& %' & *#*$'!&''1%%($.+*3(-/%.,$,(#.)$1*(1%(&!$#!)#'&#-0%( $#*$,(+"-*"-%+% #!+($%.'+''&(,&.%$-&(*%+", #)")!$"%%",#0%2)&$($$0$+1%0-%3'#- ##!#%- .!$'%.&-%(%, '(#*(%#"(!*"$"!%'&*$$) /%%0"-*"0"%+' #&%$# *&%+(/#.$-'#.$)"-$*##( ") (!*)#2#.*$1")%"& '!!($)!1",($/!(&'!)(''#!#() 0;;572-+##0Nk|tzceYMTBJ<:. Evyfh[MVAIA>C<9(.~jiZQXHLJFJ9E:<$"Y~|edXKRBAF;C=BA@:,3}~{cdWJQBBK?FB?C:@52$#7|xacVHPA=I8=<7?8E>:-'#7ybgYKYJCSCFI=C8;7=44'%0tslU^P@O?8J8:B5>::?=<1($' s~}tdj_T^SKWHEN<@3,4+872('O~hl_KWL=LB8J>;IKK>GI>rQ58'+" %2LxajbpbchWbWIr68JC5DD39>-_W(5'V6$"??oP[SeX`ZN^ZQxEHWQFPRCEK4Wd"-UR):9k\d]l\f޻LKwHM>@R;Ru3<0On!(@?XKOFXAT69t05IA3@E33L,By-&ALj!&'402DBx=BRI=IPA?T3@*2̟&">C͞VQ[KbBG|?CUSDCY:Cڇ-A&*"68E:H5U-2x/4JG21R*5:ճ$ 29E>D.Q49z5:OL97L!,9ϵ$$;@J=@E|BFWVDC¸ً%>'+ +.<*-2w/4IE2/5ָ  8:=&%*p&*BE307ſ'.(&(ƲۿTECѶɝ%-+&A.-Վ#-*)5!!ؼʷt!$)ύͼ[$*'bA"'"7mȷ")$ԾͶ%$!aβwP#+(%#*=\žoL3#!$)+)-,% *",=>KOT\`bcfed]URI<:$  (&#))($/),(.%/"!'#$%#$ %$'& )$*$' &''1%$($.,+5(-0%.,$,)$.($0*(0%(& #" )"'&#-/%' $#,%- **".)!,%+&!#!+'$%.',''&(+%.$%-&()%+", #)")!#"&%",#/%2)&#)$$0$*0$/-%3'#- "!!"%- .!$'%.',$(&+!&'#))$#"(!*"$"!$(&*$$) /$%0!-)#1"%,' $&%$# )%$+(/"-$!-'$/$*"-$+##( ") )!)*#2"-*$1!)%!&'! !($ )!1!,(#/!'%&!)(''$ #(( 4?@9;610''3Royik_T[HPB@2$Iy~kn`T]GOIEIB>,1qoaX^MSRLP@KAA'%\kj_RXGILCKBG?06ik^QWIHQEMGFIAG<7'#:hk\NWHCN=CCA<6+'RorfR]QBRH?QDBNDHUNM;@46+)+#}msgXcXKXQFSG?J>=TPN497;3*% hz}fVaYL[WN[RLWOL]VT:5/.,.2+7o|}luwipTEUK=MH:JEOHLURC*1#2M1$,>G`gaaierbjskp[Tfa]hMGWQFPTFOaX]PEO[WR<@4:O;"$+FKaaQPUM^JUc\dFB[YT`A9TT[YS\==WUT_@?]]\\B=XW][V^>>XXU`@;M\S]L:@[SUWPUSP2C#0MLNJ.0+*0WZZ][Yb\a`]g_^ld`l_[fgah[LP`YZ]VYTQSMNL8D!)1/0SWUUWT[SXWS\VTcVSaYS_ZS\G59ZSTUOROKOIKHHI@$%0-3R^]X^WZXT\WTaUR^VQ]YQ[A/5XRTTPTPNQLOLNOA)&,&BWWVYW]Z^\Yab`jfdla^hc^cWNR_Y[YSUQOQKMIIJ1 '..AZXTWTXSVVSZXS_WT_YT^ZTWYSWWPTSLQMKLHJHKM2(* '.YZZ\X\YUZXS\VS]VS\XRWXQUUPTSORMNPLNKNJ$#-,TWSWUXWX[V[[Y`^[b\Y`\W[YUXWTVSPSMLKHJHJE$)''=HNUUXWVXTVURYVRZWSYVSVTQRQOPNLOLLKIHC=2!&++)(&-23,&# $').,1.)%#(!2(.71:;8BAKN=;=Fq%O)/JBHACEj<'0&jy}wjaIA@<>C,#!B,(-9JHKRHOAnJ/= +L@HLAMAN?HG>/> +GKLLNOMN9GHC?:$/APLLNOOMFHGDD5+"/?DGHKKJHD@;5'"0$&'()(&$"..""! ,*"!"!'&"!!"&s8mk/0 -0Ɔ.1 1Ć2icm#8o۵ʿեWmc+??icm4h߮޾靝޹ؽ޻ۍۻсicm8UVUQ{]Qvv|Ruu{RRvRv||RvuuuuRvXXRvRRRXRvvv||vLLQLKLKRoRuR||RRRvRvR|||it329ăDžȃڬÀýԬ+ǽsod^taVU^^pά+{snl}zfbda{j[TMIkK?:7Hd^ɬ5ȼ~{stea_UvaNMKEeZGIIEfD;:@uļŬ4zxvorjfe]zfTSOH_]?@<6UO:@=BP:[ǽȽ+zvsnfn__]VdrTWUP[jDDA6VB31A|ǽAŶzxjhd_VzbNMJEOi=BDBElGMPN[b@@6?@Kżǀ=}w|hhd_UzdMMIFKl=?==9h@::<&uK#**)$E@?I:9&^ǻjJBBF2+[r4;<=?h?MĻCǴ~x}ijd`V{cNMJGKl=?@=:hB;;<=eEIMJ`:+?õGŴ~xvrsdcd`\vRRMJ?aK;;95WE6::N\GE7Tž ȼ8trmjatdVWUSPkOPPSUdcTWVK[\9:97W9=?O=MĶű:xlkea\r_POKHEcE??=:GU;@GIReJRNE[K443T73tżOȿznlha\p_POKHEeGBB??E]9<;;7S;=@r:<*9]J:<;<:GP6::;0[;-/,+I/;DPG-#-$fíHɵ~z}{xrlc`][Rd~Z\[ZVOx_MNMJIHs@B?@?6VJ47#6?O49::3GO*1/,K/&#*F;@?,Ļ;ȇ~vwtspjsijh2ijikomlwk]\[WRTaEFD?55k&1/*F6))&=!$4J5&:į+ʤ}}|ljGJGED;pO:;:979r9-;<:UT;<<:9O\6;<<;9Z<:;:9))-,*(H+3:oO;=<6::93B!-+)*F "Ũt6/-"@ǿ/ʱFSri[ekS[[hw[__\tz^``a\`\]\\V~]UTRPMOF=@? 9nP;==<=7nF:;<=??<7nP:=<;=5kJ:;`09977(3&)(":6ߋ#:GD3&EŻ_WDN:544FEBjJGFrOHIIH@:FDDB;=<<=7nO9<<;<4kM:;;<<0Ne/9966'4&((#57 !" #-*;Dǿȷ69/M;6@3DDBjHFFGEmHFGFE@9B @;R<:=7nN9;<4kM9<0[k/9765(;$((#29""#,#"í̠+<4K61Jw4@BBeDEDEDnFEDEB?3?<=<5Q5467/kI356r-hH47667+n+5544&@"(&#-;"""-&ůό,94J4/Sf0;:9^;=iBEFGFDKUWWZTh׳Y\ ]V{[KMNNMErfWZ[Ot9DB@;*W@ $"*9  /%iju*22B2/[dDS\exdjnppptronlˆahhad^oڶTVZW RtUW\_W{OZ[VSH˿MaPPMIIT?94u!-"rŷb=KVa[[v;GFEDe=>==:;t,77991S359767-d546+}p'3211!2S!+*)ˣ@@=I:9%^źjHDDG3'e/=?i=?+=At4==?=7Z::<;<<4g;:;{OWPjٲSVWZWZRtٲUUWVM܁Mݺ_1967*ŻD--<3266/1&47&vi*677%m,76 /U3565-`4365(x 0T4)$(7-(59*uj*9(o1< ;4Y9:<4e::;:,{?U"" ޳1. #*ȿ7/(3;*tm+7 'p3;<4V9:;;<<5d:7:,{ÀHT" ެ,1 4Ǿ=(&-:(it*667(p1;<5Y ::;;<<5dd97::99+|N" ݫ)- :ǽfE;;@+ \v'667'r0;<6V::;<;<4c979,|DK"$5,47`Ż\1?HZMMm˽n''( p'3344-P346-_223%y @̻??=H66$\źo &$6# K׿ʱ¸ʵDŽ[_][YRiհJGHGGH@kٯVWZZ[\O̳ùDԿ,#rŷЈ-(<&!D˻ٯ߲ЁШTSSRE]ջެ/&ijΞ-$<&"5{./12/1#}ͻ֨"-&ůȶ)*9(#+l346554'ǻԫ",#"íNH2;%234433&2ÿҮ #/,,7@GU\jbpy~ynia\LC636 &"63&2/B+7įϣ1;?|xnonlhswefa^ZdfNOKF?VH=??=NS=@?;T;7?I`I<=(UľǨvplhbWhS+OKeoKPSRRdpV``abnhUTMFHU;<<9NI771KAEIPUż@Ȯ|zrliebWhRROMG^mAEDD@Ni:@?P`FPTU[oTSIBEO364DI-/HO(fŸǵ'{znkhd_VhPPNMH\nAGEFDKn@DAK^<@?=;[FIMSPjRH;5N121D7/tŵȸ&}xxljfa^UfOOMKGWoAFE%HnADDBAF`?BA@=VI:<;7WKPZSaA2*@2++ŰCȷ|wstfea^[SaMKKHERl;A@??@k@ABdABAAmF[`hzw_b`jejjivhlkkhnihfe`h^^][Uebebd`]|_EHHGG?uVBD%E=uKADDBAEsXZZVWVhS=@@?;RdTVUTU^22/./K$#P[[UW?11&Dǿ'ʳKZwrdjskkvp]a`o~`hhdxdhhfdhdbba]b[WRf`da\|]EGHFE?vWADDEE=sKABDDAEtWX)WVbP?A@@;NdSTSTS`311.,M+)("FSLOS.4EF-Ů͗^_aIHfnjkyiZ]]ou^ab_ww`db b_`_^Z]WVUTNe~^`__^WxWABBAA:sS=@ 9pK=?@A@@rXZX(WdT=A??;KfSTTUS^51/.*K-)("@SNOS+"661ŵwEF\IIjkihu`U[Won[^^ZtnW[[Z[WVWT}[1UkfjjkjfjZ^^]]Wh[]\\[S{^TTRSONv\]\[ZWdU:=<;6@bPQP^6..-)H.&(";ULNS1"2"[ļ#ȾFEKWGIkhedrVPRMkdU\_`|ukrvx}|~|uw{xxwsuhjidrfhbnhjllllmmknotsfdd`_dudb`]VeB72-&D-"" 4VONS7 3#$$«ͥ=BNPBEh_dfwfios|~}~spomkppmlkhNNMKIBbvV[[X[TwPΥ&9)"*<""<,29?HF32,&36""# ?+$$&&"?1#$&&#/D"&&$$"@-"$##"&G #"?, "7-7 "&**H??6-3. 6 +1"ľ d"G, ;&$"5.""*=-6<;EP563.&;+"5/ #".F# @-"$"(B"(<&9,$*./3I343-(=5&(.)@hĮ1-:9A/"-7"&$&9 "&?)15:7KF; :6E?-,-,*/F$)&"?-"$&.,A$)*,-+K7677<;K932.*+6#6 ; 1329"/ŵγ *&9O7.$5"&&#:&#$$#<"37"&*,-@E/3669=R6?<=:5SD9;<?N56432/I/*(&#:(/*1 $3*3G."&ļћ&$9.+<&;Zs0Ez 6Fho-;Ri  ,AKbjżؽӯƞmNe/D# Wn0@lt:J7L b{%/E1D ;F "3dx 9Lf} *DWk} " )"" o~FV#-n~ @Ljw -7@H=F =Fs{& D̑KDmУqG;jȠo? !@aƳeD#jajuk-1.9.6.orig/src/main/resources/images/core.png0000644000175000017500000016366311720500104022123 0ustar drazzibdrazzibPNG  IHDRZ=gAMA a pHYs  tIME ?tEXtCommentMade with The GIMP.6, IDATxwe}Y{O =La dK,WBzZ}Y]ue,[m!!Ȁi Cg't{?vZ;0 FbSS>g~Eqnbkoo@#]>XJcٲe1Ͳ~4tMGزe Tk{5~`l9wNvǶ%}vv{l@Ew6q*FGG)SXWbȷJ`tJf#&I/*680`>94 ˒d y^:.pպ>3<(ss5ddž# A`v:.C8_k6;'8|$5Gӱ8ml922wOKeIߊ8=Rs^9~bj[S1un޼ۗpzZ;ΠiNVJ\CX9ErHP-!"%RGQq1]\HA%]VntDgZ}_{D-HZtd$]ocʥ @L_JU+v'`F#ё_܍Jo k/7͡ih7$vM2FO%`D xL9 lX+Y7hOh Wl^vTEߍd…*t .–蕎՗lb8 P0|٦?S"Um;]h5YȆ?4$P7%fpxBϼAi&DOp -^W-X$m0LLc|>DR*g('/^UwESQOL\Hi21qCb1|o/\ڑg i6F7mi CL؍¾@UiqZHKQMo0.lmK à^12PZʸyeQ[ٴJN*r\f6!!tAV\ݍ@9S7 XBF ˲phk[%WˏU:PZKMLãp>],e-ȶ\,Fqd\֧[.7)UrtVFvdQG@i'jBF`4fe50_WZ';V .6Ǐ~?޶-\GUJ% frafgfI i:z0M=?|Bz>u~2DL6ѣQb{ca$'/79 \\Ju:[~@L3\n9;T0RK-{YԤƢ9dK7L+(27?Sf޾>4Ĺ N;̆#\,^+?BaE ,fh%uΜ?{yoMӛ.43I. &Mt},fyKtl.FJ{˶mf%o|hL͙\<sr]Y2ً6Hd@M[;lݺ)l͛70Y:^cŊtuuOfٵUlq©t%Yá˛{2f/o4en&&'cxxp]*yGG˲%kk;SgUOFq NI^>ZgݠGd(I91 ]ܶwޮo|ɦu V7q!).]")8;{IA키Dk 4['\C4R4lQ&''Yt)]]]T+N<87ofWϋ9x,ٌA!u@:;!Xj%&a~RPHqaLĶmkҙ<\wVsI9kmRO牰]4ݡaؾF_ebba.j'N0>>/꫷(o<,h?X} %blfm[E1z#WJ\$8**r ^;-ZiRz+ipp~tKfSԅS yF|FeSF,F=J2QalJcjjMf5\ uY0ep [vmĄPٓ7'~ $VͩƧGw>&u/oOʩ'^<,JL*CC躁-S̝B6EXIJ-4@ufggy饗(Jy>O[jrgޡf"zi(IJ%Wq|JfG/D JzP tf"#Gطo]~~z$nH7T\kX) &˰4Qvv/%(q^M@uҒV5> ϕ8:V1AJغz^\6dI%_ʐP&;uLӓTA. U Sj*5DX,RKըT*T5d;ZF7-_N^رX*fiQeg 9fg8{t\@6!311ݨJBp!vMw͢E05Rt8 WWUBY'W=j):RY̱OR^p^. %cEbWzrH]Vc7D^Xf1HUr8L\>O6%1;H#4Cٽ{7]"wŲZ7b=nl?g,j=`"ƹ+z OWȉ>[6 !Jث-6[diPuY09>)hqMˡPB@:B4*i|+N>;ISi#N33;KR|.ˑÇh"4"&b"NrQΡk:=Z@pw3 CNb AQ:#mn(-:tfj6===JGs˦3!Y>Ț.B <}]LcLCsr~'cN~'Nŭ)zӚq$gsYe6 9 1=Y) APHJ6km$-r9\y`ɩͼssegqM42Ra -1 ѠaYmaINVw9T V;\woo/u)⥗_4;"ecH;@&9~8=EU}LOMp)Yx1wy'}LOO A&pW)m,it0vYv[YV[\NuW h-PA .]jeS0C}Brq`:).,;WdY xFuV9U:F:ȗ٩3N*&ɝ2Tk%["9ř- ]z1kT*U,Do0]()'.0 kpU GkHЅHO׎ХР;qvVvt, ɯ\Т4HP,W{x'vU}顯3^V%PƲ.9#?rBOW47]0O)%e:L\摇Ft ˒Mk,[6 lx۶|6266ƾ}@tJ| IDATt,gP=5Z&2Q5h=.|BvԔɆw@˲5.<TIau /C0۷ood t Ic&j՟d$v:{w83'-’S&+;*g(ŠMK.@ȕKl'q,b׫233KooB9z__o˖:(mNg+""ʫZbZX͛ZWwbvf^.ǎU貥'8ySW3 ۲t]G4G]V'˲z*r\P$e ދT!_ci.0>kEzR!M#P#cC|իVeG0Xy`,ކԍ C <8C>) 4|Q1iW& >2zba/oDG9#h8BV򠤢ly|3@b}|>%m%_-0T*"aZ' Z[NRIȉj-!>OTeC^T TWNY^b##꼗Er9l۱05+\?zBtnz^"=h.[eЗRkrYGMf1 Ǩ{ټkC+/TL彬J iR޼w"6>fWG ~N9[DvRjA&bRQs|ʥ9uμ %vD1N ҮzI PHPxQ|4@YjȰTL%}" Te [S7;Ҏ]6 y#4RķoIjESݢR1;mJj8C6dT.&dnMCeHIR)w0Lɕ2  Z`bp(0^J(AB]wh|["(3ĹMb##XZ6wǞ8?27DS|b2KI/ MBKK/cϩ7Ä*/%YUG~mK(FނZ,|PWID_Lx{.&ը҈ 8G\ZFa즎`"bMV]H_W!?OD JޓC{c*dxUI֒j ^ 1٢l0CW_92&)TBFf̯ ]Ʌ JN̼e1_HKQ|"O6l,Lt6!pd(&!fؾ kߍ dAI . 2 |l%);2so>eF_ tCi;iVh6bIH-Uwɹ@g qVsGIM(DK/-;y2q씲s}:o3%gh^c2JzDU'kCir׾7|?х_pbSdDǵ2ݞbu8NN =bt|?{Z[s3 v<; d],]9kbiXcy_ݣm.K;8PβdZnZS|ĪO~QoےћXEDg HJ%Y,Β&dM}Ein?}e-hbÑ;w%Nv̭fi3CHY+q}>,&ĻERCvc~V;Y hbܿ]zS)K&>o7/1ta_}zFl^#<~f%/Ꮋo?*Sy's4"5̧so^9Uu\i#_ﺁGe|Ο_~_o~*}G.{npW ]<7P%ꋷpǭWuK}+_wnvD2>r\86+tJ]JǍd =\qoK.Q61S%.{?gKF2\woW1[+_󟹕g?r'{NO3VI?Ǎ{"cLfȥ!>0R~g]=Dm\rz~yE\o :v<Ŀ|5۝~%w~O.:7{>`|~Rdq^4kVӧRߧ+iO>{tg,!׸ݟ0zē|?A omp9dߎh/{ɉ7&^>Gۍd){K[>_ϔ8~0ό?1[Tx,{9-y,Qmռm:sOCKxJ.綛$~~k<3En;-GxEucz˜ŕt ٰc<\ڶdfz@BW Wl}cs+Hyȧ>m46\1z@%n%bꅓ]\ -ϧrЀKA-[V;/ ѝY1JAo$Fr1d;FRB2sno~ϩko#%xS'!~N~oE)fI^]B Dqꋐ-C?"^Kɬ G(U cYԀ_Tu|(<}lBb.QuTeES\![&ރ՘5 @EwЊYI)Zi[᠟Pp_ґ ^%6S]_Og1[|#(\97gxqn:|jhC‰Z&bjb ]'[>2>DN2Ҟ+5V=i[hY)jyfiLTЇ!r9[Sy&zu뮺> 7K&a5].SFmN.&l*L =k^s3K:0`hno,sЫCsß~ѩ1]MLp )"߮1[AԾ,Ni3][1ZB6 oP6|mV5;n6 3f)7jdXr>ѡsx*{[ncC ᳿mooPh!{>=mcś]-}9c|lr+fhcjOqg;kjufE?o{P? qU)U&Q?u#I*O$|껼

Tjll1l+;&fRcgh$[raYh-E+BHzж`'TH,KțM_snNӔ[{+ۛ34j~D{ Ib5uYױXww)oo+7L66 xVkx{w9\x͸F&r9RY>Tfۋmhfv &l^fx AXVVIT@ExiCnbqVJHl݊ )_Nq/%s}Hki767utk'DPj7}#jZxF3.) IDAT>P" o|f .\*-0*ܗNΏ.FW{Nx7B5#MhiAz3 ^[CCyzm;h y d%}B?0("M|bF/վ"X"`f՝zʩ+X^Ӿ"/u^:Uu35OQgժ.'yYfJ0==4,k3nbllq_R%I!Z'YsϵhBV}w> ʋZ7Bl8m_>P=JPOp0@R`qC> O[8d'í[PuLe;lsS4f v(Xk{9"j7R~bUÈi|6sݥt94,pZUrf|^S9K 2iǀ'И. , ۶ф(C5z`QFK)p >l2EDKH !e#OY{:GEnmZC7o[˃MĽ¥j$<*!T'=2S*!>m:DbC9 'j3 %7l|2IH WbEՅxBy?MJ]{dt}Ų~f%\{:u{;×4N6<01oyuUB [hf.m]7+qXrb±VK5zނMsnfVԸbC==\@Y+%ԮY;^v,\M;tv5\ܵڀ2,`)>g`Ǿ{NTپE]Xԑq2Z=weyroK&#<.uo؂}p Җ,/6X'u=.$8|b^V` g$8{D=߰7$VCA&)-̺@'L9Gj3<ˎ"1JkR3Sf˲0T d{RjUE/:j2eUfttI.]zG &j\q,o)HȝA< "Qs2|]HSICv՜sEoX|A.a|Yu%tf88 \S9(ˬRY5^/oM9s1]rQѸ%+}nTS lLqHE!/ÖuyJ9fK+z 2ɹ*lH1~%>coayI2X>Q\G1WE$HaZ`&Γ,6~n% 3WHtͦNDӠa٤SCUN=+Mltd-8oE9+WwrČsLO9yNL 00-BVb: JNfN(8]Uc}uU;SlXasE1{W ;N͖k=5irtE]:wVEѩLaCݔF`lBwW 'E$պiG4X$)Ms+σZ-wGդm >K=ݙ,!qؚsC"IZw^5{=*䵓Z\uQ9{¹s%|%9,~?V3(ՠ0k epSs%f.+t Ԅ bxTKܴcÇ/ +zJ9ɼڞi .AM~v1v?7dfZ{H؈ȴ%ePj>xi]L`bFnq]W鋾-Sw^jx9߱Gy%2ue|#/}Zf No$:S[NaWs,\ûZGiD)B<$38]ı6Qm $ԙT]Cӵ}R?z_f%3qc)v%GkK9[MI)H @:^bpCKÓ lwm䴤JSF^KFq0t9M/bYeRw>zDd$0jz<1u"x ,<{FA㞝U.5nPp2I % `ev |q'gVp]/k,Q%NS #J`(r"U$i"?ŹGT%:Gf1Q/W*f9u.Й])cݒm&z _vMY,"Gvgo0މ.-BG疁DT8phB2)32/̯'M Sh; ?m|t BS-yEXcY&7.%~JH:i39f׊5@͎W+/Hj0#mvL(&*E66sHV l9G"TG/͖,햕;AvK*sT*2eyBQ9g.R)Rd2h=%.\ aVBRT)L2.Of)9|Q*%H(I[ QZzJܳo>,4vZxAnDjH#53xb|ybB<1ƥŔ[=vkG:pr&p=5s._.}sx6'N !p6nu] %_{Zl>P!&L9 Mr<3Z sxXm ۳S8R`z-]n؆]yK^ч$8%:Ö^P2-sLϕ7tZdɅW&#M.6 >+蓙BFg'li-8u9, %)X[0$yy`m,\"<*GW'I裧g.:,Y/pቓ ׭+2Pcm'wx,_ xd{YX7]`%Nsں"^4X(0`E_r9:+xR:d D+9|ΦtX3Q+ ۢ%lOOq$HMC4 *c]ԣה"0imU=.MY ܬ`߉&M޴HMJ&~FP\a֖\P`UHvmkcn⩢˞X5bpLK.I®Ba 0cԪє7`Z>7x7V;ؿzY2N8صk'J%XK(̈́{Ԉ20UG}'ƆgVbVL?JnFр "AW"R_}FaB"ِjhޡ&ÉP 4ۈu]Ξ9Q12ܥHubjP(D" g?[vnw@LuKO#/C|#(#KǦ<(7ƣ*K@ÊA$xnfLO}N҆ (M30Lk\"ʍV E6관DaՀI/Z+"֪ K\.181Dj/Ͱͩ X3`2RL\0 Z6mN$"WӮ^z/U{qGS1iq1xѢ ƱL\`hhr*jœ Oz)'JkipIl 3'"ɠ U6 g"*bdT8 k T)r@)YU ~+a}'l2x5$6APRy)y~v}2GR=VxTDJw*"?gtdæLSu6 e!Ia^=b)eSkPd˅NsuSpem>jBZXKҝDy~eC[0d;[ )⸳MS;+2>1; J1d#ɤN(V.U0\%rqbO8>fƥ6JjRiF&+;t;m+s'zgFAڃ.NA E A."#l\B/_NXdvf^~_< irl9[6m``p۶XBRwnr%cV\Lbz p l+` <~5Vb_ɖ I(8Ǖx9B0(ƥU<Nm;\Y3S:q謗oFo#-TMq'ޢijDCMԞ% 1U57ؙYqo(+җ2eU2m¥)YZy_ VυyT.kun%M>Qa1[uxDpJvepGuMC IDAT:'ͱ FJ:PƲa뾈_Y e:gdAK kaðD2eݶ].M:'۬jnK\RD֢=2caLOM"mr`W-391 ;rիW166Jv0ؕl޹cZ`qNm}Ormb;NR^E$dGXf_W(k2£\ }EDeeGuv7Oy%F].KQp4Á6&kl\P.W(h2e}t3nY4$k]8۫,&WL\ɕ+k HiqX==C ,uu{L*Jb·_rE{ł֨RY˭ H̢EyOnywضmSSS! 2}Gkz"Waq[ėy f݆&4lqܓzWK^S&*+ \vФQxT {ل]k^%gg(->t+p,`ϖhB˹f \&*~ȥ98{nP,ٱcG\eϲrJzzzx衇(m*N`> MC4LogϞ=LLL|rzz4-N:پ};wfpp{p1)MlGõ۴gs8:0jG&ObUO`:gϝ  \Ο?ף+oE'u%msSGb |pe*-fvffeZfA jɤReu Mhΰo>:R;ZZ櫼 Qs>Wö>ab3>Y7)%kG)eamfyX6k]R)~k ؙz|+xLɖ=w MDjMu뗘i0vj6l^<=7Aͫg_LXt鋿2wu^!i"SWYetm VG }qMK`'jRJyN"21(rDG>N-iJ')%iߗ[BP(lOTYv-BxQԾ2C=\8ɉ'MC[ugwiz{{^FFqlG*) +/qtmy^{y*r]0tVc?{ocGt7Yu)%taTFxTB*QGװD;6; f(-sZ>sU}5\>Oc:G֏17HNmaM%Q/x޿#_|>}Γ^Lݥ Bh5HGx'MO242Js=V<ѡ~ !9}=}UؑLMNrY._̒%Ky=0hBP =Vk Q#/vd74,E`xTdy9E Q>utՃs(WB<<*-WGbU/<]ghgIQ7~=3E:]jPTT* ڷJPkLX &}#2زe> }T>!8n28K=Dĕ6&ؼy3s.v Ξ=G^4M߷qWdzly,s (c>NVfQ53xTZ<3R5\&H$cG$|"^*%;5Y*pz(>s =}j\f@rLBX'B *l6I,0S2㛈T"]*l"LTa7f; D0R Ew 0Luhڌ-_αcG?ˎ;q׍T{*ǹ癙EI\*h4xaBd bEy=UZ,}5\@4 L4ʵ Z}1F2 O =̀<3McӨƑ8tELAj1-LL5s`ǣfX;sC*aЄB+ Y\H0LfD9u,M;79>1dcu^vL=3EQ4ylj՞*B]!^"\H` \rBʲ1X2{v)SQdE#I0뮻~>Ϛ5پ}ŒO?ͣ6o|8yd_72U{=믊\B)_>aO#0Oq'ؙ.]U%xP$HZd7ģ tMWʎ;Ce:k^~ عWKӬmx){ֿs_|HCWW<0ؾs;##9ɩ uzf<Q}rzg phy;4=Džg{]ʜbP ڳEWQ>LuNxy͵0AGо|fz(gW3>W^^F߆6ś/VxPtS%&(ZcxyD`Edy[nBȅسgcc x\)su j\YiVT* 2Ho}x 9eyV./X oŨ~9ȩiyAkYZڋeHdu#p"\rR/Zf/,ᆵg8H+H2>{.)bP `=nVS,_3ʰ^^L{<Ϊ=kN2D y 4MكXv bi6s~fW9UK=@yRnGm g6bJR`/ӑ,{ߦJmC?\gg֣(ZQ-M8|Y^^4KX n<^<ÁӱjL#*Oլ7{:[֕)zMӌ@r:4/Ji{4toF\2z)W1hĵZ?fG5Lˢ`YJ )*.:앎 =n-Z x5uHJuc7ZO=on @[ravmB@\ae圿< r_P):׮-OɿV_ņV-mDB͞Ehe)ٳDZYzRBx^\U94lbcc`rQﵗcNGלa.6R/ty&s| ˝7ǻǻ;RXje&wjY螽5kS,vR\bYڮYxm.)GWC7QcӖj3B(zcIMf'!rJ/h[:Zqփc^*l<ww.y  ̹Z/(Ȼ@"b\gVsav8:uO;_ 5.mTT*/Ox"K]0ձ4|bϞի)uS taHBYs[K*yf̽ejK,WwvMr'H2Dpui Bߤ,^jCeXXD[үsCaymbs-gEf3ǡl E]Z_?oΡ*a QzzlO`2BUkߓ**"WT*."֘[5,/Fߍ׹UV\ەLh.g5߳3޾jY3:{o{R a@#w#S{_{^hBn;JE,=CVqqf02V[ɿ̞}3ck,zRI0M CG .ZA0Us2^܅\.y+U{ڈ5sk%?MtP/a[!+1\8Rymu/.bxO~>s!іQkbӘ&\~ɑ \Qu/uF\SPty=T8o,2cV{LU&(Ibs2H/=鋳h2W޷>ユ< 6ٟ=u<,g'i ?n"d}I\/?fȰΧ2M³'6e{Z Mt %DJx*2)sWJS)2U 罋Zn.IBkT˰v[&JѳPȽ.҇P..1H_q:)6$,ɒHQAxCr+ӰRdR=TirZX"9;CO MiHgߠ'Wa ɳyi0Rn6~v,M!}c}auMsRZщeXbj8Mceox7GLBKڝznL{_4 cgxY%џ^)?*fزz<0 4t4cyS[>_f#I2ퟢΡT==jjFhA3w1!xM*Fn[$'8siaUXf5Ѽ? g8Rwp ܰǞwy80Wpip[= %'xwmѧ1YsYZ·3ے[]IUHwһj.COd 024z^.'FYnpe&7.;LZn'GЙԓaL{M.mm틮mMw51؆GӾOrΎ3z`a~VL v|Ϗ}c4f&9~I~~^uvDT{?N9(̣GImț/x3|_Oqڹo 7|蝔u 9~{qtT=O;$?SkyTso's|!>gCoMzmٟ h4  <~/n#l^䮻^|&)^yug}"0W_]bKE.XT2k#5N/}2]oع&6$m؍G۾~ц;O}Zm,=91ۦª'Zݷz]o嵙6|܇Hƃd-w~mǨqM `ep[Iku?jqâ0$by޶a!vYc$lyťl[wFZ_& ~^{! IDAT~e᫡_ooG¾Ul׬N}{ęil?#ě浀yz[0glŔ.?\1)Bp7q9>:Õ #cK3Z\OqSBO L= n/dQRPe~\s cF7pc ;/Ňq,z}~co|~>'O!_yۏQJ#+~RO-r2vyM^և]AIp_$xR_BUKo{aFrIir^^Ù/0Wʼn5a゚?}}8j w{`?V^ڢVs}hdJ1oB* SMW%Ӆ`w\˥gpw{w$'}_ܟ&!_S#W賄=v6lz*jZsVW󧇘 -;ok;QN4&WTt.032Zݶ6*߇=厁OBhj)ni~AC%A3=<_+G) ]su#(0W $OofU2NsGPF bW>?Gҧ&^+S 9dtV|uazHڎrhIt0w(_MfL?e5=%._5b)wٽX@5LY{v=2^+=Hy -b)cM,rMe'N-"UB#0$}@Ɵk*#K>h?/sϚw=L~QX|77j/hg?p[`]߅JRmYĂ/9$柍2ǀtr~W6 r2'8{&.rF'H~?`}tRR=N>YH#G)GZ!Q̞xiQg;FQa> Rb6m_ϓ9\D Z`KψNjqP\x\(_ &ß0_> ._iFSoC` n*E{/r|븡)c⫇xcS2{NOr@1ʄ e1ΏpPJG.dbQ;ˁj\E]xT6).Ga1Dge0cN5"QdB† v|NNɵu˦߉uC= .".={n8 cJ >+B(s6] D"'BxuK7q2OʒW! D\+n,‹^?םh's{WlOn6ͶH|zה;*kd=D Z `-ޚ5م4߅]mDissb[aM?BO m2X)W>/d}tU釹"U!FsPBI)6~R)Yn#[' Yc6E&*gLK.ZD[Mr-aBoOĴguM}KFXs_.i"H w R2/CW~SdlJw^fzy @o!lBȴ,vd)t*Ϻz%#k_Dζr=HEdƇ L!bƍoQ$3/"K:,fJrI]mi}{*aPl&SDZWg7ߔ@:B]@?%aIFktȚ~˧XƲ X~*$)Vqzh=-2ϗHB*qKh;]jA8LdV#awX!;=gEVe|i_(6"fXB24cJ4ˁP5NtuWzD/90H PLL)PL24!!)C&#\S )Bb.&1p*oz:?}4-ikz}U jt^=Q{y}kwM_t>5cK@ZHy͌:ٱ3q ::^mPG:!C$&VxB'3B-XJB T/R(21$X`dKrxs[=rBP:c'm[*]/^ls_$ZߺeP'Ŗ_cRJ;])[Ybap8&h[| }Tfs$ -HDAx/(M =9w0yMAjf{~\uzA>:^JjtC ˜|}nᪧEa 1﫛m{"/&mo%TT &D쳣'3Ey# ӂߋ޿K_2O[8wGO`Z(bZr;2U>iu_;o2>8zaC[EeTPd&ߤTD#f^[[eM1&uǦ|<g QI~,Hb 9"r;̵T9P8 &!}  (˓e]x6*᳐tXP z`!"/HtU^ۚ4B=>Nn-며PcE@O%ΨH-ʃw(]f)>@ZFK9&!=tu"$U%'S^[N>IeHoQ ,tUAtJ{m-qzjPIcC9uXEUQd]v`'Z/z*IJ盂rG0~WK,7]'8;svܯ ~aL]Ə`֓h*."aM|-H+`bʋp!y99P] s6B16=%ż r/\կ2ww˿70yW[>";Oy)n!~5V i:̸5 o g/kgԋ7}f> g+Е& EKd TS>4-C˞F̹P܈,/wB ˨z(bb@T\*S,(WK&B TK3DwMu7y8g3z&.;OmUz+'|mD"q_Jh5WV_CcIH)p]+*j^_Nθ%20cǛ4 t7Sy)5E(UG HZ16žrU4wzS,,Kz`eY,aӐ Iֺ)=ٝ(;@i) /-F5*ű>|KtI- pE>yUo$9x}{*~k+`Q ,uï0W99K3礜ᕝdy^\l}drn3v: p\%jq_! 8Ux?ł*rKH,*4geg ro Ɩxz遟61[~'|mJ]4'\(ZtN5ۯۇ7{_m䓛+P,EPP4͘"Z: _U'jw}GulqK.=Ȩ2 ¯ pGtB}&e?VҊ 8 W}Wޝ0y[k[fM놿S͍LpX "icC{oc!t1pioO^ zׄW?n .!#-TSX$BIm=$!U$5P0ekr[wUxỲn$jMd`\ ' %MyMy g~[O3 Q`R , 41 va 5yǾ2: vJ!h&&YD!Ne!HfmR(1iQׄZ=Y4,Ih5>q\*aH2GfDǜmP;o{PLr-}ܫ[dV7349{~VZͯ">E %GR୲j?H m2Vc"iYXg4t%/@v'4˔)QoHY-<Г#j:Dvuh@5HT>ˋ}]kx4p\(0הL̺x^PK.} 7(L R Pa\Gykw^"1+azK-L# {#u?Ք*gHx1 }^gE."D J_=.I6 Pt]{zpXگSBt]$-ۣѴ=l0{ ˮs+2k/UJRIJ2"%CLDxzY 0FvX^$kl%jʪ}݈}|o.,,U ̮B!l%5 %,v vuР'vR}:ƖH ^/k:o=cW $90pd0lb^}t#|&g~[.p}X"$%!9v̮ ^]/]uJmPl'-ϝh!M1096LuPҤm.a7*dRFŗc ^BKq x\%J%ZDJq$s{SuNF`sO|ZʄHխ%A~.v(m oBYRHRJi\%~vLvXi\ [ZoS WPTc&Ixm^Pm(;xm A̮"R$.}Te !oIo7m'- ɑ4+Io4-ǨT ͔aVt+|Ʃ&$$)\3&`z9ų>UP(l٥ZoA)+/֔|+ &g|r` %5Ky/cTUmT?Ja-uks7?gEAT8m3lMO:<}/զAja? *nDY*4q,*ʥÃ!B@)(B@R1sa1޽9fP_PB9rv}ny'O,R|bvN[]| 2#b'_]E(: ^{T}v]֛-M{-,Y٤׮B?U卩:XK09+5\YJ~1 zv3 ah##$ ޴A*,zT"uRT:ï- Ih{ie(CbSFsGk=~?'~>%;3ޟ_pǧGJ^Ujg(f]5D*Gޭ}4e8#0'0jfr{Gs\Zl: XYYŶm°N}Vxb/8?|Z!4-B22cP:l3@&.>^tTY,pf׾5'??>0R8:p޲NrAGyo:htChbSz>{N03bfV;_y}*n+'m&.Xkz)R XZ3>VjՓkژQy7p93#y\`;Nӱ9&K +e* Um:y.i3Zb4fIymѡBE{L.0! "$$jj [,m̴󁉏#inw:Li p_|>?~ۖॢŇJ&,.wu-ԨTC*.r\ͷ\r={ 6s A(n0R#C[…y&g6gwC/q fxNteJOcTS7FLH]*V.F%fI%vg*Y$Q3τ?qvd]cф%V9ķ\\T*-{-_EW[ZeFڍxiKoL@J)D &'-K CY/ ju}~M,Ⱦqqu8a`R,gxC%G)ܭ̲}[Q#eOr\5-cyF<Piqί4X8#p_3 pi]?Zײm+5k˗{Nv0n^Eޛ6~cK|Ho(zo\z3k,]ٳ*,M@1=rglù,Bi uj)ѷz&{aHrbKeHwMJ*lVNev>L oGyڟⲦi8D&<t-3;O{ԣ׵/w Wb~ 7?|=rKk>kMlvK t&r`^crÖ^(kl U=w'CϽTz9ܼ-{K<|G_Q0|Ņ zd;_}Ym(6uW91aH@0=AdJojWPjU[ IDATo|o}.Zc|࿧#ݾ \^ix<~/'>mB;>;k]F_,/AAT'g)Hŷxq~JB)(8ZA%sɮr#{6;tjB%8dsvartGWx:Q.zY895Qp8+UK+lGfnq5Sn=ۂf κnճH$-e8DݺPz7ANw+aB5L@ һz&` Ψ|^9@'/_/c⇊+KMZ~ȑ%ӋT2/l |P$Sl6C.#EVPTG%^8kճnZ F<~2nN0_K>(cZSƔ]AԿq[ި8vj#ly{OCJ)&FFaqQ"N~f *5J TYmT\A˨mDX\Y,3sWj-4egtZ_}/c >K׌u:ͷ\QR|M4<CX.-紺ITUav ʲp/A^BtgCTmT N[|PX+7Qu1dž{o.T)V =ϣ}$M s fkq]ü6 'O es,V+^\wT s+9V?SwCϱW(媺UGXp x9+UE+Fzq<d3 t6-ϭG>D̪MTx_+rtgaAomiNL B+kP[p\=^UT'%]$3\8vfaW]lnV"ߞv{ }eH&OD0QenaX/3%YB5<(fƔp~nugn5~ ]|fZOa_{co|Y%}U~=xR'oߞ%rs Xm{خ,Ý; ,-&%}Pı-ja\mQiY $Rnj'5ىOF0RytFUUcګ(TJ7*[5tRk 3g[-,sbVV!JFaOu"x6CEmtb`FgUJG%~h/MqUr%{dmv%<<*HS}zvJEia{8E<rwpcw׏]l RX:$EooHE>)5Om;](CRJY*mBb9Iڱ.GHF# K`Yk-z% ;:*m{v[qYeᇂP,U^B$Aff-ށO1*cYi詡߃SYܜ;׵CJY6z8ziMw3 ˪Bk("Ib Uv%bwb!W먜f5ll#ݎfN`bCգ`7e$}YhVz-dhSHqiHu~2# .TiTڜW@yl|tLl gt=ERYe(Bv|Q_Ǧޠ19Oah> K}cz vP >ϟZ {;jCU@*;}HW)<@%mdbXq[P5Q .`;.n,]v,KX4Bv4eTj&2@[)x}(!Zԛ [ZmZ:aXfR_6 N 0pp*dL/Hս#sRpfa{ sTKMn0jL Mˆh[\Hh2 9?쑳diE"OB% <3Pm3jJdVJ{3DȔTq 6xڶ6džZ~w[rFx4:FKԚ-Z ݃=.: &3Uxiw xpX a}8Mf׬A#3_[FKk-bmiRsi6ZѤc؎y2ͅe#Eͷ8{Th.8JİCmI2*zQm.@;7Mj}M!CIki '7z}O\z5t `r  Jy䊐+jX+d~˧^^dyzP8ڱz˲muq BbqaYlqxc$Xi*Z!BɤX}yB{Ppy Wyl1Ռgiw)^v{l' ?P|gstW=#6סJDBU b`I2[[uf+C޷plIAO{v ؕ`]%w6.hy9r2nN޸ GvC9=.Hi.Ž̋楛8۲X .lۙ`JK8d"cԥ*0t`J-Cvm -ٶmͺ4m>uD,Xao k259$Wךs0= MQY!`wwOґ \%'gLm>|GJע3^2GL(0})qmX:y)t?=z0ņ٦@juY{ٵU;f-ᖃS3( eWG![v`qTƩ!RhHE5P9R ,cu0W;J" CJ̐vA* (CӧDPY xK0cn|ԩ7u+\%Y/^ Xc2,6M?=6_0)E£(4LtQ]x㬷XH^}?TD7m`/N8 ( VX[+ZbaBPkPY4;(0nO,ؘ^z;l wUYaaDlIQBypD{$*IX,-KWR86{!'\ R+k MmsxUKDTF⌢AP4ϱb,Z]I0{w)P~F=S!R誷n Πg(|6Ί:uE 2Gz%ʬ4UceA͜ gP>e4i+yJVRB>KuF}Rűs.}!_n\|80 +JEg"әzf2=$) +GS (zm9ݪϺIp{o'u};D2m7|G69RהvN] jskwDXm;:% d)^oeT Yl%Mip cj(i7 Iv iIK CzԪ`wB(5F"nz~ KLp}J_Ed;{IiR\yNo-5N8KIHxNoF{SqRs]Q>_iJD0gW}s[[0ݯ5R-ÞJFXǔ4@N D=M[h4[jGnQxמ$wAae@l榭oAɌcT*F펠Ғ`%x̸KT"~x& ֦U\yc& uv):E2l`Cf6*]hCO2K)Zpb6 `0oT 3줞E20J':Ts7ou^M6 m[J_&`:zA.DΎ){j?\(>z7pgJU3 k){ 0f=P>|vml=D(Sg; oM'Is45-6hȀ質%Jm)َй2nGV#쐒zJv5ٗ4T LUFmeo%{$^sXCt%QYb$%Ja([-c]I,aP(B/[Z wG5Wb&a6f Z| pcE FKl5連T ;&+=^Kvr3`.^P=XY*UM"");=.M5S`w*Ju-^닊B9 }A FH kզ.JT]g'orvm#eB5x(ghR2z6)IF$q@CEd~5'W } ,VPG+tkl[2qwr_t9esٱƇC/.ضI"qNj-XVUmSWPaxr۬&V|&Ds E 0S&2zS*gaE5=*S%h6Z-7yJ@@[}syln7T4xBG'Zynr~:g{gGvT?o.))LI:tawoۣ.J8-u,^qmR0D@H L&!]mzC|FbY ".669ii,.!nڶ)_ +팳- tQ긺EjVo~@pPi*pӰ8Άiα8lAE:I\h4}xѧ%[\h7+i[<"C!HPvja"Keh)gir'`VɄ 㛶0KN:jҐB%OдFg"(<vĐ7ZܻeLTR"yV;w $W֚P]sϟjPk1Sl\ύ4.J) ӛvhPmk{OoR%V`i4Rg a u y+7۲DʹE`-V඀QOrY3N˼\O))̿ZWt<<#.ܙZJ!-^69;JA <%:lWBEe5b#;i2Id2SguFZ6l+a );`Rb[YXpeUb_4݊2ק\A__\>m[~ji CO!&R.̻>k+Q‹B f~KoԉU~AF3+>JiȘlӮeVW68{ygWpo%`xKk}x9qtVC̕P"umhW:ڊLRT=v35dbȡ"vt۵ BuSG5aE].1 +0$ 2F/cnӎ_ `g9 Ju[:V : ؖXuYN/L,  xeSJ%ZnplhƞEDXJh6!  X$_* w#[NҁȰ] 04Rj*JOi[<*4%%0S~f6lF?W.k퐙>2,e//Vy/;\eX*R(ݾ:rt=^ي5."۷iZ7ޟX_/rj־3ZMV (E9_i@7ZZRǀQμ- +TtKB1֨#'.S%sCP IDAT)) H.Hj盰[X1'gb7f<~sF70Hia$~J&4&W(Z JeWc)xNxĶvIi#)̌Mʈvw<c4}B%Z999s.ؘ}5Em8ahWqxsg%E`Ak>*٩5z} Kչw:}.RrD.q(0 |[iD8zE3ї85Y#_6u }~Ͼ{6C[x2ukv-j\yuJ Qf!6iY+nl9#KbϥE}6ӫKQg'1sfk3MF ;9J" BI& M[]hkL[u]m$6 gK5tKu% YۜodCc9NM78'ϠNu{r+XcOXT.Q,q+N0sݝL{ЏTQ/Ł]zT2"~`yNU WXX"u]h5wO$U²Uժ<- I5m_+SN93^D0|[TvЂuh4w˳纻n\D>W$_y.-xJ8X楥9`4I#bq.iMnQZwx>eD6asId$' bkw#1#R1[9MZNmq:N߰S,|^rM z(xsFu0nA¹k|*vX羛 +E~Y\wѫ2=̜4N`iU[,qq"!Ⱦw09p!J0.Hgy1M$.C-6R*֡)~:vӠVB!%[083ij me3Q,lXbv{%8.h4h1KJeF6 TI2M2¬7 F=tDu=S]{5R>/Z!gۜ 80tGN//qq5(KOhNI纫Ll%ɺNn[tcAIAe[ضj6S!(Z r4#ˈ]7m(46ax33+` ym\H{}B>(KÓ36sL-GYDaٕOPaE ATT*FR\!;ZV{vF鬙6E$Ǝ]a2gWb[[W Aj-bRBoVvi]Ea?ml(M%X<%3zT}*/R)8qS1%Z3H6T;{-cW]Xvq;㇩ۻ)fB=ܱcNV4)JJ%|0y1ڟZF]RCI3\BjJ:Tl[h֘Vѯuiv]pl%@Ad cnk X] JR# ; lDZ@n2ҤmW"m"aJR(4 Pe\/ؖcbNxw'ZNO&չ1 `2{<[ O7δRYz\ +9X菞 =6"ߊ)/[JuI꒏zTͯ~VՔƜy][@]/[uXX^FF&CixpKmv5mt3$-զ{vT8c>V⤔Q\/ˍ|6[QBTt1u=+J˯&hs"܊"uQ`lvEf]/-u[\\8ѩ["-ŵKk]HD6zZ)qOgꀛʃ_Oߍ]6y8Dpsz{*i V0J0 ]cSh+ B!1ѥ jg.^N.&Ld``k1/ΰoQ!&2Zٙ*) UfZ=*7l[2׍IZn~FIՈ.KpFɭH{g8̄;S KʰRHU̕t7M!~ t.=+oDcE a#РKױZp\-WZ~d˂;ϝ^6t3t5yi3AFwKry<9/E!D4]R2,?C*Jt̉28l#BoViѵ]:dRl5y6>v+U]"=|jK) Ð"^Pu5LHԣh[.ƌ2ؾ:۵ڴio1z1v h08FslFs D%,wck|]yH5*{Ag<\YZ_{ ϧyp FtTE⚪{ /}>ɧf+]z'Vz\K"Q|uC,NJ9;2z^sw]Ag[I!ygaw#CX_Oz J;5!0iRVReg6V<<>y oCk52,fvLqߦ=NvSl36Bҁ 93UtvFsF:#UחQ'øaEZy6j3"KN*{FR1$&1^b`9*0Yw$o[Is eD_N[YfV5~eM#G[K:q(~uOF#W^  +#ۙq&Dץb9ض 9#w5QmLܯ+o2Vbˊs}W_7}˿Kdiks^fW<1mmެeF;ݎ>Q=Ϯ٤S| {+K]`S6yt|_ڕ3@K?8;ZKȇ _zO}tM _0r[B +)~=h$xD<'^5-\z9>x{+i=& kY th  ıl\Q5l Nt./R5ے+KbVkvbuR]vln Ás%se;&! SeUuFܞ.2\cBe*9jM~Tk-:'~>&\cQT b/u;xɉ:KoN׸8Sb`q=rLEWo6H%tEURJu -uk:UTj+sU(P}2Z'*v/t) Kuw4ӭ|>!hAnԨ]h+BqݝrGmQE]J鲰o8ϣ?sPHp/|S OȿH[7\XN(.fi{ޣ_ wqLNw^:p-|9IgUt`_$됖'g Tܛ΄s9< wiZgG>.^ٹU&/,o(egl2s4{_30~.u/?(~7~ϵp{ǿ"SX";{g{!qs?u(5ŕVJY9(biϾƏxkVt޺?Fp㬸k -x<40ꋔ/3wj}+iwPoFzd :šwqoC{^dwh_ٟ͓'(-E H͔Ǯpbw6Iwj# Fsws2mfv=L_N6D}*ޱo">N< Yz_qⅿLԪi,>÷z/}R\YOx V 5Z+_F[XXVeT' Xh4e*ҞM}A5)8wX*Wokm{}6_mj_F׾vlRPvNuGy|S~Ӽ=S?8؎e_- @%Ǧ{{3 mHoōpJH/Rig&9{~1QjBs8Km ӫY"mEW s=rv" y4yQ~!2\7p*΃8߅~ E/ct<)_xyo3>y~[aP_;v(&Mt X SWfx3m?įqS w=[2GPJےMLZ5x^<6s/\B} ֟Gj'j#筻!/[/LͣzMG/} 5( q=ԉĻ?ƩǾ9crUĻ??|a8ȭw?RǴɗo|jCR;?>Fٿs/~3A<)?t_P6M~=(ۄ w6=2H $qd L$ゐ<ӇmLƙHx(8e&/ʹA^[ x5{tHQuu(#~}2fam=hk'Sԛ>nί_u۶ڞX8^gYvԶي@+u#DF#jPVc* >U#Uof[6W|}v$ن͐[e h4PaT/][oT1c \ 2T%&чqĥK"5Cڗ>U*/yC@o uH[Hi+">c̜þg̒,{㙽k}u1|0 pނxP{X>g3?ijbsed"i@`\iZXȚ7ќSb0^} n;EWu8/`v9Z\ y B RJH)  wcұ_eW"V'HVO! na؏!Q- IDAT_?9Sȡ6âpP o]:T6:&΢m+ͳl<#t{BJ$VZݺv2Dl6_U0ەVUqlב>+ .eUs ߺϫע0v|'o5S5)J*W/| C/@&P?kI8}bNb"K;E`aiV1uNV^k@gul?j޲bHd_B !|?2Eז.,j# YT=_x 0+h0[?C-ZuڍDbmZf. >!]M_q碖 W?Jwy Y'@rx,jwNhƩкrlgXXkzphG35|]2&2 KLXHa >\D.KCcsJ 'c^)z~ $ ݓnTtjs{pAA9ة^UI`*FaOZk6 U۬~%ޅ}W |ZG]) j&6W*ɞ^5440>Tw7t*y:))ZR uJi2:)`pnY#=Co 15Ɲ%~ Aw JqրR a ' >-FOc_ݩ87C8_0J (1(=di 9adUrx%ϳUN*C [Ӿ, H|*!fdߓs}I4@0jFwVx't6>3)DBJ2" ! )Bw΁|ޥ^r^]t%hGo!Ov ldMv44%\?hsE cP1T"h-H?vOU?;-# l&S?|!3hMf#>H.Ahz8=(>qzDtϹ_DLj[3O]/lv=c$nGIuDꊨ]aWa )ʏ{O':zW$i/aqR}|~WE^ 63AvSo3oG/7+#q tE9@&@#F Q9{Cٗ&j H;B7(/Mz=:d7[HeM"f+=*?Љ %d". BV2?ޙ{=b&Wo&(U'APzɶ[Z^3`۪J݂bvZCk@)'($2 ^?:>n_Sy1՝e(svE"{5¶7MW_A"ߩW@Raq ^K'l>J"!^y_uM (dI|jngK*"QP Diyup>sU.N8G@%ڽD~_OZ=t3HD%PcI6'P;[^ܕ;r0#!#>tD"8tuk>-3[PH4=|RٽO ^շVw|Rcl&}p;\g_@Hˎz܅g|A( (PfB! hD4ݽΏu:6/pE71u7cJ+G~AD(R@ _NntFgHHXƭD>h K@W5+ hD*s};G#9DB #GK<?.&y@ֆnIBԑ(v+rN6lXt0X `ךg-_QsoB PckOӀo oorgo>WFWR>m-|zSP;pM}*OD/}N'nН]?+)\gshX|$v&PM79/~8.ãy"# )[3A@rl< i<5B(*Od<<'?Ń_! @tJ% QpXBAq g*@DZ!P W`iC $ b 0~Jcr$*6D"D DE9l&K)Wa-7^&B]!!S) :0H=*7= tD I{0-f9f D2`f-!!?"p4k,v6}rn +9xāڝ(n#{S/Lc$ i I I~a 6 ca8BP2CM.OȻf~x\|vns,J`g89_~=Wv@8 !Qؚ>8w_Wt 3Hd:_9FW>Y!37Eڀ!|wnhMܐ/|%+2S "(bo; qxS0X5~FYT/y#`6@=ܓ/}Uquf9u` 4ׇ~~_~gnc-wk l.Ql& ,hm,0ˠ!2%ӟ}գ^2臈y–RNf̍ O713B&gQrOe0 mE<3}o-7 &MveKl 8TBYO=ml.%e˸3|=vR@'[ (rçO>_9|nygLqF 7[<Խ3Jg=uLÍdz% vw?>YF̊zFg~4pwt>eNw=L{N# @"LԹtjwk''սX$xm3Bps9ex9|"_[?96ZLaDzQ)u1+''U҉z`# # HP#Kwv(lŃJzMk7 .3Sz x^.:UT B!E+;}wD* @t'{.VQ2PU(؀=,dYIrQ첰H+h.ƩS`i.c6kkU DDݛ $qz8kD$fی"CCoe|ؔ(`Բ@|L!Hs xj AY%H,I4^(\~b \#\E{0{Sz#r!,wgQ ]6o?jFZOV0dT z[ÿ_K37mM׺`X1MX%-T೵e.ar@Dhhށ# YvlF5 Ccg5)B@еpcU6j C@$$AТ F d[ At8h!nq%/l,QP^hız"p,eGǾ?!wC@DCh}Z͐ȭ4wmBYInm̡Gz²gz>#DHBX4#XpdH;ƱCacxXDǝ6˹p:.R{ ᘖSMZw@H%a? Ci@lKq'a3ARD-^r[x{ Eoቃ[Ù|hQ̆j/om*r^`!" 'jx4gf1J64 vUL9+OH> Zqa KFb4 o^xL +@ح%? b$'&Y!;o-~ Ҧ^()q٫˾"b,g$>doT{W]r6Wq$-.H&w8V ,8۾ :!A@k5RxBic7ah0`00H!b35q2!P*zו(6{L%9yyohVjxBed.(PhYaO@bސ)q%*~D$m#+{Z#@3;TE X%Kbs,EqS ǰq~/2^X&z/B,oo`>yP "2_1\`7!ak#R=uHPy`G:o]iHK[r%K}6QD+\aj n ci-X}@A:1⽄5@ s:Dـ D#.슣6Oc J6'o* _Z@#A +`)8dߵ׵'y"QP+w#K/l['E J7J}BG~ŏkmeec?}N Ҭ?۵z5jɣ w-;O|g.5o/%B>dqvF0ۉA_|,KȢ:oHPW )2 R[ĢВZQբw j<,_{6L2|~\jF۩~>r?iLvNx:'zy$/߅^ȁIir ݻOx;FҀ0l"̞>r53EMIGJ-=duI4b=Š\ifV\b;x[c:xo= `OQv]bww'#LF׾Ow6L?+,tޘ𻐘rn/<=o>t_]z?ߝ:{ ?cG;z=[d|\&Cѯ9~=]8{JzߥG_D?0(q>vF`5YBL=  Dt~~wG^v_hϿv稘L_ލ`vr6>'=19#lm'v~7siן]l=Y(S`7O_;|㻿cUܛvo^+!/;'[=陇Sig1Ɛ1[Oӏ_R,鵡\ZLͰ NLsNv+\зuUjmcʲ{G< D~nWb1u0.,ww+=s'fS(Vk +\eKj|gGhyjE6'ûۯӪ?,7`csxwE8#C8׊`CE.%d))2 kƆT0^_nXQ}ӟxc?Ru%H*%?DBF)H #zמe;t7dN|#@ cZ|'DoN,^TVy W页~Bd6$z,DRMBf2PeDРᤢ@EۉTD%*^( 'VT=YzʺKGqn+VP֕ZkP;6 I3.:sѯc*Yzd IDAT̈́4~'LoCM֕#;4~}NJ oux8ú 9dgaѭ>UF/QNz;*6Iwbe`c}~a;D0ZT'P&I+ReYƤ U.((TdBDB<~ ܶ bܒ^ׇ;ҳ̝ۜ"Mf3:(H D 0ϫ 1C9Lp XKAy 䲐mbL@K_\KGo^K^߮gJ;?b`Kδp8~|qEEL|J׋~7Xutd%`LQyV?_$T'Mj ,7Z`C6T@}#j.,GيN<+ K 8w#GY."XI a}% @Ԯ2䔹Z!rq3 1Y3aD3A=mbE4:xUBצ0q4Br~RZ)ptCDtiNNatZBEF J (ȤވI{~+_\RX o8J9H492I:t c|dTzIҧeytYy]eC n4"b-B@# d[F;ZF%\iЙMl6-dXr;`98!E|LK 76: p8 D[h} $vVRr (cLTg[(bl,G_xi:b=#(sB@e ]R$,@L<[翱"Ľ6]S9\6=Z.@pf1]&Y"Ai H{sC`G3P6m1U{6!7s. Wxo>'׷#)Pֺ,lFB2nnm$&)Xw^QrΞ $M;_Oxsss}}=l~rtrx|$lmtj\JD.e.XM Y(Б(Э!}d#w_cܹs^p;#Ig흝ݻw^d;(!`̖ AyI9z*0Wvu|NIh~n{֭TV&D[Ydmqe8Xa1@Xv:gN )ˢԺ2FkJ8XEQDTZZJWeUv:狢Ƿ SA.(yXvA]h <5p=ĩSEQVe*]UZ"JbO+]U3g,c j.Xin(rD}cFQ+2J@a& >1޼sٳݲ*{Nt?U<@w 7M.Gh T!,F7  /򢨤b5qC.tJV@(yM"sy*;*O⵲'4΋BkP`eMvY =e@i'ΧbDDTY (]>}exEFCeJ֐ bȲ̡WB]_QQeU B9=6ZLGp%rTVooɵqiҠ M}NQԫ=2ƑJp6|3hm*]yuUϠ\ f ε-8$\q6L51?@$"CUֿjþ (@AD{UӕhmQl@!(d',3͠Up+X1=SxI7pL V͝4* -vSYѺZWUi!x] S ]iD萎$9B @&rz;.HjV](tqέ^#pXsQUUy:SF(bS#rN(q62њ'ɠ4Z/y8Z]U yrL3y5us>.D2Uh&5~6o.`;6Bȴk տ!sc@w_:2"vF2v" RZ,1PNC^12;4]##4e7Tp q{ Ca4yn cItO:d%B!Y²`Xa6$3k狓NZg~ $<P 00Fѻ-'0=j 84jdyᄺb>`AvIA\UB9-jMZn? g}%_A!b(Jd Kǘd0 1`*A!( MAMXk]'6`YFh&RqN'pU(L7m *P2H*5dfds#c}8_[M`2<ؠG{3uyw8:yQ$IJPQEEف|n:YW/J/߄ʭ?ZK9 Xf|6!?woM/]tPF QEZyոIJ2J1/T ٟD4BEΦU6YMot|Ν̊#GTҸ2af'IY bKTDI):$+cIN]Ce ~ PFjy^/Gl۽wxxx¥.ʫu`ZZƜQ2*+֬q 6c&ֳI[X2rqPD탓^*]UU͵靋. d:+1FBdU5PE4H.eά8 -9@I8|F$^w8|"?:}L+T7imtQUT2(Ti L]J,F9Q9WrjDk׮w龪ҕ.\v˲u?Ц(1 q4[Sѕ \*Vc+tߐ#Ő"BUY](|>榊l:dhcF"CFi!SVU,¦Wysc fb{*/$"Rq4N._ D7nnnlJ)H%i wn&cNf`cn),3AU(iH cbjuHRyv4EQ|ګeY-`0eYnnFJaI'S|Htc +iϖ CV8]Rq\teHEJk-D#{%v{EF2*EyZWIҲ<+VRq].j5o,ɪB(%NZU8>:*0F !"q!SJ qgӲ,8J] &YP,XPlzTiZV۷oY{#h6㓓b eB |mm}{{'I%Ui\>1a5Z(4ԤYMUUHI$@*tU$IڵֆaQTHk @ѨԺ,"ϥQw{1Dǖ&/)as^UC5+!JeYUU:N=GJ몪vv8,(>"JiTUE^X14GUuYzxc5ɈUuUG;4UopXEim`myciVP| eJ,` Y#hC6$I N&iMH;ɠ?8>>Rinln bȲEJE(d]FHik ,z̀gFq%2e#`R (BOnǘ$R*+fgggo_ ^Sv4AV! > ?06)im*o}=+T<M&SCVFQ uic۷PEQ(ג$A !% 1^h \mzS&*@u/k55yѺ]|Qmo:shQիWh2TF;B,!"2B*2Ɛ3Uo$k[},ly@ Q x0[[[2R'!0Mҵ_r,,[U{nj/E%D$B FYA-ιVZ+ɖnq6",Lt07eI琩IisҥK$-ˢglQDBE(#s*qs a=SGh"3joVGeUemmmmlE&ʲl2gƉ| >eSc2H Ί8VH8[,b [klBtz4g J)xC_>0,i\j!BǕPsCg2[,T% BEGLR[\YBڂW!`Q0T?[iQ)J6C%NB]`VF?tU,5R$)501(j_C"lbKc+6}tGyU\jR{H-] ZI^Ӳ`XFnej펪@ui%'qio0Rnh4ӪXڎmDs!6Sϯc30DK9{Aݞ䃎^ M#]:cBVr vU8W2.B>YU6RwTੀkQ6>nd(SH܁:U^NR?9I:y'Nlv:bO'Hh ~KsM&o g8Tt[qiQvpowgUczQ SI~H^%֣ iI[ޝĚ'ؖ!lG6F2i,Ӵ+$׋~QKng O"8ב3i) !Z maVv \z 4M7NOJ6]ŝHj-^z="䨊5EW!1()V8ɕFI#82kfG'ILt2L*ZttR9E'h8xgHbH:;$2f-tUU{s(A7`y<Ч+*pE4Lpp1b2"`UJI+JD$ }UuhgrZhmb%KLhVbuS.<Ϧө1:M8"-I"ˈ}!`VӦ٣gcE[-am~jIE澝x<)B)E M("T$2M|;%դm=pExp)md?GqUQi/$Y)Y6\~7<-RMJ 42?5.A:+|-6R !fD$D]4_ބPd|j-U7-1t:(RZW?J=BF#DƐ Q.Lq`^hi~Avn|>OTuobB!hϧXk$Vab *`E{V(.kdN¨ݹ2N'T$b ?hȓ8'6fmmEQM<˲cw +@q7 }B l>OӴ6ɴv-b 2U;z0t:Zx6O&T](d$d'囫*(hw2j bcH -2)Ei3δ6eYͦo94J6ƌ6TѺ:-fB866tL-_YVs#3bNGG#)>lA@.pQaڪ$v-G|{E IDAT Y;Zu"i_ERŁn]r|O a)v0 ms|d!zFlv:F6dONNƥH*5(#!TSe<8aA- x@́BY{YZ +ׇ5SxDBJP ooĶ0H^UA`k9B4eEJ f~hD5!aQ%A !j]pP=b+`xvȽ'@>"J0@04 [BF"c5OF\"ye\lx/m5L ` .餴9G7/uߴL he{dmDrw t&^ ٶ:+9o{[v9Eaޘ\=H,712<"\Jm_ Wm0bH_ql1R!Hc_Ҋ걡#{ k}Ol/ 4X؇{?۶zbjF|-Ht/b`{լ,&[7ݹVIO)m+jhy87\'ڄj+V$۴{)UW@{';X#{Y &<:bf-r/]b>2w> { ]i0-UM={\6 np(XS8-c+&P > pj P Nx C2_]<^BfWlmn4oHu>#C^H*t2QF e.L.yet6 (A{, REԉEd\wV64w.$\A'lʲ,bj{{{:ܺ}P\W zyލC]>X ӷ8IQF~,[#BWzeyА3 '5da(X2xoٖ-!򘘕ocP>ut:P$MH).|< ^7LʪlrXhLLAK8kljY!c.n t^g8xm;::2&i:J]Uxsz2,Dw+ @5}X"xV^[PfD \V+%&""]V٬,hɉ@4s Pi@KB1֠bɉ0>x&Ϭ"BH>%DS7RD@G'`0sc4ScZ $ڇ-7$# q\7@qg:LُʪvTeY9Z7 FkB!&-·`}iZWO\(8*2Tl$JI)}Ή &1Fڗ# ^%s " idp ) c<5 (8}N-\ D`J4&`Cl.  'S@Ѻ%Eqr|4XcveBN6TQTp8$ݻw$Y,.@@pySUwT(*rRɸ|Dd6FePSx8q@Z"Rĩ4dQ V+"&LoXD )5u\k>7]Ͼ0Щʸo{߶$9dj7}i5ȸ ;ћlͦmf2#Hs!MsP XOˬQ>\79mTt-u# JBH+|nOOv~{?^&0_>mQ_q 17D!VajOͮ_J|]Oӷ$pbXwB$o$b$$z{lTl5ia9`/_o_!$oo)<4d#KJ,wZGYVtjc["a߾}ݮ_O[$b,3 CÀX K0 m5jꥳ#nr;O H1 #bJ0 bwj[_<>ɼDĈń\(€iQ1>Pig AqC?$VrD1X"VB0'i&\tf]>5ץl4oiq <>N M*پ-z# XmMԲrbIU}t>b*E=S%zh(ZřL\XڵmZDl?݊FjTPqu? ݦlWJ *MVP̔TV+tU~wGs,_Zx>< ƂfQIVbOidg@yGQ/]nj0%Ҕ0&V\jx=4b Ub 0OMA U+<֎MQf&X-;zVM~mukM[9Tr`lutcMKop|e{Zt0lu}m\֫1qihɶ|C evÀǘ/5kЦyԈaKcwȤY D88 Ouh*YN Sx!\Lct>GYP^] l L=")i=v[xL6Ɓp|y !v9ː’AQq*Ѧ[j\-VkS <|<ہpߧbB Ocߦy/9ֿyBS,Qtj""DΗ4Mu\ix@v8ч K߫4 XW/J@ǜdy2:y&<7YY,\1Z {YC&c@gHJu,1B\ȝ˿OB9/LJ׷W+EKq+Њkk}S⫣?d 6,\3ti !4 4ݫzMR8d*[4dZ0*FVlӢim<> O,D-a940wҋo Jl}m)H6PC2 6ٶ%# |͂֞wnLi:J4O˲iA@CJqL !3փKiT`Q-Temw2qVf 4~\|^2E0S&q8cL)9oT \lqqaa}t_u1>~O><-y) 1"fzXi&SazAViuEd^2f"R\LoRs_!AH4] q\V19kऎz+5'c!D)!$$%/26%30C<-n R 1ac2 (nki,Xfܜ(e= u2Hfp<><<@Bp8imt:^Nw"iߦHkX%眃L'j!Q؈ rCR.ā6]@krv>ǧO1/Y^o9CFHpeƔc~לbBhZmi%\gb9Mn Q( KC%)zY!,|݀c\% y<~d)4 EoAem| #m_[@40$rYr)4M2ȟ/e%ɘPJtjM7k={NoQ 3E>_d< x8CyaF^.yY$1kY 0l jroGu*l@$tN yƲ\\WLJpe844zuNe]E{m Պ5Y 1>㘆t\u1x\o90 P,)#l[L$5SZm?N Uݙ.s|M2HL'FI8BHܸ%l6Ԃ$1ƍzFWm n8uaDp!Ϸ@ iDB nO΁2H[ф)ǃ1q4B!5vG38^+ 칆T]xCHm7'&.` }alrmlf%jn@Bqvpf#.cF&:u.<[MkK7žrN[VnڦBۥ@)If(Z~ƄREZyٕc\йR PW8V6Z!kԨ=\$+A=Ms~~mBډGOၕJ()ԕeZs-HPs IiIް&V a7u\vl5X)OFydʂ#~L'cN"sǗGِT\= bRŚ`UaB|)]&(T:p#j_U.ꏱVj Qڣ|{KE4 [\1ё1$xBSܪqF7j4jSZJ{wxzQf^2m51.baT3)E 4ͮ+nр˗I5{W(Ew#15/  A)&aHXua}M(tvABzM&QUUݤO  rSiX\,_bwC935/v,y:6$>-)LkRzi,[IoV Val>?#-ͧ?c 2zǿ_K >.r}@!5(g=IZ*,O/Wzq|lO\0>@%n @|3 ԙN3TG$Ȇ7kd\&p$8NμE&5fXl*bo qyolU:V:$sn-%ʜ)ƄJu8&.Wo *jpيy{rbaZeeL¼bZ\V\ %/Ybj=qIsMCpzR)_ Oc>=??W_"9sA`(I.y+~ ),Tu]>1ޟX?e/0_C"bZn s\)ާ5o'UW%ޡKi?{n:OOCXE3,"9˴ ,^4BߧJ%5ZY )v:tHMrc[ƜM}JM4]0S 6C/\Ն)%݅(̜|z{{ţiſ@2.X )ò,s?Tdc\C1$Ay|~=$Dۺja_Z!k4WK`ڸJX@!<8nw8Ӳo7 uN;LP9񪎐eq Mœ3E$K^2B !Aӧeuxn?rqx nB8o= 6%/r{}~~QlF7-e 1ow }>ø7o2荷r/$°ޯלDVhᆙh8V#i kG GO?)==?te9/K@ҹǭs&c\`X4TN0DcO;UEL"_~~}}sƦi:5\jmj"n!ًvQ4DfMP2r˵8x//o4@ffnY )k PRPKYIH^/_q{Ɋ2V+ܜ)9CDC%Te4+$A!IdcқĄ~Ӑ kjMXN Y8EDW!aH+?9`v I@!$03"2-4.6ci I=7/5)/"0BBaPg3z>/%6-) !`8!F *ZG&X(g*7-`-+vxyZY?[! s1<|GPϝJShR-TRC-_MX:b8uDzUz B"R`-f{ M|ѻP$& v]0?Q%eyx<!h,^WX IXO"4 lM؎|BX' 79ro?8Rת IDATEݎwMbFQ,E*[w!ÿ-קç84J};_/LXaKilkeFuEtqB""!۷_.'HFٻ "1t.%tfŷnA#7OVeх CJM:vVx>DAU!I *4@zVz,6FzqdzZYL6\[J*q2D| |a]wR v;Nt0[.AA p1b#ٻvst6>_=Lن z̒|,ჴo]Z%foPƄRXά vRvYluA:}Lk&c ;E\m@=lȅaVwfH#V\PliREGp[i->LHT Fׇ;R6`uk=? PFja(?4~^ :eJ+81 df0@je@sҕ5zSM[xoOI7SPI`V_~,c`H7.,)tRQyYk˯NX]9{01`pee4/^Dz@3+O0qڒ5=1aqf߶pQpAU$/ aXm?٬'o!'#//tzB79`1ҠgjS8"aH>U1~|]ocNOCH mI@X nXz*q c"QLJxّ)z]exBbJڃ؜&ЊV~@̪{33_46~q͔]%vQqqx|eZ5㷧Ӷ#K'&e9f{0_3#,)m|Z@kbq6Eʦj^d!Bmq \0>s| ΍&U!zlR/i,*PqK< a-*GYӴ*,UyUӸmL30MSeY^_E[|.-/6ª|T^5Nj6غ. DyY2]/$q !Ф64$۠R/NszɹU&"zY24]/g<|߾^Z k*SY)df͎G*DD?! !MlV{/O /*C"ZLK_{w AHiufCj֊ʖZ#CC&4f{1cXpHczߩ͝U^t-% ]:ɽ8G0ZVg7(bp0*)$>@ (poN]O0-sa?%u.c(cB Ϡj 3L <if2fⅭOdge"ttObz>Pe +)`pCWi`;i-X|3 q:fyg[Ƭ̿AUzN:Hd?Ucj+G"iRh )Ҵm[Aoaj{ ݠ(Le]H _0I&;Fk!Ɩ5XS?+&UiO4T3Ch}wBK,\k[4Eb]/0}M vgi%f$pb솬co6 Lyk7Hk{^ ۨFP 6/&ز>[ac͞=*FDVhHE80?@=ت<ΝVFűr1t0VLWWzq W`0*MIK96B#Y - 򵎨}1NRV{H4vs\Zά&hglؤGv͋ ts^7e((û7ؖ&m:5{CjiuЖ{{vw͗c'S>De4t3md`9@j1Qq45w?hW!zǏ;iYpduJc-M@L==mїSz5,XK+UrUvyQhkt<ݦm{z-![唰P tkE,a Yן݁u1KHhz,p'0Lp6ܭRIi1~H/xXJ`E[ŇzWSRUH>X9 AMzUmꃷ75: axNlL!j`}+4 4@pBÕh9օmm{ >lt7)rlHor `[yazhpA6 z&-zI۶VA=xt9na;v#[p&]BʌlgϔijOv,nBM }׌٣6 oT=zŴѓy JP*~ӷoTMkݗ櫃?u4}>=E|iܟ}|wRAv^O-|kßHThqo[AFWO;;kw2[>H(z~fA^ 6bFB>6[l'v]Y!(%.2@Zg,^9(@PknMǃD)lrGsҚ#2j/܊^ujPlFN4.͕1g%7~&s\}jje,k'E1ʀѴUӣNgR]hmQ΁mt%t1a凴!$AԈJx)&]̴kX5i\6w쫶#m~pQ]qMo2}pSC - =(rB5snHUWdXIETe! ٠͊^<%?e؛4Bt9N3ً?4{ aܓ}ĝu~b7KAYQة\fo7ؙ\Z5y@K72(5H8(ѩa}"ekSFYf$&&c(jۄA)ؕMg쳷7*UFTp{ opVF^ \7v͂=]X@y*;RA-.쓻[ͮ!D3yq r w٭B4UѲj,3xs(֧3Cgⵕ[|ȺU2n zo(xlP:p7o뀆QE !{T&si LfR®2~ߣw9ok4)& th(yfLU}=y)l|C5hl3̼(vA-3~Wg qF3;J!cu`[q.>{$T@u@i=q-mKɶV1~G0LRS7Xsm9Xb"Ѩ飾I"&aв%/dq)rAFzhgΔ1=9~;j5g;qJnU,J"RhT$Xᆺ)Dc61KLeu0A97$ >i97DG(ȼz3+歐mc[ ]l xZ^ Ԡ́4w_eKeqZFsq"Xx'P{7xwQ4k Cp:LBL2cOr:+Ϩ5j7}uYHwRWjKI-be &1 :kꯣw$XJ61)4a{0Ԥ b(Kh %kx3fEGQK2&hW XcyT Uz+gn0`Űi$[Ƞ1H2vԵbc@VRD5F)5&c۝Ihe`,\@ÆA7xwsֲ =TCPgXs3*iq Gu+Ԩ͞戩xV4Z_/VΊIj3:gK=A[>؇6?}:_߂JC3(eβ%vz8(‹ˠ, +:,3٢xitXYHH̀1ZeqVL4Y&" nu`k6l%d܆{K8jwӭdՒPdBVZbA=Qͥh<ͫ4WKO4dZX&k.t@M(VFDYSR)gvjQjWjg;nj< I,'g2?@W|U3 kx>Kzw9`owD'􊉭/6hb+ f!"TԽXЉ= &Q-eʧ~5҂;G'l&a "hM:B+ĵp<]g#4iC15s;4$l@Rfv]qcmܜWh[*L~l>HfIDATF3d"֋UǢN^σpAg Z#-t[`Y{PhN͋EHy]z m %B ̡g1t`HQͺ~\-C@SJwv7&X6(ѰUgsNűXܦ[ԪhFܡ B jѸ)`oPeѱCXZ0a>hԬ˨$:9j 4aά5e27wuZ\#DWgEEY]l5{ph%J&2%tڨDR~LUwdP<-@Y=g IJ9uO6juEXXy䦑d!BvE Eٳk$NV̌4Q?w[-nkp:yHJ1nc$6cT0#:ĮUk)cև{t?}d@ DEܹ6칊;ڼ0eq#kʯŽ˫#|HSL1ZJ'SZI3Kң,;JNlo$0}}yMPS5!%ajP 7ٮ%lYc6\^N#o>J,i9S|zn[)`WmدMϽ]O=io hJp^1>r.eIpNbth;- TB{_T^2nw5ngh$5 Ʈcߕ_q@LEIENDB`jajuk-1.9.6.orig/src/main/resources/images/jajuk_icons_v2.zip0000644000175000017500000031461511720500104024112 0ustar drazzibdrazzibPK)5 META-INF/PKPK)5META-INF/MANIFEST.MFMLK-. K-*ϳR03r.JM,IMu (h)f&W+x%irrPKMDDPKm$5jajuk-icon_128x128.png@뿉PNG  IHDR>agAMAOX2tEXtSoftwareAdobe ImageReadyqe<nJIDATx mwU&ts|@HB$ (X8WcЭک(* Q 2) $%o~wϼZ߷{46 ZJp=Zַ{=gCz-u^7uD^szҫW5֫מ^;zuUzLuV?nTYjzݮ-z}^7u_y'@|wO>0z=^5 Y|)| |_|4$Mw7_0( @|Ya,YIe{Y_YzFK9׽zM/O~nܩחbp.aAXA_h<_zM,^o q<%ݕ>>O2"ZЩ'eo_ggdvnVfg;$v[j*#M/f܅'z^|L.愷Eە=VreǺcL b ix!֪z.LZͶ\׸ΗT/ᣇ%raxLE{z#^ zaSfwzHwolI'2ciZ@a(%RCIՔM L}t@cJO=~xD:0߫1$59"/;%i9?]<}zz;>9<[UgہtCu{}7j;H5ܒXw,\>4U@ŌBk)yKj(\OLp$n8R}X-FSC@_}? =֒7"'۟dOť5Ҩ78$JE~UZ *FE f{N_^hve~~GCzO&ϸrӍˍ7z(r}O}~eCq_tq݇/[;}qݤ7UϨ!`c8N%jׅF𶷷WqeaaN@K3P;Ұ;=09;{UԘ;Tr\w*=n \yS"fWJ5tp4~^?QF\ص7e;Zwo!> .ҍ$v/.E.hN_:0gէ'X`'dg{GΜ9#0aF Ν%?rOs0jh^/z]> Izk^R z,Ζ`ȝ U@1,07ZfTIdtˁ.H^ey 8B ,G H,FSfu5SO߬5ewpR9>loog8fC_7<;yyQ}/JWG0}w:kM }um"օzpy>|zTiqa1cmVs l;qXpG ˁ3̐g9n@<[S [Y^a PCE|Y^ZgH뛊1/M*y{K[nf8"'ѧ^f+KڐǛ#;zDMtݥo'acqnj)FNR'eޮ?xq@ 1†Y0 LC|^lWCo5VxAm_Aw_=XGbMַɣ/{n7Qj/w:. ;^̱Ch5ݹuYsP4YPx!)`8 ŇKG* {F1tH9|"=IBzwlgwQKxz0ܵt˧y4TWSZZD=0 ~宻WsCcÀVl;z}[|͝r66b.XV!jlA@I-{Ǎ4*Pu.g*NC4`(qm, 5đ6v3fEC\!v#+:X>R/,!Ufft}m}L{Rׯyh&Oﱈ;r:]8|09st%I yr2Ud  dDFØY`Uw%&$P+`C,GJ" E~. PRAaʬ#;$c`z!vfaI/-Tʊx r%q_[#E# AF! sX)9zF94lbSr=rHh4C37-7btx xzafnv-/|i갡˯39u?R<{o;f.\oJK4xw,>ys;aUp\؂qq>"nҖe029{f"jhE A hƃ\Bs)&{2P,R|Tѣe5} (h޿-ʯ|5 WjtXorH|^_(突c mUڼoHxf4H-P*4nϱ|E]W%&e!c1L qS`h{.w4B[#_ZiZzh_ n\ݞU1ojZ[0]t7+w+A!^+I^z.KXNSca 0ܜ=ٔBfY,"f]7dX)3:/gkC *҅.d[Uo0a kM*V5#>]5  >nM0PCB]#j@}ڟg%^Wɧ!Ct wUHԲ\pܲjX wFBU5(XwTA8\qQՃlMB%u~nqv?#s [)WEؼ0>yKE#r*Ф DG]A.Kj( m1=M6B"+ +ˇ;4E_w-K`5mE"UcpRY!Y00L0W`Of2PRw(#3y"xL(t(PH5as! l`K2׹~WC.e<AV C։[VVVG,2 \_xmc^`nnFwЖگfRćO"殬o=&ՒA 8 iȉ=17}LH cOvan;P*LS[IŸ٠pA,=te0FR ^:Xyo\}6 so{kl ,0hI8wEQ IUt VqT+t ^'nmRR%u잸]Mgi0=G6֛<GaL!i bec, "ny4:^Zs'@EdM[! {S!=`kk֪,-(x=*ahDa=FPH5uP"C^Mz' %G&P<<&:F]M%.@G4m-YJFwaPQq&TލЂW̑6"9\QK^>SY+JEugm 7~_<v@IN-`,#N"7UyW2#I4dzfNcA aәTakmc nC8 /T4h&|nCc; l]<1X*ٜ)0fB֫7v8yߕI"d41=5ۑggH Up9S l/uX/K=WG}mϺ;{In(~NNY0ƑtnܗG$>zN&)<ɓ̙ȱ7pkʌ m/pk& @{֏;a]|tNQV ^/Ҽ}~,,NRp5R A z6 \yQ1 %&+DPl#qFOI?,'K\:u|WlN ;POYd5(՟z?4>eXcx3Vbbt>ie^f}OU,2B'{FǑ`iك~"wGqޠH=cTՓ#T7,R!wFbE0(> I* EnP4X⁂z^L`"lxYw8|t׼"-o|3odY=6?Uo3qS䨸IXcbnZ5iD/ Ѓdz j€ZPhlV 27]:Ж֑z! yIU}4GY9?,hIĚ|Zqc𜝟oɧ"ńj頷{ϔ 6AݡKY>NGv5]3ZgܡP.x#l0X93ۑcǏ)V0^'?U7(W9|aEckjX{5Zo ]ib0)w辢XL]UV X} vh 1R("uIL ֜9xHYgqgN>Z(Q=t|Xdh.^ Dl{ H 4Ç E&&`G8m1IPUfReH4q|u4.OVCzVVLz˟/FT{olhs~;zVf.D~0˱ܵ0hPjNF xvvj z㯨UE޹{4|&Y[]+yB!0J lt. 4i"FOI@lcrsײѽ>~Uf4E rWxZF2QO+)P/ɷ"~% 9cS!\Jz}qqb ʡeyb5ȕdaq*zyj\;e/{ MD"/5-Ӄ {殙-DyKv6sl)Ёjb!b]@d+i\m"ZG?i;bP S A/ \Oq=% P7W-I|Rorv)39.:Hf ➙Yyz­NG>}YZ1"gnvQN2+72wRug(Y#:(:5P0md41F~+lF]7ݽ(̤#^V4KQ?Ŋ;yʠ> K K5ʋm-oϠHԊAT$=$!XJju p^3qiY* )!XL4}9~(iw`'/y]\rAy_"`wUAվ0Y"IT#%rŻ 6g`m$DC|8sW_O]gU;Yh!gإY)wz(F1Wz?vbҲE3 ;sb•Ӑ-_VY,G z fi)e}LpK.$> @#"QSw]S7 7^+6hXBɃ$Kn@#K8po#y<, ׍gPÍ_pᣚvyYBTv ԝu)p$/S)rq^Vp3ؙ#\RVeyi&wWrVW9@i)İB%"CVKNﱳtM%Cyc@]}i B&CE4¶>?&a0hHC/U–dODCJ kZP.z$r.45BM,Dj\`rIN<)׮^_"Mj׉XuECǹ.+V6yg*W6' =\al{ zF_4 S{_6/`a#sgt˙] /Fqś0(E Q pfƇI&#$Pny9QC*Rf(#ux! )#ggg?9}U>'/8qA^WRW= 5~Bk]ҜSҖUuY3#Y/gϮVQ1]E8rW`P5.򤤂 z[^BƔqܯ_`FI \`o(/%R07@?ohOp6e-fc5O-G9We>:` t9"\^ݷʗQ0̕s=r 1/W0/;/<0Lbster`愂[ ]oڕRE:s,/ʪg /ʉ'nwk'F`.^"OuEyQuF9Ш poFfj=sG&`>tK\M SeDѺq 4 ܢs7`n.IF0/QL +XQ|~g$zlL rFq!pC`=J;SdVtƨNzQS)$V4+WQ{FҔN>O"p^w?wt ;,|lQ0)r&5c؄#q,-\;7V'^@/ Ɓ 7BG-j#VeScɴL^kp )ۈ@@33JaU\ʤ Ű޸OW,s})-ǓBŔZky ~"L~Gń23_OneccC=$/}ɋ{3^իX,y]j?3G0Mc$)ϴg'YPAz)HRC3j#5EY)A0CUͫ̄GeY \3;7ih}2)y{ԖYhSs.4cG;233ca+T#BFn)6Ǻp]@ĒzIH3*_yHWq-txlԱ|Nqǀ;9L赃je7j滽͈|EEo~~VN=N=3洮܍o2{V]( :B^TRyg߯Y\q, ozhT䅕~0G>-VE&0x&@vAD/GPoPQ e&l{NcK~^̵g~u,,՚M;"~h:S6@eQdXGkh[= )3A3 H[UK T65-i\1󏝗;Cop̭ܮ"P.D#;mw$ӻ"L5iuF䫁T.u)ȕ kVylu__,8з \V3C,fQd8 JlNNJ![LANR^#^,"TTpFW6d0#U]áltz!꡾+z# t= rDsa}~"{ BĻl5$Ί,rPjI栥'ԑzۧ P䳏fUyiZ vc{upyE{o908-:T2!@:"( +ڜPȳ/L<7+{=ǘL+zK&~7s\f$*rlf|9>%` Nq[.s1DɳiAZ*7 /keEmM1>RM.ǔGPbTLչXiٳa[W0)JQQĩ+Z<[z=|ZiK3+q֦2{K n, w7YyƧWt&NN>yt#.9|ޤx;1)#G>=M~"!^rT,^LM J\бyMx:낶P$:r nSnal 3+ךh:q 677ij{b_gKku(Ĵq)㘯#MpӑT&Il$s[I,Z"ސI._z0JsT'K|^6!s+g#OF%৥{7ߘI'rC0'ύ(oÆiFNHQ+A!NE&k0!-]rkdqZ㱿0MB&xS#Iik0N `0Vdks(Ԙ\_sUhlw/e= A}((V(c:φG#IzkN_AThyqeHh頯yo]օ K?d.h0/#`͓~E M:1$2(ڨoK}`j[\VxtaNݨm M7$V]]sEͧ{ }e4ua+CWZ8bM\ ϳ\*UNm(2,d$/gc^=G}|Q1^WL1IͰHn8ds3WΝ6|_Kɔ2ܥr3ל"NY[VNK5qx |#\_PgL" L~KV2)5}ZxJk  1,ْK%9CdS:M}RE_.R/r25*L,s{Smoҫ eݬ⌷ҟBvXNYI1@M2d^6;U6t0n90/1wBUnh1t{f1[e{/&97^;Ra$p ̷9{E& dCP S>)*ˢHHYvi`I7G(Tp.k/NSbz5A&ўLmq1l[l3RixN>!|cĨ/LT^'ބ8 -BVbuZQN}ls>yvfd=kEzc;y%+ 3_Lݙaʁtjh^I`hڭY7Jʃ*U|i#Mcini1")DzcY]kJ_"px̴ri;̹y_W76,wn"o7ĩs$eq0FT J 㭖?uHͧ]NFzGjĬ#MbH: TVtM?;f\MWѬnpvq~~dOr)\s[aJfaXCݝr҆<ӆ8 ^tma͑2c&9;60s}OXoGyn^l h3Tĝ~P렛7w#抑- [G'eVVsPb?4-,\.B@hRyҋr0]+՛mH$L"n؅ѻ%j\ 5vg|cZ[=/ -v(vff$ *?Cҹm+HLS0kkhEeHw.ClH%HIĦ5N /){uyRkT& bFW4NDn~Z,\jw[-#2zSQ+ P_=^Xhe=2ty]{d1fYV*}Uq<1*bЍP;@Bv.D?໶xq̀Wޤ2O&vg6ʑ)E E5Sɭ^)~(pe'nON .߹@Wd)7/zO)mlK^4+!NS R6L mde30 1d9O-+r"MAN$seV"9`CxfԻ{>Opsz~rVK뫩ӒF9,uJذ'cR#<+C) śF&B1T3굜yeҟ.7g{nSCcy05"+;/82zyMTF^d2%y~0'7C;٦SXS+,I3hB7 k[6t.@D MCkǪ!]YNX *Y9 gn$?ɏ!KUy Fw2}G@3tQ^X=˖)r.Ų/q=;Hw.sZL&,Q6i"bʦXE//Jܝ&G ȗI/toN6NeqGZ mʲf#'ZFqHEBF 4cU te{k[SXf4YM?]VA(i߬״qnsC-eɂ3H|ͬT2OA-9P!h,ǎ]1:'D vXi㱓k&l τTϏ5ЖRv50" ^1iS9I/r +[DLzRE^/UebP^$'ϜPCl4xfߔ#9\-ΖthOOH̾enC>t"?(^]OEĸYCz.9uBg&nI4_{*Dxpf=C.Yu.@Cˈ##dnX" es=U(l G&wٴAJhވ.C2j۾>'G "#oy9 *}4!W\@)Y(7="-./-҆q{?tg1L#9uCX\"qs\ U|3a_3F.[PFKOY[֤vh,7,\XWZ.mKȁ和z޹nؔ֩.KE 54WncgPᕩ+x\E]=tE3/33U$N2;dWqCQX *'v':h*dcN^0~iQq6֊@Z\\*F_bСƜGХV>PEv|c%.i `:aEhX䈟BWn8֜pl J`ǁΉG7Ǔ[ 4Ev06B: x8!mb g,P?'k1A9mcǠf6tAp4m d~y!bC޹{d2D{&V_mT;!͏!ubTza4__B`b.77g;h] $bra憁ؙg͜3t73-2~+X pV3n8Y:<+eYEa IY)hdRjxHfw_ Q+- L!wM^KM1Ɉ8{{?JYp3*KSI󢜝e~ТR'p.N.6Ak)uE4uG /zN+WefjنC Υ1d<_K~BYjMYDlB_;@[Lߥu v\5 E. k#ƹ˴R +`+qmy@})&M(I9&{,sne#mSp@+p:bBRt4ʌ'cR4X#< /us |nTȱY7tk׮ӧ ۫06+:7} -7$1pCcVE^D9F|V`?L#CDU;:g_[g.\ ^vl`t=ns+pro3(n2TRbrٔ=ESf^j<CƯu`Ik:g4Lk1I{:tqǚi]UO-xlY|W246cX?Q/Őr-e 3| $馛ˤ B !=Ikr쑦Rm(5 5>ܔXm.U%l U ,<(RCb$mxn^\~7w ]s0E+Α>.}].g}qE&ax@=æD#)xPq|&Y7iv;i(oqjGN6:l_A)'R]`dK1jvX!=QHje C$^;Z@ Ӄ&Æ<"p5Y=-ɾWnNڶ̰k-]zc6[rm'sF T4FJG6eEfF6.Іhor4D4D,]EL4OtSS*!4Rٺ&fmV.=WEqO)lV!;}u150peQd~׻e7sC.C~ܶ u]JR:v VnJPbÔT'm~+}>.FSRj372գ UF ٥ M!N\aqÔaXk} a#_oDQ11NCPD3]fbwBL;;+4w씽 +؎8/-¶'fv@D&E9sdߊ[edOq-xl>RuTLEr myO>cȵKc0=ر<)#N:/KcAW=\6{d.VZ\,+t1E;3]J^Bck,eK ~d`Vo:3W''A93yI-tu 9 [yu:哳t^QfԮؕLRuf:P彍Hotf[Xх-$'9!rZ%@O궟Qox3JHMom}UoKfڲpk6!ei$h$60 4aO8(*0q0{92! ޹6fP] w\q;wMW.D;[q|s%-XPeu0 'H<;(5hw$ }/#h2Q=/GP0R65Ha2~ph7 AhHL~WΝ;/@H?9YBpkz [;q);/]+cW}G!nchJ6P~K]OfnpA٨8*q I V6ԓ:́I`cqO`N$?Kޑ+LG9)O#ocm?CQ=AW/}lnں\zI 4?}H>5=VfJbvxv˥91, s|CiT~F-}B>X]&&߱q8cF +:iV)K9PB:^Q4}f(;AY9Tz|M>;<Ƅ8 ༧/յ9C&hsk)KQFyIXk-~Gg-re'5 9m. $80/tfJ_K F8OP):&\ r@JP煖ש\&[ѣTAɋânHr?_tX+{R,⻁u4 D19˵\Ī\=zRCyV8Nc=Gx,G?'#gnU_{n+Z#mG߳&ۗo7=۔r)G7S=Zڜ/uMsc HSb3Hs;(*s!H%'phbg ѻ ӹ~8')wGh?OBDžLWNCTLMY >xKYsjƤy 2e~?ܖճٺfFV(kk`12kw~,FSN |-P/| /]r=}3lc+iEO vܔg9|\Ԫ[2PY82+GoJ[sr]"Y,P3 Ylm rPAKw,DX4.C`0/[2nQKP A&*NΝ̪SPUDj>ݮ,*'K6I?wH „A$] #ԗ@v7գkDRdeei ':5S9;_ U_ӷʵha++z]N*^NTp~I T>:p;oj:"{;;RiTRV!EߟLǓ)odFٹƃQ ٿ4`{"Q! )-SHnתr5thuc$ԙF. 1zAyzLHEփfh|5t VVHSTWO 7eBGbx^F:v5?!W\1rukFtIUV̽gT`fqEJ:52΢b/I>uvX:z~MCO]J^/ iϴ+1䮫y2'eኒ0'(HQS'S`p3t0uAR,mG(tKѬzIhرzàFיPᔞ.T' /fkjS##pv\P@֔x!+.NJ}pNZ9 tlM\&SD^'Rg\|FZ]]%h1c SdguMMoch*z}÷D |XƵt,dx!YY^aL~MȣрC"b7nnH Hy03Ijv8"ys0ԩadPwcT,rfDL:Ip^ϊ:f3t兘QO5Ǝ;*J>jKat qVb_Ig,+W/%+s\'O}WSt *7_}9 oCC⥗UHcڞ 8N?\e qL ca'j3<JnQP#CC*PdڵD?p6D @( d:gW1kfɷy䵷I*c+2{7͝{ Ěj;-(t7MhQ'2y+b&f hӦlDݏ,5,Sby1/1=.7p gѹ oH3f׋O3Wcgo oC:r}dReG;"^peDG}9v@~T׷ A.ZT7˝w#aR*NvrXCRd Da?x؃Cfќ.nA0[Ij ±H L(ƾ@,0.r!Սr3VЅ1vQR9F޽G܊D (HrVR>-X_VO=Bس{477ݫtlfZu}Oߑ-[~"Oo.éTVUYm[G{tGSWwLbeȓ 8YǎK$H0 ɛZ䭮#RV3`#&4զnSeԄؐH*HJ|6 m؋0h`3*TB D'5Ⱥi wl *KWH>f2|=%]7Lɣz#< qrѲ G<({p c dQXiEI@X@F &5eH<)SV‘P'x|$'d>wQm!Ly`7̕6͛rhTx_OgQisU&HFBTJ{ܾse'?aM>uS{OEO,L8<箯?}DnjuD:tHeJQjmIC}1DՀ'ANݍ\yԙRx@& '9MF|=37>jBF&wԹ1#45j6%^{Q:tu|܀#]?{ #WBlmpgשԿ_PlL:Z3UϽ}6ٲQcuj+k^]]aᔵuXo, Pω7L6"%j?w LKK#'Mm>Yρg 0٢ {D@jjJyCK1f.Q'Gv5׭%KU$IōmOe.\@WǟǷ=inz"Q#C QszӃv5Co>o '@l ~qK3~,'izR*;}}y?5uМDo; f&|M@`j0<r 1'F|ifS~I2-B9O%y6lXYN4?iŃa؇UblԒŋKΕ+V /h 73`h@GTbO@֏ ,%̆ yZ4FCys{ψ;*9WJ0 k %jFF= ϳAAP;6lgfs1\}X]5:2K&f͕ròo>ymNy?=l7r!q1G-n 5u\5Y*5* gA+(1;zC U%gq,X0_fϞcyi=oli6]u dH7A9x޽Gvmz]&wܺi(ayv\t57eT@ג5&dv;ϓw]VI5Zv̄*:T_"]VZ,< @/CHf[GZNx4  H(3VWW hֶVZ[ZL`q'gQ$}YV] & 7~Vz3T;D\ ߣ/*|]_ѲViüo> alҶp.ﳮb'`<(n29<ק#_UZkWߨɛL6kaLM'nS>#e-w:z*?/6ykAtԟx_F7^V,?OeSiC][GVӟtWxW1BIENDB`PK<nnPKm$5jajuk-icon_16x16.pngOPNG  IHDRagAMAOX2tEXtSoftwareAdobe ImageReadyqe<BIDATx$SoE}3mnjTHДP*8T *zA|Dp\9DU9U*4$w3v{7om!4#HӬG~Jvxb;a<(J;/,4uض 4+(Y Ƙ:8- iFϫ ,}O߂5MS$x(ǹ(HBJ"`Ja gӇ\㱏0Kqö-dYc2QIZF$SSK^Ul[r/ؽ;qbtqq=BHL[Y]`&|?Xm6׳_A.3F'> ܙ sйGkpFa Fc$IBX*2Pn"%q.j̓Q(pb R s$Q% Ko.IJس9ԂfJ8reri9$ ґ(XpF E8sb%/o.^]xuFﵚyf LHR2z&3޵7*x4ZoeXh24}3Ï}o )JBvz X`~9lIENDB`PKOPKm$5jajuk-icon_32x32.pngh PNG  IHDR szzgAMAOX2tEXtSoftwareAdobe ImageReadyqe< IDATxڌW]e>v)ňԔlZ,ԺM Q/ Eo#ޛ 7ވ7*BM1&E-[h|y18_<99xYZIJ)R2E$N$Ǝn}5A<=5AP88N[+MRٶoP+ÏMw||Oqr2,ˌB( :f)5mN[uRvRm;ﴆ=FOQrNe4%˲XRR2B1꧗~|NR|r`BFg${ 8E N3@ e;k׮pg((glK˜ 5,!}3Р"d< VЅufin7kNA?g[Ijr 1hۥNg HQ>XX8J"-9#}<0ѐҰLyf%m=+7M( "aeM:4=oQ$lǡvo?$I:z0Z7ϰ!S~p*Np|mуl, PZB;VBR"4I:j'S?^,/Ta !EQSgS0`qmJ++]&bI3'9( {jmfH}ruiw]ozvOB8VӡvCA'< s%߀U HB`QqBZ `ҥO0W\{:hڬlt9}d@q@@j4Ptc8J@K02IF\reIpbj=Vc[qrߏ 6rّ1 L٘ +U)+rG*I{ <1IucKjz(":7"0?1%#JTH 7#-U^~HSUCX`6>6tIƝ.*rP!m̈>@Cl6Uc4D"! m vp/ 5$Q5d@AB.>2Xp"K)C HۑM0j{fQ=0WQHbѤb";E~Ȝ-mӔOXjEAB뾢_-Ѷ*XLʴMzG*>uhJ2|pм\TB)Ph3CLѩ )gffZc-M #R- ױ %k:Ցі!2LXm%vҜht(9~^%a7K6Q~E)]RDb֙4W Dl+g.G8M@^ٹsyׯ_oD_|ݥ}k䆼~ufPrx<{4tgf֙QOF7nܰrc@"F4`[*07ۃ1\hiRg##c =Omu8:7w?v '<3G"n{ 9`4/-3QcvHx7xܘpݾ~ >5%®WlP̘ofG~bǎ{_|Z\\#NR}4?![v3p  j|C>>fssv?`ZRgoލIENDB`PK m h PKm$5jajuk-icon_48x48.pngoPNG  IHDR00WgAMAOX2tEXtSoftwareAdobe ImageReadyqe<"IDATxڬZi\gy~~r{}m'v8 `_'m)5p m* jJB* um(BZZ dq~g?3sy8@k<λ<>]>(?a #bYE!%/R<'H<ϓhx0<׾:+ 뗖mx40BoVw.mlllK8qHjeoo_nu]nQ#|X'Qt[d7'kVqdC znx'z iO|l4ߎ,Ųz??,fy8MߚfIxb2;k\o޶Ĵ,/Lc ÓdoA\瞥4M8 Ї6 7ϋGQ`38eێ黮80(0p %93 x?oQtjozA0QrO1'l^/2Ϊ@פI*I !ǚ[Ɠɧy#.=wFƼ~2<mkAN 85ڥF"g,ŵ 3Fl̀9]QlŘw|[w ^d0ic<[QP;?05*CQ5gDVVk&B 9:yI&Zd ^L0 u0P8}߹wwwtV 9h_1yݶe5-LB6}| #aE\aF7szaѳ>3ϲ ̍XX^^F!d!rID݀o+L*#8AfDl8+L@8jA2ph3I$ ]ϕxւ~_|Is_S>~KϼdNsЀ< Ih!4 Drmb. 4 +\a xiߵIgF٨50jg#e)f* K.?o]# RNz7lȜ"š!ڔ:g[  d4Il53&C6ʓR^Yj(l_\[Aߟx~#}h% XNw#T uь8ҁ\.Po4*@2 %|ӺJ],Eɐ`*Ie˨u9q)  H 77;+O< tرgY:zfwߛ%35c-ݚ؈[- $ܲj"300*uĦGGZb=IRs5Dd24JG{U?N0ku^JSj$R%A&JKśz= LnGV8 'v*Ι./>u+>2=1=[yCj ,4^!{{;Ϟ}ٟzm8ݹi)Ou,}&B&0>&tBea#qۖ: )q:~fc`\#v0@n 5ԛAD.'ӱ767|ڿ]emmmrsc#gK5l!*egRv*+E(8Q))҉bG#O6,<_wWK9 GO8+ؑIە2-e~yFukc=tx u:t'1Z20H";!k|c_3M ЀHLE`(J !$"GOE#X S;.4bz776K.3c/Y|bɷ{ &G+HT* )pF:Зϼo,*H4 }5Q 'dְeM+R2S=:g=.YR*5 R  ,9rx!(4 .V >R"&b#0FI Bĺ$Q>ɹ^ML4M5Zeи̙|ͼ4W,YB-O@Mh5!&:T' Fv J[9UʼH}Gc!EȋVmFx]|PQl/cH* Mс h$ wu?ݛ:M &1dtP6V* w6eS02j0cּ0:lpd\9 hrlI<41+&ւF sT:@ئM:l<6nUw] KM$kJi_V`uKn )3D)Рn0B؀9#1;F{{{0 =P@% 'q`0TEtk{"{;%xfȀ\8'6> R ")hy`͡'Z jG/TC :Yg\ho)8 1 <_f|ʡLz{yRT#c 4El c\e4 +H"]z)d>Ϛ#H^2I" gɫ{vtR0[ 0b6Sqgc@®Dꨱ`!qNKQ8~<5Gَm?b%:N"}b@&`.CT*X7>U$C A,R(e'^d%!sQ{H:v a裨Nw5I'!BZN<cR(6CM6)vx|TvI 2e\d>6,AC4D7tH&9>ʠBn7h qGF/Vnjb,)Ρ>( >o6"LDP641Z W"ϼقq]ЈU u\ݙDTL|T? 6*-}/R豈A@# 70_{A(qCbof[*OϦp) aKJ @(Kl2+5qL(HE&t͸:4_3Cc՟]__t&>zȧ\j1 4^@}u0bD#_[FұwW&\ ywl$ڣĸZ&Y[mۥdV7 `aI\@٘ ۅW viuǯ厮7*^tl~N7ۀH`ؽʳO&zTDKGf$F͚AJf*dF 3,iPPhjܚ'Pf  _z{ChL^`qro怱WWWY KǏU{`aq>6FLnr[ѤP=*@#A-8}|_q; -eTV]wx,] $ l ޸QI E՚Cr`wg ԧ~uV`|% GSDž /I _FC@xca4ً8O8IpXQB(b,NkxdU':09G%ycWS+~^uU1rʼnR2zݕ/}o)bxvuS<~y;7qşL7sK}ZzbLl j%n{kWo=}PiuSE_ d%U =rFqee>Hr6/U؃Ɓ:褟j6z?Q+_iw;߅4777O3B8`vIENDB`PKFߞPKum$5jajuk-icon_64x64.gifw\ߑH_Hi`)jPD_`"0h}v6>nww祹&daf s:sRӳ 2',JVJG /L6ys?&e*]]#n;sߊ<‚9lHx6d(PmÏHںwAKoh{3[gSZdz; ޼}ϐh->>.%%euo;qOg͞XaymyWk:q9&&l iG/e9|Ākq}VūG;pS𩄅k]溆2# L~\׭6\x{E3OSI"3k`ZEzS粎]TtQjqzt:V k8[mwLgq'_&kVR }pmYRX՞-w6kH6uSM~t0sig] KJWj~b7ʻ)EUydgNt-Qt#%oBh}v=EӁzl#Ζl <:c\cma h-]AaKF|;svVxE^kr%+/Ub ~lZU>nXh:| |bNb}ϏFNw'~Wl\e֛ IanV$]bwq 0 OkPRë^r&q牍&kgC 9ΫV"\/C  T 'u\MMя5AG~O,.b=)%v <ȡF,fzk9!T$0V^zl3y0lcZ (\]14amϙ$dkl19dPh. ,aiN{s}P*oEy:=WLi).3|V77׏,wF^Bk ot*uI_ zi$!`揋Nu^tb]IoգNE(58bu={ C˻b)M %aMsr GPIN4\g);„&yCU5z1JJ#Ԫ F?Hg,rדo\۴듁޼Xk.:j@%D!1uV]NV\ bxl<>Xq <,DmL0.FX>ۆ@6bBejfD1ӯ"fYUFvoc)AcWsw%:#iV=fU.o)xZ !/ ̋t PȅfqY8u+J{8W\ C'V+h\)٧ba={!hsHg6PF,y.E=Y$ ZtjQ`7g9Yg|OV?y㛪 @ s9Kʭx";ܩQ I1kl޹70RBĦ݄+R\&eǴGXuR !XNe('b8L)0ԑί+RJe!ϘOw-N: @|bsb4 @! ntb1:記zf 3^_ 0Bf0,=M蔜Giޡ6Cmkԑ:LQuyP e `'ǭ6 ~Ta֏a-7Z&Zf;V &AX8tDDzo莼 f9J9 ཹfېCflO0G! ӓJ1 T'}&T$9AGU꠩ jgS-LLm\KCU^#DPʔ\fP (8(&Pvk&X .a}OKtBNbtCBiyh{ŰB ~+Pc&R ohL`E [[_)OTt2U#18%`G=chr=xDa 7Mg״Pm ꨑ( TjH&{UO q  5J\G=b3q ! ᤄ<PD)`D Cx ZlVµJ'aC06!Q^GrDDr :*@ MnhPZ̰ C@|+ Fc!` z0QlBxNgdn|K-#崇+ˡ xYNPo\p 4$/_䖫yb[} &ӁB;2 }&* غ/6 qU nt_>EGhBc25ێMci_"VмTL;yi.QA}Io& KbkDGZ芉:j =W0 Q}QLH|bv5-Bw=~B^*G:hM՗Z_HZ#CؔM1h 2Zgq1Oީ. Ĵ驾\1芨 '<;s1٨ 0DdT`Qh =E|#{ }=u>Ke g\. ="QB~SQriVls'l]>]GMj\bh.v-~"?R/R?@x KI 纃a4dH.-6=uF{_ۍ464#$k(KqQf*izzE) /|mOٴz9ܿ,7̏܎ð> e W}SA}*sF>Mjq EZC~F-woB`K-*+?>dAJbTIFFIAQ[eS% +Xn(1EPKS^.Mso"GkQFZhQ_IAfiut PK.IypPKm$5jajuk-icon_64x64.png#܉PNG  IHDR@@iqgAMAOX2tEXtSoftwareAdobe ImageReadyqe<"IDATx{yeu޹}{;#f , 1*$"v% 8SeNJ\J%"d" ,0,~o=BaI޼~;ws~ZEGǓ1f$/b./D-؎5-  %XV!aX \g?q-[<'۶WCiO@/,$mnGA6Džy;==E*y#b}g8n_$:+Fk?k/j DFNF`!RP*- BZ8DxY-+|U6e`erp|*J7T:t3/+^~+ov8kfDL?eX1l +fN.m zQQt\c$USSbâ(V5>Æ*u`0Af@Giyϯ.=ڏs]w1R׾0?anm#w-:PT!]o\\] dAVWd' cY1D(zO*B=*ź)ZJp_T4x\Vllll۾\F/7[1Y]k{wй8Ok4sXL&=z iz(0o{*1T(sH ܞ֐BC^[>O/Ȳ (Ҹzns8 I,ZqGȱ6yaqU.ig-EU-Ge` v5`M@TGHYkuN35$ l ŏd3##b<ۺu˓90 Yl~ʘ"W/>hgPJ-칯xg'A"i=j_2ؠT`41iAƗ ;_Z\.J0wKwKK5[楾yPav} yß=xޯTFslZjzqU ME)Vԅ.9(p}XxMXw_klG%8JX!FL![^8JwmC&@9 ^#>gί\qbRАzv7AjəQ~啼7)(3p[y'.Dvc.gr-*<ѬBCTj5鰐h"v[HgcJi+QXz](:c%w(^T\P2$م8>@4nÚHH7~I{5'S,)}os)u Di_C2mx.J2xY"Uf@ k@)uL /XtΟ{+?|M/p),?m dO]GΟIVUD6.ERa!Mabml]MˋPǸyajf"_0Q =rYXJ!#/2-7Ic] $=/>wޯH^?xڡ-2i8--)J_ G\';nd Q{ Z!9ˆi4&|TW @,8De&pe 4t Pzae_q$-@& 6MeP7woʷ}GKK*?uzgTlFt]Pƥ5=mډҮ](e] R 85\@Q8D&"Ez*E3$x+9u_4t(@ \=J hQGaGjx0'uz{.?l{ŗnq_3@ĕ)Ek^7zJVHBu 4% : @nw(j8@w GSQ'j(,usJ}T=kXH}C ot͂A+4(TR d;ZrePbɓnymss3\vR7N `u[ο 0$3 mqqj.mEХHR##+s"Æq^v(xe9m1h!MDž1[ FI5I`ۗ!t;r-J,t8t>zyyᥗnEq^j 92įYa'BH&r.O'F kx^(!%daP{̂rhՖ8L6x-ttyLX t vN1]2""eԋe}q*;SUJ N {gMTu>Xk, s``pXf Ń$~TܸTanOabqdi<+3V0%]`ʱ ҳt3 dJזj>{ }=+<ߧM? c*XE*g%3W,D\\^RRM(CV&Ѭ+4ւ|b/o3[*LֲaĬcCN_R…edx pk(0[LG Ot;5(@t­bbM /2ȃ3̅B㞵iBE S6S茮m^S(+"7o}(B d?Ɯ䅦df$G"܉0k/bm=ܹgwLnXE8DSew,%s/TL'NMLFq1+)󸗩+ G$XecowO:]u\&/2Õ~):ȗ/dSt r.yZ12vk{FJ.,-*8࿊ \(5c &幁Cu8įkvGC}V6Vcú>*@\@9KNe87ɾU7هzr\'l68 B%+UXNdi 3-R݅\HJJw H*CPX6TAXHtSZR>tB=3 X?Dzx~;F Om7}=p&"+*\zZ;6kTwurk( $6ߌ}V))TViim2n,C yjk yFW:&[oЗ;Xgs݇rG|4L|T:@2GXkܡv/^\)]UY$U֩LضX.4{g ܴSm" {r0Huw`YFpƖk{ФDkk#\$/L,Ty 4 Mܿ[Yahin UG݈(`Ya('PyiئGx?Hm) : zOI٥ E-YI+ӅR񡋚871{,)r=xS*֙ e\3 $r 4 FhlgxiB0~-5u3n! P E\ ,R/ tQ,b:2%&pˁ %b^vR KM)[cf<u4 Rej(ڍT:br CM7PݞeϝYp_`0^ZZm$:zWȭ͉F*.Ϊ_, 5*Q m7??њ Ґc˴Q*^5$i4f‹$SjNu7`B]]l"@`B5h"uE}wۏ^3H+рe-3 v0%ԶưL$#73ica; On}5bZ .r07;:t'=VN^?*}.s6@έyDӜUb!A;64 vh,;DG%i(KsTR su(z6RωW\nh&=WF#X=>mNΖb d QQ^F[ls2ub[aY:lۣ߱05+jp%ZuB넇FչɻHZ[q2l 3[?w6MQւI(1 pKNٻTL PYX7;LupD9Pa a: ӝ;iCW^䃭?yfeyhLm^غZ"tVV]va#3mM7&7$F!`AN?uLN i`I`,LD$aJFHRgC:t*83_|eEٹg]uՓF8#< krl} 9S 2L_ 3f5hJ m YLULHL/J&>1c\ !p8gdI `8 E}[Pih>y!hMp_np wW!+#CaFE~F#эka֭_5=-Jl k(5OTOulRb{FFq cW4u] [i&K-32H5E0Ԝe-S%{ l$,C&nL^z4j&]W^}U3le]Wvq'~)ˁkAWVe+sWغ;> ,S$(eOtW(3 l䘽G=B L/>mLJ*Y{ՒSY}e*˧c9wfM=jW__dnn: {_xnrCfR";jeoKP4KRӗ18^ȭn!Z.uXnNT1(YL VLǾzY_$kD92Vf7e@Tܗ奮]֯K]soXYE[/8ymYXPaǓ, {@^9uYOڒ7ClN9tO]@$NfBdK6P7^8BX%L(G]x8U6>%d lEŷ:m#Ff9P6=9rپ} y圡g~3/|ѿݛN%ѓ@J 6jk{~Flq@c3Ǒ>dK9יrR-^Ut0˫@Ӎj>,R?sw| NȏYgZ48nҲ:B?]vihL;.ܖ^C2%内*F /y' L)>[cy{NmV6*dLA,KRl pew1:Viq^ZM.$sPC_^vC |_ם ?1<c}Kw177-Ie#nYfsr2}i9\<W%}ޤ0 -Yf*,NS?2McLRހG7gUAf{~qV7|yi\lx睷uۃp7,;pD^w9(A)m4.*80,5THgz>yF1:' \T9I>z6TY]:HgS33׿o](WGtpYE8لdYTy::i͏<ӓgo5s:q¡WAcl4y>EbWeE9P7>k9r2>,^wC(A 8]h|*$'; r간ycї 9sٶʩPG/XCl#t qS+mRa(!xݟMU?6 ߘ'o\N09ǔJ7D^sNI+9;G[,3Y-7i節EѴҺCXPq["g.mCfֈ0Gs)] TgfR¹w w?lZ/v-}l m'_/S77j0ZYCi&*3$0 =&rTQk4i\>-y {\F v-۝γ<Ӑ>% |jZ 2ߛ̓f $QbN&j7k7{,oQ} AUC}yyp_߯ǻ݂d`qlf0P4|qr???;N=>>]*^Ds?Z3Mގ9F 얼sog:_;xTefXSЕo;СCjy@0wǓ0-}!I"s%HRxv۶tFk5Lh,/ /6A/ K/ /r/ / / ,3/ [ / 7Aï+5+ ¯+ l )M+)ǖ¯+ ¯+LR G~_W~_c¯+ ¯R~_W~?; jb т7 ~7ooq$7 ~7 8o@`Fq7 ~7 84i4bLf4}L{_'_tO:_g{uus=7 )Hۈ&0}yD~\׷SX_QÖK윗2|Oԭ?\DUuAD:r]z#k]G uWֶS?g8+lX>D~n68V9߽ti|"]yDK_-K=ivXay[}[>֥<_6x,ʺ"C޾/S~|^oY&z'#丹9ټF41|d| 0I[l~_Љ\<*bq=vH,6OcvyKf;e/ޡ!I߾zOI޾hN}|y./hRzp=ky]R:8,PKPK%s$5jajuk-icon_source.icnsԼi@S0lyooܷϽiQ!02HB& aFX0O22$lm[+-m.Zk@{mo'Akߏoork9{휴[<9z]疶_ ){hnE{zwQ9{c/{P^{hX!$w _'QcZ? յT3ͳ/Y՚KP뚿XfպͿX7^ZFY?@պ} 壏7ʓ8xB!,L ;-q5O?kꗋo-@Źyb[Ktn/.Y@5;|i^6w"8@ N!ۖ%@=7?ؽx M/|qnqݓen.b`{a~ŹW.F,.N,NB"/-N,.XO.Et9- X<~2;{.(X_3xgkbq.{ݝ%d,bq{ruKwg\3̄yrpn9afbu@7qwr2CMT^weiifsCՒ @LLNL!vYZrP[m&Y~id/6hيjyT6> _<°BZ8Y濞0VLˏP`X^Y {Y[yԇ>07@hA}Gͫр:  ôJox~Pom:m@5=ԅr÷eCPZ@Bb :e句mVe@ezֵl٤γ+WԹ+bXYl+)4zSN!Qf;dA zc$LD;I!Sl1sM!~Eg]2& )tJa<׬҇[ 5lٲYyD/WC9y `灏3juZ~@lM^N6lɱȳ9r|HZ49y9prjjdVk4yuF5[o AK/5ef?j>d2h-@MNx^hf%PϴZ!0ǟ,?Pmqb}%%0fU2F 7[Dmirl~LUz%9BX~~%K&5k;]{U,q2kka/Uۋ2A"Ew^ *-+J Y>L/K尗MMeWB|6^ [Kɯonn+ݕ(`s,O 4:Vg=}<\ZS_W_YssBܟ]X$QTZQZ#31RX^L qw2ڞ ,&]D&N0;:uӖM^0"p|,6%;G)Ȅ:/LJG$qDLBPjY\@SjMF#Ca <RyK9KW UfocěSeL][ 0+2Qَ8Ouy]SkRzJgA={|*ۙ[FlE9a ܫy5zWyO'ϳ6s4RݓH,DedVFM/EnA;e{j+ZZjE-595UWqT̮=--]{ZZiݕEE!v4꛳jeUT vGE;[[[Zkˊ vZt-=]-uu5ujjkvWWV`0xwsӞ=mmiR/Jsr#p,pPȵ;s`1(AuB:!(gS!/d4ho(g rB Pk]1()B#( ž`D# gD99a08(3b($:#( r P1xKiv\2E+ }\ܐ\ %77456f%J>`sɿC.X_kK|Xa=\rW VSeNPK2};әq.<ʹh)c܉%UB)ZXWnC8Ծ[^ߝfz3?c]k8v%y| mr _=!$zd_G|sUx2/91멮oަ?ti%Lh^KwQ¿t^O>=q;8!ݧ)Ǟ_8Rr//?1ЎD»/]q7Ͽ`ygo|<3c{c)7}y[o޹oRQqGLqnxƭ7o^:}200uNȒ;ܘus_=_-N8N0W.-ݾ1'ӟ||铋}{{K.tQ9:uOܺŽ/?q] B%֭s\<Qd`/98_ \Y'zׯ_Pp4pv}nIΨUt~'B@'Bٜ 9%S"h px DypY̟Apux[nؖ ~l7dll{zRX[ᕖ֖ҜHE9UwFas[{ksUH$iQk+ٙ* ~,7*txf}ZUEFFH?˝$/*N۠ z |Xޡ99{WQiqQ޶MR@rBǍF#[22c%bJ}i"(y9uZSr.4 H!ẰPZ*z?͒>Hg'TTU+ $Q<S%BCx`L$|E(`@I\J%S}'zUbTD T27#qHb<8%UsHrA bP8 D)3 W2XEz X8,QȃJZ q?EB!ˤ L)y%qPT| VHUiԪT(x!H T$A(<W  ^T  T4%,(H*`P@;<`9bXd_XEc1ϡ? P`>p[=Xp^ g= H 18 0㌢^-(ЂAеϣ8 GB9l=Ȯy\`2> ߯Y&l[^Z+^gYS`Z ?@GhھP PGt~AGhھO'uxR76o{a;룞{mS2`yxRn_//} zh]uannZ^=WUnh|j]]8V/\ֻv܅ks źpڅ .E[DuΝ/$@KJk9 /^>hTB  }/.^_`Ƕ_,./vC͠ ž[&-%d3hwݾz{~ql v+ygζ b%yKhl+lsWf!@|7hG 3mɇŅۋf&nEA;ٚ4mf "g]Tu}i+ ߽0 '@B `s3sw/Lߙ[Y:X̻5+ss s LM⽹13 'N.\Xzo%73f]D8옹jY< {HC,g鹹9gbfvDe9,yt54 > ֝3s.;8[wviΜ$bvT#Ȃqvfh@Xwfl*s;s9`jC;s,Dw 4B+ǯ޹sw%V{JB趀p5eaB&[ÖgElbAqoǸM*䦶m%䐖UwXUI]rwў@ڝ.>ʵ +ehU0fLJ8(b l^gnA|= '5ɂmxJ<0,/CؓO. 8D {eele̴=ԂbK@ea(̿ljjЊ-Y*0C@?n+?oz Jc[r0}C*w[ Z;w-IZ'lcjVZ[ >@v,̫ Gǀl2bOGtBCӾG 10(}d/1 0{L%o:e?PdٴlN'{%C(S +&{cd٫&y@Sڲh,? ~ߞ[1vf(5a^Y& PR\~HWl1jKTw6&?t3cQm٤iLel:R#ԲB`L.[2M2z!@/BiJӘN%@ V?X3ec+jfJBAcXNmK,d@\}+ߘZ-3LjC@<[Ȭ@V֦rWLLblWe>M.YYV,c }e D c$c ,d6a r. M&5vP>H gC`<)GsJĜmd2j6Fm0Թ`AfL-[1X2v4d2p5#b5U*RdY_cPNOl1kr5Pl@u:5=;;7WMهΆjv^N8I2ijp<tgˡ2@3s!MmG.e2෶l99`5_#2չ9IM-!b^s!5d#LF "Yl[3G1=Ҥ@c96HXn|jW5l<֭ϳb.Uk:mҀ\| <=! T i֠?фey {}8XX8d2ozÖ|0y}8d1Ӧe5 }_vӎ|lyb~бC@5zf.b^i|H$~=Jl*hYb~x,g׮#{X~|#',?o/4U=Y,GEi8 %žwre{yѨXܺN؋/]E^MLP_Vڵ55'%B?!LJRl=#{OwKn>=5*8%<(\HBo6I,]:zZj*+mSy^~lq#JaD==m=]= wmKL t@%dxR|$x *onR\1N \_1WPf ŰI;w -5UU %nWGkDY3B¨EUu uu5(U& $X" PI %nT2xz+ʪ +_ݵ=9׌b? ݷ ձ>ngV^-լ9WoM>8,+J1۟:$1t +Vئߙe{F\ց}B/('k{Ș>D*ܔܐ!sCaҧ9 =}LC~ PE0 {*R PoiHCO#H2l-SdLJklVMM,8Jm վ–nܴm$7b2 /ž}IM Qhg1 գs0ɽ1sD{ =c{}|SFXl2<Hrӷ ^_[Wu±I{Ebm_whP}ɧ"DuFR}#=,F㐩#yXxdlX޲ww?u-Iwvtavrec{sq; :4ٿ'il2Ñ4 t%@ڡo..),߽ Щ䪑ᡡƽўQS:QVX2 KvwtwG]{{c}cCL<ӷהTGpp ljJFFsgkSkm}CymyC@G< F!zvv t vtv5SRXY#`@{מގcOޮ;vhY)(D`0'2m`_h@{_GGo˞涮Ζʆ$࿈G+76 vw wuu;l-%@b_è@֙”%Zg00lnؖs!hS!L%өx4HR}"\Є(A/ rҙHđ`dA8Ccp։q$8#g # 0"#A4eqnD@ad,L/tW<EPP8D):EEHM%!q/kD*H  <" tjH*J+vHA^"Ӈ q|#y5LeG$oTFwNOe;w0td  k lN˶/~&Gtwnj|5f{p\U7;M|.S Bdl<8%x<<.&*NLAHwu#G, [zO㫻\Fz-DQYk ^תd 7>= ݾ:?g!"3>`2.=z =\>Fwayg%P濮]Ǟr0κD 9ד^lKYF][g}pუ(s}o._Ҋ߾u[ǧVNM#Bq(g̟/@ m7?xSBˇO-TuKBxʖ߿I^/f]x}ԛ}D o~gW.xWgO{~c']g}nW^+_/疮pn `??g濞K}Ƨ?_q̹N:[Y/>'7}vk~xON~x]8h8t|gݵ/[_\6?v᳋3Ӈ#1")×g? ϖwooue=N1wvB`h\?*4zCBbJrRLFa; IjLw1wNX#s^GPg2t1tՋB68 J!NpƮ81b b:іB0hӑG41t*ӑӱ£bXWjLǠЎt" G"H4 d4=h:Ӑ@c:1q48 Jp'c:M`- Mƣ ("qLP74qAxOc:؊Dt瑞<>˗J$:u:WO% qVWkڛ6n#VIB?ں&nE=}=] edƇ*B4`L ;G [۫ 7iRL?sE8]ÃF@[WU1I%8P*sUصzޡCAhNsxA";um3~wpX,\*WKۇR]}. Ae21>.My96%JNԄ*]JU LQtM> aCzJҦDRVe 4͙`c]hxV  Et!rB&=H"S(D0stx> DkCb!]:, 4 e\)SitZ9\.u.*jCCr$H##\2 0MV ІhC*X m4纣";PT2@wea!p]t6&"hӆ`:47x'I o7P| <pd'<P"z*ѕBu%AH$$BAP @#RD4œDt\t7w хFp<Dwt3`ג$*@@30D,s\CF` 8M\[wt~2ŅN"b4Lc\*#DcѝI#Gi*Ndx<\H^d8։@t:V:D*B1.h<#ih4E"X:W;cևHa=Hd+ 'A[1k4хNpc\ n("JS1~-bi4Nш-H=p * Ks&p/C(p2J(TԺ}[^T_vN' "q'wv}z0N_J;_ukgtʁpv tol꟡>M|?@Zzз~Ttѭu?إn0&?CZ_;O}V>EY[kWcvJʶ)t??r;^^ss+{s{~ύ?~_soʖ5kwi ?ǯ|M@)~}~36 Z?F{"$!`M? `/~n/Xikmo鋜~tկu_dž vџ6~*bdy#\27_i[Q$1[g7{NM^e 57$V/u{e _V ,^׀dr~h?C27^^b׬X/_R0??8}w_+'2>91y11;QÕÕ/-mݵ-ͳVhKtJ1W,?{[Aaw<&;|5Do5_b˅1XNy'olE2 ffŨ)YsLy

bcnAxz\dkz͖¼G;-[xсU ]),ͶQwvlv_M{m[w%SuGєWn͟2>O^PG~uW.M_l""NM_tb$v AvB;:'n?HD#nQO#PB ܜwx,!1vGeU4M!:_ݵ==^*siX4'sıizɷSs{3gΝ'|psSgޞb2U=1}٩ɃMM}ueg)bIYtH =yC}180i?q08{c`玆Ԥ8"(@Ċ`eTeMS0=}̔HwKh__PSc}U{[QyK$B(qT>$$ i­9I|$ѮΎʊҊV}>0KiVrrB|veLʋ,OȋRDxV:uչ!PoHGgWށNSgK}Uiu֬x7]r IJц"Abj<%W1 ﵃&8dzGGcz;eśS6DmS)ebQRa%YR)emMTڝ;6bimmnl(1,ڴ19p Vɤ)_㊢Ylf0ۗ/T@4μ{&#FFGL=][J swlܘ!+I LP\_҈ؾl/XM87 :SS:0׻XLn}hGw{Kmge~Y%Sb6"#5O&a@O/7J(pLMM t {6 ;44<@PwMe>>o#4pr2) xB,8D 7uj1?61;|d|\+1w67nޘgGR!BH%e렷MyxB4RbH\9=5k؏tv5;248{SopG[Kc߱)+-9>64'J!. 엘2'0Vȸd#iulݽ#C PooO>C477V˳ԔM[b"11b,fʽޞ OwoQȋ yebMCD}FGMcF{kJ;[2ӓ7Dkrd `tD/D"R7(d<],ts}y"fݩN4 tq 9~`|ldP'5uCE;5$FA# RX\/+p. eH\&In LJ0 JOy?;4qSOOwg i-15iCN:rQ*a ^LP,&H^.bf1~xjc]-}=c7z{ޱƺn>o֭uI+@LD( 1|H/Գ1U0˸E/aeNnN{5 7 ,{h}`*klٱ3'+#"..J*G+M"0,7 L&d2e\:M&pkͦ:wuxv(&:0tip^TR[U^XdˮS!9)X2KP>g($=a,2yd&Sk R4uv;fёCݭ*eWn D%@|,+mdl`8Fx+nn %Gr?wnSS57 wv 0?~88{$>08>XS]>S'_KL7X[X,6+Ke`] x{7h/@q(;ŗP:sv=|d]%ⲮޞApaUڜmԞ7Ox#y_ ]Q=[9`:05Z/0x{GzxގnCN!qX'J{pS0MN]M(ܱm[]yCk L.m[33RzOx"3% ݇n~b&K4gۭb~xX%6(\& IΖhಞILKR[[U\^g(4V^^eSם?r[xV2 xV$BqŃN%w_QIss-31NLMmJT朜|}~St~GY%2S'_]Cā"-!`XY|,i:. u6vht)N|^<'3gO֍9nJaǎɷ>sKʢ;\*`- s#O%CY8\f.dzҽmG(z7!B7!^sgKL86u~_\^r؎7Oy8#cKfN}6i[c֭Y+rQS+_6vfB$xM)ii9ZFũ;C .{ D–#L#QQQa{c=hO_g,LrcΞ.6L;iʪ* fs䤄(6Dk|ؑG lvf00Bm=о<<LiV S<X&ŀc:PdrycjI#S_?tiWQβԤ }o_/up 94OK$r(Nt~E&i0θ FwEE&MHoHNJ+Nٰ!.6<(Àà\=xL  Bzpq aqX6J 1}.?Ea?wx`M֦#oq|#= <;gmom ˏ Ѩdaǎǐygצū {7Kc'ot84V !NaCûqSkSͺ(!/c цgEElA#!C{A]?jxC$w,{:3~Q~شo|'qMYomڎ LILC쓭 @׽u{$lY *.,VbT a@߹~乞\:}%eu_w؟b҃4?bhNK8z]- :>PL9.&>v8(uq쌉F,ŗ,^Ze3jiqqq[B[}ncO,x%*SUq_~A,(u|Jr#S;\We2J%tM,"IĬL4$P:g\r'. M2YdPvBu͚FB^%zHEnBd>Zz[ Ѕ* :  #78Ly}b"rdPKcCf)UYA񐏂Bʛ3Iz7)`g<  Ȭxtg ҏANl(Kq|iԳ:lW%FƆ3\iz A`}̬mbb(ڨXjijy(Q2/EMjk# ]tb1xQ}Vj+IT189 Å膆3@e P(+5Ah֚wF&$&&ŭ4SdM -_5O쮩«?] Tx;PAT?̔H2l2%u9yx2"o\afæm*+WL_tJfuqjbKZxDm45)%5uYҞJK"w9鱱Q*"tq?-:Zur =K[C-\ [sd2#tFP+;R(@:wu#rY_7qf*]+ Pj۰t䢥f@ujH6k}i)X`z:28BXge ҃%L)L%˺n#Q0W٫+`k@$堌eaUg t݆ʭԋ.\m@lj(uv*Tm6@bS~.V6ꫫE38e\V7a/ļ+pX*{_wFR(E"h`p8ll 7͗J&-`*+-.ӕ'h+˗ݗGƄ*JJ MEDGCmqq* )I)))q[5+ &%'%'GĚ)\!n)*.*I ?y==S Re/x`2!9 Wx[#XR)iƠ+/-*:r:f۞]S~,U)~uDk Kߙ ?!F\d vi> 긴4'V(*)ia;s t-L {K O=}PSZ|XR2jvյF҈N9䔽5TU#c+f Ӛmc=uW]]6}BLU|q{1^EyImZWSo8U*()E:˗!PS]5Wa\FF{C%=GeMUv:$*Q9ؑ5r뵕Ho9 L۬uvk.0=iK@^甗-iY }(BkEcu݁qb%rsC}uErh(aXT*#[eh3j3Wkużrx?^ij=¹d9Z]ux,ؠ h*;6Yk!.&WXRm4 (GiL&棾ᾴBhuaHvCIv~^ai!LVvKE`/asT}X,B-b--ksgB3^è)(-,חº N959Qs׵t*~Q_b,;Q-)--kPΫGo(ZOPp fKucZmQ]Y|fy奕>dr/9{b\wi^i[_`VSd~Y_PZX\ˇ~ + +fHTv9]iYeǠe^9-f*՝$X9r)+%:^n0Ti^ow FifYYfCX` PU[`0!)y/=]ZXR ev0j7C"{_8hYtyLUehjh(z3RUhFz͒j/-beϫ-X:_> !έ0@Gu@gZ%G'6E#z)䐅ptFXᛲ6Kes^_ j.n*vX9'쥅vRyF@9*ɔST_zT4;- MU`_a_Ceb: &n7Ykk`XזM}h,$\3̵iÞ6[]װtSF)=Z6L_i.)?+=FQ2ϡG,z۽X@bqD" tqNJ*-eƺ [怴)Қm=] 3ںHAɐSJ_' NߚR1\6HdaDv`r.D)UNTcI-߰++ Xֈ7n26፿o̫qv/kݑݰ")Rƈ>>>,Dc$.^cH'&cd at rH2<2oiI˾^aۯٯٱm5_-_+3Ƙ ZPL B:D(@E^=f윳H&*y0F&)8@N0u1} M> +!p⇾Bd!N‰_*|>>|| >t#YXDxIPL>=sǽ/Y@g!jaD CQp4khT? PS4lMߠbAd ~HG,8B"NI lD  RKiDt u%%02'.^#h\&Q<T a d'+w[CTIDDd2(p|ÄT.Hc ѱSn&SR2(aA,O$S$@gJ5 m1IC(0R"'2ŏ <, (ng{pn3(bXcșX7ˢIp=MB8łc")d)ZH P@ct32lN"w-qU7_"TI2#HWYhH2$D_Eq"P,x\6! >I>!sjɳ|rHcH!&$ !F2 N r(&Lbv/F eRDK2"/al$&СHD`&ir^ȷ|a-QI"Tʆ?0(T*Y9BfKH(Xb'͢, ww2 ol&B0Jn: 9+$8Hp$?(V*]FƩ)ld=,Y7M)SN0)JTy$L T6WIAto*,nv7a 8pK”$gt5 }HBSFa,$ Ȣ H"=nWs0A@b +=xkҹt." $_ȋ q l,iD2l.7(2DbvdqEUX{R0Xt,[+x Ʌ׀pNaH>Nd2OƤ^A[,NwS?+ }""m/PSRLSEqyo:4zH!R!SC B\:]M bKFȂ^yqV[4pV@7  9,.%\ O|Vh;{&Ki=@WO˾` aDRmj1諀#dÿҘ MKOׂ|opvvُ&A_ l1h&R||wDƏ}|kXylF#(Jϼy-=ͤrZYnv[*mHKl*=e1}frq,2qR} ZdXZ|ʼnq=^:\o4X_h\Cm-vGS[Nkt~ﯴ59,w̳M.N2t^ Wk׻nt8/k2g;Nd9}bƌ[ӓ-lڟgju] ~eemnǝKgLy%;7oXg'AH۝KBW.?;\Ng{Yh\mg'ۻw+Ғ H YlEt4qwSǏedܱ}MkV/ݹ*1>6tْM|RbdJ*:Ƙ$UbQUh}OVzSVS+ڂC0BM_MJ& ˒%)^ǎDy(j34\k-M5*C0/,c֯]"u+fTK|I\ ΈTpYѦ^wAvN_X[cE2I[R[dG&Ak9{fX mvBjOW9ٳ-o[&R1syr\TȓrD ONR8<g[Uo]J]buΘƊZRS\Rwxfw6CE-Oؾ4 y ؼX\&"@\4),6,Rd\qRf^؁M&y R ?/}ټz6.MKIMM VIc 4Z$E|)HhK:a Y}`Zkj`:Xu-vKmQo;}YqͪԸ]iQQAEEDfƦ)i@*U k0*8ֹRG :[UyՈ ˎL+zX+=yt`ޝ۶Xm [q /YVet*~x=ǶnٸnՆha;RCUa$\%FNՊ+"bBsG2cQb."f2Ruvs*9Zc2K^NNuCY{Joټqm%-9(8(PQ• iz(:K,HUIa^qYwXB}%5’*垨9r8KpfX݊ sr%75ْp)@#Xκ1|x @"<ng ~cGL&CΘ[PXP+XSw*fg/۰76.Hy+ӯM2)]NnBcAȿLyp<+ 8~>+{WamΫM{;U-)?~$2 bnM!wܱ)g7iKSINMINٱ< ZPxfu @#&vv!ȗc<.;K1CjLh;fAshVvȴL;'sN3!5gζٶvYaKSSį RD<#~ɤ?]O!:]l3\5#w"ѣe˫*Jdkٵv->5 y&\ʁ&+B""2$/[zPäUt?E{;5铵{v>9p,W[n(UyDPV` 鉉ȴ-*4HI\HtCKp_ܹգE0??L$0$T27k6߿c:[7>Zw2#y[Aʮ;4p@ QmSjT&5Z&BqJ'^ iI!+M;d! {̶wڸ&s*h8q~MYY vݻ{7_fy[|cϛGBCC|WЬeҘT1|K( |wc Ǡ@2ۜg}=}rGޫٓh/ٱ\>sʔi||pQT$4rX*IR!` >4kYbU{NGA˽*}w[Gf>߶q֣]>`Gv6Dxt3o=9?>مb6%%bBHR sT,(XD)dd WWYMk+);\qÑ][miy[l޲H֦;v8qx={]7^im'v֭]@5֬.mi\l\σ6l޾+cyۺ߆uiJG4JtmVw^<4%5aӍk׻{2<]$0IYew-Y239cM\mWcgkܺ+3V,լMIIN g/J jqrY@;w?Db|p{BbkPh2K5]s:%Fx|;e]oŪU8>=fDGo~T"6>k1|􋉾"%|=rȳbsD1ҠT%6M&{{;7ܫU I^}oOM]+6k^cR>F G%CdtUӣcA.~z688 shu_ iט%ή䔔`i两̍ K7oLN]4@jJJRRȰ[&=11#:=[.JK*d32BNЊ?"B a|t/% =fqٹEכ{ѱk8Ȏ DzXXָ%xܘtxǗ<;ёr#cyjhu!Ȥܿ+%s䮎sKe5 tj~K,&!)y놕6o;++t~E>lݰ{7~u9}9wEeRw^sia5W\,ޮo 2- q a"Dkt0m߱k׬GL[g޼+deHxBtX̝xƇH? Fc4r,V+iu9fsSG>(442eX19*22d]|hDXmF㡽-C Q)tW ud} 1eFK2w :-dL |9~xJG(5TȠs0ގ&JrUߤFv͘ ʌ >7/ϿF|w(V af/DepM=>!r$ԅw}B!׎n^q(Xl3O(kBBBׅ@ S_=J%FG;s$Ȳ+fT塩})c\)$7tO|)T9" D,x?M|v>D'{6crZ2_)2/3Sҷ%0?^h ^,ᤏ"jğv{?M--6445jeLhYnMXPP7y7yŕT\8t-B/$?{sYF/<@co.QՇ~~6pQgHh3ؘOy/Z~vy#ߍM<59Wʑuh/o<m⋒N!ֹ$.\ƒ}sYN+31<ۘMŐ{ '1L{2njjf3N,_*Gx83 9e0eS"1;}b!.pf;aW'I>T2ߠBps}d?eKKP՞{o^|歾] aQQaK?knDPjJ|۽7{nHHNIMN}V?Ѐ[|Vz?=}]7:;{e2g[ʚζ T"LҎ/CU}nwvwwSW֡'O/}3FD]Oo5%"В-]۷gE始k^Γ%ζߟo(|Bх:iGo̬fBLLLM?vԬul .-+i8i^,:*;4G&5 z2~Lcˇ|C<d܁CI8 I:=y+5L\6J^l኏xnEs&P}{I/Q|D59:jxg&bu^[w!P4fθ%\@˖wc}SPX/l3ܞq6 Qf h<(K4}r 0tutx+`ӧ:ݾ~Owdxd*Uwu] C &-F ,zЁp6PCf#DwAG!E]?:22?.>3r/C:twXwS/g`W}_όI/lWO_߼f|t{ZΑWPPSȔ5?x3-۶:Sy䨨u==o߾t=/g`SS! 9/f٨59&я|`֢oy>z9x=:4 WG>\o;Rh)q?L,KN@iO~nzgך:.:,_%t^ Sgt͛}v?`?#xv_h}-AS]a\ex;Pm9L0ASS/{MAo<;RuѭW/_>/ռζ۷Z{4szj%K zу\|40n <{C"#vgW㧠cWwcW{nBM ~E71FL-3OΙs3@<>G= {t5o?k|ݿ栗_5%#5,ЗLAc= =/n^ ul)4M>@5:nŠLž#aHbu_vGȤ_g36qW/O#?x;^`9o&ϞnuJ3>]+R {=:pm%țΡǏ_wi,ėE0ZtEx;G:)a_N"q?B#7ySm.?{ >nxdk塧:;}~y4tYh ҍfm$2V\mTӣKcۯLMNOu@=S'xhtӲ#;_=m[N,cCNVgW9aPxN_ogzggW?aPqN ̍k 833ϼ}c0_&'B ܛDN]|'\| 3M7#֗8ߵƇ|{{.-w3}m{0ANw:kl@tvHq/7;jl9axM{/p|2*F^_~ȵwv>}x~~g>;0n_ ;г=Y>,.3X|>ЪQH.=F3~/]쁽GާϚ_?yidˡka~='~vWTZ. w_؝W[aPtlw^k?"~x| ƛ ,O/=#/n~B /\9ou~nǹw>d]YM]H΂_:{)蜉|.~|5|5*jh)Ӂf`{/Џt{]ɏpoG!"{cFe[ƞLyZoAy4Gn'zRntGcha wa]ys n_\&Kfs` EAsFf?);ۃZ׃^Hߍ}72B ZG. د.B|vG9{z.-ϋ2D?3tTK%)DhUsx{7i袣YNt_Qʑ/_|o/_ol*vyH`}alȓ8NQz!Q[w#Wo=ihÅ/FF'޴y3fi+/|F3]>Z.9 wAy>>lNH(]JEeT`('!26r(Q_ϼPbKԡ kރ9G* Fc)[}\S{07{ϷWHys?2}/!jD& dn ,M=fm yr9w* d8s?,9wh~Jt›@B,O~_3WD;yg;>>4^"> J&y;X8{3}1j!GB MXadj`j/>Q#;lM`<` rԐmX$1B:zI "+VKhD&e~:z*Zw8DM}c*? |U0ard NNT`!QNCDL$0FfdaBK&ؾ"tzH 9B09ȸ0r J5lX)\~!,D W F B ('!sGH&\|$!ϡwu\1]A è|N#CH%hˢIlC©2;{ylBdLY9,$1 x,Dy; CO0rq^)$ý44"_, BW)XL?#@MQȹGWbL0P(Iqa;R+"syf]$:&21[ Ӑ#7nDeɩcǎ;6i/[(V,B"0ظ{ER%J$JBQBblDEY-%9s7}4|Ivx%m@}~W2/FHyN#Pk .R.B15TNiD ?XZxLwofLY!˰ ( ;|jln{`/2|t[EdR&vK:4üP[6 "<1 3H"s-iX^yؙ1^׾/$˃dtNc¥ӹF<(ܛU˹kH9s|SGOڱx&O_ pO"Sfµsתr1Qn^<>u̙#GgoqbgZ^ysRu1wެTNO8uԙS&ܿk ]B"P]A GH"OP[f'i? ͅKSg&&O]Ν?ej}wlٸggwW{!ٟH]t;v'fiRp'zmĤ݁]J瑼ޞ857%g&Ə9Vέ=B~E襛1;m۬p~E%N߅X1?[m;SsW 'N͟=yӻwV9=RAO!v2fj-1jF{,g^15=37s 4KO&.MOϜ8ur|Ծ-[*#:Jl!J%=T}E荺ū^tA̝kg櫰}`σ &2|h~iNf3SDk8[HAo MQv1wfNW[Uo93f/ya~Ztѱ=a#G*=|ΑAo:hvMl'l_5f1wY5suj3gfOyҥ .Sə';8{t훇w 'KڼT:oI-6͒5HM&lzWR /?Q/??=qjg.͡Ϟ<1~xlmT7dž0G,jAo!&I ˜hF7V"TH'N]NNΣ_;[/N_>ucgoRp L(6ڼ-x;)hwLF:~U6X.]8==?U%\/ГxjcGy ;PO(r4yZaswi&>p}Ŷf#lioS915U<~rzNM4=;7wřSNڱaxo(ֶ1UH~-"d&ݗE^#1K(MV]s[9vx>99qzyŋW^q`t|߆ a{w&)dcB 7Fj'|^%HҽܾcǎM9vK`:գG!۷wM'\wog< $5;[-r &.ب(j* 6BCH(:gD;䉳̞<1;5~xQԡlfl/ǷtvDQq$=즼B[י0 h &L+8f1!VuNU;nM=R={GM7{ @ ro W:h:[bmjRFapx R*eR ޝnk[W6WƎO8MX;q0}T9;~Ccs6}Ɓ;T"ܘ < 1fM4I@G0wcCmV?zԑC~w ]::;]ݽ}}=;D<)[\6+)bB O^CkMmڳccc=5oGO:stuzjٱ}Vl84W~uvYzӠ X#]T=ѡ6熘v(Cv10$Luh,Nw%cm.j5W%`7kwT{nپqh'NWO;~tΝ;ڶ}ѽG6 t]%t nt XS8ci5e9 Z} n˵X(pcbT-wvnuhrl=c[owݲitdρܮCHi#vpҶGf2k͒3?iRĢ ;tR%/߄VmV3rpkym-ڼu립c+]1Ӟˍd#6;@[g}32h'1ItV'{k[\l/mTl3:04wHetѭ(>o@Mr!ɿVn/ 鑒ݶ>299*&> R-WjqFkjo|wv [rWGFvo24<ĆNvHkGb, >DSID&N4*)6T-\TgH2aG~u N+bп%_.;; ܞc`v4MgqLN^ IC mG`\.JnM/ R&h!Nj]t3ŞR+JvnLA:2;󰋩ؖ4Ֆ:ٝvn7QԵ{):ħȴ^UOR!ID-B>w{!fݮU x"juKVb}T:10Hit`zjICC4D7]n(;C<*0ZL&;J&b@7=^jٖk+U#rK|_2:;"xQZGRш,XR1W)a#bԫH a(Ƣ0 ":ڜѭMZ"%{2&.T93,尻) L7kk)eDr?8r`BӣώVPo; cޗ/҅uݹJ~]zSG.RGgoO.I&2}t2Ffq$c+8\[TkwVj'2\gፕ]-mC]h.kDBP1=TkwDPN218d"o ì1PЄ ;T;u:ח002%m>woC_M7=QغpZ3:CWT#Vk="q=Ԙ:Somu|o54{,)R.{oRFN,Sɒj 9]ȑT6I-v{c԰jGG"C:`|VKo4 T2GU1ZŭB0px}K77of⮀IJ>H{ R酟`_&x2:L b2Hkc2Z*apd2w@h6eBT0<ЃP׽,~kw.^? QUZ*N;B.@޿awdKPa13"Q{a D͈>^.F L1O`ʶ`/ d =wkWՖ6_Hvww=jw8vs;"Tlf"c+hַA$-y/Hbi$ÑX0H6ۨ0wn2%d. %&ڦqۜ-5v5 !(9҆jɑa0SjѡoPT,ht:u6DncJMN;jީRP(=,[!O{(D{P!G+yoCd{cG<Ēz(?Xa <c8n,5rC '>&kٜEw. vYG{!y!pexn:4Bעwȣ >M:,+Jj)W 6||`r IAvPukt&'@#L<_ͥGmG>]U1e!^Xqc]F5IeIȒa~>4قltZW5"%Ĕ$ tSl؜va!<;6v b>љ/ː(B QN4X(=d"2WKt{ 5K"CykөLr:t6AջVE$a(IBiѨ :u77gl{gX(zQӟNBQ( +qNx~\؜%7JV(DD,,*iS;Y2^`+)BU. ܬRto3 J%Oc "OÚaMB=`dɀCEuW6}z/r !,T 9/Us}&M #\5Ix8J':DOE#:F e: ۓ|BZDJG^4IEב焨(H0Coq}![hdKN!R"TbU"Ϙ!2N3ĺ0W=gsODPg` -Rhnv_4ބ;VOnZ<dTkO'В\;|d: 룆|#F+>GBɡ66CWB&LEA $:~a9 blq+,LTdD1Њ_<-Q}w>P1axl?x*Ԭ48m'=\6 YY+K2e,NC R0X1%MDc/ً ww2YBI,>)tt!&\P(G nʅMtS-}`J~Z֛$ &h@"xxnu=L~3jK'r>RP4 ~(.8A  ?\&.e &jsd^9F!_.DL9U P v)D* TjrX\*F{&$(K V\0IH:$(f.\.~!KNh+@P@]$2@_6TH fy~UQPb[J'`qP77&w_ms B.1Sl(1ZFLdaQ&Y$N:p(Ne@60tɅwVWje!d$  1(ZѮƻ (1TJqi rS._,tx!,ldH:$P]h|,lCo< !Sd]jTBByHʏ"|0zד~ǽ<Be5+,.'8(_VS`n#AR0(1)X/~Si7&C&b`(ә|;S, ?O<=e2>[wG{+DGic 6m_X, d2Ix6&An cqN8$Y%8͐f%AC8h R 1#if܇ʽ\r3dr6eR=$xi#Z zH]ZR&.81ܩJ/;2|O>QkE(b1dlG02Е%dik '[ I: ģ=i}.w~^#H6EU9W}+ 8ӱ4hU$:BXICGf; ̢L~*;~j (@[&6s[W\%ҥ$䇙\ ed6/VBnY=r8dʢwZV/xݴ-dW\XXj'\܉ݭ>0G.CfqU}nݛi.9 b0xT DKAMH< (T(X*ҤBh%մBF P!uZ\oaoApZ}Z9GRi^Dܐ ÎCH8p>Kș(MJ @ P X|[~kǽk۪Մ|i*kBH޼uهK!`7 E!B/::hx:E~ 9gPn",..mp}ug*?Aœd ²`^2@}Y!3D*$ 1ne|AW8FZ4!cFkGś65K*q3r-Nѩ3t D_P,>S@"s(a3`4Pn}p mniT !31Jz*]`T(ٸJq+Qj>T%cH٩4S`pD#c ;0u ynB"$ptQ&&qUUE=i3nBj3p!"Kcؚ_MYҥzQH.r;}~bh\gaQ#-b1|&p]koî~iSfΒ8EKb-.%1ש4L#9.GfTx_dGQϐKq_!vBp # J1Npg߭-5%iu,7{M2nXc%q,"&܊W>x?qei *pL-`٘DBc0u\c3svON1[&~JIUqh %,G92;}q#\Cl=LFd& FZq+ah4Eh,H55;rP3Q3# [ +{p57D%ɦ9~Hbjl4lM&X!a`l5)Se-ep'JqQ6>Z!!S%%V(ZYy*"@"UJgdaj;I0GCWY.:E0 B :aT:AԩPE&FHD.:q/tkA*P 4,=ɐ)Z\U/,]d W#=1T&jfTVkmjSmMVϘ<*R!a>=/b<)bd*SK VYCpYZpLvCj"ѳh%DW[]z0y&jfbdhC#|(Bݕ&eb g*s<\&g:Ѥ*B)EHy-AOi(@-LD꫑eE U; b0EBGglBmFs %*UZUI~NSi\6P1Hk19JKbR6ܾ̉{N1 W Q`lpL <[,:82F~CN`74RYN`NGLN#RH4"4] hl:qO+gkc, f~SĢ1x~"z6\`᱙r%G5{TJ@G;iD,L^b4L~uQoy")XZQJ⧫LY(&b Lij hDa ZפaF"T0:drW,xaZE[İ`I. bEi-VNVxL*Zl1l*W a[U*D$E׿:/,-x BR=82tmΗiQ"K9<1<;g:} W.履:t5Db#3lHX@-xz70 WRZЩ2] xDbBUrV k%Tv]._m& =e['1U*E(P|Iǃ+bIwޜ#xLDL2&aGΙaXDba>'܎;\V"ܭ1Yzw=<>Ä_^~^Oʷ//;/awJC~yy2y[eއwC㻸˵|= ku?E|}oի*y_-e?gO@ܵÿH;a 1m kn^Mc=y~5j[,aq*rMb|u/̭.~_]>ԲW忸xU?$'Vşh_]͞JWÿ [yjn~[c5O~} kC׬y~#Xk<O;pEt^AOZKX y[JG̾ׯnփ:s5=9sy#]@=|z'{~m_;O6C|/>\o.X#>fj#k}Q/(/ 5|,I ֏|5,PfM龝1ȧ*`jT5k^oo?~{$GN}h` V$bu2vO_ (wl~a?:lG?;g|JL櫠Xk>/͏}&gg3_]u|I50Ͼ(~qqۮ./~,/9^𫻓d~xlcʼnNx[/S??_^<)k %7­m~/yN:;Լ߈ioQ=kT/쾚=2]oޙ>~_tؾcK |fkTh?/r ŀF~ ߑ٫(1?}._ܻ=,IgH|eso?oJHp =@ m@dswH?1xAz~` \w!ˆI_K]K>o*% b;C_hc#"/>/M~xzP὏vt/?= l _&fzQ<ԛo5-}$k{b"ݶwC/Ru*ɀҟ:zo~{` pۀi|1_+磯ӽ#,WR![>6nQL6}.k. t N?)g`p_QC$ @v-ib[alPVa.?ogS6@5}~W3=]0?6?Bp]Q+sQO_ ^/i2^6~$-M܀i;*X.oV_) {Տf[/5Vf@*_hcy_06 vb{3?~ >w4le6[ *61~s;OjesnE"wFV&*JnlS-+@Ai%l(m?prRufu>F> ۫b!")Il/]'ū1(YRJDD  Qf\}]{R_c̛![\x0HG@eֺa_|eJ~zoڡϠ5!1H1y _?:W߳O0Jx0St9;!F9c~s_o/E@"@y fs,~㧯>8>LƇ5O޶G yQOp_C !!n ! jy~1[eN}}p<$sֹ('twpfw[( >:}?_."!) j7j6}S7hY ^4k޲ 7_SYx.p, Ma |ep1Y /oҿpOgPD}OZ8ON7yz٬;n]Q&Bhh?n /ӛ>K3Ucl릞׫ْ{5"oL?؞]"Eo]w߻9~g,7{ml2:nG.!X2+ٝ_w+/7W) /ᕏM~nی7{@.۟}썻N[m_ꢺMӓvl %>ztc 2,A>ƇxtNFnH _gI677{pOӣd8& G|2/O~,` X z 0 LF`y }a_8#"x.2@W5 [`|͛GYǃI>/7ߘ7TetrT#)q2g>8iGs?3ܮja:pFZ%Çǀy9 ` \5_ڔf-Vk|چ1i~x'lE_>` 7O^a0 DA+P 93ݿ[^-|xwfɉ~ffϫtJ1*akbco&f5j%aAdOyy axhH~DJtt_x2Dn8s #0 09aXPV!I`A~8s" 9 .40UyóSj45nV02Ψ]<^ Tuuvmܓ+g6BƳvBC0"1/JsP0L&3d)d 譧gß8fY\R}Lc>w {NE@nyG>6%KXm@4,G? 73΀ibM_?~ta\3Fw4n?* T l+0,;o~ ;@ B4(_8|lnK_ #epkBS~ZfAT+Iy5k% J0H 'Zg_Iv}/ͽ`42]xi |旿My2?8Q@Qr n8I~_+7.2 `:\1>|kwV\Zx])y 5| _|[]jptT~%wTn~vUy;kfOö<˝PlޛOw/[ˋEO= s—ټxY}hz?|.[d3 g߁]BG̦`y*M/2W0 (B U {Ϯ}{=Ozųx{-g,e=P"Hd Qqܗe!X.7uQ ɣ;wyK>\fݼQ~pT6BBd6ب/9yqWXetvg'ͩۜ~s_!3kZ^rYzTz9/ovA2:H'GhF:E$rUG}co=yqLI:9٨}݆ecu?󷿄 2XkT[Sbk60#)J3`%*ծble9(F'D.e/E} Js!pm4WFga7zI|!A{HM9J?,3=bp)QݩRC@NV?;L8T`iy(}b\#G0{S0r!"wP(]6?~FZOV4T 0O<KW?pJ4]0"bǘ7|HDwPAֆ"3#oD+ d͡x̭#"7na|8{/ˍN4ƮGV"#@$CWhn uLa:ApT@A{yĦۑSXx}\F1ƀ2 p%My"n!_=f |0 b8I~m¡Gr`>1 ȌBX4'8y@2&`ء0e4̺ ak;ݔv>BiM@]]w`9#˹ewR$%Ƿ 貿@+]Α`c`ȸ"sd}mXL&l|l' P!mk n$m:`ĠacejedF@P3*ו96w=L %Ey{}d7x`5|n2 8"ct #oUy sT?{"Q={t]^" }n\Pѥnp쁍oq9pl9BcYZYJh3lߋn=vJ§0);~OȂȰhC-MN2GxY*> ő[W}@.?+$&90\p+=w-ya".k(;!ߓ@>9{&;qNb82JԁG$8,1وtyheƣ):ExD8BL q %8'd8{..SGd at Coo?GgQ㠭W]v1\i!`I0"<9 Apϑea+#x㠒sB.0P([o:K 0|ekD-xi nWRf CMvY7ߟL'53[Ͳl<?|\]^-dn!P=aݎIe0;.4!D!i8%D D|nyGHts}3_,90 MYf4M9ף82c,"25IX~=Q=t|A{Œ4@47Wi=@ib`ZCJ3W+v:'turyyiƖx.JΆ,ƽaX9{%HX0SZry0!0(,mie$Z;w.,<չ=9hW M,:󰑭9<.m}p~y$&)*HkD#ڲ4MNOO$KYoL)DQW/a1AS2r~}5_9e-3t Hu3 ,פi-3)fXSHTecjƅftb34ͳ%u;@I `0h fk%E -8&j=yz|T&fQR8V +}{nǒ:@QOق-qm 2aI%i*!0%Fh eH6^Frީe;w&Y^]^t6 Ͳ޽{׺HUI԰#^d;4Ʃ7^7"` ԤP3}NM.4"BAgtb͞+$`69R?ShZQ: ".цtķj*t1?b؎U;W=v9ލe69`)P!!ZnA/f _]F0H I<ЀE 6znVni|JEH81lV-\8>Ch/6hNnfl,Xy [p^9Q!D}B&V WKA$" N!Q@"źer#1:(e`Qyuf'cL[l MSS*)R#&NW8,DᥠfJYH6 &/-3wNNNʲTJi뺮v~ sPHhq#g:8\8~n @*d<.ΐRm`S HwKaa(Ea@*%!IqYRrX"{CDFϸJt8zȒ#N䗧1ӎ IDAT$aGc!꓅襴2+H_Y3T5#F9K&>GY0u";`DE:hPv肄=-`ȨR=P1v o^+K > 5G.G!IH䣠 Kʎ>=,3 >cJ (n4r!=!D:v@cԉ`Tƽ o2]ҦHnG%1G|LKDȝ>ؗgq`z!H1I>,G!-3=^ 6JȠرGJ9^2Oą7@5%o""77Ks:s'2 ^+=}y@hvڮEQ"E<& 䓋]^KJ~w`Pt\ʛ}H*$0X׋zXp0&P11zS\'&Q-J#qo;v\~/0Ƚ ţ 썝;A!HO^I)fFzvxgQ+D.+0dG~zu"_2ճwZ~t:mשiiȲM'uvQEMf+܌ ܥ<_{;xptvzf11!a>==<~'* >9=~ٳz *{I?Ւw4(!XY:0*QDb iƣk?.vJV}P%V&  2Kgut(Nlۭ1v<!aQ ;Zdzuy9vFJ">> #JDB#vƚѾֺRdnEQ 1= H.pUUuS"B)ZLOpeE}N!Ļ$0':ij/ck= W7k11MY4 Rv HhHoiobA63\!i`QULc*"$f>?hilQc"ussYJ{";:)[rMMwgE (\jki1MS[k:^8öf4Qy:g{3FjT z;X,jV]Lhtzzyi][{QfNĔH#tJrq Ča'`q.x<iABDcWp tRW%QGF '8L^cm\ vDk,! A\d)ߗDQ.Hu] J)kmnir.w>0ؑP١#?GFiiPw˶n Y@+y0HdCg`08TNO^6~/:[ # atcP#"!ɮUl> Ml3ԝGV;oM46"RqvFpC|K@WRvpTR< kh kEm41Mڽ D"BA3oNZVl^^D,\,he0#+ja\Sd vKi gG;J)դSJc0 xCp0t:lV~@-H5HZ~!sCJUe5='i^jl0ȭc#"N,K&UY&|u@S]ݣbHH!aQxd-ky{щb R]\`;Uz#M C$'抾%6[ d:y]7muDu ̖P%InMU/$=_+ǘ*?wY(p? ܯU]N&$Ii mBTrAJ-tNd(: \2B(E DEv{dlDV'u$H) mTPeUm"b2QEiiGM]=e$wγzx6$PeUW@0ں62"l2^V֢ Y9)ȄA/ѽ|Ύ$rmk% cR*3"@Qj[6;"aa\˥C&b;|?5PY 0T9IIsP{Կ3qMmpUΉƠ їtaw1P%%e(>KlI|)b%r,W5L'/FY `d J2A Sq#-,!ZJ׆`)dXE]p-*IG ]ITgdee *Ncn;B7˷8ߗ(QrwyR@e&r1K#hɘ,zyW##]@Q3+TIms#$ 鶷̚me>BdvT}`/VA.݂xUESj 'Pv b&`~6XhGZ*n,!R-~CPsPuW& (t2 ʪ",˚0pUUU@&{,eUD 2! MFazZm[i3f_ `-'I҂\Hh%4I$1PY,BY.oc_+dbז?H8ykSbX\>Nӧ-&:M/GB@jr,OTvaB=}}QtGh8F:~G>~:z; uCD0(T_s7,z;Gh4 N!dww PB v$5u1Q5'bt)55;P;fB^ #5H,EG*om}47QE'4p(kє l!"Q |2FaA usyy=h'?~ы/;|71[Rˎ^+3Z%eYtcMcJ/h -oBU+K|4ƣ4Mrm<{£G\dk5m"j'?Rڪ#h? B9s0ãK^q>~,Fx8i믿kJo|޽טXk;iS2((\1B}"F9ђ9AVr늦P*>{ҋ/5iLѣpX?'ƶ| Xfl ιc۝ocm]S42Y EyoErb(J"iS7}Rt]$l677NzZ,l5k5Xf0enZ[7MJ^a31AsF=RE+9cbqUp4Y*0_ѱR*It6 ZKZVT5FmGe`PG΃mK*9Iwn]7v2Ll֑/8DdK[/Sf|Xk(v (C^%]#EiZk$1N1RJˋ˪,k,22NeYYjLe9É2! Xrqx?eN)"U>ț 77uU#ǣlvs{cٶDf:M,K(sAQ(EթE+.ѩG:c )lF)c'}oIQ$d:,b-Xf6;8==L+][EU~~Vt{ w)x"0 b4 J1$1Mެ,o&Iwl:ͦU]-+c u]"Jt86R=[{b=x>jQC&뺩3 pxuy1MӜ__$iz|t\7MUMLcDTHy5MSUY4*DU u X,<dxOs;11gQ_\a'.&W[tۖ4/ÇYuzMq6H I RTY髲4z(_'B⪍Шb]d 8p,S+Dti|]խF^,v'vӒ`Gx2!EfU+&Hp_("L44T "!mh:LeQ(V'fy[3#$%@}4;mpoKkTQ`ܟ.w`jP-N0Wz6mDJ bGH,^(oψ8j!W=(EaX :r:nK DnsUv=ג#aC~1z%{RNHi}w{8oRCF*fkpߑ =G0zF{3ޫoR~{Z{eQ(?S@l d9 d30J ؃\_B-罋+>vH C#ݔ̢@P|H/K :ݸKdz U'=Aƨe[ˑ \ 1˙hWDow❜`sǂoO yQQ.Cs1(9^Uc^e(n IzdJ\w0ݰf9z*`Ats :t<iVjWzAR r7hG,04<Wy2ľ(E0<6OUReA":NQ j3o҆rĿ\G(N'"'r3Ij) #ti*Y<F<MN8V7*X*CCj)D&W&6Op,Almz&eh4&2Kx墱%|DUkK{E!O;J!K` llؚƐiZ;Aidb 0ChQo4 JާMg@z`l a+>̊d:f_2bqOi`'ݼ/2yD}===dΚx} s4,bYU:I$BHkgr,­AAY[<~.^i܉C1٬aԖjkU(Jf&WeCڌǣzSEkZ"E+URYmRiR7RGh ?KRd ڢHOv\ `h\.VWR{B$’VK7S97^W `:IDzRtxp7ztJcRѾqlNT Mr $40J?!". kd.ɖϸwшa>^mkp8eYn6<ωTX ߽=DzEQl6cLUU͊t*UFH,#Vt`Ff$l>ߘ D'Ym/f2Kֹ)rXkgi$- ,ˢ(jL+L1JEߑ6fOƿU9{3S+fyr5 b2ۦ6a~s}3L֮כrQ`hI%?)*W!4~R!/zȚT-4M`Zc뺶ִ^x<>LZZoED"u QXJcFo@!+^{T,˦nHk٬P)2ִƓI{ʲ5F7Pe@̰(W:(.EO)v!ci$lip4TJUUi],UU8\N%W` XPǓGꋸ?V$I_2pӘmUW&xRC WտSX1Q?hՈp@@@P)) xQWpD݈0X/=8rE: I"a"h;BuoF۩hx* c(T4}! |NƂ{6ٛ f/ͦoH` ޺4f83A{VHf}{OZ͝| qh DaEmmUj69kRT,|RP!`y -Ln.Aq1IWU7f]Sި1zND1*rw>4Eث#8 Df[b15eHwACf"A6P8{jШ`:=8!bZju2@ Sލ2۾2V=0u|P=2V1f<VmTQ;tM cbXa}șF%6|IۏBEmNZq$uS܎% &{7A2 A#4fq_ц QcǽQ90X =y{~b>YҶ%"" Gm!,^5'K$9 N*0'%-p/[ xFʺbKIfa4P1=C5:z@W݇Ebeg%<ZGZiL,1S@W5Dt40-Tbۓ֚%6#:e CqlqH "\uKMZ\mtasŦnufADuC$BQ4b,E7");wBL%x08˪(z5 '9غV@{, -RDYDd\w^64w-$RU i꺮vkt\>~򔑀Lþƫ=^^(/Ro F L@mnu4>9D"ӘmQEqppWזMٶmMVNh":P*&ej ޲QgPھ]ud4ԫzmRˉ吪C1b9NGja+2!/nd$UZ誹R<h0xh8y~Ԧib{rn]v*` 2u}D"eAAZfD`H%Ij1[ffS7ãiV)έa ڂQbAaŒSq:C*MYŌAuvz(Ʃ;)fft2L&Z# B@APt5udDC %d㤜n@'IQA>Z"]kNk #fw?|hTG|0D>pJӤXCVi ud̆{R2j_JK~E2ʪ/Ҷ eYi&TZݽsf5Z1!f6KINJjS( #2U5̦Zo}, ltϞYnJSksĸ)Eþ;Or%r1 S>Cf;/1'֚.= biN4M:0hfIB)*MsvsPzN_^Zô*Ѻu_(b>O}#Ä&TZbitn&.€Tը ̪΂\xyuݏؠBՒ; B0էch U˛|>h9d?gjefN c%BĄ\(€Jyc|x1ũl2ҘXn7uXv>I86[ 0h.qNC3nAwrgohRylSijcoK-cS')*!*+GC *tdծmsz%%:@godnV5R#JQ 65`:& tbhLiAj3J{MG>wD?RNeQ-yÓ@hm,hdU̮aMHzf wD; H-%9&cO[MNQ mSťEC&-ˀJ^x>/0 4P(h#keaѲs$g䧦^W4CI%G7ݴT ]jE7^ &'=7/ ѦE`f,{Ͻv<)w# Ni70g 4"livl#k#!3gVB^8~d]Iv!]qrrr^Jf/DxlhzeOڔMmc-A:\v8lv*;i&i0N(۸[hӭU5mNp+Ty ܵ)sOt궡0jBNOx臦7n@ߛy)a-C:j"(" "7]iӛ8N4}6.Wǩjʇ K٫d XW/J@dy2<9M0 },ePMÉCSdx4:~5ff%Ȏ.b-nSQ㟟֬DB$a's?G6i\V0 mӞ4rUo. Lni} .ZvMMdUs)bhզ40>l=f2#%[kb\Ŷлk6fqS.hm]h]Wz9%/Sh!v>ܙL,4fx.񦘄a#aU 5Mx[Y Xy "6ML{FWU5#v>5`Qp(,!Ecq|5pԼ˱@NM58q as6Lkz,[IoV Vdl>?#á?w~+~oU)8Ԍ"nx&QFc!az:ۢ%m]CwV#t]Q .KQ2M<\a4UǛ0H[ q:uU}䔔V q+p;viH6N+%x La3;O)2M1A0Œ$i+W!IxUSXթ$NvǬtctqaJ[{y7B*T! i)"V]5KyepYBKA={Pc mifuL&N2N#1O]PQj 6u?m!},g nly,nLNjzWIn,~ΘS=q0v2O}iB]@júEuBN0MsDžG\, ք>Ƃ]8uՍ a>COΛijil 0qws>y(2-{.[!%gP2AsK*fӴp8q~>?;RMB,BS%&`PVڜxUGqlv Ei("LㄦC:!Ap~~>.5'w#׈"XXpiSr՜/d~&sM~CX[;7pDӮMNj~@ z-du}y{Crr*°i&i]4NciBR(<\~>Vhᆙ8f#i kG"GowէgU8^]]0c7#&T~쫪1,*{"3'Ѫw H"&#P`;O_<C~4M]VYBJM}Ƌ|4Z 2!IEw5m{폲n R:h6 8q UROTF‡(9@jE(ֈPyYͤdǎ;M'"m./Yt==9aC?3%w(隰$! N` uDf&K)AL݋wOQH+nӍ8Ncz1;0 L ]#7*kr̓-&eDKL񬓦n&R1pO9Z؀M]@JqB&A]hĩ^Z##[* hY5 hB`svD ( bqٺI&3*6m묩W٤]k6Mb)zNN0ݍ"8u4OX&]BS` j8rbjc?}4Ƀn)HEREK e+h '~ֵB=;$0$Nb0oLMK %HhpzTuӄ M E 3F0 C.Nizb֏ff8P iXa{B&?w*ENCcH D"hš@aj6(B5(!`y8_0UI;94IEr@wk1I낙$24ۓ4-1BZLӜ>WG/ԋH$'kAifZ lM؎7w7y!y҉P84MOle).ǻ&1#\{(UiVE*[w!ï>}^mw~vҵm]7s&l2w/ov׻a DAihRm$:TfDY!S]ѷEHڳ4]8]A&Ľ{A;ͦJo]l+K<ȧo]6ڏ>[EBVmwu^-zi,8n }#B:t~Ii >Y6l+LƔ4vlHZzؐ NM̐GDg!=::=2nZ0p[. IDAT}w8m z6:/G42Q.h"u2Wp@cc@k% .aՆˀ椋S)dj^4ͷz?{?}? @q1R^^ *S}ڋc rYI̛E2\5E] ; '8pDN1˷?>p>lc{yaz94UlL/BH[R?| ?o66dM4Ģl+""k]|__/Wc{OڋĎI嘲V/1k_jLKzogBኳY떼^ů'p.߽ds1ṜpyT_Q>0R=/]}=O{k_~ Ai"~s>w?z7?OߵxP7I7pA,QdD~7?kQy0=x?+W9jpzxm?=.~߫uy_={/vݪjxYœ4,3$.A|d"a o|r~ݜ;?V6DD>/}'>9:n. )&0%>C>EP7 RNoGDD>"wv~;ȏldAfOϋ|Z<=]ۻOړ;hf&jzfՀ8v̟#@$T?/͸W7?9GD>.rWiD>#/?gl.'R5d#怀IEG[+DG4z(<>;~_|F7?''$UlG/.#T |oVA_;/߻YʄwnKFXKI fv[ѥp<yElo};9xs$o8m, 2Vۂto7=F됹}Df%(ݣ㓧wwpE "ut Q2ьX=ZdY܉U~y]OEaڜA~=s[ ظZ}!)>J9 +$_GDwzosQ{r!u_XJ ; GbąPdn3 TQ>qyWwyVy2-.[vm%![i)>|o쯞"ԛ UŌ|M-9BF| Mhȼ7{xLBhN/BAvXVQd M%L#}l,Ӭ JujU>ep;e>-2M%ʜ2e#fN$GI":R5Tb 11e-e@W.2žAGҀ*Z-.JxlYJogBIؗjuW1M['z2ILQ;2}"l5=:6 )kV,v(bUK3);LwRR:%BW KSގxR{^37HgI&CO!J'S.ivҀ pֆu0nb~hT&~ lL7KVυ#D֒D傌ݙ{ÜP:yid9Ci)m~T=qГV }C)AJl* ~..85UUW0NL/pL(vl0/ِPcLOe9-jBe#pQV= SH(.N3q?p. B8-p*dPc.B `XLk]qb.c>6MH)Tyftp8QXRÂNߵ Jh5zWA<)Dk,d[&H-'W^kjgWbzD$[#f }f}X;.Ơ7(>(0t&>Կ&WH;4bwU 3RGo8n{|Ydv8HSz3Csk7Hn{ (FP f/&>[7ghB,#H gu4$/nsnUawdQYDFW$v0LQ3Mf"abVV7hOїs9+ n̈́ \_G4f[k,}з~6!0+B /6i0t@,n;iw '-uFF<{Ȗļ4ө9rbz8;pҡ{e-~G푵wt ˛J1H_HNEe4yB9f!t[mfyHJpKhʷΓ۶֡7a;b 9ѐ7>zޱҩuej'C/;%'*gڱ $QU|ѕarڪva^-hKn5E'_rbʭ,柎cf7R0г5 %njIŜFő\"_5 r? oe)I41[EYbN{e[%('XE|`wuΎvFmfC[ re2^a0<'cӘܪW g0K"&B 7 f5u,M]ϢBN "V8hc-m "RqMi&mlM"ѡǢ2boIojt3.S̩/Y,X : P;kq%2|u!}Fi^ƹsQ=K?]뛚n9f7wl-0]:4 w|~z $my +GޠQU mu}{F@AwۥPcy=Sw&ۻ+":7UۦÒ[|bMP6=^bIJT-I|%-(/m6{*k|u缸N~ϧO8-/듽w;.dm[>??KvuE"Ak W? 2h}މY^!4c*JkYQߑ۟S#f/y-c|b`Ǫ\5l,ܜշBORBw!, ڭoo{b5 l;֟Йt"Éy{m "gdtdT'gT6;O a :@v%C ~Gə_ !|AIzȕ1gisdm6X,2O b9i󍓦G:ͥQ5K׶Cy2erĄ҆\MS#2 yؼ|숦&]̴sX5ɠ\6w쫶#m~.<10ۅe${$%hhQ$-=MٚEnC(f~)aɄ&D"J,* i)nV))sڤa5p!ZD7c5, +\k%;8+/-y9g Da`x(FF `eSsə(e/ȼ`$(F̂w\!6J eXd#[n`QVgB WIQ{F?7d#F™a{ 7RsBX4 ^8RMbm@pH,;_O.n56-K$wZb6KL5n"rUc+37@>:\F֭–q`E{FK|` ҙ%~qWdJ[B(zK?L=9zy-yNQ&q !w潰EInW/0UD+Yay4[*:d`eZyN #"XRIftNK3[ ds\ܠۜϹ7Ǝ:ۤUyǂ4&$˳Z:@V\8Pz4~HFAYX,Ŝy"KL**ma^3\/$ku=O2$.Jk L݃U r&0 sGr LbR¢z?/Rg5Ip ;hd<3y*HCO ardRfnf^t̻O+rˀ3k8kԙߐ|R0 :8Tv^]=+ :48NŖ6d^?#TI)C9L@1 hQG$$K ]h2D }rthgΔ1☬il_AAdٞY4JbQŨh`*"N_ bOnJ4anITF\MCsAM 铖s(!Yt̳Ub :16ż1 5E ;J A JZ);1qWhzY |_&3uo4g^Q'u7}"K`gp#wm;IA0,9?HcR!>J[޴GطEK0"jL Mu9βS>w6;gj} ؤAHHf.Z`_պ֓IA7( Tx)3 jK [DӈΟ^ m E|EtύwH_rIKѣF3ZVgdt8jH[dbmh@ ɸ4ʥ?Zb~vH''9;JQG>T Wn"tp8dd.Gi}K'/Hdɐ!Yxު2,m"PuU ]ZcރNn#+'Nbdr@աX5[y?YB9j:WPnk =2oCe=^N/A%pAݴa/tЮnށȐI 6N`82('4+ i"yae!%"6hY1Ѩfi((3-r:dU:ID02-[sz.rtN7 Wm"2 ޚN яl.EV穈j^%Zzx!ZŢ5YsgZoJE/'7">v̚J9+SrEp4a 'sXȣ|r&DˍqŧZO9+ݎ-9ѫw# FxGt1IXmp,Xhhn*"8IEah::/aadS+ F;R2;G'l&a "hY:B.ĵpGH*(pPF(m=f!n12[yTb]R -|~*,%`&#A(m9l :} *RoiN薥ͪAem^JӬegCU "`IC6ʀl, aZ A1/[)`r$*96oNWE7i%q&zdsCIeib2szۊS!: P*NxA]h,aFeK!2vbn{hilpց&Hl"jf۶Knh=0MҠk# '>M 3jO-I sK,qiʞ</`*)o%̒ RVR H! ~Ho˖{ag6L$zq.Mu.TF%$Z[e&O(K9\ ly,ڄie`O-OY[wKWz v5,ğKq&z$h#jc%Riְexu-aa Q@(/ΰ,hS 2rCK=YM!)Ҥtc"i,uy}=8fɀENnQ< b5F6&2̱G[Q "љ>ڼXĊ$X&LP+`zCG~ɬ3.#entIDAT!34 {gwco2ΊUk tv,=XmQD~f"= "Ի˝2QIYK) ;JF͚DM @Rf-cpqWQJϕ4Bj}uV],V V Y'fAY H*SBJD--O1 TU!xWO&%J,A* ]r 1ND^hXgD,_kAVgYXGn)LV,dX]5 L!mH);sm`?~0 ZA),0'"7@-h״vZOQ߄@F~%"8HS -! "(VĦ"+b.bI߷ΜyEYkr֚C֚֚c"rD)uPk5RB\.Goo5 q1v*ZfcEu8R'Z;W8s7I’f x0n)TJ 0::S%<{˹Xki4BZ65~&oaqqFEq^7U˷ϟ[P%֚Do(CC}r^d4 "1'@'\ϘK!˒^`Z,Kg/<'&[k"\.{B?~1=>ZUJu59Jv,\r$JIf'&%}$gμ$Yq{)N!Ǐs@d!˶iڙ".CC}3q.ccJ*b];'05uϲd yuJO~0|,H,3!$) 366Ijn}A.)ܹlv֚CODvV!fpq$IJOO֚_lZDPV0P,K4 lZ,bP үLZpgWqbb{.ahaDooiÅs$)YfQJ166DE Z <޷osISC >b$u]|֩T(40>\.Rrژ_8hL6*"{7\*T*nG| =6%8cu1!M3Gy[}5$I P~ 1Qk,{_okk ^z6ks$I@,Ř +/{Z`:,#cH>g=SOzH=Ǎw È\駶D'*nݺKx@$iW- [ϲ$c+(76+ >ϝwU\ڎ+<$jaQ0 H4UJՁvP :٫yۻmGZ7},39; ׷ pg]nIx^PJķnLL"$"RSr#Zw@yfgpq6rK$ăk_…?Q.1瑦 Vz1ԛZ;Gkˢ~rX5E$R}_JE\!MSv;FD3>>|$?`qcau78NGZ./^^ҥ9>hZI.8Vښ RU񖖖e[fb+qvQ6Kr|ߐ xKLN՛\p ld0XZ} :hT~IyfazϞQzzvul!ߴIP5Vrμ 0yԿhJ9#=_bbʋZI,3&˧ixKunv.qE2?_euu%jw@{q>t\ҥuZw|,E;EQju]9_qe8YYYZkAպ |7XZfUq1R,؟-//jJn} M%K'VWX\\fiiVIǡ1fVk7Uw#;uWJYkSJ=8rypRJ||>z_#Ea$)v@Lre׭5)/j?VJ_QI.]z]3ۂ1~yZ{ZD~TŢ@RRmQOX)UWJ]SJ8KڬZ9cdoQ>?( v}Y?HWg 'nt͚NIҩ?y("z ĥzt駯O@R%IENDB`jajuk-1.9.6.orig/src/main/resources/images/border4.png0000644000175000017500000010243711720500104022524 0ustar drazzibdrazzibPNG  IHDR@X]wV pHYs  tIME8=DtEXtCommentCreated with The GIMPd%n IDATxymU w{swףZj`D $B @lS &JBc6eBHb5RKVZ-SOw>>> R⫧{w{Ϟ^~ {!~tW~wX~?GX+'~?ތI?/\OL>}sO§=V>\q  ' to$|93%}DZSy5i*T>sP}^ؿ)tC BP^r'ԿqtUoʸ]cZ]#<Z1p%z1;҃5h'\> @l#ߴ&>tHb݉we{l_֩XH53N>s^^;ֵ(D5 @{ W @^| /PGZotqygkX$-w_;~Y|aOH]ק1F0!@/x0؈@F$/V~z%ڧ蜹qoxug ` %PqgAzW_0_=b*DSC P^|Q=VOZ"{wg>>Vc0%(])A網_9):oXwEσSg N'Ȉ(ADvdw F6dI=˻ Sv?Y2@E grDZ`VozP`G: @@֓쩟br[04_ Zm+@GoxG ?Kȇp{ůM>Q]W9W~ӽ_p<Qy+tO^|ߏig{}C ;./>|D]K,0*3CI܇?vM"i1z{3P63AvU@BǃMxa]$]J}P  Oa̝֡^|/\N71!m V@7!٪@ ,k"1E\9>o  ǷQ(ݒ윺~h|Z2|R ǟl0i 6*-(Fti7 *ab|Pf1-]i 0ZJPF>hh\b~PFIyR3 c1^S棛 @*2 Rz -dwq‡@ќ{/ֶ%qfqϿwգ @B@ X !?7oUsStD"8taRfN_l.3[PH4=ŸsVw?ì|Y_Wk[Qwwc=ㅳ%um8}ow*v ?z<; BP @BՏ.zA@C>;|xMmƽM!#$"$vn`H&O7f V~%m8@??~t7HYeW@ PݸqnFkt]RVv+O> $Z%{@vup4"{9>)DB #Gϼ_ocM= Z:5WƅQGۭȝ:E۰KmamzIjCck/_z+|1H@!PVxϿ̀k?7?MKſz.} ZY3ڌ[ v@],dŽx 5}= ?~3;buv 컮o|yq&)'ѓ}<%b}?ِ8cI-T$u  ύV&p~ D~ڒO\~'@qm֋ݷwJg?^;c1^<"؃As[M C5`]<{.}Irob':kp~ b pN}+%6~ 4{Jk?7nq#jFf=̓m??=7=ACp4z0>3 \ڃN n=+FdT߸bl[kw}㫋E,fی:k2NQHw$>tTO޷ԿQG`m7kͩg7AJ)(/T/tMd1%`;]ߍ:k*icuQ47w Xw'w "JO?}/+4ނ [;-=X=oN?[˸B}A/B{ Y { @)h'+)xC۳7Ahp H@2nI7AXZm;I|: 7ws'" @xn@ĐX D۪6:|Fz Hh(,c0 ` aP }DREǓrb 82XtYI@ͩh@֕q]Sp^1&S RugŔHHH"H"$L06U?d!!5j_ՕiBQ@ O{U`a`,I'c3H,MzI"a1B/XXcCRL?`El•7>twoJ0!/,!/A*P qO&| PG LJp xK, U֑ 6@ V "Y܍Dw{r""  C""R@`C<l&K)Wa-^&B]!!SF)ZK=*7ྻoY#d> 9Sn=0Sۭ@).'ƿ?ږ O|h`(o@@QU,hm;7a0͠!]2%_Kz~҄FGd͛앂03W}듟~m2]rN?6eڲ-'P f鱟zX']JqsMou`C+[ 𹧇[G/=7EkTqJ= ЋYg:}ag=o?/~+WƯ$IoKuz"Kd Ap~)"}u哣N%[ݨwnsf[bAWoO泫ovҵd# @"_׺Ws̓V<،PW= o6ǡ؇j ȉ|IuɘBb<\L%6@Q؏G2P.r޺J:uk7 .3{ez x^z1-)́qluUQRV70b1_ oi^O*{`/3YV\, q*밴?1m*N9"X?F8_Q= "S RM!Q2>lJC0}yjY D>d9wuۄApG(\0XΘLs0$ b1(Z k^8Kn"z rp /xӧ 0OJۆ\F`6P=^"s)&{L_F~(1' qǀ+HЄO$ XUV3AVϏ|/'4|Ä@h޼2:V[1߻K~71ߙAIOn-M06Cjw09Z%@e;uP*S.W}DeXH|nިdI lm}=?ny{7aM@ShH1[ $\(0Lq6AX&7>q}tvC0P>Wokn8n:`aadBfj v6Z=ͱ2j_e#NKbPBC$x!dcMd !]Ay /8|!"p߄͎H!Q@R_uw!-Qoɕ.һ"Dy pA/9/І.b%w#+3\|dvR6)5Zd6dggZ@:T+?qw!(|6*]Z*$qh $|i?aRnC= 20D 7W3 qP4.X4`}W廊lIHԊx  0ۖ wx Rs|60A_(@K33=:[b7!r~0AѥY^k9SjTcG jK&-F..hvd͏ũɾ*~"F[l'}ZPAD@/gEl{Ю7=!&=EK%ޫE؉To[&yXl(dR{ˬ*PEw'VFLM@U*=gEhSֲ¥Ϧч1ԪEXv[I09=bcR IvSK&#(E`>; d*Ghw;U߯̆ z/ /n 2J@یAF)ơ>HZ| oarž:6ul1 f6HȘB~S 3=;v yߣ{kViF$tζ( ΊF>"1AEŔcgՐq@DQՀ DGɜ&G ,tO;m}[/8$^cT.0mGU=,i9>M<B(F)+k=nq?n0̊ţ 榨 zJQ,7Gfݚ +Q tIE)ޱ, bE_naUg>U{hJ Bƌ&<Ϝ=; GVKʼrTdsȀЀk̊S)E,c! ]+YҒ1HHy]V %8oߺMih2Ȝv,Ge!UQCK齆-Uc\QB*Rʈ(|4w{"zE7oޚΦnj+tN*jւ*ZjҪV KϛBT;B 9Ϧӧ{EAD!"c$vgE)*c%PĐaݒIjd0k245ԉCRn,A  ZϡG0MҴAݚ-p8<::tihmȡ(důceQLTQʲ<><3RׯGC@Ch!!^W*:880t;]CJNF Jڰ,FaSX99&HvcNxm0X@!@*&)DQ'bUR%+ Vkwwp}c#MECsG;\Acx̢ܴɉjx .\KRR;el8PD!OLJ Hd$9uTUng* $jukϲ 2T~R!C` TBD$1r:onac-F#|!,49OPq&d2g JZ(uP'(H @j' VT VbʺKGqn+! A RJ!P@4d3\^DD7.:C5" ra2 88 a >10xB  `(U-j]h< FB@auPj>bNrBHj Q F@ܞWg1h>T'P&IDD$!0WEABXP` jei:&_/V-=Q~}X/=!5( SkFyZWKS_%ePĩ Y5ѿ B. I&E<ܼE.bR*ȋdxC X,a3?b`Kδpq.d:=TH2nYuT;ѱ!ec"ym(!p*$y &RJcm R?G\XH#5xFW¥ 8Ap9'f`v,')0  IDAT W,lF#m\Y^F DG/ dϨU HxDĹx%gkDW%dym *A#$,噲 G8i贄‹+QIK}aVh¹@>jrqPssdth>X(|dTjIҧaytYyŴcA">mF6t=ZGȶ:vly;UzgbOs쑉jrE/2"vl3N+L"a!-@ м:]qMq+MAih98UΜc ouW^.PhOqe`E$nP.8qF99LOb(m.qC.o ]8hl: ֶ#)Pֺt8>:E1Zh{^=`IEjL/% g Adq+IonnEQԛ`͆ãc)Q!SH@$,mH֡|ɠ%'^i̙3~Z,p;#IҽS۷n|M퀢Jo"3[f$@q :7] ~B[/۝8?HBuuwoookׯZ;3΍&W% m+]JQaѭVuԞ Kc8UEdL1h.uYE={6 }r#?R8eޥFSc gWHyQֺ,uYRk!kB(T@:HSNeYnN|:ӻ,:@@`uPș8#Y__/uI&Pc]V(D'0R[ۛ7o:}:U8[Y{ɛs2hnᆳ$x,!T!ȓZ7 `/Bx?Q 6uSz"`612f@eP.xPey>km ̲l< `M+0체:J2OOňP<|EH0;6GT5 yeN./R yQ4PLM\q%ƥfkH247v<KHEeWE{d#*mfڔ\,Z )m@Ο\NRȋ#VsEY3mbvXYnFJ B RDt~etiEfjf z"!S}IJ{,p=*)]x* R)׬h]j˲0Ɛquq̄.5ttHLjwgT,^Б=jvJ]6լZNg{{GJ<˲tjmkEQĦG2圠VCm d [a% 57p<NnM5Z"2*<99*6<9,GfRjc#*#dLրPM!_bO U^}L"aP@JisM;塚ukr22;H3Mao٪Rΐ8~jDVEe1f5]>;ܶM|`S( $TՌ%7%\T8B+m Du%IA iJ(O> *Z@V8tYjT=*D! 4cJ@tש~]Y[ 3ݨ戅#,8f9E- sdAcS(3аwuG#VߕJJ)˸F qzO4;45 3 { Q/Hf5(vB΍2_y_xaŎh;$F *Z <cU#Nͭv{{NGֻKQ_bJ) I^ ,K [lU78>afgV+5Ƙюv$@ E9\,*_]*,y{g{W.ejAD0I1Gauѱb4BqUOi#0Y\Y6Wt6YZ_xclm oVEYJT[HDd(f΋qZWy.1W ;"6ay1^EqQ_-Bmq|._b9rWO 'x+F^ `$ J2P'cÜ#2FZYL:3l- q+A\7"j1$"vZqYW&8Bf~6mmnHM'hDm6m!2d4ȍ1EY)lz7=2h(*a%8rLL3*KGŋ@txƦ2Tp 2&m*K0"2 eRDK0F!VyKK/lJ#QůrQټ`P/b{gۛB"SE1͓4gƘ(BJyije8򐲑!Nnfׄqc(ZZJJn777ł6P%#S;bXIu$)-ñ2!j ,_Ffʒ+!Q)R2meY"/Pc"R ''ֆLup++)q2N(Ibw)fxŜWxdA=`BujʲN{Q:Zk-$e)q㺕7B(z^ ʲ6g`0.$׫0:WvSE&@IJ, $BE,ieYFQ+x0,i\j!B'P&ou^/_, "ˤ|h6奞4/P(*4/u*/-\EpuBHkʋS)Hu%HTes1tكFF$~'(hC5,5R$)50 $ WH/Dр&Utڵ\E Y %5WS#K|vE¦7H?OҼ[~Sa|'FVN353턆#pqN=x3Ze o\~ZeA *F\ X3`2hU;/6Z!aUqiG)a.xm7X 5ʑF_&1J ua572~5+E($=&8ODW6 =|rr#GƤs94 Bl_g]a؉%r R=Guh YɁ+prwjV*CFw^V'+ڃY7;/NkQ6>YVQǧ(>v4,rUstLǫNBuʟROpY9zz`ʻFM066~p_]?O'aij8Xaj'UA`'FI$Zu{O'U?wW;pMD$Z- @^z4t-AV 3‹" w ~oĻ./iw #o$/\Uq7~ Ǵ FGy\y  K@@ !ojv3|?%%v )ՠ 'ϼsq} 0hSɏ zzeqɠȓ3;-F zxOWK}pU;&Ӎ_|ݯ~v^`|oox(0==)uh#,gRݯ+ϴ „֊. W&t8"S~ _ۧ Ia:D)&,FaA>|.%W7bH)c%ۨ\.j^_'?V?0`c6$))LG@$h="~yy93r޵* "ipvH6}4 fmCg 6D1D1!Ux~v[<"b1?F7?J@WOa~qfG=9z }tQ I @J2juw޿yW?{w_{6|ߛhzt3@_+wY»~6P5 iA&N0jGn}˽7:aPvcFfcw߂G-=Lo5P1D VkmtG>_fg{)̧/-oϦv hc6d+hy272:y1}j{+}=z˛ox2{?Ŭܿ/~w] '0+} xoHm%)?)(\W7fR&/ l _(6Z=p?SWxO `F0|~߾)Qw;j@#O47 ? IZ٭QK:g C6lξe+8_#:> ^SzgSq+P/[YЀNVʉ4Yn@BGzhͳ)E^t G!vW۷~w+WO?~6r*nePP-٬ƥ~$jeV7ރ.&B9ɋVyg/~)a{UtS#ZщB,ҝAv4$ o*u6GKo*c m(@\ {5*RZ|"5[;@!ip)@ @7 _]_=ZP_8f^:ںϭ7Aªk[n3U>%ie'O܊$V1 /|9FǩXO a)v0 Msa]_XZmH0Wn_3/}x%~d=W9v,鮀7P(廓uj47%`z州/6zwݣh;]Y)FAFtijl_GX+hl:ANHz__G7~pQk{RcB^rTǏ/UiX 4*u~-s{JB%Ag-| tË<^t2xpdqtcq^@ۖJ0ݾpWMtm'juW-pIPFm}^/;mu@"h~f\h\~G:a䢿ag6Z(kQ0QuW\E Pq7ۏWK6cCv-% gl߈ I_*bEk{Q``?qޖ$.[zU0dC;1\"l5N͛:)MK,y7-s|&M\;&^ ٶ:+9j@_ס#Xj5rg˲SCw-ݙ$Q@ C!ؖwDFWwBW?zDw"1fW;;xrR '5;@K읯;K_sWͦa>hE/tVgsԷLah^ll>Eh1Ҷl5Ͷ iJ9;*.r]+}VF8ϟT5d:qэ nUYhmvEet{!(A{, REԉ\w@T{WEF0/Kd31 +/-yBr3"DP bs}+Yrsk .tZ,Gá6)S΍&@-1 <KNLM +g;ID ;ۻB8u-Lt<Ih]> s<ȋPCCF*%uzAd4!5y4վ9UF.kLI oI#ѽXdq&^R{;;;p5):$ xe" RR+L6׬N!"χ'ǽA㬶+BZ(~ODo݊d>-tTB:L˛"^D!F.HǣV`p6F¡qߏ95`Ej>ϤqfTV?qȓAjV_ZCbeT`eѰ%iZCN+MS0>n`/@@o_uuj*!q1h<t:-|wwjTYyw:])%_Ϣ(TR$z|\fR)]D?>>΋bmm=Dե5+CԪf-l, 0xl ~o BB5/q2ie(EQӝͧ KMKi*O5vr`I6( (%K#Iv p%#3g8yw;a/U]Kx!yHHwge;ӷN\^S {8뗧xz~zyo{F,ЂT-P=dA`'i3S!gN}|Ґ?<>>o-w,JѬ_x% wEۀ-vTp8hz,RB/ߎv}x8cIlP򲼽eC(ޤ%'˒o5ΐ11 qqйgzDnTd4|ަG[h1%BNOK 1Xsy;|R@s֭/JXffd^bDbB.a@Դf&j1{ENk\?lh1X"VB0'i&\tf]>R6 4LX8Tz'w&lϖJFڑ6&jNL>F :1uqlک^9JVq#p֨vdk+5:{#[O"TjݏEդhJ)3UUo(J5m;=TDZx>< ƂfQI#bOidg@yGQ/]njiumEX)Q"-oLj}uj9oa&-gJ T'=7o YMz5&N> 6||,xef 4S#livl#k#!3gVE^8iar!ˀiLx|||( KW$IF+{E$S6{=mx8>伄pNӜeHaɠ(۸[B4,a?/+e<|Ҫ;/NUh%S:ژӭ! bPDek@O CS CIHJ^eom9Kf&a4yZ$S-CJ1q<1O|/ Xq`Urs.`o 9/ 1piSXvzzqL:EJ\Ú(9dX;'isd%w.@W _BS;q1yR %L+xH1dL$z(/H{Za07ɢBMG:9h]0?[ VӥѰkH9 ؆ӣlQ6$0h7+q>s7T+n&hDaP!8* ?(0#4t+u` q=P-gTc_[b/iՍ 2|V ̥o3QVRڻKÌ7Ɍ&lӯ5F؄MCif?*u.fiY[o4`?DeR)AjB5 fj&Z_3<}σrSL°*JPڀanA7y+`)4`jANj(4m%^UMԀM\ 7FťUJ.Qm3SBB$HqGO}kC`K@鉧~y~+d=8_tBNRj*_aw {HtFϿ2;a/%Pk m[u" Iu jU(Qʖ/qw-215qۮ,^(ʛƼ V[cC<W"y^ybLT=mQc~஡;+[w) (ə1,!e9_Y$K߯)UiyKev>fpG\\Pm$^TJçR)|_(3dRױr a+²NNU'ڵsZZYߏe_?iX<Ϲn?|< ?5 "0Ǖ"}Zv]5Kyep[B XJå\?v@pxzz~{{{BX93"L bӦb`zr;< i'lR.!"$\fVXdYer>f w1 "g~4TEWy>ƀ@H! sf\/0¦%$ 2h4BE(`Qu LLEw6Oi&٘! s1<|"s@^ ЂZZ"$H/&u")q!D ۫ @D),X -v0 si &1ǣ IDATI낙$2/9/1?F!@˗ߧeBŠ,Iz8~\gI`oZvx?Ç8:Deż'9/eqؖ"/vk3MRI*R/!]uJO?/߾<=>h, {/`'YxBa|&]W;^Z< BD/4!#)]p\Vqa.׳d0֋;2f1RڎW3%U fgb nܱow┦ f.׸v fK`kl|z+ %"Y/Wip=p%H+32,XKގ U)Y)οNE:0]&8u>6l+Lƚ5vlBڀzؐ N̐G8FNGFk`tm->LHT Fׇ;R6`uk=? PFja(?4~^ :eJ+81 lLfړ됁.\4']JQ9o%q4 @q3^^vh5]0 tc2B+/-x Z|bL ت+1\q> a0cY ՙ eqΧmN8KJlmTZښ ֞08o[8( * Jװcx*=גnoX.1E 7IZ+Zs|ET&ۮ"9( -^me&)$c֍.5ps !! 潆! Z8 nu(3 $_>| oŒ\*T}%޾O)O??tzopd 11S}g.xJӗo_5/O`Y`u n/1e˒qa@H(NnEktKcZ^}._yԠkb_~d〘PBsL v8ɆK^44MN7S0^<ÇϯOdTYS!v~3$^ ˉi݀}Ʌ464|! ӫO9>#ȼ,rO'"Ó D2̴uȧ蝲6*1U2"C]o1ȐGNo/d~xx8:xoScRB47+7a$P[x3+ݮC5.PZU4_+Ukgy{{#xaO6v:-q !!&Hi'4>8ݠMNm+X 445U@7o%/ADa҇f̆s>oRs[sb-('֦"r\¦N6=dx68BB.^vdv^qRC6g&P3^LMxoܬt3%oB"tnszx@b a=_x (eȒIIaYv:o l}YOHGCis6>Lv51J]8"QcueSf/q!NB.ea>|1LB/8B &X ^\YT! 4ݫZ{%yxAZ&Ti5"UX"pqf`g['arS3˲~>/sienxV}qW/eti<!t˒yxy9.<~ c q3"NA6;ն!f,M:dg'Rtʈ8~i@;l׈f[OpXqb8>ˌt\^1@(_wCzt{N$z״h!Lrf:çl\W1Z:LM 3hvQ .m̽aNtʼ48g(-ot_W< zJA7Dd].85UUW0NPL/p(vl.PPQcLOe9-jBe#t x<0P3E\\gV~\q5i"LPXXaz5תHН Ԗb#GĊ{ 3sRKؤ]d:E{e RDv( kL͉Ƴ%,ke`c~iMUqB[]F05$y oRLVjyTIO#! k?ZK )ڙ0P%' ŅMJ&ojU㢆< u!?0TaOqI裯  ؄P3hŹ5Ca|yD:mDZB vmxah<YY`H2;>0|cO,ԿdYJ@ U,NZ_:BYd3|^V.1+oP*2OʑHat#ZB4-tV[DXc^A>a@7(,J+1 +ny blǦCZVYXK?SkO[%T^g J\a]z]Թ9lE)`o޳-6rDlKȅV9%,(TuZ w'fc{gckw m3C]1 +MwiREҋ*^67XVEaC^Քpҧ+/hbi-åq&kdU-MNshn;.SƩZ,X  : P;kp%Z|u}FiރƹsEi=[?Mm Dқ큺ܻX46Ėjhv^uл ޾IpK^6Ƕ텕mP|(*6]κ>=[O`KEMQH#} T&b64R;RUKIP;I(.>݊ { mf{ŔkBE,5&h!ߝ{~ma;UrꝢZkC>o2#3}gڬqySmB5aiwM7nUw1m$ev$v;m6{[-UZys;MOOp_<'{rtTד{K'+ZVq|'xgѕD{SNڝ̖("6߯zWsGB V#ۉrרups{V =9J ߅L'{־GjJ79T[?@gk`ya 6\{f '.ڇFzm "gdt4Z'7T6; a :@s%C ~YGɍ_ luWZiG{Z扡pQ2`2Gt4mqSgTy8Fscd[x14j->]*GL|!mE45"+Bp?h&^DI3/VmM(f9͝~;H%t2\TW@_Ӣƛ t_TPBKpe9DGOn*ܴPy͜a"Rtp>bVҮgUYHC67vO8OY#,& 8n+ A"æaih@؁"o_+qiߴX͒G"z@v*nٛnv/@?5yn7ҍ; F bt(xXm&xeB@QIfX>Z6aP veu-`}ܹgkxC3¯i-Ձ6p.%tѩ+ڙ3egL8ckl_AAdof*yEZ:U~j= VF +M'=Sr4 uP If65ĂOr͢4 2̊y+x[:B)h`(5(us`-(Mh@h]gْ*)lֽќ-zEu-}Ԟ4ݶ+h' 0ð6wH(ɷu'R!< Ro/$*`E>L#  i@s5|0lvl*Il]Y۵ƿRegGH aC]WbKٞaU[~OW&ƚT"MxhS0TPׯkBGMjY^ [Jmo+3Pwr:izCs]a7^UgƔoHp0@UR`-1P:{Th`qxNh%u#YXBdt졬E6em8pHf]dbN Dk16=.BU'!}CDh ƢŽGVO쳝v)bi䄁Cww߱64{od j NG_Ay'Lt#*WGSYBn;Xj:/vm(>a}Ҧea%t6ŨED~.]-.P1e!d7kR#hZѴqΘҒQKn;"rт l93:Q JO&7ؓ3jڍAnz]+`ҝZuxXlYEILB5@ΚML m$6MeX^45X!&R-B(u )^YQQRnn㢌 Z&X(Aթ~⢩ʙ> l1AI2h u-lX?ձ/QQ 0GvgZY;-/5K)W&&а!G0ު?y=e융f3܌Jګf,Q 5*d9bjr֗͢ˤ"D{N7RmO<aE뾤-mhs_.׷Ќ (j!n4q iF3,6N`82('4+ u1.~;VR%Rj3`l}VYjI:"gݡC3X㚴M[/"پ5+GZt+|d3YtzPp~ds)>OEv*(S *ɚ G;#zS/%x?dTTYZg;ZtUY1c#s ə -7jUh> Cv;0OD]|+I'bbkK ¡&bCiYj$uotb ncK"_.i IXu@ q,ܼ(cMZh B Tٰa恦gWoX7'UZ=0m!dt4hϐC|M'`rDUF[iL?;viΪ?,YPdd5Ll $:?KzG#AG4Bqn31p us$f7MQܕϣ:ﺕZh o&SAc)Ɇ\e6 bG!n gk mUQ8]WS9[6a{ Ƨz*MMz64]. 4:4 XΠmu=lͰ2 &gKBzci;u ^ݤtN4 Q B#w%ˋոνim+j+N(@j; u^.e3˨&R)w`WA M 8Dt W{Cm,e84sB4쿂4E(̨v->$/lFaUUeHVQx)k1Ny+fmq?" @7!-[=O@,XiI4-358Eb}䝯܉&KZvyMiF2ٿ93OmxlwIf̉w;k?'~gmr8T m#wvI &bAk Dp֘74fl7_})$ކ=n *Fo;<4bSso#SOu[/h|mR%ܩFW~{KulmN˂=W`]{4IwD{ a<7®+{w,PzIENDB`jajuk-1.9.6.orig/src/main/resources/images/included/0000755000175000017500000000000011720500104022235 5ustar drazzibdrazzibjajuk-1.9.6.orig/src/main/resources/images/included/jajuk-splashscreen.jpg0000644000175000017500000006003311720500104026535 0ustar drazzibdrazzibJFIFddDucky<Adobed       , !1AQaq"2BR3b#rSsCc$4t6T%57ӴEU&du!1AQaq"2RrBb34#$C ?cuv tMlH BThv0u @78$Ђ4IqhA$ޯR Ov A$Ёw h;A @ J X j'bq(> mPX@% P1@ HtkA$Ԃ4@ %w'|j@ D[rJ@ &Dp ja= 6TD'@ H=A@ Q |綂4CCZ;r~ /M >(TpЀ?ݼ _ݽ2t@}H v쓅ALAuo@`@R B W Щ@$>7cP'{(9Bͥ6 Ɠz& Ɠz'8{EƦFuLoPLNP1;y@TA4U@ wB( _(hA$]P1C\v pC9<Ǩ oySQl6O5|ǚa2QRit| k7^csmZ4c P gyԁh/1KӲ6 +^:̺LotPhH£ %ɦ DpI S,OVoupԇ,ew/8Y({WF [CRHk|JPlY?tv-{ %{'Ep?ߦ^fW ,[IvQݓ%(7k>hm0;l߃Z5Lé5@ t}Y}@@ XA @ Ko=H"wxD@*&(@'DP(8,lP wlC]P7#Sjど l|6nL9sG@Afq=T AfuѬvj~rU"7+64YPUF A*NvuT:bZ aFӤ(,7֯yP4}*kĨK'/`,ŽKA>Pabf0A#`m %Few3&EhgAqm##SHGa -%puHmd$vҮm@f/Fז$a#n]NF4j&Uz蜟bI|Ա\0 .lht7 8'Vb6=hsHs\*A$>񾟑H{eP:>s @ D de  @A4  ց5AI)_CgC]fĘ"j A,:y݄7P:@ Ńuu (bkZq7k8$ҥAsF{;'7R5v =ŬkI~WsKI0q 1 rǵJ Lv;b'.#OnASK\h(p -;](!m;!تӅv'z @mZ80Ă Z$ q ʼnpQ KyKf&v؂(,d!(D@'oN7%sm.v,q4Jksᯧj g(}ݔ7v bknmjovkװ45=h@ +;?Ђ4@ &!:A4>!@ DP*A<  tjw@\OCF4J 3W\NiA|h4s== N$= o sH@5hߵY$9؝A4vENc[:)+vX>gh2r -kZjvj Z[]k>QL&0~tWo9W [B+zwWuA#QXmvl}ck ܀ɅPsZM^ A&MPV㲽}c@}Üxh1RA]q lp1.'CGS#HA'=naew4=5^%^cL٬.o;MZ1jӸF@ s;? @ &h}ې@@  9 t}̹,asݰk>67Zխe &@k'I:訳4nkIkmZFj`lqi4cIONT1۶ 8Y g(+xD uM;nqEl1&yKcvݧvߥT%%S&F7C4Qr 5er5>@|3ekes@ Fx, ui~ Li ɚ?~1@ LNB=h+E htRyc8%{tém˶:\vdg|;]Dž>)#AI 8{H'P{̀:1yPLNP;JA4 T@ t x;AA&FUati@,cSUmc,:a:~iDhgk:>U`+6 dqhsIL[xf+áy2LݒC[M{?aL]t+n=g:Ll&{x7/ngugb{-Hi9_kPM{D-mvfЂf]rGCb=XFI?5K6.v`0:|<ƛ8i1J75Oξ7%p<<0)6FNźr3uƘ Ys_?sLw ڝ: R9 =maB+em3[)`6/<mb!ƾ/V~I|(n7M" -XmVe|23چ'~ ?$}kT>[PIk&&Z(kv>kݍvjcQ<ֶtn$'.5rǓ_o&Vcbun#xt-{Hڍ}tkeq*=>vZ3tө}~Pʹo5 qm|\ڭe#~}s iؘA+eav-똄 .'}e-$j|;tL_}ehӤ9oNW|{uB 8yEWל_Ag/n q Lr紐]Qk8ǜ2|ёۀ^%CFkQ c= rRHz'b`+=* 9(8WͼvQa#ņ:H٥ynw^6,Q|˹O,\B,ukNAQ[\}?1~$VZwٶG6=S%}ud *A< @ Doh;|X#D[l@$0GgGbNٲw1[.akb}}Hhg.׼&vZAqtlڞH ɦ4-i/gH+#Glap_3+euAH8q=e|y3+鈓q_wSY0rMX>?qRO.z7Q];|2o)Y.~w\:#d󱭥+y~fw#Rc3㑲H#! ^jR'D9[K"VIUuN߀./n`l+mz^Ɉd:xOic@ mX8A@ 0Z$ 'k8 s9++L(]Gu3\h0<QSsp0q롤cɿCs+?E~\`6Z㬷^*ݹӎj(< F?&jrrdm(sH Hq<e&uϵN8y4ѷ:Ͷ>K 6FưHK]m 5}XXW]ZoǶ٤Gfky$U峧9!t@9bs")硫65s/6/9O8,Q;+n4w,сlV[Y5ܮ;laa@}RVU`wΠPƠҼ<LVR{y7fykxy9KaGav=*&2FSWI!?%U"+yr{97 9.Um(J9ߒ|{s9sEh.4P [gҬe۸qbas(t~YUpS\ma[h$df7WYZMdsΦa%<{#d`oTU~HG89=3p6E3*h ߡj{v$W$6OW/DA-7<TVHnkyi?(\FivGj49M-od@~_yqMu-ɩ$8 72=X6cqFh kZj,U@ @@*P<{5SCo"K+ ZϑоJ961s 9yt?Lclasb7ZrAz!<hAwXqT]vgȾ~1Y具q2x}_f;z9b_!guá;zF<e~nwai~Cwoe/z_U/w\w\z] qeO#|Vo,3 d?y$\Gko)8]]յӋ_7C/<˧!FyG Zz;Z>(y9}GowF1<"|fg- ]<3>e+uCy9Ňڵs~M?ˡ4bHR5_lɲ~C[i^uӌqيDe+)RAZg=ʜmt^f.h:ADz= s+ϴr[Ct |m+DҼC=(UZI)fp=n8:4=C, _Kue"NXwoTW_~HIso7\d3"Ea%}=w~KՒ7+ȑH%;/W/ͣ?1Pw ;>ENT&iyyK%s:W%(=oe 05c@ k@ ` w|#.#iV^k]S .GQ#sPC{pO>.!PxntMwk~%\1uj=毘[evg)'fG{'_jx]?HGYsPS!{Ɉx~ [7no.V3Úl67G=Jd*95x]lLm0'0~)f}Nw߽s/rZ8F1F 5,qZiۻ/źcX#$!27Kǫ!s~%之ǤT쇶V3_C]'f&_r丮1)LB>xB}uJj10]Y>QVO\8bW[}MO?H홵£g 4#YeJN2|qq͹l2o`6;NkZ+74º ĞY?9|'~o5 k|WNCuZk15rs^5?{+M\\Gt8k [/[l7嶟juCh.fnvS5^WoOo/,yo#˯&ZF6=N+eſ&鮙N-LxKd$"HF8ƏlR_%Y1mTH+)?5|]5;~-3FEy;qѪ6evխy2+;&iQ.&Üg#ݹ̼{oEN}7!ºoiNو˯@wۏAyg0gH H̍ii!Q9 \C6it4fQ6VF6cԭeY u$ߓl]~R#/ϛ[sx0ks{f 'D)9ϖK8Ǘ3+(*IcxA1t"كs08TԂ;&۹d;O{k3]x-u=Kl}.nv;=ilp13.>/ίv>=tBl%3>3O\elԲ!'~evoI#d:U嘆oRbjڷPI[xg=.Ǖuu-Hli~H[տޞx)GcoVY?ZؽEr_>KL9W_KTr6~V r&W7y;׎YП( -,VkJ⼘'ƝE? Ew[]k_g[y 5`~W [~bo䍁cޯL 91tQ:Htq}mKlSߦO/W|sYn緷}q2e~ݥo=hlDѤA@ɣl>7x: !gI_.Iw-:E%VUJ5<.ݎ{inR\87 HŧR|iYkk `F@}ӴU#D_$\/f3SѸӛPZ㴏Z>mu后鋿R|K$FCqnwa>U&E+"&X3WxjW Lu+EjQ29X(<{]v Ǐ9 ]oG$d])RUd[ Y3'p 8qG s-fohip9+^"L6BmO Pq\tR Na'!M030 c6[,ga) "11o%^mӾԶ#4g3ÊV7 7#IiOw\YTmeuf.̚]DсIp+-s3̬ԔɝmTXp{WXsY|js[tlECjijpl]Jzb;v}7Ŕ~j׌,n/L8l}md2~^Ɔ@LźퟻĶ)#n7[4>1X\V"FP B+ ^?Z OҼ,_kiH~0[޻<7úffĶȝ7Bsט[C y:]3&\?2qÁ*śtVv7{LiY}!@*$y:^=@p-7jzX\.α z^?_SJm7'plm$1P'K鳂oiHGGx@3VHf=#7 WV[J}+i%Xų؏z(ܫe6PLmsGkw\|yEo[+ӰLG>!%exc|RM|ͷNs̞Cs' PlGP;2V]!p%~g~`RDmZչ &,: y-i$V[Vod4af"tl1P@6a 9!.sfbE`yW7bThCdNtp_ Q`BQ*gΒ]E.oqh]MMVCԜǖ61{XY ƆE9v? kD ` ፂ'7P4F@(ekD 9P;#@ߍWDCǣ_ăveSm `)I pp{֬dqi m1a%1:16s"pk1ZKW7sfQ_>cyi!>[l3vǫsKhI$mfHF]q &ˢ.;6nҒ0} T  ܱ.Sؖ5[4gW_|xe tm6cJ,cul[?0FszV;ٞ}5eϻwɇ=YD ` m]vZ uϡyڏRևFIʭ|[ޘ)&u?VϻwɅ=jbܹܰANI#z_n3Zne1͓/k+>u^ïeR(C^FˉXEm7bpek: Jllq4 rb@ kY?8e[f`I,\Nn5kʁ ĪQA_֍w7B+uР@ /rOȂ@wt19sK\*of̹n&]Yi+N s<7Úz ºųه|k9l38|R^ñ_#w-ËmٳNU\ ᦍ{3F&GinϾZ[1Xpti@X,0GZ[GÒ&>xRkBt(.}dŏn>ٜ{it摥c{nCI:5VI13gfYG7~[}L~$!Wl'4sDiJ=kE[cs>9ٯrٲ8gٷÏk&[ - ~#Qlf=|LKӢgMhEF=2e,N+đqk|ooBlsG<}O|/yƮneԲlƳ4ߎGȼ>/Dy)r$$:%(^ظjQ72;qtK#\<{պ=K]eI7b{RwoVrX>F>e.%J[w`6OCX[\? jf"`;z8ʙxF6YfEF85º3ٙi'+Ee7{- |^ոtVYċEj\9,r6%>gc40ӺbW1pآM>s3bI/pK,kAH%g_Tt2^^ۘ/4I$p8cs\라ķ3^U]3scwnRC'AzR2yėH]6];nsK\+[N4S]͹s |FMns*1űFKEp(0YidV_#YYK\h>;Pfo g52[Ht;aѿb Y'm~X73F5zr,n8yKˬ}Ø+CFgK{_m$A :j^w xw̜/^_}(39/L\˧6;8mewHlMo{Gkc7&4c|qÉhs^lrLs:6[&]+ms˵؂r:b: rvGʁNdn*Yِ}|܃$ Xݸe%+$Ձ ųv6LK#[i 1iTX3&qѯp :v*b'[`3^!F c@hʲ}ה嬝` lxֆ8p+j,+f&읳5h8CNeriZr"hDy7>WPf4\(59xq-&.2sZyNtН~V܇=9p{]z۟D<3cxb7Uez|[$Z> >Vr2&ɐ\fG+Kiũ.ndx_3ѻsI|kA]bو[\d_K@o:$z+,lH~ւ?3xr|5;($$7G9Xϕ˷O|]?50J0L hUCsWGK|c ٵ Ix@ؽ{ PĀʾeu;9_1غIt4]e.'wIEV sc 0@&<\+hM "7y{ycϕ\Z$)_#Y s4+x'f'ZjDB3|܇(Iᬁ z+Trcestx[pnhfێ,3-ktQ5Ff =79!Z21s.XnT?l]iolAE;,,JʳY[;xd,30:"b p}gx\\k5b:=)Ys^pJA@%1Rd~uoY٠zB߇VCR2ά mɦ.@2"#6|s{RZϒf4Z\ٮUn QZf~V]dΌe77sH  05p>yOw&D;sCHsK*4Z)Kno9|pF">H9璥y9k1F,] lrr gk^2*+Pl*g`)n.䑬r֧rfN<|]8D$IxoųЬn@ )A x ʂ: {9k0+`rˌmŰ]NϠ(<}ee\[=\4TF!Ad#i iЁ >|X&h;ݭ#A@peaJ[J##8d?AN %d.cGjځճHӬ8#>6 -fZ.? M(#?\W/܂PM!$? $ c4p9SP$->TGÉAvSM %p뙤8X=9O\_|0$bƄpSze5smCtF -[hvѧj$؃e.Kl7m_-i:A;Cj[rK1ZڴGmE0 t4(6nי2i,l1{^(KEt*%ʡֆlf@>>R .|4W.5ҸְHַ Uمef9c\Eqmsq+ 8.#1Ρu;GzTeǐkʡ_4< 8n@KK japvDyM#-L'GՆ a(ݕfXm%"]@ˎ@˜9p /cOe lL'ͧVd֬Fpֵ@Zh c_śAss/^# !{z qYYf^]gZy&`(s\X5y tyZVL?2\60\7 =:FQy +rI.!* ݘE&Ɔj\1TiJd>XY~/3 5w7m(#X*MM'IJمTjb慬=)c {+b:£U,5̳L: >hkjW"9\>Hp-u5 yqgY {(}4`hm7%Erl{f yY%kK6U<6[+x̩AJ +"L,<dˆ`ǀju%Eb)+\i༲[ھQpc P![fnl#{\bֵmvEK+m[uw&[fM`I}ge+Ym•<9j\iv"\=]J*2#9J2˖: 1Kb#Et&4hթn)!CLS!@@ @ D9^qTւqߴxk3omC{4V|ǭ\ŲgYc8y y AVS=v|a p!b8]&@[ޭt,d)"FL [8 I-6F&G@kB3.aC1,S)nE%uII$R@4@nuf2YG}'\qhe;x<&c+ pF ?&fHH\T kts0F{AdoPs լ.$1OK@@:^q?M\Otu%Pvb%Fct iqAfPsckhv +mlq\ԵuTD182̶FUN)|%-g.c{JiӳcGB(6(Ё@jft man @@P ݣ a L-܁P w ZB4  F@܂x@ bǬ @ >N:aĴG>>y|Y̒avcޖ1ku-&-HMJ vi4j[KĬN5Z' U&rCa#A hsm{=[ƪj^^$$ipwu~* }E&jk,Ec×wPW-#~riEvtoI@OP٧zڏN`|XPI,gkKp離 sDka=n%DTI@;<8֧ym~425mnu"fGV]dJ >ZG; urjϕXAÊ:PO[}_( A\0{H56Tx1H ~mo7@xq 8+Z$;@xs <9ûxA##-amuûx@xwo@ûx@xwo߼ 8ZAڂ?ݼ <;>>*ݰ AVVhlv;8oQ70G 5 Z>l>'vii-]w2bG t⦄ y$\ZX[(5#^RZ)(8 iշ i!9x);CȂ [.A5lxfOР,aav60ẑŻEf`p~cN ccЃ9N{5܁Sw: W'/f8j#݊SZKZ ,h^c7C$ ¸ +cT2Gy 5.VOAG+XӉi Iwd(u:>x4@ SA@ @ Oq @ [uWP5OO b' MW+CJ -qΚ?u^Vu,_<S[QS ^7O2[4crACN*hyILj=!{Y & N{OPd.ˣ< k=vS 67}l2,f3ppe\hݽ]FY56n%39'Vd-S OyWw%鑷ai~(7R&rE''wjG}}d>ZHǺ=Pfi ,PPI@ I?Ђ4@ x}ې@@  9M*:0XK=41FQh# a[bnsB;PP5Ѥb@oɍŽ41?ٖt 6'_wAQRgzGhF \[ouKkN)Ph;Ntlҡ[۞S7:TXTZH.KN'IuA~[eNk,ъ1@Mp]<CA5A#sBV6|.Ei3Bi^Pg-f 5'OȁY@ RkY'Y@  @ ArPF&xj:P=όuaaqh{'GNk & 6` j? -_h1PbPa.(1sWɡ158JY'2U 2|M3L-A [53x}B ´2POjwxjOH#@  GY@A< @ w G 8 qz*5X*u ~cPcڃ wDhs8ckM(1W {(0|& dܿ%O`&Bq;@  _+iS9oF r eDZ 4 A @XZA$Ԃ$ @[}nAǭ w@rv@QP5{P т4AŋIi杈*˕)rZANL菁/ф#J|rA+9vb,TC GǀE7xA;2nA;27Pz"dP+: @  fΤ A-x ցh;A@ ' O s4㢿+M:,=h00eFbL#r`v ai؁ڂ/reP\ " cE`D"R LKн }va~UU1PJa&"p9\|l# D"1..d2>=Dpl߾xo 8<*oIKw"ȯo`H&mO8"Foo/>9m۠.sΡiTU{Q 4JpY>} oKW d2 ~WUsMӖػw/>P($#Ja~~~%˽s1 hRCCxbff*Ο?)N$OW n+pD> '> tttݷs"^03&2&3,, !t:#"m|zu["IP,188_|,'gR' dx;pyVZ@8y)W X_*5qܲ=xXrhhhvxql6?I$uE/AhL& ]}v|;.>SSSrKƫaU34еkyMײ,˲Ce-3-qΗ(oS?ԅbKhiiA ਧicϏ7@Y ObKMYUQ28$LΤ:RL= Խ=Yt$%]XX3g/{=_D"aN *bǎz&Ԕ!WFWQJ|mpccr!Z+-BbB:v&|nt6˞Fhjj*!ҥKxNm%Hzuy Ra~~?P߃~jyqb 7To()ZޤV`2b6' tj4ov~}B8*=  hooR,ahh< 2OWUi ;ġC8srrrIGiCWYWGwW+ !=pSOK1ns8s`4;?8)K|})u}q(t]GGGc088gyeD"+kLW d2X),.b' s;=0 M*DѴ%_r  03SBt,9'#[GfQ4n Bku]]]e600_B-H\ tEH&) < q0;[XI? Ghwn8$j{wKosZBBQ" n؏pݗHpy!bͬ)~nĆRFӴCܩ"۶C0!Pa\v:tTׁ?BC!pz&''M?<# [ Yh=ܳKKeb1|PW*z%U|QUwq⟙V1^; VU{|"RzxZʠSI"2 2tRfoц8L-YAa?qB!ݺk:ҪL&?p7#sbXf,~0aGQZhx$(l1+i {Z6!| =F J*,˒@4b1ڵKlhZ<=||馛9c ssst76 :GΏuw)ո!8xg(#enyQ"$_,eyc\\7Z='sB u"ףțiHzܹӯN3f:( 7pwI90py/-L^v r6$̠'T)X,>2&zn?Nݻ,;Pē'~F7!ݽ+҃^H7Ülp')FJҀ)30 gVռx44S9<lh>wXo_Zx9[:8Kl0鬦Æo[{2d':K[ "ǜLp̭,yϞt# jHvM7d9D"lٲśɍyf8,^8y#A|F\)R/ori񌃊Vpt@BA &3)5#!"̤kZ&"trWQה@[[|CRvw5)ZL{j ĥAVp^b޺S{2I;S&om?( 8Z s\.4Mio+n;>o˖-PEf J,p-xC,JƝ p98g:R8wA*S=K-/m3BabĶXb{k<$x\N~H @<YEH&>_;?/㖦⼡)jk-uI;L f{Hsz;/f%NfQ hWΕ\_1s.m8ZZZZ c{|2dBGOK("ʢ;F-pGS99s$ ()  %Ľ`(@ wZl.IAJYz}`^FcCQ"wiCJL&GWWTU_DhKNh,(>Q=/vVP=pt*?n"-k+  @&oL C>󡹹|wRy[K 0])0( !mQěAtsiS! JjU mqĺd l] &ܮ!/AkstL_=_F9R]\>L&kJ` 2K)71P2ⱆQn ~U!Smë&8-$c\0]6wK@8z_-=QөlѢEǖp@ /躖GT63 g,:HV}o䂓衪 ohlOx)KWEp'pE s}/pWA#! Eg>~rpaN-"H(_H(P`EQd'unV0^p2~oheiVC\A2[ #9H)BKc9OWđd(s] V38w&:9j3O*jZC Y M'RZԛ.7N($vU9qZ*N@pɬ%! $ PEnb^"ahН_4%l.cX2`#вp#m@C `R䋎Z@?jW+z'g34`n{#e ' ZpvPj TZKȖp/l!|Kxf@0tr qUx+s9c0pN< !^D ͙,;Fd$L/]X g'Q2@>]& -DEAw ג܁EJ-1p~g /~sUG^YHϞ: -V+p u>S.Dx18`ۥ#gP+1¡pN82ܕ2L&~x[J!9fޞ:7rgU`HJ;) JF {ˌx4e!Ùer q9c.970N pב(z\9%q3fˋ 7PPvi=hMz"` )a9a3Bx N! DTrڵH@*(ie&oޤ1!\B,tT|"Q8n' Mҹٷ&2K LK1\^ PYwx` 'vEQ$S EM會-_W怀+p# \q[s{j![O5yrv4Q_˯d8iWxı|`پD"A^TnwW(;~=n̟>].`' &Aı5* ˣ/.Y,ة㯶UV Սi^PO$p@P!lŀBfwk0d6`m`ntq>LhBrYόϽr~n\4z^/q*'06 J/{ֻ;*SөMg9eMR9^nn//sە{v9m8,Dz/_Å}[J߮*E)s@xv{P7( rr'B|>[w7ǜJ.SqóTgc ^¹!0!pN%I&?@ݲd$]~ż!Zq|u_W&?mieS@R}N)=WG}_S|eCQ J)uqa,t.fT5URYpvtq5 C_Uݰ N8SwQ`NIb33' 'R9Ȟ`9fUz6̧[g^!11JP= 8ri 2`TTt658UB[|֘?6]4S'81J-X6/\~TvƲIWJe|ű n;`oOA11C9igY K_R-ъH$' ql۶ ~!VdeRB!3PX*i$`(1XysE;+eE-KsO0Ҹp8G'r͂D U`>(?] #g?iR !]Mt502b[j1*O@gesHn^*]4o毊[|;je-@3 o]9FFF 9Xi?KvrrbQ)O\\pH^*tqpriq8*t]!D~˲0>>.G}Z5כsǨ-!lrC74[ȶMϦ[*r$2׫]!pZ9&U],csӿsX:=/^eYbe D]p'D9LNN¶mdY G O7ken5&V2_{4wAYZ]K[lB[;~]ץW$J2o g)߯םV3:ǀ#&&&(# ޷%[6ҙBldlv gp*ebW|\I 8_=Xu HS^ptZi|VwyRiB*RDSvڼ44uh1>W޲w/_ r%*t`o3aƸ꒮!e4M0p ?9 D"H 744>xbT?uf~˲u,_ˉj-x/+ՀweAprb7pMrѨ4ńQ^ـ92H۶1??/ͥO:ڃ*[sWbj^M{j_N3nOeo/> p8,-!_SJkN@"(o… d2,KN*B)~d7q!|!痓Ucs?S}>O.jI㘛)S7(Vs4Ͳ \(SŏB8ਆə{9;r;jZ`ZzXImxtf剏6ihiiDW^̟ӪH$8?̙3(eC~Gwȱs ~rÖeXJx]/M|R}}&ܽQmMfX\\O=)o~s÷~`mD)ONcffLFNIA{{t D񧿽C.Zoy'Ӌj3Wkmؔ񉩅u8R HX,_z%x{Rךּ^@2 0pQAIP(066&t_Y9XSs֎w/vGe"\+u+k_ozP6OWrE\=H>3::G^拍QJkUl#> =]ױi&*W m<Қ [;~kN A@uԌVؽ8:षCdHr1FGGa&TUX3gpcg)+*z,8ΤHwq PJ111!(/.\{Nx.Q}ZI:jFmM;6EgۉXmUUUN8;*d6^y<䓘`R~iי*ec>;v޽{b IDAT1e3y9<3(E!VS>:>oz&uM ]F:>~WwMac mۖ+f2 88.\ OU:zcdAAKK,%pjvSed5M]gNwTUP=e[oəTtjOz1hZ]|։DJX8FkkdicLsI={ pX<5518L~>iZՔa ~)UQ\P(XѢiLn,3MݦlBpt+{eYLMM1P($%B.ó>t:b(H$98daax׼ &ZNKǾ:0`֭ؿ?EwhY6l*#pkʭϪ`(nш,1^Qq4??/][MжmW_E**ct]eP. x j?p\}zX:^Й3gϣP(?yb1ԩSo:(hooG{{FFF0<<3g 6?+@P2m .]]]سgwe 8s9.o%b!"9^sӃaҥKeR@uhVB:b1twwE122'OzG?&H i{8 O)b{{{k. 0  +Z[5Y%UQa\f)?~RoЇ0::Er9,B0DooL*JahhHw>_kAd=p_uشipb"^E>W5Tj4::Ǐcbbx2(۶[ X,"AUUa ޭq(6MEQ`6<.^z˻ >?[׉9%{@zXuzR)`hht?׿u9ӟ~R&z뭈FBrp0(Tl۶ amXs… 5$u ć;+뺎vtttAGDfzzccciR2xmR_ީԧTJ(QJىl߾XL###u{A rJ)n*DJ)Ν;aW`:KdrE>gNymR M4|/Or(PJo"c׮]FkkLG&Jơp7oތX,&Á ~֫mx)LvY#X%Al~e{K?GÔPJg! nCKK\IEUULOOcnna5ֆ60N:%^bWZhCKd2:lrbkFIZX&j2SJ_m_sK~`oC nu]ؾ}A*):lۮb6o, [oy=?WlWI+Q24qV*/СCҝUUiZMX,"sضE ԩSގ'|+Mz\/?M7݄h4ݻw&XMM<{sI8}W:ݵ{yj; !?}}}شiv؁p8,@)]jcM<}4Ip@praP+:+%umaPصkzzz7FFFP(@x D۶D۶qLNNz;ᨃ'AUrZ깶-WA㎦X,Nފ6~q,...5s L͛ǥ {ELLLYp ÿ^]UT0rjǵέ7->_ooB>8‘#Ge/<Tr7ѶmaddC*Wn+H)깶rίH `{(p#G Kq5 {m.^3gx~_WϪ+ -J-W;^|="+?woh;vX&*Rq(6ߏ[tϞ=Y7U~5P78nGknnVcDTMTϧx@VË"[XX`tѡ!+x3OW9r}@[Bw^@, s^8TUEoo/TUmux4Ϯ-`~̯$6mR9bرbF86t]}>뺪(:Ĥs\2۶m˲B` +X ̌uӧOh[#-lݺp1Azs cccxǼ TwePgkkb#Gnhkk DQ34MifhB EQTEQ4( ]ehYU(BdT833|r_̿BJxoy߾}Gp)DBFFFơm8p::: [O>|+"-O^0eZAPvþCH$ B@ u=_Ӵi>UU EQB PWԙӴmhfBPB&ɧt~pp0{ĉ>[ʌ/;ٹsUy( 71N/D1p eW&رcw+?wر-/axZj}%);8 555p(  |iAM5M 'E1!~<#1s^cE۶҂eY˲ib> B>Jfggs3gd7UKpX;x`RUnG"[z 0[N/ ۶|Fd'x>e8(Kq[r̭tL\K{;wh4B@ zXiM4Mj4-iZ-ޮ&]70malw[ vk֦iZ5sw a~݇BX,;sL>S7M11_ 466e4M)'F|^f6kKGv-Ӊfi[ITW•b i9JM'hs9 [ܽg('E +ҠjiU%(J !>oshss3t4ι(M9Wk3O-} ?{߯PJi<"@ ~뺭뺥jQӴ9UU PfsJsNckmmțY( y̧R|:MNNN8~tU|_%*׽o~8@kk!=ϟ]]]]D"4 EgV_XXEܹs.c/P qU{я= p  ~ uPUէ(.6B E0CeYmۦeYfX,B.+f|:._y啅_~92rF+޷cǎ-[|GQ ஻Bss3d.Xw;v x≾Za ʍ۵ljnna0 CUU]uMUU]QPQ+FPJ9cڶ4M4M;ϛl\\\, egΜ) *ns.W>8}{ގ6l޼|ޛTF닋>',ɱc>V2\=]U۶mm455PHohh0atcs-ml6kr9;NE{ttxҥ$tE׮2W.>}_4GvTkY|&]oO>$04o}߬s.W: 'bE^qo5Z._/|ѣocp=oĝwYz 7_Py>}>[ǎ75~sA]{WsmrzވjIJ׎9r_ sN<#^vs=ۿ^|g}vo`Z"Zk}eqs+uTe:tc${3(ÇDcci/K (~ꩧ~V+ע/j0}sk+BsíuB{?l 000P9b3`岶p8#3L%ynm&k@)_n9r&!宍?[ch?YEk0jg) #ȣUOF&-`8fH7=̓TW1m}W];>^.Y3յk,׀tCS_붶S0MuXe:;s떾Z.93\~3ٮv7l\vJ fXCs{҇4X].[| H7mE{t6ƹhh\(oo\¾ 7.2*ޭKM_]С!6 ŏ7麷]Fx XDꍾugn|`8lI;H }D H7m}(;v̒B6?C,ܻyCNKh)J ѳ{zvGj@.maW$࡭omqKb:Uhڵod5_pPIL O{3gS&hPkcGրtsq}M?>/r<^5vvupa|}ke\7}kQ|$)KfjH׮7? S=O1&&`#uK_׀tmhj2g“]cݹL5 ]W=%>Ŝm9&B7OmK\UHk¥7un u``ϳy5z{Nе( }ʉGXd {ͻOM5'PpеHn_E&3?_t#g%K;$s[g]3w Rѻdu/z1/,Yl&_SWS H?=̓ax|[4 :oִ~עӹiu4z׀тd3I,dYot*}S }]ձ+I⸅yxDCcU[cO&r S6 Ev۵oj3S%WN Ij-JOW0Cds2|gL Hf( tFoEm5̱ohiqXEKz#ޟ^UX*G|yzzkz'f^Ա{QNlI&/WQ\lصoMLUEw=`448;[H>QVxf&r^7JP.[4ŗ@szJע$U-3_SH_嫚(3Fo떾w&mB) #mYĆ-O0/֦&ҭ떓O >Nnuk7.LZe}oՀtCi*(x}^1Y{= ض2L%W<n@b4=ч׭i?V[=g81@$޼{-taJPHvୱӧFZ;o!i׾Q7=-%k 21S®YL翰ͭ:2=uf[Վ\)kcG-F6䶵<̓n HשUI_aھ{b?vʯ4fT`ax]hhdݚ'NaZ򕴭[%K;`Fin{[udk֭'6ևxneܩ 53=ں v7d]F{rɢhYlp5uݼpI;d*wP^@ڽ?fĺZAcni9O[}]֗ypnxV֨7dG~!@Jmأ+k OJ0ճxoh׮"O@t]L=\DpInVou/Zukk+:x~X+7zD(!b[:.xּjX&x6v\󺉑vuBsc5xq`](F3]@z+{LZ < ;|}~z@w.<{aH踮_@-YKOWD8y[kۻcGW۲pEl?N%[5mk97 ?ٺգccN,YpdagO~7>'A;O},`bbZS\X 6M[О0538?iXڳOd9ppvHcSÛouӟx{ׯXw:v %x]䚮UJȺK.h|xÇoٳUNY#cŝv[#:lt,gy`}7>_*l?"y+k6ץ<Ǝ;~k-4B1:-JC!~WO[ʦ[?p{▫q/Ņ b(i3ǁCw!G6[7cnH,{-Ƌ,D82|q>-^:&kߨ;5\|v\[JfTzE,^p-%e5 S#:uYoq' FF#dpaj!g@ʧM׾ۼwLdHuͬQ[׵:{U" h)GyE> \39WH뛙$e@ѲR rYh5QOl<}XÞ}on;RӢ٭?ְUVűTK1\4 !)u:LlR2D"N2"_{bdx@[e VyGX$撮]3_^Pst3 u_j7%wi]wy70n[59stx2@1Ntw-7/0S[z[F 66D+d^LN0:2AOrBWBö$ld"qiNx9&fyds9Ύcnnj[b8Иh}Jy%#G.|h]]t@zcIܴeѝ7hd!U#+ؿώ7v*?ՊwX~IҨab` )BJ 0{JۻŦa,!CG651esv|-$걤M2!a ) ,.4 CTkBo{{4|Cw:v%pܩ{1f5W8ϻ Ipq Dxe{əP,Ѡ.^ruE7B(fs:.Dap|Ш»}Q=5tB%3)K2.&ΞE pK&͍ Bmt2".4oUHC,#,m wn dѱ\}>= ՝ڲ}Utߤ2zE)\uN\iU:- <[Wo\owּmlҊo[W ON%5MX]+t0h~di( p=!յ2  K.nAW1-z#FuuuU  ݫleaJ0hokV@ݶCmۡ,sdfp``w?5T3ӹK[zݵ-jnJۿ77Ezf@i "kԼ#"xj$A `Ŋ$1F"u"")m,#yew-@AH۔<%<&ύ-}}7{z{߷3MlறF#|7~!翰u嵁YX rPr2vftiz?;5`yrW v燏!k.b:64ӷat航hD I,S\uFv/)~}U5oG׮e{=oٷa|2ݥia_)nͺLOXzKdܔltѧ<4sqjOC@$4?fnYN,Ҳ}esVqnlj1OOU9nsgn(زЦ8@~z|tFK?ޱL&wւ0t)\CPJ"MR9G,T=B(8hRT9::6JHpQ+\: JҚe:V]EbL(%й ;O$̲%,_DP]ia- ͬ6::Q'K :w~XxA?v~Ϗ lp2ZCX\ypKqi~vu57tf8}jgCdX-dA ےQPбPo{[ ]] (XEF^:@Hs!eK#}]dEʮy!tѱFzoLquAU5+5]u:pp 3Sw\<֥ Rt}LrQ86еT/wW^u<?3 [; P)A42%iJzP@(TĖʼ6^tx`͔"r \F _V\@p_v)Z^uaz3g4_iZܾ83f ppe?~2oF$ƒvzJwG /r}HypƵo~чwZvOav5wO_,4ٸ& ݷ9rJ\FtvZOO't:~_QtA̴x^2f(|p~6%\NYo-iW"D PUAtg4D내4Җ^Ȓ5 8ə|+f~N9X0L'/,۳`JԀ#Vۿ?.B;֮:,~FsʫG2ҎFb kF~__KrfEn7Yyndizrt3[h|l!n*+4 g8ز\7@`S)TqQdW*#(@ ռ3\N)UfEC, ~=eZd,:n#d03Ff2Y 1JS~ (.ǎatlМMݺrE>l}9\{U@ᳩ:=֮)#ݱe% P o 8܌6oϝq^ݱnw%#ȩA?X/ZXw@Αv5. RGxŕ— EtfV*l?>%\t\A g׮ !miK .+*L:6oar|ӌyW*[x ,Z Ov̺ƅJ!up`ॢS[m<7l끰oa3 u/.ؿk͉KcHn $z/j0BS* $@A[J$6TЅWrs P-u*>se*&WņjwE@+*7*=\*۪ vcN]^nc-[>Y(HwO%D Š۔)Xh:xۻX<7A iV^t֙'6=yr౳#Ë?';q> IDATځ0€(jaMk8]uې並pqy:%Pvoj PUk «]*K(Nu< m(}**y@)鈀N\z0]lxٕE.Mf-,껛v}Xz}P w ;5LKo3uڹ`䚮y@Zsoϝc-1zb5<xlK;D͂Z G 4P\զ|<TJѧCmpeq'{E .A0/4a*'tʔP/{E lO2znE[AmUli %M/!D-5zv.hhLo\j~_:1}S_[ţ;W,/B7$Aw6&lyõQG7[K/GNOw;h%7RB)6@RVYd.xœ%*H/vL"J 'u<s"%:.2%q)91UmAA=у̦w8G:(s@mNbYUlBp]O0|X߲Sc!\i *LL[WN;6kkz]' lTJ[?Q>y<=ƞ}(ۖ;u zHX|ҝ *M ÉҼyaUS沥 UVH<\JS]?N^肠T;œu{ҶeZHSuad\!D8`qzƆNJP: 8 %'w_u?~h#\i[*]FY )?/qeŋ7$M~󖫕i>}fC'r0mck3N ǦS}P84K2V0]]Tز%QKIX1Hc;yR7HOtKXOpRIt*Uމ'ZH+W_Wu$(P"Ua^8X G9 2"K".ZQBT2G{,"j S"o7wJhG?/t,ٜ87<Ax@z$ :Y7vj :~;^yxu4mbgg't[LSc5 "AL&'tH4 :%𛈼3jKAT)1Tށ@47@ Xwg*S:ei`]HA\]UfW~bXU?xP8D<cllE,[Yl#hcc#޿?:wQ|_>G:9I7* עY dWY5,(Jm6yp_ڱ9Pd2|Ŋbuߦ En0 JMmeW5"f4,[B0 03&6e/cؔU'EPcȕl)i:q/8x_oK5uzqƾws8k׮,)5Phh sAC E@V9N[/jA$Ky QL`yZ@x ".R G~l/blP؎}^R)lΫ"lt!p G6O:.tt`KՏlbH TfQO7(e4E_0xW):(S)I[K+?}տ}oGl-}#}AWŤ\_~QGs5,]9s#'_mCgt. k(/l̔;m ߱;pHlTC}͖r8+хf]9JLUݓJW9GH)> 4tx?0nx՞#*> [AEʼ=y܇T z*^FD %ǂ]@.aTJB]z,^LC{D b8E3934_`d:k?| =]oo|DqCwyCҁd,dݚve=lڰ}׿[DӢ差L444ymLΞcݜ<=D>=Ň?k7IK}cWPyl3ϵ(&inKHRZRRK/l4W/z"4j8~HK¯݃汓^<7 "*"twA:;nkoH*m-L=t2f:$oWz*~?;5$@>3ȷ6QjV3xH䮕ALyd3I\֭iw% 5>wzb2ڻ|5~q\Eע.23Y23Y,[ {|muT!)R m/U9-?z@Y{ٴ~INh>3ՊJuPѻ*%_\\u/#=V_ W^#F,n&Lu|Q!S3>}ər%brnݼ/MrYr+S>/~古 M] DP0ϲKl$ o7xclldu* Y7X63IhoӃ^u˸k="Ms# 2Ζyr~fKϥ̂ϓ%/huE8} .3]V ~88왦el_P}໺;B"ހ !-`0HaЩA'FbB'k@OrnpWN c;]}?mP(~nxxvueY];>|ז{ @ON iX *KR4E !C>ĩo}|zUk'? #9(TcYxs0b2''U=%,yc P9=$.:g@c3Ssc$EꗈT.sqNA*vZHÖ%b#(u:FD] h!U ud-JL\7HMь: @CT_9v=_PUE,2TiV kr3?tk' `ș`,]0 ~] IQ΁=s`{Ěy(K")RieJ5 ]ZŠ ]@D$6OlP:s)s灥Te$?dPIMt\wRUʞ戼{-ݹf|4IzDFȠ.VIX,qJ0D)KUan\몟ӻ|5Wӽj a;ko{c/}m7h;?mbi!=s՘CJOW]fzΞoKp,cܱNO5 90!#TUE.W2.יGTj.eKA5//qjUo1\Viz\S*1.R2men$ O+(hX6TckAAt2I29tGN"FN&%1 ffβJزn~³>6PU>OsG^.kPH,ȹ3>WI;tic!m4B_O?/:?'+/Oo,ݾz  mzP( J0e3(Z3Eh8FAAӓHSo䮍wyk1g 2 sا "l+twQ%l[*h 8He:j%ry?sE*8hبQEy')cA@qTҕǓU( hh꿇8PE M8 |k(~X mxp-M4Q qtB ΝzSaUӱPA6[P:*UAS}Ǐd:Wbm+iondONRJ?p޶v ]߿ʗt{Hdf1œy@'U/ ;?plṳs~d2hZLEt,F+ O՝}K R/'B{;>rV~3:L˦0Ъ>KVp)ҭTCy>TRI쿿Ƭ*7 *4B6R*VJj)q^CQ0xDDQMcQuu07J΢cg\C6T[K4쾅FJC:&o(*aN %-._M^9[ZX)竜6a[ܶz5&G>rLz#}D53cWEO}e[(*._i02^2s—ܻ~ 4u}!/V:ѿkUw.EesYt!876װMwxP!!<=ϯm)Um*nKyJ\e nuya wK7oג aBO' !F$B (JDz$1+@HIYJ\V6((>l>!X?a+ Rb%BݎD iDhlkk6ϛ^z)$'=Oʣ,H\E]P9֫ W޻͌pVXK?p7iWa[Lr{~l??ϝ<񹑳LLwd~؈b課;\܉2@J TUc@01e+{0|vwϓOO~nlֵ SU^:wQ;:~&Js\C?Su9,Tdy* $/APBPeO57E*(U\\$m݋ԹC2*h4D^K< ͨzeDXY2\ŭcdye2-W2iON8PB*^WeghŒGy|OSF[/"|ysWW-qتF[Իr#/lvVbe# eU&,˜i"7OOnF;02hiY~24hN~HJ)sjN4_!sPSm227:Ӌ W[uP@JwMU[ژi*dl1te4!pѽ8#dT_BTcHy .(Lq:5Ti zh/ ":~!#"KCZo4b=꽥w_ٱˋ5Z\ɤ(Z :S,]H:x/gR3\=T,1K_s7\)Y7c?c8?E8QO3i¡1#L2B3 J !t,0 J(~'z{BR5"D-U%f/[yJlweUߍ C1r1L ˜[- Zm!B:!aPgU뷜ק۲|E* 2 p E~qjVpBH>?_U"! OОhu\?od\t7O'2u2-lWGWl??~L6u1 ‘64ǣy{k´MH#O~üZZ.o~T?}ɤsy%EjK?gGiHzʊ,ijn8DEoG>n|.Fs rydF,)K +\A.D]ACT2Ql֡t/\}>!Uñ2XD2@|HTGQ(*TTUAUJy:8(8~|Pi!];pU_Wv$TgpEQ_8_pmUʊ"aXvH=B׃z) oCzHXUp,JIQ(*%AmTMTRp8 `MEqGq(]M 4 PLMPV(\LsfxiP.HGh*xsP֤?gΜ HȠDu8at($ L3~"'O L/nhiX0!%9f%{o*|5;T%B!9m!قI3Nai%MSlklu_05d>G&%oKD:E:epUʎ'/b?Y.Q"(1M Uǡ'9?<;6ٵ%Pw;rpQmZY 6Œ:ظ8.TATT@2H mUSQU7GpQm ױQʓ!\E pU,/|SeBE0 ,"ˣD(8uEǂ" p\pYKPϋTf;hTB( re3>KԈb&8hh"tH[(+.!GAYƢj*enR*B !qLTݠ[o%6oZG*|&*}Va:&{O8=8,fF5;-knG3YJW~Ὃ'ײeêVu}jpz X@S{+a#D<5#dI"A֮Oz12w*9PtJXlm] f K6gq)"fX"P`(u:F9y}W%v'qwNc6[Il,Y’%f#0B(u?Բ+l(mYoCnAP)̂ICL296{"`2/2N255J&F]g&ESB̼XQ{(9^ȵ**PUAwR(Q[^$ٖ[-ό{ش{3=vw͒}$KdY(YdQ\\@wTj˪-2ŋEfe%tɬD.{w(#AG%FUB,c}f<&z( "x,&r,KoՋЧڵ'N ZRD "BD@D td=]+\o+3X*pqQ;e IDATҲ&®IuyϽ|Tg玑wf- ^o㑶n=-H=>1422IqK^#W(242BTPYYZry.*#76$-MhP dߗ8V8WH ''aRgf-uH .XJ#l8UKId2} e\D)n$}^tQ'LqԷ R8A;ֻHJ$pVC<ȦM%jUVWk(_qev8SgNS7{6FJ=@)O~ٿ;,ل$faep (Ii\r^=¦"o"QIo@.ow6޷(=-Hp6틮a,B\u4fcff_lڸZ 974'y.6o݅4)׾E3<~&CDasi|O(a͠(dmx[ȵbecR N |'2 Llم9Ξ?ulk?a]g&&DS,a -٢qRP]r/!g{>cx3X^no>}Cҁ([_:w"wNmU|a8p?#}<$`vf PuZ[1zo_rnٷ0?ߢyau-K:hVi@GȐi| Tkfs﷍IG"V,Kt "ku&=4$iÐٍ7CuV0dh6dsV$ S۸e6ows|?E!gʊ!lm$Sg?blt@H2 WG\E!E-5gu5J􏌥Z@uA񘝙ҕS,z"LXG.RR%i~Ar_OjfEGٿfئ[9*,j7-C _௾4)|C`d-oWΜ9ֹd^ov?_=Ozonfw'I|c}cϿ2;l'1Kf'e+/G^yvX#JQT᠄Cˬ0Mw^Mb߭h"b<#&G "\w~ vlo4C4n$]AaZJKG";(4DY9ZXLmiBƕKe+)$,]aae(j'>VsTxiGS8C-Yc:9Q (#gx&J סI_CZ'8#ct㴡 cMw7t6H|"D4\Vq%MnٿZ@ lQyuu0q3='Ϝny$Q@)uc_W^x$}z>Ϳ??SI3;84V׏mï1SY⦛vS]^!Іъ l\qZ:Bҋ}>)_!'w@btq/3:PfbF]Jر囖k CD 6-v +tRX++<ILBؼA;q$M"^2XCf:1I'h\ ͓#d|E!ϲ>QziF6 O07(8_gR|qJCE~-h6={sch4Zd>BFIزUg"I\E>g˖zQR+С!Rqy\9Ki{ŔX'cP-ߣ\e9rD'6o5T~RU.^Fh֧-(qC+_e~x~?{?{}o7e8Y0;sK8\D#.//x8x!qpzcMbq$^Z|lT8qB-& :ItLdb$bcDh%e"#l{t D8Raҹ/AC$i.(qI0k") Ȕo>Rhw|r8P2?myWxg%'1uL6˖-co9v(ɱm&`?q)a[Q"`ALj7 F&‘vCRi! C=$"/%J.qU*9uF+Q O:1:8JxxkƔDN9S9 81a+Ae=4tȹ3W8fH㤀DV5-FUF7Mp|r_&8=tϭ_tu!dh}?P+F? #{I\^dgמٗFrb Yd!yZS'Ns1<XXL#Ԃ&2qzcr\AǝnuΙþDY~wXh/ǡeEh *IE-\8-^o"Q8" 3 "tF8mp𤝂&$cU.*CC!Sݴ6(J>_:WfkGX^HC1Ȧ %1鋳 F~ }%+' ~$FDʩW|2ۋC Rh[&F*\$EiQ elY')^`RrqHXX"6t\l CN8$DO!m@#4ROyzUSoyMi/Oԇ!Ǎ\֟H;d̵Z^/}O++()PR 2I+q #C~;O>|02$Q2Gadb +T*.(#[l[T^>O^WB7N%ۅC\?g;g;ELgNM=mEDDШNm@k!)JPNE Ztfe2\p14j 3,/pE73{u+3Q~?/Dc9s8wIpˁ[E/׏7bX?7r?8ǹ2Dj|a3yb!CQ* 1_ۻVp$JP9fx@keXY-ppSVi뽢c:Qkǔ >. y<7ݻ/>9mO܏{x/٧o?55֧>ۗ[aS;[1]WJn˿3ԪS;'_-'X^ QU%+,ǎ[X,\LTV,bo~\$ %bs4yܥfv{nѷ~^}U2 pY՚r_?BO(0|pR?vȨsrq*3d 4:YR ΐ(NR~k3=[ٴG5mT -0kGo:DP^fP*ieQZ rBCO?ϣ~_nλs> W<}KG.I˺9<9e|W^{F#CC4 \Rc}^Vk9Wki3Zz Ez{,.Ӭ5H\fQOF/.P)28J,ÿQ cðd!Q;#:s$F"d:R:8$ K2Nn`cncd b%HLHm{Z#$1F%dvn-$AIG?.z{6pqz_| ng}|?} #EO2w*?u˖xZm|/2:>B0>Ob>J+%癝HVaay8HS8E"}JZR#2NmRc" J(%ҘuB.NwbR #^ljfV*Φɭᫎv/?JH, cL:%R9Z q4Afhe7o~hlobui&!} =ZT;9f>Klݺ4̱qr*$ʥ74M$ܹ>;˾;֪Lmن, &Rڋ&^8mxDZ q46&Y3$#0({h2{QRCHcjm+PrM7N*|g_}39ť2pd0~m;lȿ➛wwKzsQi6V(1Da$4G0~dYn`x|?EJ=yZt|#h-KD$Il\X. o~֐ǟ=Ä~5S:uxgxsO=M QZ2IO^'51f vAqVĺctMsHdžY+0Y!J`%-aǴL$-a#c _GC)Qc\ϵu/1'-[[d Q I(GGX^1a7]߻/Z-O0OO> 8'|s_bC6WbP$P?"<$JWiVβ5) ̚&F Fւ\86TmH1ROU$ݰc@/00\d@y^Z`Ouy Ah|!hcX.viv<.#P׾=qC$O_8Eߏo}([nV]҆扡' oݬN~j+-ٸe O9l<$jNf"n5dk8ymTH@2RSSMLk!O$AZӱID+qeIKȑLZ<606iA>Rk)8i-=oh,;$]-&m[7eA^|E.fӦ  y#hgIULsܼs7{OqbOG∄!ϡuLl$:>4tCQe l8F j@%%z !ǏNS:oWJ aTUHL+AJu7Ku,Ne&:J1{Pl&ʪņaTrAֳRx:"j qA8L+]'4禳:G'>ɡ;~vgB(c^fdGP0"/DxsnG~aϼ0rj!ʓ_~W(FLv޼r͕Μ[h,~k!6C͋/+ 3Og~.\[ZxMUnfݐG P*)F*YRarM97Щ:-<*:Q :ϧQ XSZU*֚^UP Q@B#BM2ˉ Oq OL1q=;tfźh G!hQejIL)0;}cg 2ʻA=$pբOw-tXjIGTiUmd)_t!LH5 .Z%,$֍N4i5e͠}X&7ǣ>ʉgUn=t &iƉG~=w7< @x{6QX\*P>?a]댩4e]@舨ܶKm8sMΝ>|jyj] FtךbkT)F:4QN,A{'lu͘u5r_ hQ,\9f.py*v ®4Lz` er \ª*P,g׎12Ϟ- ZV|fg+[dbQ.Bޝ(3M#:̅wRV.AnFIE*H0Md2.U& V((j q^cCc㑷4=ϝY c&X A epi=ͻR/s;سg7J$+8 Faf2jx3:{y ?ÉXzBՠ4te,.P*=;{N2QJ<9rK5sk4Zi뉋).㑺(d+5%yOYGe.a3$\K{wυΑQj{msNGF4YJ%TUFljhtq'9ubJ\B1G>qROea36i8~/R,Ө\%щMJ=m[r=;GnLZVٶ}Fut']_HTmī_K4RI&9v珱G3q fEj$@$iKq-XE(Ҡ!QtCR@ܡhPmP(%sdD X#ud[6yǔԍ}4Nf(n ǵ'@(H !mlS[<+i\DLa[;k}fU3n4u^#9'sJcuDCui`L\U0=@&6 H;֧ceʳ>_3saK;X^YX12ơM۸Qm#=~V '~}Y* w}W.Oen{py#xvb亮ro/f#pe55X.3;D. FGtk^Qc`vPz:4ZP(]TV4ֺ3Yhfw6˳^a~ O*B]#=öIr'.& "u^aB*Gi9{neh|STyT&&G7 l|N;ŗ+ˍ]z ci q;8= wZ)KϢzJ,>ACiU+09lEv}wݙ6 ϲZzk"e\.+`iӵ+A RQ'64;#zkL$ZF?Isy32ܠEHa2..+yQ[Og"5VuBհ@> 5';+Ju-X㹊\,W[d@kRMJ~]eq')}7lVD\AM*kD}rN WXNE$,{F7Uj'.~I迉GTYuHh%F痪|_3|WrP*\_x *޵)o`071[i+;ܕ3'=|-ۈvд:[B$ڤ~Q,kwrjʺ> mkm;: FiOSiTt7J"~H [X^Z[̃fӍ%F0}ͅk畝I 1(#ۙ1%2n&a.= sWY\#}Fwߺ-$UHGL;!D AJYYiuΟ"'_?|ôL?ӯq%#<ܶHꄱGh[P*\EAGJ'yߪ!|c?k$ْ<739x q]j|L&CXE5.]YD-SY^,\a4vfhy}V#tR>\LtGN;F uF 82J$!:ܽ@[Μݝ$m;:t0lq  R9' ['w004L+(/!h}BJf8?;GXu ƤYl4;3Q{r!)8Z_P"b& M(+Pr@_ %4Ruc/Ne E._0o`Llpq{Am/aVWjfu%JЏk%tq,־h+x[O|^g_1E'2Aosq'j?PE@Ru 5[p`i%_WſʥKuqٽdI$MўkP,Apժd2K0==͎Gq%Qu=xV~JAE֥WP@YIA:ھ ,dS#ݕUUJ9q]Hشe3(x@ RqѴڶMdvW$1Lbތ2PY@ [!An#y+!aHD ƨ\`r O=6 ?s?o#2t;E%|P+DujJ~m/NЄ5֮)Yme,Qx+#b3VIXE$QuwH]X< )-03* HR3xRZ> @>ѹL@\$-).Bz<@p,W-#Zpyl}m[WOS,?՚mSʕB(t p7ݾ7' r2&2:?hM-7^yv{'fWJܾzICXɫx:2YʥtlwcҰj8Vz!UFr}B% s$FG0dY/hOj%rpumy.*B DZQl*" DdRё3׉mrB^B#/215I"C1"Tf"4FVREw4B $ TI!l^XA@4ϥH"esAS m%GY>q/\? 2m,_˗y2q޻!n왷|+Ku[| z{g志?@|O~ E,޸][ S/X"zz۽ܲs;j[F/pqz{{Ϟ}w2=3m{6nxKoyKLQmyNsnc:ה >J3m0fIzDBdY!$ի+6E IDAT9ijk=ЪfH*c:ΟerqD6T;j ;7%Bj@^&T߷`>mFH1ueUذ~=3 3UK߿MSm{nC6U؁fT҆ /n,{X*jd* :Yo~d/Hzj[FƎoJnF_DMe!gd޽Zo})ggy5{ٸi+; reDyFyK n]sP,z2lR1 IZSYj i*kG$R{j&1]7X>ah`|r|)O#Z4j0  !.w- [ ɾvSVQ 1 Y6VX*+8^O!2.'b4=r\[:R!Vlҹvq?BMZle {7/ O1Q];>ظqyv KEoC{: T٫4Sf ldjb{=Eeud٢5iVB$Bmq\AGTld gQA\DQ4bC <Q@EB'L~]XMY q\ EU"t}f:uTQo!h kފB;bQD@"P@kj/i}btNFv qD\$uRI<,ObwӞ3|O>̦4Cm#ۇ?nZ27[ⓟʟo=| D5?;sO~ZrkDdsS:@Q3.Trr% z,DWc7E wi%3-;~oOĹ=z&MШWb&󵥹^b]uxZsro+& f|DR=j[vڻ F/#Z|$< |UL|3=uKiHۮۆZ{LL=!F'l@X\PH'e9=?EOOlf6፼w5 [GTvEi~kzIKMNi0fV~zaq*a]#0`w]7Puݭ2X.33;YJad$]m{Mܼ͛ɾ;Rn`攦7 GouIL du\<_ GTkl6ā]Cn@6FϤ> Q fNVSlot|~r H0_?Gl *ꇡsbUM70=uX*k k z w 6oH6_ƴ-$5FQdVAvqS}?7I.D *b 62)TI .T>]B}FGH50A4?pٸJteU ž]Os7̑U]TGxt嘚yl ːH$A^xn~F4Vݫg؈ * se~g~2p>ϞGtɇT7WmXJth$2[WضN>Csl L[==/$m_2ņW)(b)DXރbҏ}FzQ,R-1殟i9t+earP)1;7K4\0Vo&|! )qBqtr9)l%$tIO+'16:zіlxj1IM z,QJ..:TM&J1zi_V׀1~sQ Ql^| KY02_ar|-P< :,-&1MCQ4|fhR1+~@P9!, ]jE1R@GP}$D\#EDdY!MhHu/16rRK4<338(H!ItY⩚縈bH(h%hm Aq-#y2ضb(>]}SO0yizLf)A4IEbJ @C_ڭGY.#7ʈiK_ 1榯as|ؖwG_.3uYL/=8l FT6b(_z'KWbbkJ/-.wmtt319.Xao14IJiJ$+ԧ?OXex)\HpCCtZ\EkG`M.cL_(Zu:$GeX`--oy_gOk hwvT~S'hظqRDPݢKs,\÷bB^EE,4i8M i.dPPsk螆:ڳ_}ߛȤ4Je2v6mkҖnEªWa.!1@3bHΙw_|C0>+GFORc'G8QzŨ)J\!oG٥\*+"6{15?Z'Or$]FVUly3[7~ gpvu{z2̓oC3'ٸqb ٤y BA$T%,EEn?p'vlgnH0i7x_`Ǟ]]:Ok?t?l.k'cRZeZ #>(>/M:D}=R/w-dCAũU(:Ȋ ]78 dvnD2AGGCc. E`]_nlO :0;bjޠb*XN #"Mphdq >iu|dr :J ַe?s iJ &bH1?mF%㇟ Tjps?Gx5Oz1(9 RJF%e@5d<.l=ľ;0SgxIVs|Ūeh /'5! L&sڟ^CGH_lݶ1Ps^ȋGa-MF)4MPA2]k..?˅oSi}W܅H4!.\/zK6ygx/iFFƜ/~H2Ej H7A`Ϟ m 0ICa$lB~" Y#-bS^SeʯL&"/FL`iasvtuPqN&/>"şcnv#oI64+gv@ci_0mX,c߁g!2fl# KEhx->F@ZS&rut ƞ}\ 6CwKL/U"XЄhmڐ)AT>'hWc|/`]:X-d* ׇihYjVy/\ϒܷ@'O<AT#:u꽋 %<_Ƴ+ '~np`Rm{mJH&"k@ 4KB:c=w~ WF(iRFȏ|#GSRΌR B@5JH0߉dE{9%zӲd56ltgXbdb̰TDELi7asT6~!J9Ϝ?Nb.suI:'6oB{O {VHC2^yvիؖ̽18}2oN&a1 AbCPea"![om6!:6}<ܸ1EײiIb(F ϲ<,M4SvEnVך}T;޶|puuqFOos8a0525=^>2k",,=Km7Ұ\+dRXȦEgD=dㆎV'G^}ClR/"J:`ry""D#HnǵXN:(1][[?H0Dc5TT] l| jۯ.O4]4֏U?Gγ\`V,%h 42JGz1)vE{&ZJr빨zEQ9vuj,ϗ(*l߶'}ra2z`W;m^K8>,$Tc0ҙulp=Fa6X>28 O=i흾v}OIDATʑQ T?]r菎04\z٫z2r~?] b+pX I %1tUڽu83se:08s$g8޿ +%f0:<\(/,;#\3B#[_LG.^gXGgXy3yaiFc_wum][3&Ӭ\/Azqen "bscۻ=Q_̩MNR,>Cog`?KWP!E J}kév4Y̆M6]cրwGRJu)jy5坓'8r->K [^l}6oh~Oyndд5 o.cle7t7xRJPT2GD6y}_]04dMeaYTS)Ď[n*k^,~hl}׀7ޞT2S?|O^'Na ΝK/O}),'_2׌+dI~ l` TMi nѴx,Wo@IM\xe/M*PW={q;ToZk1R 5To2ԧ_kL73;;˽Ml0πle%ӲO>Ɩݷ2r AYS*zb K1Ξ+ nR*5ZPq[ adێ-a[2ڳT$=c9.ZZMA@ SO\Lw{vh;Ebf}tCfӶ^FJ5ܺ; h,8GKdI"NK*,,ƛ1J@$w^M-CPbt&Ʌto%%{zx>f'$E73#\SafL&3o_XaKۙ'hZ)󍧟҅Iա-FΟbv][l' {Ƿ_scbR~^{ѱ)F.OD ]21%F~N4K8E^e9tv@DTPcYUbA[{xWOve+o)fkD>~lN䉣vfTvc12v1D~*i1EOR1'y8AMdb{ t=;M$-wjpr{W5 }2WF|obѳO~$?Z+Qy2YGX6rMSi$˽6=ݶ?zv8 xљ҅kZ>0=J6/fBG/'6?wLOh K+6vJݏs$ *!EB1P7ًbz˪:owb#Bݑ3>R??AWW0X;uwrlE>L+V)*= !hp`K,ͲPRzhuK{v;4JeHgɏ>F۳Bd +O'j5r{srlBSSfADŊKSA<ض랿JUdLg:x ~rdTml]PԠj_WI6 Ū5@ ֹߕ[S׃˺W|_ #}|X,=]=,-Y-}|`wd:bL.E=Ru(4̹9zm~Gnd_^N{ l bZlXq-#}|-[ř9 O3'nW>Fwv6lxko7LRԘeui-Vz!f3?|!.̯+K~wݽgkT[W&4Ԩ[[iXZ|0 Mr?z'Nrg?}ZZ % B<a7XZZZZ<xIENDB`jajuk-1.9.6.orig/src/main/resources/images/included/tray_title.png0000644000175000017500000000614211720500104025126 0ustar drazzibdrazzibPNG  IHDRIbKGD pHYs  tIME;'\tEXtCommentCreated with The GIMPd%n IDATx}l>۱B ޤu*CJ[6!֩2v Z7ieC(tT X4h뺊nT*m/kKUoKiKH{ξs/{3ߧp 'p‰a0 a0,\lsq8<灗QD͘qk"fNISz\p[N8qgT;*C*AVs.p pn^?E T*Q]95U_U@Pm7^N8DD6Do*fd)DDoDJtq8[vw<~_ T+`}hjO_~v 'pԀ(QajQL#dAԞ(E8M πw{L{>Tx y|,"%&q5܁ӗhI9+RS}H À@(5^0j'܃Gchx~=ﺜCJH98'Sс$7&PpFBJd4ș"#C UeIT=ޕHD{xnaA)0ItEh\+ftpҰ wli| jl\{x (8g\Xd9BT ͺw:v= ϟ´ISи%,ooy|k>Cx~6c3A08Ɯz&QOfgA,G(с2Af9%bB2 !T?톛ss2, %GQ\ uZ._B{CU+K:͑'["g>+I JHzR'Rԉ'Ǟ99]_@ͳ\}81(i4*iZ_hfMT Zv#΄2QtvΒA!"fCC7;Їh2hhl宫x?0y+QvRKv=8.y{x 5H2fx'Ujolj;B 1/5Tr .'!6 80@GZG @r{"aGS~N4D r S#>Ǣ茆p%ԉ+tFB8cc4*A 榳dAXIK_<-HjX0jF}Xl(h|ON HHcbÒu[FOƨ '?C <24GKtFi#Ȋ"( bq  џD4G(Ag4茄Y+[!`YVD*> f; sa )!ү~Ѱ ,Љqٹ:q)B Xb\U|aUǨu1Zf/hRdJe !< D#ҍXoD X #\-@R.s8{ =8,ƒseYl ð*?}\Y@lEdXs(XL_y}G&Vc pe5ͺT}ɉN>2d㣟 ! @#EY.(ɒQ%""h뺊H"p,p,p QsŲ"hhG7|X0}6δϻ 剤UT%;)Ys bxǂ]+}YacQ\ܲ19E?dDr;=YT#ŤLvJOv^A$ރHd}JteҾ,~f#ε5ˣ܀hbsc[b7^9+Ly`Yzc6A{87Fmr,)6_'MʅXt\t`4bbšY,b X46v+G!Ufi v"+a?HYe: %kIOo2~eGm46XÕP҇KnB̓s[1܋ `6{0ٽy;"'ӛȈjϮk꺇it/Mߔb/"vSbjË(ȘfAc؁Ux]r P';>:Bpn)#JueߑJtFǑ;NCq;NV V!P$҇IJ,Əƌfm\[|sX="Usct`0AQXG[z4?dM,I1N  D!ɐޢJteCbBu ]AَWG\ wa+[UbY,> 5X1NF˵68G^g[{us7m\bIo$gOaw哎R.QHGN~G|8RCR uM/v`̨b {)B-<f=# W~;2H~' &jRyNR&A5A*2._o-15c!n1p.NK9֛Pn HJ%mh ^p)( 0TMQ؀~c|Y|ɂ" \3IH3-h@Ji32%t˹[F>R"rs0BXx~]VɝNh >91H7IhrY:< j@jT]$%,@a͂db+*ERyPr`@$Ʈ&8:Y)td;1ܬ @jYt~b4# 꾣LV=.H”Rk;Ht4:+XM]c->G ~MBl;RcNhK;r_*p4S2F(DgzX>HRN;uD0iaB+IENDB`jajuk-1.9.6.orig/src/main/resources/images/border2.png0000644000175000017500000010225211720500104022515 0ustar drazzibdrazzibPNG  IHDR@X]wV pHYs  tIME77ntEXtCommentCreated with The GIMPd%n IDATxieuLwzs1tc$)$DQI" dISr;NR4T*ʿ*+ɟq*ӕĩ$V'\$K&I h4z~ϴʏstmPrTr^5ioyB~|wX}ӟ#O}kg~?݌Y?ÃNҟyHs/!;}q!@/x0؈lG$|~o)sFs/\>+O#+P5ps  }1OJ{|d fۛi<l6FXemQG.>nONAנkTU__viNcV Pu<Ɨ^8"MQ:A$d'"tW/<1d xh̔~ z;_%wgl!I@6lϞ)f = P ӏgTB]7T 'rʵ.yD7NSYa#JgV4zW>Snza=fAb Ǔ/0רjT߆g8S<#ȶAk{3W՟"c q̾h? 4"|꧃eM`m("0#d#}|kYBA-Ч@D!bTU ^:{ޝդSOa iF$@ɟ;ӡw5+YD bK| p BH@$@ (UN!I$Q/7ON_LoYB"z6[Z\Og6UeiO]э_B 9!I]a~mPwdQT=hswf aW@@1P.ɝf$ɺC=ǿ|- &a ^9]u M Hb}vG|nW+%ZR#DD QzQ(5g!/8naZX+ԝ{ ZK³'wW>F@$$ ҋPܦ|xSíxE"!3G3 \ 0X+{Ճ}8Y>`ND9Ͻ|CGy%7w{{J :v2Ǔeu yQ{p7~dqHI AHH}t@A9waQ^%7wz"$,;w3d\||߸uPDH  BB$@ D0ؾ?_}ǦSzxEB6u+џ|@I4@7W5+hDHq8~ 5G4ӏH?ޤi?=s}}ZIUDcW݊S'6LZcr'c51mcx詭ߒ_$B |O[a&wzkU-Tʘn^Oo L4@$)F̺q5%̡R .>:_w>q5g@ЫG ?pdc+)MSPOKd[e '/NhwC R"<(eS@:w~'={__x|.yT'a6unkaȫəhޥK򻟄 g4R(@x)}N_fڟPK7O.#wk_{?n&G{{Y~z 4G׳@p/Kvy&=~9?;?<hA)4'jA [0\= @ ~+״Y {X<}]ƻ7ˏŭ*h'DMH9>/{Q &F=P 緡ꝹzwAx, R@ \bgs||P뚵RJk^7en/rcix#@D!` |>_+t}؅ @LawWUɝW~"ҭ>?趶 -]x|aXA4+Ds/H b C7~zloq(@M!5!Hq&d_x2;r #0dmr L~"(?S<$$A,!GܹZg@Fb_/SPTPkƠ5C 5@Ű1ݟk &> }z&E0h!:6vٙS;"@֍qݔ/x Z3y9,Ϲ։zjO-jv D $$HfS 2]#H2&0p u"MR5pQ3z1_ǧ1B"ENPđ. h$XaALp+v9NdXd`gvaku _~G>o>tey e u e BL r6BD   { jTp(80+d` f_$p jC"" Mᰀb v: ]`C˭6?DWȬYװ=Q Cf9<`{~t'.YFJdr`,hD#1Dx8Dn .2Aճ,M?ߥT}L݀ ٹ/[9ĄI8)N3֭`_84΅F8*N߼;GMM?z() [Ԭc.ʪ<,BD1!fshvB C0"1_b9`gCf I Ioz^PcFJ%d8F'd`6Ih,O0{zq|Z~nnsRA@syz]O3@wBH$HoMق] Wtgl\3F{47>;GyƐk8@YòA1D_J7><D s;×`q _=)2vͿĕOdAYL-{ET,WaVҰTyB}a_Qr|N& `+}tϽ4s8)'X"5(zx9BcF}f7PJm9y0ϡf2) _|鍓W_>BGGҮRsxFn,ٵk,s$R p3(ɧz0 sl72M_PE}߳ 4Ҏ!_¯kwioByYʯ=4Kge$pfōɵGd#\ 8pkۄ@UU <Ν%pq!?~n]{t'Xd;s2*gA_:Iv2ܕ!E1y,`[:}2U͜%hxi9U7n̖73b:}GV6kՃgX&xc'mP!MǫSo36ǢgA$k3+崜bI XJj:.N'z!,oA2F$ZsR+wߋ[p7nɤƾf`2{Ͼ> ~^Z*RׅK`F'2l ㌢hVm`֬{JѶL(#DL$]y ͅ0NE` V 9m3VƩػ?sy}sB'I>_ȣzXk5D$M9Hv?g ;ņaRSBbJo4zq;Ppz$X ݏ#5uD0~?#M * &1<1gu4 =@~o_1_ /7M-M׸`Qcț0>$7PֺلEfFD߀V8&?lcfn)qpzAmnqЦ!0t-*[;t `{ 221xhQDc|j 6-h@8{G-CM^Xʡ<Ǧ'-Ƹ Kt Bk2cbo0_l?i׮=`sraٱhBBfdFZ!;,%걗1ddHj;c^#6b@NۄCpGp(\-a1 0u$ b177qG ﷼>pEtޏÑoxя7] ­ÙF6A0N/sB/B'?DOi' ǀ;+IЄK$0*w`VF. 't|wÄ@$ydHYvl] o/A{1ߌ "fN|rci5R2\d_6Sږ 1%asuw@d\5Zٟ[67+v?loys7.iVu$؃1Y d\90L6[Lm|O @ 6_dƹ]J.` 䮻C]wEyzd}dojxBe\Pz;?wٻ0MA-Q/aǸ}OGD26zeO+|ss~/U"ui}vLK=ɱ*[_f#˾Š,Bج*ћ]ɐFA `1~A[@-ML2xTm0#n4-ےYz{Vț(fp50wH~ ZhBawGפ7Ђ gs;o#s8Üs'&`C "#GmJ]}wCPtyhES]%tJ90؏[0L.a)eS>a';1sa: ӣ2Ƴj454ݪ6|@tWrp0ؼwrTMT>q$OdjEao\sd ya)#{xàBKkM`PHz~j#4ulB]rf=6v gYs>>|lvAkzYd#!`cc~̥O9k'hcRĠBCj?qq%^e6Dk7=fS XpВXQբsցI=|fT힮["戮TމZ tXsfiY&el,+{lJ ~r]l5b~rrR%!@"$ FCƚ"7@xٛ8^) L{fQqssT-R$fUUd 5Y"%˨[ ߜXN pVVX ]ތ'I5;BX.bfZ3I ãt:"r&[1I f\F=$u9ĄH8R/_Bd&ie<99qf<4I҈OX+$be`y[maKu]Ir![Ɠ1 f AD<4`8Gzhփ,9`=Y;qa&0s8I'' 8IJ1'6"MR FQ'QQ,0˲㣣4I$}up m4e+MY4 9sa#kٛN|y4M21⽽=XPZ !ZFf qMݝa52lEm)b9Hdiq̜ep4LLq1몪,KT`jfA޺qSҪtEhk+ƓrP.S3,4Ӟ`P0kØqEgYxAZ+M4k0lMTrxdF@DE ZkX%s+""tta/V>'Z.53+֒D`?d(Mxd~l(F^JxD(n1ܲ7uu$Νk] @@j@M0sl06>|ri_aо $P3mNQLш _ ͖>K\y&=P3JY$DԆ;jw2[l&X S&G;,6ZͳJj.-5Ǻ̆34hBAB"HsЋ٢hFgy\ I=0 xt0vVl|Aze#a@ư9FF(Z5syNB>|͑ "QČ5m"`mnGk3޵´v}*gPfIDDd"! k FA^Ջs6{eNEb[ —EeF@.BژvRMZuE-Bત440qa\5ѽ B_G<&/)]^wvwwBH!*t| cK;h1!g8\8~fz:=T"&YmT!JG"c"9m(!J%y fnL}n 9N."[SXϸJtOq%Dw',favOR vhlKTg IDATdac3:)m䢟H_hPYgԨj$< "rx%gcEzym*֏YI{.>C`<:-#:j9QsZC2 zRo쥾M;~+t_\rX`ou9N9Hմ92tI:4},A؛|B͒Os&UZˏ!ʼnCDIj 0꼣`TƵ of2mҦ KCD3-=%(@n]mŮ<0[Po:l9;7zgxcYccYċ ; h(ڤHXjJ9ЩqtN\S>+Mf tqn9˂2 V+-myw">{kϿƫo"Z}O?|' kQaXOOb(ٯC ;6aUB~zftT`GuJt>ov EEվ&/tQmGߺs;bK.Pr-1|9Wn}8=Nɼ̫xV!Y-jf2&WN#p+h?*>unq|=s7~c-QNj?th`wgh;',:8f.+gw=;ރF]蔸1i$V򵗦 йiZcxɲw쥱x͓[$၀ ~?zD`'֧l"J._Gbd&O>d,k7Oy,Dʺeub8G/w_iG̖ضqAc闡ى7ylw 'L$Q D!$iȗu3SDPdVnMOgҌA󇮀@?sm|D8Mmc2moƩV4ݖB) ;SOOcGO,,KrO+o'Vd$%h DU/_Ћlgl <);d&dVuݲg@7&Ci"9se+yu:p\NVRĂm+1*J!-#J1-dKeqr\P+sdQRZ j"4_?w?F%(oIڨ!e2JTySf#=朠UCw62q fd@\P?ʂ)'ZL }0nNaW)E^aGi'DƋ@3 8P-|C^ҁR B6Q~ǰf RXBCL/*f}RO[`ċy H#W:عn"Ѯ|ʶ"f Zo 2;]fRGp9OՂm5:;:C$?PT}aD@DD*l$-ECՃn&&6nvy!/Z,9Q@(c $FZ&ZMkhWNoc.p_}k!^֯SHT*|aouͷ^\8#DIhW$b8"1!,%aMZjjPd(a|~z%M YOS*1? omfTT4Y$HDBHAI4QHn$ȐE"E&ETRs GrJ%箜ˢތ%1g?<Jtrtw͔C"N|9l ˨׼]_?$Ƃ**2-̀(AX+=k~eAL\[l&6mN??K_yO]zph^*4HGDM~{kͺRݝͧ;[HzS!}5wC^i&z5BFxy9u{<~fgd:iDHA<Ȣw˃ًe\A]2+4؈FEh`X!>3}ޙA7FoV+ cK-T]('o+%los4ΧE|v6޵Kcv4I+z'T؃I݋l6޻"TՕjq$KIӯO+!uVL&?!h atm;oǀZ WoVky|6ed-d0g,/K귴X@/0.Y4a`P؈J6 aax-mdΑB|'kZJֆؕ`_aъTؐٗ~@η&wkj{JzI14z+]pxMaz -Q%k!p``4|Zn}#gK BRQBD9P`.Þ  5V_2X,~U;aΔ-&)* UekC0X6~/ۃ>籄1@ݻH+j|BEe^тA_{0 $ Rblq}Ƿ1L%02:Ȭғ8) :BҬ" ,"עc}q #lNDh?`.DG>"2/h8gEYb$u,,TeP,tQ63V1\ᶾUkkVt7^lX.-`=Xܽ5{YE5҄GQEJ)*Ip%QIg#:^:,TJT>i|zrx{4Lg;w0"őHHaT7IAWF;akﺖ.DSGexꟌe~_FҮ𭛷ʲt[˲7WAA)%`UmRɪZ'SJY=5 E:K谆p1_zSH;^ qHk8UEUea|"ݗNܭaھ4LO ӼqVY~&[7ۭUK/yy8(K)QWk_C.$i Od1r肂5ˆȀ":ׇ$N,݃˗FC{b֍9&|EZZ\x \lOʐ!|⚗9}ѸZu])&g._ټ* Zk!~y ;UUHMG~ Ji\k^ч%tڵq~eq=#>BDLܾZY`4kAV[PZi` m;3?FaON:?ޒ|:ׅ6H$HEkoTU\,p4hyUw̽{v"ID֦zeBkEìyƕp!m@8ZGQ歭-IQ+{%eÃò(X)4722NEQIT$)y4= Nqب2@"A$HkpzrRi(ronlJim$qϪ(Ibw9f9S{,5YihcR$k!۷&AQ 7p23kК|rw&I)deޚHh7G6b'(DAf"BEyu]GQtڛƨt&e୭JʢDQZkre`Gl/)vs^lՌ>j^AG꺮kȲ"BT]DqSuYu]DHiu]eQX{hl~ ~W&%eYu4$#F{j1?JJmnm4b@XP|FQYqIÍ"eamyCI{;RlS =mhD &$I5K)͒`xz:JU=88 4IwϜ92ϗiJ!^,5 aj ,:̀gFq%z`/ZDNmQ-d Z )eZקHʺY3g-U3!^Ɔfu@jqHy hc:if[-IZݾ}DeUe$ H4Y*I‹̶~6-^#eac&mlmC V2s.lmmEꫯ2t:ka3"/:@B"@C!|c+Yca GQ 4WK+"c @inll\xիUY{wxL2?YD zwuFKu/uRGG ]7M8ͲI2돆aYs!D\(Z,e/+f$$#pO mpm Kk>]DB1Q*TAڜJ]1 )cI뤩:Jaa{sm"A,b]k Z諽.h&;|ڵ϶28F[`>v+4ïNx-턫IAînNxؤ =m[͓FN35{ Ga|axʖe/]ʩ ypF1J>eؽs@lGtocUnzF3ŽB?MJ;LO KK4 yV}PVs/n7VٱaB"ծx#Hp GCjr'GIМjL?s N46Qܡ (w\Guhɰ16O5z)8Wzt7\n$]}\s04ݰ s0* 5WW(蔡G>+"1̴@Ұآf%<5w2U  ಲ".u6UҟY]ry .6v"I>׫ 85_-mm ;mG87Z1AGId^jOA/Y!މQQߌ+D\@"_ؔ!vF&Fi,Ҵ'$7aNTӨgq,<,Җ3y% af4~ W/&ra{1eY_a7]Y\&ea?>3gi8ԱhE2!^ÎP"}]A5!N`rV'xƦq$5IM'. ^#rZ-n&);a"GǐIeVvZ/ AGz< L߆qLC$u:Pkh!ڏxFeWZr95V5,H GÁ3K; O; 1+j~8Ql6ZI"r<//"NNc/a璉x] s\T~(dZ2"$2u҈@R4Iif ?d'k=pMx%q% md[q]i4ΕeJ'P75a/8(T"Z#!ae>ib70'rJSuhxSOq_`;5|> BU=M[bf}SuH2co&,1::$'VxiҘ]? w=4k518Ǟ.|r%"?6PP侫<::^e%oogm]$t;r,.y}xo6 IDATks+e.Ӿʪ8=Z 3_5BŠ)]+AI[Ka%W̠V }t ;YQ#Gm;&x<(PDDgv2>aƃb;[KK(ʄuM0"[\nFH.r2̦ d 5 )(bBw#ڴ w귣~]na)Z|z ||zZ3<]1|1ێN)%ǁ3Hlwl?JszSG[+daUמ\W2uc^PF15:HO!BЬpWo};+.۟pyʪf'58?6]@UՔ0c:! x!ˠkZ sh=;ʇv)邊hegb6 px   :C{|)v"Ed\wN64 Dq Q·Y<ޯ*rzooo6޺}TͶƫ=9V^(-G PPkY1 vHjEonnѱfdur4'8z{weJeya?|b͑E͝-)R,d:l:a)2% ᮧI#;V=HOWĐ^>Xeohkɉy0HӭRu]O&!sgrZYs/I`P rN"813,,oA]!j#vvXH!vvwX33UUlmmu=֞-\+4(Q(y(Xbj2Lg ^}bcV1#$P' qjlt4bԼP@+fA0>R[wC2{DC{/7@g:Lʙ:K3Ey8hQm\7 *ݒz3+q>1Uұޓkǥs˲*+_d2hBJ!TfVܑ:Q_˒Sɯ~} " ТK| iӄX8;Rlo?sԦ9tZ};$a%%) ֦!2e9>=nj2Y"ʲlcc$hލd\2"; BQ]W!WN'Yh|z<(vvVUUXT8Fq>bEr̅b8Mz!w =\R1vzNCY]ץ?QAL+%醊d Q$mۖ$Ǒ #RYU==3Z֓2=]U78z w=zٴTWfIp?~.S@hee 9˲,4qY=)̜El#QX -uPkyo3tI ⺮B-$]O 4TEPɵg2S%ưEc;b5g]J+1/M,kCZ * XYsxx.3Nop^a0 Od^ʕ!{].[cSЊ3R5,NPQ("=|Xd^^>1ߞdn(P5_:I鋱):㒦9(Έ[Otv:nuICz~^ɤ ~B]B%hJVJmaQ@5"%x\a79mTt-u# JBH+|nOOv~~La۷?H)XHׯq 17D!VajOͮ_J|]Oӷ$pbXOB$k1 B4ČגMP4ţ^)a ,s|14 A9tz}@0"PavAPڥfr=ʲӴ4aY 0o߾nׯ-RLC 1˷;Cb0 D H;4\NIը̪Ύ\6-8"0%ZZ F!B@ 1\Ny=_@3=u'(Ũ5Ͻ|XxT~6YWiI cDF+jaO*M̄}jKh`&0ay;xP}*ˢϖJ,@%D-))T bA&E ofvV JR{:2 GSV:b&ߺ5AԨR~(/M خ&DTN )M7RzC)Wb8޽'eXL@6ZUއ'XЌ; 3ɪ"Yl)]Þ (vP[~3Jr˭V ƞ@TR0KRÃ.e@UMO\~NSfvCyʹ WA=&6ʵaܭJ*9|0LݴTvWjE7^ V'hhS"Pc*IG +[1||,xeUW`5"F2iGtRzB3Y4աҪg9-LQ!p0 mZnξ̖i4\D2e>mSGnK)q8p<9/!D8ܮ4gRX2>6V%tkUM6 U^w!KJzv0>i"KN@m߶v!'Zz1z=< 2MS2 ZvVKNiXqFXS[yɘqxHr92Iiy 9OO! z'q=ZƔC .8銨l xx1QrJx|!A˲L~M9g8Ðy9O} qH)01ik56t,JnV $3e~8 !p86m t:N_Oow"i_HkX%眃L'j!Q؈ rCR.A-Ç_3|?5E1(vV_Oo9CFH~V94ϗ) 4$nKșW?!pAY.~R<&퉍h<FX;,a6 AB!g^Øߏa^9Ǘtϼ21yn+8yd ]C !UA)0^" "umq~oyx|8}^CHcH㮧_dXօZTW模ШYPKAAPC1`#8iH|]8 R 1B2eDY3][`ZH;*A؝r=$tz;/mbt!čQ6`:hO-H"SQl蘨g$߯z۶P춈ix0_F1 I| F!@ 6_j-t>o^-J:!MHr<C@WN#D.Za^A{;CH+ žkHu7$!MvsbBB f8Pfٸ.kmVRi AJ$J1,hg6"8h <<k"S£մFt'i:-G`q섏[e6Nګm*] Tj&Q"3_~K|zE@(fq̸産72RSuZPEzz_3 Y48~aK'F)U5DpI[;J{=NC:ttyM06­~f:SsiD]fD>ߙȤƬx8^Ã;nJb*ozGvID"on[(_z@y2y1RtEK۶lF(\$g^ǰB|g0/~>2W|yKev>fpG\\Pm$^TJçy^~/_(3dRױr a+²NNU'ڵsZZYߏe_?iX<Ϲn?|< ?5 "0Ǖ"}Zv]5Kyep[BlKA|v81}]93"L bӦb`zr;,Kˠ"d̓jLW 1qv><X*~!v\Ωy璒 6'^Ҳ,8[ QsdKƐRqU $>|,__߾#&XؓpiSRr/ϲ>m9,!.s3pycw_&zM? []_W^_yD6UWȜр 8+G -0m!qd4uaH!ᘞ>?,z yY:apub ʩh`cRX$~y4M߾KMCMĭ8|?{V60, ñ)zç8.׻\c;)1F0[z`HZF‡(@mE(&C}`fRǗχADq^ zʿ+%7gJ@y !U IP=p:#lHe٘hl_G81!/?}zREHX*eKB ׎5% B"#7bװ'.M'Z4LT1)2= C2)y ")GpHifR"BFdA C@}:g洵FFѶ5 hBt~(f D,nZ7I5)pRg唵v>zħEtV"\iKө:8 v`>< i'lR.!"$\fVXdYer>f w1 "g~4TEWy>ƀ@H! sf\/0¦%$ 2h4BE(`Qu LLEw0/Ox`3G}x+39DaN8OdUXܩ18 -B%5!iEzф5#I!XG!'J^%W",$BL!fb:`:7 TMb@m3IPe^r^c[B/9) xOzY q$b/(LVߴ mˇqH!u҉PyNs^._eqؖ"/v5y IDATk3MoGRf.Rٺ %ħ˷_ҰfF*+y|yn3qxcJZ.MeL}K 8>s~o~0 e" HC?X#ЍߺVVx Oߺmɏ>[EBヌ G(5YYp%GmVt$.8. 0Y}xyjeh3gpm)mǫę*uuJ17ط;qJmlSrbg3ke3%ݎd"|W0g01KE B(^ҾzvJVfheXC˫R"Ka9R4IudU;`"Mqf0}lHV5Wgk,r!Zݙ!Zs5B}tt:z4ݺaHmT\0!Q1]Hqڀl^$?"t@I$._beE({ 4CS)ec,J~ݚ IWRhԼiN5[oI}=_{>n˓RFס:X Ƃn ]X`Sx奥0o0_+n+#s0`bV]-!h^e TgV&9.a:Nӻ,)%S9hik7X{bT̾m4H^0 @+]Îyl\KarpXC4{E?=WX۪/Nel)Á°VoIž=fn_ϟ>ǘHa`k^ h0?닣P)VW2@Kȷp&ծB՗*_hYk:Ov Gi81e^yfG?k 9+ny%<=???yY=>01  {݉1{`ܭ4JMƼv9?|-\9 Aem0)p^%%lUilEC+p3 ~8|o_yHFpe:[<<>>Boׯ9cJO:0ͱ뼜 8Jb݇\J3}nCJC_Oo`1x8""z"<¶l֓tZBBL헗Nh|YqA=!כV iP[3)iNK^d0*̘ |>߮71'! ZP,Y7NM=ER帄1h{H(mbq&%\Hɔv.2Y(\ >dk1-}P|a5 ͆|L-9BFX| Mhֻ^b ư4S;vZJJu{q0azUoP 0`URH}fP8t`ZvyĬ>4eXLJnV+USAO%&m3+y̵o pYK 1Фw踍6LJӣZi@VJm%F g<ڪawH6vtZUIv։LnS`Ԏ p_ [?pa9a ЊXE^ `kF-ۘM9(aÕ0 ̽~>`v#^l iRPS(M؁T, 5`N=ĸШL@ؘn!`_ G:KtÚe uUpic s 6@T9Ci)m~TeSW * ؔ % '3vyȨƨRqzg|`EcubΆcz*i/P#-ɦ3H0ʟ): 4Ӟ nOsgaZmW܀" +V@l9"V3 `h{DŰ^&')w+[(ئ"~G4%l}eX3&`jN4e-\g^+CKKkEufj$L?6"avPa&9oxb:RG3Ԡarɘ/ q?] t܉0?lMji=G0禯_ u-2J 34h gcvIzڈ8 aXZBIć,9ѧH(.Dl'lPj5yS5M AAj3|K@}]P&&ACf #yn#Ңe;h [?@ɐE鞆5l|b%VZRfwZ$gu'ݝZ϶raYTt~ƨV4D Ӥ#Ri۶" J5h1AaQZU_yt]qn.c;6)Tyftp8Q]Wt}XUEvѻ" aN!Zhgi'ÕMvBd?-'k1뱦6~v%WMұ=ҞhgևZ @{Y i‹ĺ^ZaP6\x# ~hUK(HHhź e YgǠl n ,>Q=ō`oj(l^Le} A5w:'6ǚ=1i 6zT׍ )ѐ+qa\~zUyޝ;Fc7nc `,ܯabUV7hOѷs-+ nm _G46[kQb$^i [縴VYjM|I3QbsWnH4rGQFQwo='%(-Mtj6:2xƁ0nNat^YxhάǷ_uv6vAON윊h&ۦͅZFkIlZ>c+&єo/{'-.m٭Cn".v>Ӟhsw4{xNfם 9Q-ӎ\H.w|.nV-M>;/nAv/2?/N ˂i8fv#Ɋ!?L?srbNhkme ~ ѮC7wҲ$Zz-\{ڢ/1\ r=kXV Nxf+M{nh#b[B.d)aA֊X86{۳?[ib(Y\O`^9mz%[L.b<^T"-:>}^}DKsl.6Y oIojt@s|v٘B4N}b7VhiX+r; 3@N<<6+Z}x}M#ojS ؐl!TCw4ஃm@M[-9m/m{FV1rvFxX[/zo2BkE7){qBߡm͔И\z߭N jlLBqVd`ܫQm`W6(X_*bߨ1A ;kةזSb^()/_}M~xΞ);f՞XTnvKGmt3@ߨzxi')-S+&HߡTFok/jֺ/WΛi|z?{Hǥ켞[:x?͟]޶ݏ;8;${wbwd| ME ޷Q~Ѓ8;bmČ७|l`N XF۳]QJ].e:ػ?bX&PsP͡r:]Sz,#5CGd8q9= >4J?k_9&렣:|0h]+1b[:JnM/g=lO;S=X,2O b9i󍫦G:+ͥQ5K'ӏ;:NoNW5" j曐jƂwXqBGt="{Mffgs所ewTu6GCz!yz$wQ+X`rUL`{806W;}?Z,ͤ]w9 *VeGKrh&S6L|P̘{ # =z`S6ʨ)`rnH2+!4}Җsn%PyfV[!U"1& HA|GA!kAiB+b'F+ MPO=˖TOdl+DnOd=ln]qG8i0׀<yC*GI; ap}{!Q#,F`YHl`DN[9qg3xfWPMdszܮ6*;s$(8Bj B73^ ڒ{B6t5oCh7x~]%=jb,E^VҮNRj{[8IAʭ<3xE4\!^bԨ*hW٣"@s Kt@+A DZ'S&]Mce-)k{ƁHFzO6"xtb Z񮈴Av ~dJ? &l\WE5(L5M-==~bHFL#' 4PA?Lg }UPS(tRMg< s-?aGQz<W}wT ynC1 6-34 {@f,#Ӷ9.FT.";ݍujUvم),{! _T@ՊuƔh$^&!{gtBϼ)\j{1}+Z%mni+~@r9ufAQtW qˠ eK(L3)dqQA9YWtXYfE

[S_m5VMRCME'{# MG{6Lp[ )5Ojwho7vINMDШtVkg /Fy%Fh Fcj.vhH؀͆34>h%kڸ9:i !#mUDD }x<l:ו0,&خ:0Jc鵘G<ݱHkwV]`ɂr'+@$abK& љA\lW>) :*ԥsAkHC'1[i8Ԍ⮴ա`׭BKx39_ KI6-&X f; qhN8[Nh麂 ݲY5 C߻m0>]+xWi>8xoҳwnѡem6op l0gakQ09[X7uH۩7O@&t2vQrn w/-Y^t=M[o[Q;Xq*DG%T o <̨,r)9$>XF=72N)mb-MMn:pXx!MZl`) q[boaާ)BaFmk %i~a+5 *FZ'*gKX9w[I7`nCaGi0mZQ=,bƺDO8N¥i9ʢO+{ݚ4 e_0 [9oZ@E[QUB]3쩳e)KxY{u~ݡ%请,ݾhGJ]bZgZnBG&>[^-J%Riְexun Q@(ΰ,hS rCK =YM*tc"iluy}=8#kIDATfɀENnE J5F3&̱G[QBmו%:GRr$Jt,Cb6ϣuseUzL-[@!|nM]YѱjmPaΎcM=jUЌBC'B}AzԢqSޠ8*)k 5jcR5ñܵ`0|ШYkQIurhœYkʬe n<*QRGVΊ<`jJx!KL1( `IeJQv)V*$xZ6V%H{ζD0ߕs Hm>k-l /;[ |N4 uXֲkkL+7r?`v͙{2hcK5gNcY9;nġjhCK76o]K&Ƽ9lFfw}6ÕgYsDH'67qSP.6z6ޱ_9 {zҬzA?mД-N5½bnkH]ʮ,dOgn\s  7H@\#J>ąD>"ꙩ,4*:Դ~߰)w {=).U.^=6eܭ1 ^цR@e\Pۈ߉A;;5z8Ew#eǷswg1*A!R >VxeE!Yp݃ ȇ?fDB> qmT_|eogX"-NϽu$IoLRzW:[XXBP?ɇ?s ?[fc3#ǻ]u|K7 0% vaExwy T|.xRu"Fb@ގyzlh ß/~ó5j/k/`둫=Х}US0 ]@WWvn\~Z_* [7 gȈ(AD;z};nd#l]D)7 d *@_/o.?Dv}RTOoPdd3̞)&= Aklh2;t DSt&󠋵ߗW}D.8FTʭid4f׳=~ l7OO>OT*VKX P~_>Cl~{?~Ya>f{3P|?l,gfގ" 5Yҧ[t%1sBLt1;B㗢rK[^7ȻvPEo Q>7lJ w52LBcwN@J DZ d~ {CON_Lo뢘UB'niٴVV lrt}J@-b0 #c-{>=GwoN2B9F;~uwfBaWSW@ bq*& @*29,E<So)}y[_<1*kB@Pw1UG ?ZߔBdogR7TD!%@Tտ "^|wd8J.]p0(sK{xA_@z gJ!@]PL]7+!8}p|SקknP@Y"i}p/~8wNwrD]LxlwDɍ1ΐV Ź?{ BP @B5C Q@ TvQ^^6;E@n`H&Of V~%]x?pA@>ʮ(!u7{OL _v[͋qSHXƭD>h K@W5+hD* ~q8~ Q zzŢ|G64\Э9-V:cnE)bކ \ nӓ&_aw<Ãܼ-#?t滶3H@!P֏7g_{7wkPb1ׯX/|} ZY3ڎ[ H}*l>J 6@ ˏӷ~~?{ !@W7G%vPM79ҿrϝT"`Ȇ-K@z(9w1xn`2dxr9Z|,R=9L;˯|lY~_'o?xGϟw?ιr>>.SAg<"؃VAhTʕO¥= C5,r0>^Ǥfp wzۧpub p^{k_  ;ͦ}f0;<4p+Ffz9-~1|{ } 65d G z `zs H BK$ݷz芌?HⱭvgzϾ8?)c vېqB#?O?Ffp<C0&nކsu/oy觀Kzչ|ddȘZkh7<6ThojVc݋ ni#ރk;pn){zz{Ͽ_q'W]g8HAn`"YgS(2H9Sa}xaa\B0 P+=O"Xd 2{p=JCU2x~?J0+@*P q\f| P'% *p xK, վ6 6@ V "EgEp0; (H{Q`sH$B@ Hl Xfpvi r>0re 2l ` ԣr }NG$+΀B !`C, ^@$Ch!0C  Yf[{եHk3م:>ഀ<0:4n%@|Bx8?{NwoWV^ 3vQlDiS(bo;Y'hِG. A6|X}i#0h a8- ϐĐD++{ݏ j3jP@>#d>5 9!hdQGB=pRr6H'g__U%'dR]Y@tYan $py$@EvɷN^`پn]Pt͗vm&~O _sx43ysIx vTo AD0ا%'`_Y1;BӏW.hzl5y^qi/KF{2@$:[εs~_1g0"ģ;qpx5s6ks:Գ-D¿~r"mtӓx0@>Sb^N,T҉z`+ꍄx$c\quQ{d`3ăMn ]f6U,+c) ],u>rS@B8QqWv*(A)U 2LJHf2RU(؀=,dYKrQ첰Hkh.ƩSo\!ǐm֪8Wz{W`7ZI|!FpkHM)HͶ?D3D-")Q թeC@VM߆+L-X`ihQFFa_ȅfӳܝEet:$ǿLim<sZ@Q\4@ . w/oD%9uQcț>$"K[gk\‚v7x2TfQ<"ڑ0 5EF<]C[U`آkx ]C$CxWhn1uLD~?5 t.yac)"G M#c0/ ?:u G%4B#PmDnmBOuk_g=r/=d!$B@"ǢQXƒ $CV1P#." @N4 ~k;6>BM@^] Wc9#%{ڻ%%ŷ 蒻 WL#A @o1pD0xaͿd)f[#Ȍw,ƩP]qQ؝p)(i-TF6eVԞ$v=` ٛ*W/a ǨyOOD69b:~K]~=ݽOЬj\1 -l 6B\j|;h,q+A p "ㅐ]U7!)vA `1 /ZP c~6;"SD%J f|qݕB%WKΊ`E.ۿ0B $Iojsy-KH]0CJk ؐA$?Rh9@"P8j1tihxơ)诒:E89BL KpJɖOq \X6dAp0_(A]CӮlb!|A]-r'y"QP+w#K/l['E J7J}Q>-̆Gh+l-݄]svFf%yݮLիQ~džM5hL/lbHdĚ{))' S}uD̍6N -4惈g_*L9lzBC=b@{VBKBkEW9'ٶL3QȤjtؔY/UTN4*GU*=gEhSֲ¥Ϧч71EX/u&`szƤTsK&i#(E`>; d*Ghw;?ƛ f/ /n 2J@LEF)6ơ9HZ| oarž&7ul1 f1JȘB~S 8u yߣ{kViF$tζ( Ί5F>"1AeĔcifՐq@DQ׀ DGȂf' ,tO;m}[/8$^cT#wY_,槧EQD!Q A c#GT5E7@x8^E@ffSQsST.R3(tUΛϧx{{,KJ𕨅T|jQ jv, nXїc[@5#–O8y@@0t!g1٢(K/#C(UWTlNpYq*Bb 1$tr%*K:>~0dd:R>A@ܹsq; 4I4d^7*(W!^˖*Wj+1(D!Oa%eDu Qe1Ls{JE,͍8~Ix$kX{iWڴRf]%B.|qpDUY!cȘ$I+t: JX 1dzMXbZ M:QsHߏ"DXk}t<IvR v;8==q;7ONNz~$ZD%rl4 beXY|cpTyW`K* UUIr%;wƓ1 !cRAD̐`8*c!$g.'Q+.lqؔ;6}N br2DX(%d:6P JI ǧgQIy*Ykv:Ν;>>:9>JDWj^7mSJ.QԔ"nBLǔD t>>9OfDj2:`8H;M4QDdʲt:I*!ɘi b4 )޺u[6Ejr"cw8(BNS{ADh# 0dzM4!TәH2yb9Biư" )\V,De:PP%]nͽ'J) i2J(`?$Q6ad |@^+\ w 2DO٬Lq]BNg$Ir…իUH #zמe;t7d^3R#C` TBD$1r:onac-F#|!,449O3(RMBf2P3aSP/ B&h$P_aVb=Ve] tإ87ِ֕gBX @ )(Q 2A/" _!m0rHvI<Lͬ(U/j]h< FB@a}Pj>bNrB=~AsT=(DD c# nOk354vyT-*KK(ݤ ""`& !,X4^0ZD4Nwk\ʞN(> EF@*Tƚfu@TU)WI40qaV.bM/5Bp1-}Ϩh%\J*˲(˳ [a |bC-9WQxR!ɸ3.g6Qr 'P6T&4Q yRx]NHY0;:_K)M9$HQ+pa!=p\ .GYRIr4" uڱ [ IDAThl}'^]rgy鋂4|T^ K|Ff@ "'(9[ &t*!kSPѸ!9?f%-ϔ]8!O$F%DO-^d^LX B+%VC넚TM#CCaQ BlQ%%KMU:ˏ!ŋCDMِjY 20*Z7&iBֈ%C!E|LKȍ.ؖgq`z&IT!>̱G&3-^16JxȠرEJ8^2K7@t5o" 77qrT;s2 N+M]y@pf9[ΧY"Ai H C༖2=m;7+tTH *'b2n7؍@IZ(E~z 9dkk{^=`IEjM/% g A$fQ)&XdThܤĉ\)+$V lH6t$ tYdԑ{tp8ש*nHtwo`EV:L}7#"(5)xt9GrWe{I&A$@_{ww޾s'wƥia<7V8p.lh\ND.PJ KXOu: )ˢԺ2FkJ8XEQDTZZJWeUv:˗gw ?SA.(yXvA]h <5pvt3ĹsEQVe*]UZ"Jb@W(H .dYi|:ӻ*:@@`uPș8#-ܬtE&Pc]U(D'0R;.^LVAhsW9zpYq|:]U*PYIyQTR18Nz /aQ:%Ha R.(Vxa+c Tv Uģ'4RkP`e Za`x|tSfQ Y||*FGD坕҅+`/Bbu ?~5H\.,CDu}te|BC](ʪԕArv ]ⵘJ-6.6cSCӉ"TTz]G8RI"ƁoM<ϵR9,?ù6GmaڌNWpؗ(శj2YـBTeүR \g n+p /fn: ĪFn5k1ZWZ*1d\kaj3+(1!Gh9*tzZ9JDFb5.߿vwk.*OgVѨQTEl\}$Ñ\ ?9BưV"0Z|4Zex!"ËQjȓcɫ`ÓB|h&5~6o.`;6Bȴk 5 \e)ݗ$Ƙ&7\^jXgm`!G!#CC~T: C#X'Wr`0t:ȪI TOw8lHJ_T=h@B@ҍ HԢ|UZe -lɆ WuU4QK,춦xVbobl݂qFCh|Ma@$)5$AI4']DU_KJǑWG(@f] :5Y9q[u|eG @"ayNl96b=S?]шOR*rUB…->M ,4 CCF)$i۬&^(ܹRy19]6wvA+kԢUɨ(zqlmt;<|דB4RJ !eׇd9BV+xm ?83^cLhGDIgy{y^UqUY.ywJl Vh " DI66N18닎"G?w[Ir$d#pvG\Ufsk~< 4-˪> .^Q-K]xZ 2sw|30]UΔ tG!h{Ϻ^;:"*BD 4ס dm'j֡]߈hSiC>*TH"x `=G{&>O QKġQk%ۨ5n 'U KB 2iQClrY9Wc,a ,u yE 'T /c⊍€ƀ  (45au؀mfA^އJan9U0-*"(s*Ba$B Դ5Y |#lNB^498>"tHr xa.<^'/ $IUi*((;/L4ZǞ!K^DP*kcH|*/9Ao{%Xb1fzڄ=Xܻ3vjc(BFGQEZk1V*&)˴b(֊P1dkKD4BEfU6yMOl_Yq(Jz($I#0#) AAآ>ʺ *V^u{=)wn)ʥw- CRJ(Hd j.ӆub bv~uf2^{nꫯgBdiG.,.UsIفb60P inիv;]ɖvvw*]Y|LR uQIr!I.kPFH- :etM&2hc1h !4Uea)*Naӫ1AF=PE+ɗcbPQU8ͦ?0ߺurr-")߽KƤNb4RYf*Q*Ӑh?(WF;B,!22B*2Ɛ3Uo$k[},ly@ Q x4;;;2R'!0MhtׯEe˲*x̘2;]VBDB*@h"iwl .A_\a#[/D Sf9t4v:W]|*IҲ,j/zȎE$TB1R8WYi7j(A^L⪎DfгA(ʪ,˪%̖T*˲";BD'B6Z-xT{M">"*7x0/L!M&ll lIn?),$T*BJE 9DBdqgAUB" QeRlTQX.J/JZD(d }0+mpm Kk WQ \.cwF9њ2T R>oe$B*UD ]b ~FRC)@Rc@~ }%,7z^Ex辪]+qњIq$#aBv1zj%{RۯZNHiuwk8o057\ی1Z;ʹ.֠#ϴZa8L`hʖ%q1j5kmM`<_V1JXOV2+}'m̐A{@5Bq} ..GW+؎Oji b,*GZ}xƘ+}/iԮDpl<j_uB$`h ]˭М+z~9 vEa'(^36w(J't_t(n!:סW l:/UЭO!W̵K nv^P`hXG9۠#H O!Q(}hX]$阚W 8눕?r">6*-ϕw 77<`ןml9BPхn H 4xExrGuc5^Ϊ 0$A72r'^O4EJi;*lD";|Vr},G#O|ױ-Cl; ؎m]EeXiWJ @IoˣBK!Fn/Ζ8["8ב3i% !"Ӽ+ K}`qD 6Xt:=)tqw")Q4zDI;ik(T7 *+Cb*.X&W ڌLa'IY8;:I^Ld~gIerԪ A(:A=DFC'NZ؎ȘEԕRTUU# "369oF zxOW u:Pkh!ڋhptWƘr9֒K$ }UuhoKP,5j)<츛K,nVel63FIQ]",#^#tZMLfAa'mU<9Ujie~d2-B)E M("T42M|;%մm=pMxp%mdqUQk/$Y)Y6\~7/<-RMJ 42W?J=GRh l>'"!ꢙdM5Ǔtvt:UR~ qZ!<-Լ AE,sm6ߖ(R͍MD'eY+*.׍OwpVEr2@Ӊ"uoDݳ !&"N&cHN(&}ٸ[F0`u? I4xY̺n|Xi*KặH13!h4uQŌxD2iUH,@VgFf$,:X3tHEI,+&(<ڹɋ|:jcFaE5 ',J R߁6fKƿV9'{SIjXiZtu;il\ԝnzzrZi= :1tR*k |sM_D-KdHCh-")!e&8tf֦,Kctl:6b2TUFB)BP5ֆR˜ƛʓ'Z} ^2"󪬄JbR mt? ϳ3]^wvveA^Dkr3ʉbNGk&+2uEc&IQnOG@+tlc#uE\Ho`{VQտh!UY.ˢ, 0gAP#ZӉB,EQëA!Ji8(H A}9kT쥴Gj"v M$,r4t<U~Pzdj}ڈUy߯ Z1d* '[kc5IڄEp3ؤbQgB` Z4f83AzVg}[OZ͍| αknmlHa wY'ˢ(emm|֥'l4 AXAzg [Kż::t;>EӾ2?;RZV`"ENR'0B;h>=x ;9 D(d<OJTj PFBxp b[[%ʁ|N*YTTm #Sd2Mg%2B*)"bnD~v,5hGボT6δA6*CW"B` X^r8s+ȶĆ![>mוz4ShtR,EGB!jq$juS܎%&Z 7B< A^<́"}VU&y  )B!6e&D\p#zU޿)*vgV 1KHh ; +Y X'țpW\E-uۏ{J°%v|m)^8xu>{7 F>ЅHUa2+2 3-.V.[zU0dC1\"l5L IDAT `kpݼĒ}*5푵m݁wQx5daX lѪ9pz{j /+x{:o#•4f힙p]#Q!5ǖ3k}<5` 1:ط¯M5}ȏ|Pm׋uED,l.CYڽjOK@ǭ\fh\äҚʶl5yy/c#OƳp@*@Ճl&tX$, iFFY!Y>C AD;8I>rQ~;6?ޝ3/_gwӥ_hÜB%2JLYPUJZlqfcgXyYnA}@ˏW?0xhu9_Y( ;g\z 0]4#䤐XEV1U(Z,9153UD~dЕW~wʻ}C7ad(r>rZަ5"ȻR[C1%0VuIVw]M.&_ w ͯZ,x9s2x| d fZ87b~0ƽⱽcg7@Hu2t4UAH-cr/GNKnED:\ߚ=z>*?hc:|w3ן{81"ln"c@k'S {6+ Ǻy ?ϿCen/g=o^YLur, p?VjX^;j?_7rV_# D7{& 0eH\_s//E7@9w"lHhG/-wz7o̟:o+_ +ӗaZ}Sɏ8F+8cz~z5VBInja6%~1r~ >MzV 敏8\@^eL~GۗayS(w-_6̧KWΧŭq6*鰦^+o6j'QĒ3g_4w li v![gӸA>vlB"@i)o g<[XίOV HA &wϘO; W%P%?sʗן(\ ĕƒS@!a?:\ےoWMfUcXdGo% X܃-߂jRiCvKb ])*oSE8m`7?W=iEmC@U9 p=?==X.@F c6-%O uaËv*?2jOe'H%\T (P- E@6SAFÚ0]J )1PEs7y<0|)(#2(@oth1T3zP n6_h*hyiS=!`muj]R9GMi,%S0Ch3Ps D3?Hk.^g_̎Mp ʸD,8ʈBIrtxw=Ā1ȨY֛ XC9oCP1m1 j 0[EDf]Ωnw7 y,&<xs~$΂۲r[rpgzRˢ_m݇h==2 wp_v""ouշOA{ _/^}}>lޖ~&hczyq_޼7_ݽn?7?'?+_o?pwFCXh/u,P\$EցJ t/u?sw~޹N8Oۯ7?>_{?<>T?#C"˿UQ ӴI=\?4r<).>?jx$xz<~:]a8 pB=\n iKZ(S2Cv?^[nU}w@FBjXRqPac A1C;,O6%\C)o1=,^oVp-: w2,.I=Vᝊ _e6ileu^,&M#XUԲrbv-`POT|SB UJ8 k,vdm+9eFfEDjDk~H:5`6!% tRhEMiAUѪWBr F1aѻg$ 9/v5ۈ,x>, ƂjܑIZdOdeƠ\ף$gba#LSSTBk$\qÃ&f@eUOkzj%TQX7C3on}\< 5/ 9hmq"_seWncp]8E邛#X|umhӖٴ9[hìk0NyW{rfXTrqx9n7}^ƩO1ڿzkԹHCej"h;94c"8i |<]oÅ^&ˋ0'YsL(1i4M8fK|:FNHyq601j0!ͬMkʑ]j*NEM~"{8Gr9:ù󇡻?x@BC?c7Uon J' i~ {][3ipy<~{AH7 p^''q俬qYN:b LNR*,%}f p2!ʶ?Yӕqӌn7|.xx=!1Nqawqz<_V29]kBgH/ڀ:Nv@!n\yr/Sɾ.L|gq.3|w>ӼI[Y0*:kQrZ'0Wdi{0m ,ħwOWGOKX%FBzi+jJuQ&9-Χ|w޻y/tV]z8O8N}2u&'0tMҖ}%ԺoZh A:fwo.#:|j(ctu.O'w_,H\f#9.~\JRSJODc)1kTqe78q+>F>=>|G}?Ls|~>z>ȋ#}r9Yv*KTh2@g h eSHɢH]Z8q.$7=޼y|x>E8<>D=#<=v!ӿMt+P fY.juVRj=g9@ LGD]%( ODsRgjjX4BTAqWUTێګu*~AJ$f3uuAQ4c?)ƄREjyٕ1t3qe&`i%2wNړ9D,wNru ljVѢi-jDC(7X;BqTr$ {ZT@Qewlhasd~6Ka<‚#˽OȁOhVIdc/!@{A^ń\q6N@cbP!8|WgJ< -tc@݃⏱Tجl` Q|}K4l1Ц Q`m-xG;ɭ%0R|eьU~w)M9ld>Xj2Q- ;r͂Vc)~8fʅR[P54ӻRΩ5Q=]LH%;GpWU3QPᙀl{P^ 8i]孀MP 9@9^IV&UsMC&mjJ+\ WSr(y]2G?]\\S͔&igk)k1R}0Z89U.azÇۏ| "|=>#ŷ-RSrsQHD))ɺRXPEt7oo#YO7~kK*GI6V %åށhZ/q" Q68x'y:NWVYד( @l3F3G$%t%:#OO~NW522 {w -d8򦵾Q/+H{ĕ{eQ19qCD Sle8&&ܶUjDWR$Zc]s<O$}9^GƤ)\?iyvD?jpC\`\Ӑm$^1UJe|ֹ5b/|3"]*HrX;72n:qFNxEȻv4 j<7S]9NS[]:8xx琀2RB:.|Q_l2.!wVXJť|B\-s"cdY1FgxߩM @&vPSMX,Z"4:s똩J+K}ߟN',VHA0ǧInl~͘+z|ӑx?Ҟ5qɵ 1D0 Cم(xEqaIkB{@xfe.y!-&t>vALs|{z~/ WqjJA 4'V<}/[lg1FH8Gt!8q9PBn<>n^oG.naUg %*MI˾9](Mf%`<;ﮗh[OJ u:N]7Y3蕷U*p7G|ƛ"^-6H0.$99Ξ1)~zׇ#WZa&Cbh. kGW?_ ۃ3Aw~秧<7qK1 `)k6kaMX X80IDcׅJM$#pRbyqN27_KiUw,EESq<#9eHOF2:?MK ʼnswn0ya.[FezӲpX) Y?[ c:_ei`sgQ)`h2!_d-T 6 žDqp3 Q֘=E+si @u5I('48]k C)_b\Rܗz +2$ AbIVPp9}8 IDATYw?ww ιe҉PqNcO?|®["/z$f^keQVCHe.$~/f%$#|\&b]JyͥTBD5̀Bm 8!b''HDڻ H W2C-ÂlҘP?h^U!$33E7Q{YȬuNmLj LƜ6zlDZz N̨bʬU,WGGG%kTK&$E FӇR\i W{6/e@I $" \Կ K G(%PU!*3j+IMvmv_U N4B-,&x-qy^ok.RӃGQyh >a0C'X^yj($JF'ˆN=AVW;1_Ʋ @3+bOK7>9W$ֶdEښ 0A9[x)p~>ĹJ1Z<"=.ϘO޻E  KhVT|lO&j󋓙7dnn~&qZ ..oGe99שW3Hs5yKF#ywŝ #b("4&? q|x?yzz\/g:1S,}e /^sxo߸swAxE>oq;nooq?w\X$btV~J*" є&ym߾{No{AemG7>;psssp]/r2k@yy>$+.yT=LA\>Swww W/O nxo޼c8.tϣ ˈ, 8Rbއ\L3v;_.]]7O`1> "n7@yD; w I(CM[U0`N|\|+lDXtr/"]oo R\둌~ەzyz| \paf*Dj3 v4MPRU883U[y~~&e7ޭj=y^fp ޳ttnO&LC%-OOsD]Bp\0n0NZ(EyԳHPu)nDxqb[/!ٿv+W_ /5P Ո|YHͨ* YFED:R&:+-ؗYl+\( C?dm4-mP|w߈q&_J#M6VfmdeװЄj[<_y/w%2 |&S p3JԘF5: -Ū*hEna   JeYn ']S-sa<4T/n~LOCJebtC U&_bI0'٬2JJ2:+>Kaj UJiKB3=yP͠BҀX*z7 yUɨYdەQe~d2l"vɜ Q,L3@(8HVF:H#M) dLmUDbt p47v6 (bl,T0r_k ĕ\!ԚdjriŌG"d-ViJeŝJ7;偝mQM k_ g-{K2Y4W-8R"Hk3Ghljbj$T?:"nv(8PL27/;ް&4>&A9Ӕ1ß;'OOw)-n1ԊV ;lMR{M[@?ꆟ?r[*)5)W=6a jhLQ2%,Nl擴Qq(pGs $E=vdD".IR[1QCDq!;PTԡO1I*B#bNf&!P %Tb@!1,"V"- !h6PMI L}0j$Ni(\Uf1hAK[VXjHJcImKW>#c}?W{/V7(K}"YlmHEPM 5!En+h-"^nP>fa@3(LJ+1 +y EbǦCSjV,JJ^eY0aL6v1161gn hw.HxS$Xڵpiy fSj!dPSg~ u"A)6~z%WNұ-Ҟ Rͬw>C߁jRfj3, /z͆iC@ۨre`M-6ߊVBFBf[0[ݐyv *MAiI=Ox*@S=mábS\ Zk֧[YW>(nhX'F:?5@G~Q":*FW:w(nUawgdQcr70`,-abQV%nP6F_yԬ4 p{QjXmIЖyDmqږ6x5CZO1oR[6fE5A=c&8Jm^LUP6wuCj92*2;xi=5AuiRSґrD5qu KCZ%hEm4fm<>&aQ ZrbTd_J3Y7]f.ToV_MxafW9ЊQt_a4Yl{xa$sP**FPW-^xQ^9Of$QҴDcfma:UYłմBPΰrEԹ:ilE)`km޳-VrDKȄf9%4(uZ w('jc}ֵgcmw u3C]0 *Us S(y;x@hJ`FYŇzVSUH>_}DMs.:Y kw֒^T7ꆱ2ł! P,XG/T\#`]~wZ籷r\k*yOVYM@M],*bM5T;/pM]DWoͱn{%3NӮu`hW“*Xlѣ}Re[%.Jت fkFm@bu5dc+dxf#V5"װGQP E5oTuvHo(Z~fhAVy 17bJRB66Y'zMMY"d(%.8{N3@lZg,^sPΡ2]]Si̽EHs0rx'~ֿp-rV{MAG5{urEeӳa:JPzQrnB)`<]78gԧVf}ڑ/Ncy(\ ̑2VW5=ũ3l\y[9AF 砌ni4)Lt)QaJCHV.#$/PBH2uWb]\ŲIB-չOuc_=DFjȗkZx_W!;(Jh 8hM 7!^3kgvX cj -i/glofE+1ޟDXlM!pZ\lEt?T{ aܒmču~Sb%F(씾fk6ؘ\j5y@K32o(9HQGEV;&f@LI|L\d:#kE&J:c(2X[% n3Z%4KaW!i9WREGyf.wT o(1:E1Er%v%(ys`.(Uh@h]Q/fKOdnt+E U{@HݭۻF1`S Xry,%ؖ7DE$ %bV" љh@uUSlzl*c !!Y`";3$(qVqf*h%uxŭliOEIz+ބVC-~r_| @OKZD9XJ9zm4K8[Kme;pFjNN#+(.P,^YƔkH[,aKTIaJg##@q JP,i4ZHqS KL0lj2(EVemZ9pHɦ]dbF Dm1:&BUi'!mB@+/V*AtY~bҌ JN訠:4wkv@X+g mUPU(;4RMc؆-Rin+~4TSIѝ-5*p9.!1ͨ)va GV\"5̀C2]-;̀R&Rf@(+&*,E⌮ev`kR7%̋d|mnC=$V;f3tz(IRTI~̫Tߖ"ȴZML8A7h^↗Z)>v̪rh(0ib㘱Ga9dL`bU> Cz;0MD_ V7:OZԧlTÒȢ+fYBUE#{#M A'l0FQN4R*|iwo36IFMBDPtZg OFyh%F Fe.zhH耤͊5T>h!rs_v-.ؚ~UY$'j2i Xab1QvZNE=b鎉GjhS9Y"D [BTb+|QIiPP\Qpn5QkIo69)-şEu(* u-(%/O$+r՚UkZ3 4'hUEʺ" ͲY5pCߺ0>M+xQiZ>8XoҲiwfeѮe@m:o0 0gaŰaQP9[RY7yHݩ7O@M8ferdsl:~gҔlMSՃB4\B՝PYCʜNa+ҙCbe&R I7`WA ӉU 8D4 /V;P۶>XvCq܄i- 5 vRoQ`jvK*=V_YU9leK-+`.)%l1 ]h?eGgV$z*q&MKu.T&%$*еQ*O%̞PuڙPA8[YU[$):S><[V'ʯ\@(YX ?kULKM葠WIIDAT ,Tu Mxfk2]exu Q@_>OYPTyG)Wj *OJ@39=A+Z7iޥJy2SZǤN^σp&*̰G[Q Bn ItfAQpRlu^,REMl (M"DS(A9Y2CeTͺ~=\5C@]ë Ӣ㢵A:;s,E6]V~jZ;$z"/܅bѸ)`P )k 5rR9ðKR.#p$P93'Y\թyT *J!j~qV^,v(2 Z +d" e4 YeXv) VԓكXe r 2D^XgD[kAVg]X扥G)LV*,dX ݰ([z$Ci݊&rw%xŭtk̷hu}V3zR%c 2PM[8lU:̈FiEn@` Jń-Od[)(P+7<^3 [bĆ6tl["b;9.wdUP6yu i[)12ݍ5 LKi5-q4Vq$-ʲkfF’X Ŀ\"j"yk(NwJ>nڧ[JcaTqMKZߕoH]V ǖMܤ̱yG7q#5NKSۜ&P}*}uSG<dYʬE͝lB,) O6 (N(xyE2:yᲪ;Q%Խ`鶱[˦ i5A&۷3gɠ.)ڌ~9qwcc/Sa.SdS{_"Ptؼ:6-af+m4Y Wj9 "p㪠^]uc]u(V:@K̙6g ۭm3\2ebq}`4Վ nr82Ι8kd̽T,ɭsq@;_;h3+0ؚ1~4@f੹ށ#ƀ?h#ƃ|n( ' lq2Q~`T`D+0mVvFI-#HmՖk:E3=!Ǧ);Ͷ꿖?;nc"AqU8)y p<]G;Ch"E2߇A{5 9FF@AG2)pOxDC-+ QBwmP>ըePg]|ZM'ӕIYF.RlUXn5{i"W&<]7ǜ#_c}ՌW+XZ3AmqE@ܗ@P:ߐ 4S@T0ɋiMGOp[o{W1y ˼hT6@|[}ۭAԇ"wnFj.77ۤ_uh"LJ&O[so/ޠ d'z;u,˲--+H2PC+HHcro P3m3 ؏#RWw\e\#ڧ}4 49eePтіӢninU- 5Yƴ{,h-L}XIg7l~'~X%>[#ψř1x@P@@Pf\*{A `$ zK?W>#|!,]k۫$~*D{z&OD~ TYnv> 4 Ɋ#!0Tbn?j bHA^|h̄C"iDQEc2WyF0՟-%$eI,@-6k5Z W(*r^/m~dN| |Ln2"QF6ۼ^RqrbɁ&Xn@P:ߐ (OutA1qZ"R5~698|'q sYB *"R4&㵭k}u!3ykB][ݢ$'j#&-`-nMM^Iܗ_n?Tg 7.wgPȤMNjTR' +Ԝ+dG,pda;lgb XnW3ь!QY?U>ldLJʈ֗&J O{T$A@1c2JP *JmͰaV@P:ߐ "yO [[6P'ƀGK #; $Gdqqdaj鎋r/9'P=ʹȖC>v`'eG4v9$8##ouJVʹ9?5R|} lmFzBܪxId$v#I߾ ɚڳz;lU9NB.SǠW4aQ2e4|}TJSd@9\kkS}͈}$zӕV r%C}@GGQteP' $S@A&^ b{Ze?vCʣ6KxM}eґ~oU`(+cm61If<0oԪ!樰ɢBS_nWwJ1[lF}x*"IHkZ+q ,7 NynyQ>;ESG*v^ϤΚ=YZ)u-X7sɻ[i3wU?PzCq㛤yLϩ.7w)Wy]EfT ʵ,AYdŹ3*6;}г&3%C95+~n{};U(|10*?eGrl] B}Y? ZIzcM,ӈr#f:~5z;%\ U V{ wqZf{=\F טKYŝ9^gЂWi}­46ɦʟ,/ͤ~Bb)8)]MΠ/( Ȟ@R=̢HNXه0<ɱB$,% oݔ!eԜ>WG^e_b)e_M7m ެ̭'K),Y 3:c@ yuDbcvNt_cx *뽹`*c~q q1x}KfяÄKW1˷z)Y!H 2F6?:=a(li0NT C(T^f4y-OEC nqI/<965zxMp̯=).,ǪQ\GtGH~houR*a+]Zxh$V?IC"{+[ޠq!} @P-->@I4FG2rn'r"Mv]zOb+|'q=?Ѽ`H#8~wU[<ᏏәZoY^Pt2̓2a ρkUUej2)m֎=MFmo]5ꔏ'DЩ1^GT~" 7\]{{<ޡef3yܯfz&Qe#J}2>jIcD/Y;Ȱ1; b^ӥFzZK&<ۘ4g$ƒLWx뵉Ȍg4zWҴ:"F9 08.; g'9ˈϧ>(8k*/W[Вtw(UQ:}ڊթʝLyCԼ ^(aYFkrW{}V'Y1{odGs~6Ϣ9<,Scqmjݍ+>–h=f%)NWFaǐV#?|nֽ,yo֋LxSw |~걎En5ɔK.߶/2}H4ov7Wd|fE {`8"8t:O91 pp!uvMeT q!} s}T}嬨MРmO婢ALzȲ} V42`'O(N{$YcaD,|Znk6cX1z@m"6 $d 4{ܓ3ۗ˗YļǧPejLR1vhDsӘa"DӮ׵z]9&6{ efpj|-9kk(F\-ׄHUȂnHI+e5LlSn2ຑi G1]?M/omyQ[z~Mq?+m7gГ ^-zσҵc=;~pq}r@0mY7ׅF%&f3귊+\^Y80>\1Y_Qֻ7o[)~I<8x)8nqdCѓȹ9,%a$*NzcjFѥŶ¶ >śaŒ6UP.F1zZ.l2&8r|Hi`ˮoz (6*x?|P,Au }8C(ր/~4  o>@_Kuf*?I.Cc(,c6<\G6M>Xds>#V*q "}~[yg ;>hSVl>-'R.n Dž\ǵ 'ꯚ6?_$6?Sq)wǵc%T"ŀ˙>eC<5w4mox1ƦGho;g|M8ɜ,3tEG 6Pxrv7A!Cn jk-HEd=?.gOr"<Ê`XBٿׂZ' mc*kZ}))p[&6ؕuڊnv\ϼVb&~yx2FQ4!+?^YqӞpflhD҂TZY1-~ޖ1}J82PbC`#6y+7LhvGF<\2REsHnn~eyi~k|ɽÿIq1TJIc,c-4̯ѷ7h坝s/,ȆleȄF.Bu@{k.|FdLV1]фC>tn,<]G6.r9d86>lT\;iMV6db1;{#28uiқSg#[#G6Ƽ~ž|yyR/ˣHUGE[R޺c Vgc3帪 cY.2deªŹv<^v\Sc@$rhk 7c=∜qc''9:%֪@ngG}N^epLolx۰賛,Fl"g&nǺ{IOϵjՍ;'N^yQX867Mtg)̶3m=;~h' Ơdp/w:2io6gw{ؖNgS0M \5G{+_JmWc1wǷa'3lf u%ȕX2#*-;?R)ˏd]Bb{*c6/v{}g5N-hXfʴH6?ݡܘWdC\SfhMټż5l=0fXNDLlM*-Mo]ѿޘ (1ȩwv'VS<>Sͱ?%i #[C2FY@oe5Y֬mLEmiQ}K 8|з-Ǜv֯f'Ecp>صVu!} P@P/GP"(+Tz:yʲq 9#n&=IXfh<>,5őHdH nͅ{쬄Zu-љZJf9(oZ?/wΏd5s[bzA<ϒ?HٳY :֙rm; ""GəW"A$g(caCX\a03E oXLȲdc7c )B;j51=g'^"Hur8 0f޾PkǏr+}qذ?#yK.ʼn`hX@GR6,㶷[fͦqg:;c/\'nf`3}^-nyl$N_+q:*I،T:gHBr4bNg:T[S5^>sdij^pM|d2/,DD ;+,z#*Ț\2@]iOjlz~8s SNW4 QҸO| QYTvA w€hv NF<8}~4 f&^3|_+_q}pDN} d>I^שMX09pھ JweHA!5Ƽ2v۽rK<`Vk͏b&6<F w];r 8;?@J3L,V#&Sh2Ҕ#ch7ś3 Ql_P'Q!:w} c J62&9瑧H5k;؟P #@T6= 1l1.7Pfi q Ө6T}/,q *7i]rc_A\fBrUd}»{**8x-4\[^Ũz[( -~? [4 )8o4῔&P4@PGsN؊R6:^IȲ<< ‚N4W_# ev E`8]ͯqvEm:a&7̑곀8U2S0d],Om!m!ʼnMn {Oޠv=!Q>qdmT0΍2v`7),|GZмC!Îb?HƁ( @ cP7z e˱k:$_En=₨H9/9?El I*lvPRCVtK˝ySe2^= yмM}UGFhؑ&A⋞ҖHOXhD,Z=؜5R;2[m,}0&( $#P7@Pb|@~g\} VE >> O?@h_88y~4 X B{>46mty; 6Lyh [d\ay9rۂH N?%>d;W?/LbXNvM9 Q5 \Q5 ./Ar/(7d@(/ʞ ((@P@ӭŨ#Ā젇گ6~BOatc적I > :NKU_OiҒy> Nr~J uꠛD 99$yX1u8Pg|(3> e=㺁;;0--.,+.++/,-=:;FDDLyxxDBA-**,)).+*.++-++,)*)&&)''@>=vuuECC)%&.()-&',$&+$&+#&*"$)#$)$%%!!A>?ˉSIM'0,,2624>85C:6F=5F<3A90;5-0-*&'!OFIf`c;>hRPUǐXԘZڝ]ڞ]۟\ݟYUԘQÌK~Eo4XFc]`;UOQRb^^`aa_ޡXɒZܞXڜUԗUٚEuNHJ@@>Y̕]ܟ^^`ϙaܡ_Θ`қJQJY͕ZTΓP‹J}544?C>^ݠQ{dZ^˖SdX_ʖSZS`КPZQZΖY؛O=iSO.0.EJE_њTi\S[S_œTeZ_ʖRYR_œS^U[ȓJhVO|=]LM.2/V^X\zZMO]c]eZk`a͙RQNRNLRSN\͕MfWS611Aa;A>uuskqkksmlohggsjgӟUTPQDFQSN[OiZS:345UDTSS/}}tʠ[[XSJJQKJMGFOl\T:/20(*nlm/|{ye`_WQPRKJM@BObVMxa4+,\ZZ pjj[UTQKJNIHJAB@46\XX upo\VVPJILFELFEXSS 4snm]VVVOO]XWb]]4( @ OMM=LII754*'(-++.++-++-*+*((634JIIMLL=MJKT966.,+*''/-,-**0...,,.,,1..,)*.++)&&-**956KIITged(GDD,)).*+0---**2//-*)0--/,+.++0.-+((1.-+)(-**+(()&&CAAedc)vuuR411,)(1...++0--+)(/,,+((-))-)*+))-**)&'-++)&&,))*((+))($$0--srrR}|}b1..-+*0.-0---*+0.-,*)/,,-**.++.++-**.+,+((.++)&&,***''+((,))(&%,)){zzbE0--0--1...++/,,,)(/,,-)).+*-*)-**.++-**.*+*''-**(&&,))'$$*'')'',))*'')&'E633.,+1..0--/++2--.()/()-%',$&-%',#%,#%+!#,"%* #,#&)"$,&()#$,'(*&',))-*+(%%2/.ߑXVV+$&1%)- $-!%,#%2//1306?97F=9K@=PDtZ7SD.30(#$gfg4QEIx[0%)ꇆZVWT/$'R_]\]_]`ݡaݡeԟcܣf՟aۡdԞc؟aٟXW^ԛ[ٝZ֚WҗUЕSʑPɏPōRєDm'TRRTTPQ3,.Y__ߡ]^][^\b\_]`^]C9:;*.ZҘYXݞVۜTיS͓RΓQÌRǏIu( "OLMD?@632ZЗ_^ڞ\ә_ޡ`_cמ^Ñe”bfҝ_beۢdؠSPMKBB^̖\\؝Y֚WԘTȐPPQɐK}'"#<89701@A>\ԛaTuC/4Zј`^^‘F*3T_V_`̗H/7NFF__NLHF;<[ҘY[XXM~(EkSҖM/,,*%&=66CEA^ԛbXuI5;[aԝbbM9?Yj^bdƖPADVTQdޣcݢTSONBD_Θ\ZɓVďZܞQ-!FiTҖM.-,.*+=78EGC^؝aY|J9=M?BQVO``ÒI5;Vh\_a˖K[؛R3#)Ez_ON1..)%&WQRFC@aؠTj]SBFTONWNOW\Vff˙P>B[j_bcʘOCDSMLQNLQMKRKJOFF`Ӛ]KQJEC@ZߟQ3'*.#7YGM("#=::jffMDDg˛braUWa[[d[[bb^lۥkŘWFJ]kadc̙NCDSLLPHHOFFPHHNFE_՛]MPJJIF\ߠS}:.17+.BpXM~'!VSS~~DTGIjĘifXZga`kfejdch``ga`aVXdneigΜSIIVONTMLRLKRJJOJH_ܟ]KJGJOIZOw6(,1$(DeHt( ljkD gX\pzwimzuu}ywzutxqpunnkacjskmiԟRIITMLPJJPIHOGHOKI_ל\ԚLFFNZP\Rq>04:558A;040844ہ z|ty{{zxppuysvqإZQRYRRTNMSLLRKKQJIOMJKGFH<>NgWZKe:+08544./*$%XVVxzꈀ|~wԥ_WW[SSTMMSLKRKKQKJNEFNFFK>ASvc]Mn\@47:663/0301{zzt|vvsmme`^_YXWQPTNMQKJQJILEDLFEG6:Sp[HXM@67;76/++_]^t{uunhgf`_[VUXSQSMLSMLOIHQKKLBCO\SJ]QE@>A=<30/JGF!ड{zrlkgba[VUXQPPIHRKKKFDOIHICCJ@AG:=755# 1//'%$2///,+*''/--# 854>;BUIBYL>^KIdTHgVAjTJkZGnZ@lUFlXCfS9]J?[L:SF2F;:D=-/-)$%-&'( !#(!#*%&0,-&""TSSnmm./+,*!/#'1++;C>>_MGzaOtRYWؘ[֚\ݠ[`ߡ^[bޢ_Z_]Y\\XZݞYޞUVЕTˑPËP|GsEe?hR8RC2;5*%&' $*''lkl.LHI.*)FoYSzYɒ^ם]^\\\YZYV^ܠ[V^ם]W^؞\WZݟYߞVWۜVݜSTۛSޞRTӖSSۚSՕQؗRLGi:]K'""HEF&7,.7I>`_Z]Z]ܟ[^ߡ_՛[aћaӜ]ߠeɘd˙_؞gÖb̙]؝eĖaΚ\۟`ɘ^К[ܞ\Η[ΖX؛[ʔYɓUҖWȒQǎQNВQƎOۘSڙPѓ-402(+憅&jiiq%?eQa_К_қ`ћ\`՞]]^ݠZ`ٟ]Xa՞\Wb՝\Wa؝^ߡV\ܟ]ܟVYޟ[ڜUY֚YӘTޜVȒSΓRɐURSQSSʒ3I=fddqOML/#'Mja\ߡZ[X\WZ[V_ߢ[Wb٠\Wc֝^Waמ_ޢW\ߠ^X]\ݟTWޝXۜQUӗSڙPܛR͒MۗPȍNϑPŒTД@hS("HEFgde#522) Ky_\]^ݡ]a֞^c؟a؞]fϜfѝbٟmęjџfءnƛeҞaڠkŘh˚aڠf͜[wRqXtcƕ]ڞ_͙]ʖWך[ŒWȑT͔UQɐRPȏOŌRޚ<~]#/+,caa#ecdN3//:/2Xc١`Ҝbӝ`ٞ]bמ[`ޢ]Ya۠]XfҞ]Wdנ\Vbٟ_V`H>?4 &=*/]˔XZߟZ؜TXҘVҖSחUQȏTSRUHh/%(*((a``Na__1.-6,/Vʒ\YZ[Y^V\[Va[Xfޥ[Ud١^Wc_W`MJG8/0@67]̕WYYܞRVۜUۛOSГOPғNғM͑OԕFu)!'$$][\ECB/*)822Zϗa_ܡa֝^Θ]̕eЛ_eנdן`jŗc_nh֡cޣnd]hk͝dۢkΝ_[YOFGTJLd\^Ԝa͙Zڝ]̖Z˔UҗWRRRQRƎJy( ##! >;;955C=>EBA_ϙcۢa^F:.3X̔W_[V_D37@/3Yyg\WaG7;?56RRM`U_PNJ;23E79^̔UX[TYWٛSJs!)'%MÉNژOԕI# &"#%#"D@?D>>JJGaΙe֟edOEFOCEb^̗gÕgڢdiTGJQDFe~ofbkWJLQHI`^[jӠbiӞ_]ZPGHVJLe\_ٞ^UY\ʖYޟTv3%*854QSTO2/.3//522<88?88EEB_۞aߢ_`“L@AMEEUJLF27X^Wb]eM>AI;>`|la\fO@CG??YXTeޣ[dݣXVSG>?OCDbƔY^NXQ9$+@79X͕WPv,"20.PQ͒RɐM*'',((-*)>::A;;DCA\ߡ_]^֛G;=F>>QKI>35T_U]X`E38?04Zyf[Vb’F6:=45RRM_S_QOL=35F:;^͕U[J\P6(+?=:V֙SLu%--+PΒSQҕJ(#$,))*'(D??JEEQLKeΛhʚcfZRSZSSc\[TJKcibiܤekVGKQEGf~ogajUGIMEE]]Xhՠ_gԟ]ZXNFFVKMg^cޡWbXE9;NJH_ʔ[Vw:+1>=:LjKiTP}2,.412$""a\\;55E<=]ޡ^̙J5;QADTONQLK^YWOEG^d\hcjUGIQDFe{mf`jUFHMGF]WVYSQLFEYRQ\VULFEUIJfƕ\aT`VB47JJF\ҙWPr0#'511+ ) OɏI%#B@AmiinLGFRGId˚fӠSMMWNOXRPQJI^XWK@AY]We^gL86RLKMFF<44KDDNIG>65H<=_ҙT[LWM8*-FHDWޞTLm,"510.'(/2/SʑJw0%)-*)\[[n||:HCBQBEfmۧda_g^^jedf``qkjc[[mkhsʟlߨr_SUVJMhznhbjUFHLFD[UTXQQKCCVONYSRKCBUJJdʗ\aܡU\UG:=RWR`Қ[Wm>25C@?;25WΕFj*!'$#omn:[VVPADdm^e^^SUf`_`ZYnihb\\mgfl`c_UVmfef`_]QSl{pmfn[MOSLKa[Z^WVQJI[UT\VUOGGWONd̙\a۠SWRD69PZR[WM}c0"&843*!4J=X?~`%855~}}sooYKOozq~uocesmmjfdupohcamhgnhg^WVleea\[UGIevjg]g̙M>@@98SMLNHG?76MGFNHH>56IAA^ݠU[IJG:+.L^RWWJr\4&*?;:5+-@WIP}=OD'!ROPS^PSir|ywjm||~yx{{}}~}vqpzzvqpi_`svtjpƛYMOMHG\VVWQQKDBWPOWQQJCCVPPdњ[`ǕURPI87OIHMFF<65MFEKBC>66KDCGBA?.2UkYZ֛IOJA79FAA=99<883/0(%$YWWpՄ{|}}֭z}ˣi_`XRQd^^^WVNHH]VU[UTOII\UUVPONHGXRQRNMN=B]w]\đFCA@79<773..30/-*+<99ՂYwxpghvopmgf[VUfa`_YYPJI]WVXRQLEDXQQOGGE>>OIHF@@A05VXW=24>78?:9=98955.))fddY~~ohhsmlhbbSLK_YXVQOD>>RLJIAAK?A[WēWkF;=HBB<87:66)%$TRQ"ޞ}|~}zttidbpjifaaYTSc^\]VUSML^XWSMLOIIXQRKDDOIHKGEA56G:<;65B===98732@<:ލ"I{vv}wwuon^YXhcb^XXKEDYSRNGFC=;TNMF@?F??OIHB<;KEDI@@F<=LEFFBAGBB:5540/daaIbzyiccniid^]SMLa[ZVPONGG\VUOJIRLKVPOJDDQLKICBHBAD?>C?>>99732bd}|mgfpjic^]UON]WVRKJLEDVQPGCAMGEMGFD>=MGFE??MFFHCBB<<=76􍌌dNߣ|{kfenihc^]UNM[TTPIHNGGVPPKEDSLLOIHKEDQKJHBBLGF=77MGHb^^N)}pjjpjif`_XRP]WVPJHPIHSNLIBBQIIJDDLFFMGFHBAHCAWRRwst)bפ~pjjoiid^]YRQ^XXOJHTMLUNNNHGVPOHBCOIIIBBQKKgbbby՞oihrlkfa`YSRb[ZNHFWQPRLLKEEOIGLEEWQP\WWyqllZ؏zy}|lhgoiid_^XSR`ZYPJJYSRMFFXSRa\[^XWZtpoAu}xx{vtlfeojhe_^XSRYRRF?>^XWtrnnAgbb???(@ B MKK=MJJvEBC,))1//*''#! 511/-,$ .+,-**/-,B@@KIJvMKL= OMNB><<:66,(( 533+))+''<::.++(&&966522(&&2//977(&&.++501-*+533=;<<,))(&%734)%%.,+976$""'##967%"""411.,,")&'644# !&##:67*&'*''633$! -**<99IFFc_]]TQR`522)&&1..#! 20/1..%##2//966+('.++?<::0-.*&'7440./$!!(&%966"!300-+*!$!!:76$!!#! 4121/.(%%3./865)''3101//#!!*((7446IFF|,))0-,511-**:67&##%""633# #844.++($$.++=;:+''*&&:77522+('+('=;:)'&&##2..1/. $!!200 %##743(&%301)&&*&&ECC|!LIJ,()*''744%""-++845+((400>;;0-,0--=::1..-)*0-,845*''(%%8442/0(&&*''865,)),))2/0855-*+.++;88-**(&%532&#$#!!300%#")&&IGF~}}!9301+''-**2..<881/.:772/0)&&0,,/,,# "301# '$$/+,1-.*((2//# $!"/-,!.++)%%&##0..0..*((743*('+((%""/+,ܔ9I744*''<::/,,855+(("/,,&"#" 0.-/,,)%%+)):88+))-)*522<99-**-)*<99755.++-**=;;0--+(',))844(%%$"".++(%&%"#)'')%&1.-,))644$!!2/0ꛛI@3000--532.+*# 311*''.,+<992//2//<98411.++1.-:78)&'*&&2//522&##%!"6341--'##&##755-+*)%$)''966+((+((310422.++0.-644(%%(%&-++,*)-+*+((-++@)744/,+($$955311744<980,,1//532'#$&##311&### (%$410!"-+*0+,! 300,))! 2//'$$!"20/!!'$$-++"#!!0..)''+((855/--1.-0--#!!(%&1/.䊉* A??($$;88633;88+((.++,))!)&&.++#! &"!632(%%(%%0--865)&%+('632633-**+((;97633-)),)*9560--)'')%%744(&&&""($%0-,!,))" ,))($$'$$855/+,523!<::˨ KHH-**;88.,++((,)*"0-./+,,((7438543/.521?=;3/.3..955:87-+*.+*:76734-**+((854300,)(,*)9662/0,)*,))<9:311/--2/0;88.++-**511.++&##-***&&+()# !+()300($$HEEN*&&)&'2/.(%%844633411><;5110-,;760--(%%+((511%""%!!/-,1/.%""%""4110-,$""$"!300-+*$"!"! 31/-)($!" 30/(%$!# 311$!!$!!/++0--(&&/,-:780-,633/--$""+''&"#%##N20/-()40/@>>723>;:.+**'&431'$$$"!632*%&$ +%&3+-##.&(-$&$#3(+.!&$$3&*-%$"1%),#! 0%('  1+," (##,))# /-," +))744/,,866,**(%$-+*ڡVUU.+*;887441.-%"!3//$' 2%*%':/2.&(1,,9:8BJD.0-4.1"&%!!-*)/,,wvw#MJJ# 3'*1-.I\QMgW}[Ɠ[^^\\]YZ[ZVW_՜[WV`К\XV_қ[ޠWV[ٜYۜVUWՙWךTSUӗSۛRRߜU˒SQTɑRђP͐R~JnCsZ=KC*&'*"%JHH2..7-/Sp]ޠ`ޡ[]\Y\ZX[]ݟXX[ZYWaӜ]YXc˙^ܠYXaϚ]۞YY\؜ZڝWWXؚWٛTTUטSٚRPߜTŎQۘOܙQōO̐LܘQƍPҔOߛSPǎEpY0&*+))~}~iggu1,+0')Xٛ\\ݟV[ڝ\Y^ڞ]ޠ\_ڠaΙ\ڞ^םdȗc˙`Ԝ_֝ifÖd̙bΙkcƗ`Ι`ϙidǗ]՜^Кc`ȗ\֛\ҙ_ȕ^ƓZҙ[ϗ][ÐX˓V̓ZTȐP͒SRMԔPČOČLږPŠOI{' +''dbbu;77& "183]]ܠ`˘_֜c”^؝]ܟbΛ_۟]^ܟ_ٞ[ZaԜ^YXc͛\XWdΚ[XWcћ^ޡVW]ڞ^۞WVZޠ\כUUZәYїUޜTٚWS̒R̒UVRTTQTQǐO&"""421zzz:+(':24H\P`ޣaΙ^מZ_֞YY^ߡYX[\ZXa֟]XXeϜ[XXe̙]YWdЛ_ޡXV\۞^ڟVVZߟ]כVUY؛YՙSRVʓSחPޛQҕRǏMڗPΐQMБRST;A<3-/"vuv:c_`7421$)Er[]]ߠZW^۟XX]ߢXX]\VXbן\ZXh̜]ZZi˚_[Zf̛b؟Z[_ٞaZ[__՝UUYۜZ֚RRW͔TטPߝQ՗RȏLۘNӔPMڗNʏOʏQ5MA,"&.*+\ZZ955-+*&Il[^ٞ[\aԝ\^dМ`ܡaݢfМcҜ`ڟ`۠jØjɚh̛fϛsm̞lΞkΟth̜eѝeќpkØeќdѝkț]{kQwbSycWyeg`Ӝ`ΚbŖaZЖZΖ\YUʒUƐWRŎQōTOΒOǍPËP7cM &##300xvw0,,9658+/XzbݣfaϛcЛeʘ^^dќ\\a۠]ZYc֟\YXiʛZWVfў[WUe՞_ߡVVaK?@4#(5&);%,_ɒVWY[՛UUYϖVіSؘSДWRŎRWRTUUÍGs\-#'0--)&&uttlkkF:66B>>7(.X[_؝YZ^ܠXXaڠYX_\YWdן[YYk͜[XXh͝]YWgҞaݡXXcPKI:22;54@36`ǓXXY[֛TSWՙUךQQۙTŎNۘMؗRMՕNѓPOܙFg+"8660-.hghGrqqp&"!40/-!$WȒY^ڟWZ_XZ`ޢWW_\XXe١[ZYkҡ[XWjΞ_ZXhڣa۠YYbSLL<44<66A36aĒWWY]՜TTX֙WיPPݚTʑPOߚRČMՔNԔONGo)''qopqCA@{-)(8338.0]˕^d͛_ޢd՞bǖ^Ϙ_điƗcݢcܡiϝgϜcןeڡpfed}ulѠiОh֡ufvcw`vn|pƜhџiϝpǜgaaWOOXRQ[NQh_ܠ_Ԝ`КeŖ^Қ\Қ`ē\ŒX˕WʓZTRVRRSQѓKt%,**!<99{966yE@@HCCHBBcȗaߣf͜`ߢcۡNOLA15D+3^]Ye١aZ\e}D(1E38B(1dp]ZYhG*4C27?,1XMNcXXcVQO@77A;;G6:bWXZ^ӚVUZјZΖSܛWH|c)(?QGTȑQUSÍPw4+-:78755,((y622y511712733ZߠY_ޢV]JLF<13A/4Y[Vdء^W[d~D38E?>C47dt\ZYhH6;E>>B99YVTcXYcWRO?77A;:F69bÐWXZ]֛UTY؜YԚQUHg$!9OBRޚLؖPNK!*'((&%(&%y4/.y40/811976[Z^ߣW_IJE<45A05ZYVc]WYb|B15C<;A04atYXWfF39B<;?56XTQbVVaVPN=55?88E38bĒVVX^ߡUUZXכRTKh$!7L?RݚMٖPNޙL"'$$%""'$$yIEDyHDCKEENLIfȗd՞jʛe١jѝZZVQIJUHJfbĔbljաhآioYKNYTSXKMoziޥhՠfܤr\MPZTSWOPidboΟgՠf՟n͝gcaWOOXQQ\NPk_ޣ`ٞa՝bXXZ`ŔZΗ[ԚVm9.27/1DTJWSVTQ}4//844643;88y?:;y>99B<;DBAa۟^c՞\cTUQG==NIHXKNG5:G07]b[b]_h~K;?LFEJ;?gw`]\kN<@JEDG??^[Wf\\eߤ\XVH?@ICCO>BfYZ^R^U;#,:'-?05ZΖVVOl-!%*!$=PDTҖOΑRPӔN)"$-**-*)1.-y622y843=66?<;]ZaڡX`RSNA88ICBVPOD>=C89Zg\_X\e~E48E?>C37dt\YXhG4:C>=@78YVScWVbXSPA78B<;H8;cÑVW\QeX:.0922?;9XՙRUMj($:QDRݛNٗQOߛL"($%%"!$ yGAAyHDDICCHBB`؟]fݤ[cTYSB8:JCBWQPD==A25cs[XWgF39A<;?56XVRaUUaVRP?57A::G79bŒVV[PcV9-/911C<;ZכRUKj) &>XHVRSOؖM~) #2//2001..yA<>B58^ҙ^[nD*2N@BXRQKFEQLJa\ZPJJPFGag_icemVFIUONTFImwfcޣcpVFISMLPJIc]\]TTPGHPGG]SSc\[PJIRKKWIKj^]aYf[F:=LGFE59_ƕ_^{G6;QKJ\WVMFFQKJc]\OGGLBC]a[f__kK:>HCAF7:er]YXgH4:C=<@98YSRPIH@88@88OHHUPN@98B::I9d͗VU\PZQ=13<33IKGZRVLp\."%/++?;:0-,0$'OtW՘Kf5)-9770--^]].HCBKFEL:?diocSWgbatomidcmffysrkfejcctpnyƞqҢpݧxcTW^YXYMPpwhdcoUDGPKIMFFa[Z[TSNGFMEEYRQ^XWMFFOGFWIKhŖ]^ߢdۡ[`ZMCEMCDX\WcЛ]љ^ԛYqaE;>B?=KHG:668/1S}U@oW$(%$*''da_RLLL=@ayhkȚXIMYTSjec\VU^XXpjib]]a[[oihm_caSVaTUqihha`c]\_SUsynkܥis_OR[TSWQQicbc\\XRQWQPa[Zc]\TNMUML[OQiȘ_^cܡVZUH??E:=S]U]UXIaS0%(0,+;76&!!,$%OS6YH#+''GDDZYSRcVZlvrtեcXZ_YXqkjd^]c^\tpohbab]\nhgoih`YY]VVohi_ZYXQQSFIkrf_]kL:?E?=A::YTRQKJA:9A::PKJSML@99A99K?Aa՜WV\MMK?77=23QaUYRXFVK/$'2..<87& 230VښWߞ=LC7/1+()onnZVPP\STkrk{֬zvuunnzzupprmk}xwsnllgftmmvqpga_c]\unogaa]WUXLNmrjc`m–P?BHBAD=67=02Rk\YTZݞHPH912@<;GCC955DFBFgU670));66611($#643(&%622744/-,vtuDrnmqjj{|||}}~yx{vu~~}yxnjijabzyxmiu͡XHLMFFHBA]WVTNMC==D27^[Z^L=AIDDQLLA===89955*&&-**&$#gefSˆӮۭ{ǣm`c`ZYZUTjddb\[TNNRLKc]\_ZYUNMUPOc\[ZSRSMLTML_YXVPPTONSCGc\[Yu=.3843B==,''3..1.-301411B???~~}wyuikpdfzqsokic]\]XWlffc]]VPPSMLb]\\UTPJIOHG\VUQIIHA@F@?RLKF??A<500C?>=99;67%! zyz?~}~~qjjjccunnidcXRPQKKd^]XSRHBAE?>YSSOJIC<;A;9WPOIBBB;;B<;RLJC<87E?@7321-,;76510632؜>{{snmnhfwqpmhhb\\_ZYkfdb\[[TSXRQe_^UONQKKSLM[UUJCCGAAQJID27:)-E9;?9740.FAA=97FBA<982.->szyxss}wwxqqd^]\VVkff`ZYNHHKED]WVNHFD>B;;GA@OHH?98?99OIHC>=@:9PJIKEEJEEOJJ<77=::)$#khhs~}xw{z{vuf__]XWlgfaZZOIHKDC`ZYOHHF?>HAA\VVGA@GB@PJIUPNJDDMHGYSRLFFKEDRLL@::A=86B<;HBA<76LHHD??832ebb~~~oiihbapjic^]VPOQLK]WUNHGGA@JDCUPOB=;B;:MHFGAA?:9ICBNHFE??QLKPJIGBAGAA1,+qnnx~~~mhhe`^nhha\\TOMPII[UTMFEIBANHHWQQJECMGGZSSOJHLFEVPOOIHE??QKJ?99E??B<C==OHGMHGE>>KDCTMMHCCOJIYRRHBBOIH>86kggronJǠxsrqjjsnmhbb_XW\VUd^^SNMRLJ_XXWPPPJIYSRTNND>>SMLKDDD>>UOOrooJa̤||tonkedtnmhcbYRRYSSc\\LFDJCB\WVLFEF@@XRRMGFIBBRLKMGFhccaO힙}}upokeesmmidcZTS]VUe_^RLJRMLa[ZMFFNHGRLKF@?]WVtpoO#dݒ~}xts~}smlfa`pkjga`UPO\VU^XWKDDSLKXSRICB\VVzvvdqll$ 7d{wvz|wuxtmmxga_xsnmxjedxVPOx^XXxWPPxB;:wSLKamih7 ?????( .OuÏÜíýýíÜÏuO.6aááa6(fêêf(/}pnna_`^\\?==724201.,,FCC8650./2./845B@Adbc\Z[qop}/ltrsLIJMKL$ 1//744 )'&)'&$ FBB521%$!+&&(%& B?@%! .+)IHGIHHssrl2×\ZZ+((1..@==)''-++-)+'$$GEC1/0$ !&##%$#!EAA2//!&##%$$!B??644(%%,+(-+,+((GEE%!!(''a__×2;ê~HFG%!!722#'$%(%%!A??)''!#EBB)&'&$#'$$'%%# FCC511%##'$$&$$#966755! :774//!'%%%#$+&&0--HEF~}~ê;/égee&#$622400 &$#)'&)('MKK0-.211411622411ROO6122//2//411/,-MKJ?<<1//4001/.1-.B>?KHI1//5221//0..<87GCC&##(%%%##=:9(%&('&baaé/×866+'' !+'&+((KHH5115126220..744HFF&#$'%%&##%! &##JGH!#!B@@1.-!! ,))CBB$!!%##'$%+''LJI+((2//5111./><>(%%'%$'$%# :66×f,))+''C@A0.-4000..755B??#%!!# 755<98!! (%&GCC! !C@@.--!! &$$CBA! !HCE&!# !$!!%!#GCC-+)0--1..1--CAA .++h)õB@?-)+1/.IGG,+)&$$$!!:870..!!@>>411(%%,((-)+/++966MKJ1--642855865410PLLA>=522855855521421OKK.++/---))+(($ !A?>.++   =99+''# # 644@==0--(&&<99ø*l><<,))512,))'%%-((<88! $ # JFG0-.2//745987744URR=99876642400/,,=<9HEE+&'-(),+(,((%#$GEE742(&%+(),(),((-+)PML/--0./2//642412HFFGEE522855512.)+<88<:9 ! !=9:!'%$('&866%! <:9lëjhh+((?<< !@<=6221//755<89=<:QMM1-./--,()($%%! KHH!! !654><<! ##EBB1/.!!! KHH$   1..>=<($$+'(-)+512OKJ411866511,))?=<0-->:: hgeë@@>=!<78,)(,+)612854QMO5112/.+'&# !200=99! $ $(%%HFF %!#$ $ ><:=::###FCB1//##!KHH(&&!# # !+((FBC# !!A?>!%!!)&&-++977JGG1/.1./'%$1./1--?<:@khde+''(%$622LII411512,((200>9:$ $!! ?==401!##-++EAA! $ $!! CA@977%#!+'')&&+'(&##JFG654(%&)'(+'&)&&#JHG-+)#! # !! !# IGF !A>?,)+ ! @==&!!+((1..401GCE+'(%!!%##eddkÏ411#4018551.-FCB0.-# # @<=1./!## GCE-())&&-+)0//2/1EBAOKL754?<<=::>:<752OLLE@A:77=99:76976622PMLA??856976976=99754OLL@==966=99=99<89754SQP4112///,,)'(# 966411  <89.,+ 845856.,+1..622200Ï ë /++EBB.,,)&%'%$B??# $! !!GCC)&'.++40/966:77SRQ<99:87755642.,,>::745&#$'$$$!!$ <88+'(   B??.))   966+)($ $! %$$% !@=>/,,/--2/0412642@>>HFE400511/-,'&$2..977  &$$<88&%$-))CA@%#!ë ü%##-)(C?@+''# 50/744&#$400<98B??PMM855755200-+).++>::###:78/--!$!!%! %!# A>>+()# $!!$ !$ !FBB0/.!$! $ !$ ! <981.. $ $ # =:9)''  $! :77% !+((/,,200865IFF1//0-.+((!<88%#!.,,754'%%# ~}}üqop'$$&$$,((722 ($%,))OKKE@@=:9:87/--6222/0 # # #/--866#%##&#!%#! B?@.++$ %!!%!!%!! C@@(%&# $!!$!!$ FBB0/.!$ #! # <78411 $ $ #!:870/.#$ # ! :77#   652(&%-))2/01/.CA@><<'&%# 754# %!!!jhi`^^)&&$ =9:855:87?<<<98CA@%! # # !755.,+$ !%!$%###966522#&#!$!!#!! CA@&$$!!##EBB'$$## $ !$!EAA.-- ! $ # 866512  400400!!! <99'%%!##512(%' %!!?<<40/:76200987.+-$ !![XZûOKM /,+.,+<:9POO210,((# /--622# &$$&$$%! =<:'$%%!!# # :88-+)$ '$$)&'-)).++KHI200211724855<99855SPQA>=<99967<88>::977TRRFCB=:9><<=99866:77KIHFCE855977742401/--<98@<=+'')'&&$$%!!511(&& .++1/0# # 622!!(&&200HEF1//(&&.,,OMMûëMKLHEF<99654<98621 &##$ =::.++$! $! #%!!>:<(%%-++40/966622OLL?=<=9::88:77:76855MIJ.,,0--.++-)(,'((&%IGF'%%&$$%##%!#%!!EAB0--# %!!%!!&##$ 745>==%#!)''+((,((+((756GBC1/.644624754642C@@?<=1//411/--)'&+''855  1../-.!865-,)210745=:9 POPëÏ][\IFF855&#$!A>?+(&%#!$!!!><:%##,()0/.966B??OKK=9:866855401+((EA@(%%$ $$ $ !&##E@A # $! $! $ %!!IFF#!!%!!%!!$!!%!#GCE1..#$ !%!!$! !0//=<:### )''><:!!! 0..977'%$0--500754:88JHH521410,++(&&)'(401 /-,200#756=:<]Z[Ïhqpp(&$4/0=::%! '#$+''@=>!+('400@>=OLK:88@=<7451//876521!$ $ $ !'%$B@@# &#$&##&##%!!.+)FCB!%#!%!#%!#%!!'$$HFE$%!!%!!$##$#! FCC1./#$! %!!$ !!1..@==$!!$! $ # (%%C@@ $ # # !)''866  644(%%,))0..754856IGG412-,,$!!#876! $ 624+)($!!jhhi>+&%$!!410511!%!!=99IEF@=>A?@966<98621# $! $ 756/,,%!!'$#&#$%##-)(>==! &##&##&### !1//B@?!&!!%$!&#!%#!'%%KGH#%##%#!%!!%!! GCC1//#%!!%!!%!!#0--A>> $!!$!!% $ &#!B@@!$ # # #&$$<88$ #! 410(&% <870..754>9:865HFF-))!401&$$# !~}~>)&&'$#!<981/0?<::!%##%#!$!! 1..=99$ !##!%#!C@A# # $ $ GEC0..!# $ #  +''>::! !! @== !###$ !@>=#$ # #1.//,- !#612+''# :77EAA9674110./1//%!#!ï# -))(%%<98QOM:771-.'%&867%! (%$($%&$$=99)&&&#$'$$'$#&##?==%!!%! $ $ 610:76%!!)''-((/,,0,-B@?GEC2//641965975<88@=::?=>,((400855=98:87MJIHFC>:9>:9>98=98955GBBA?>0../-,0.,/,+-+)210HCE'##,(')&&(&%(%$$! A>=0--%##'$$(%%('&(&%/,,C@A'%&,()-))/,,0-,.,,LJK:88977:77:89?==>:<<# 411624521<87%!!200k)caa%#!IFG/,+# !>99)'&'$$%#!8561..! $ !$ !-++@=>0--966?<=>:9GCBRPM8669656221..)&&><:.++% !% !% !$!! 86620/#&##&#!&##$ 1/.HEC!&$$&#$&#$&$$# B?@0--$! '$#%##%#!%!!+)'EA@ %! $! $ $?>=(&&  !<98/,,'$$-+)1..200622KIH6547446440.-+((@<=!856)'(  +((1//,()B?@gee)ý)&%<88,)($ !-+)?><$ $! !?::/--511<99A??JFFHEE621500/-,($$621965 $! %!!&###A>?.)+'$#'%$(%$(%$%! A?>401&##'%%)%%)%%&##2//FBB$! ($%($$'%$'%$$ B@@0..%!!'#$&##&$#%$!)&&IFC#&$!&#!&#!%$! A>=/,,# $! $!!$!! :780..   :76# $!!(&'-))-+,JHHA??A>>9760--6541.-# 976# .,,411$#!ýf?=89GBCTQQ:88:761/.)&&862/.-$ &$#'$$$ !<87854&!#(%$(%%(%%&##GBB,'''$$(%$'%&(%%&#!B??0-.'$$)%%(%%)%%&$#410GCC% '%%(&%(%$(%%$ EA@2/-%##'%$'$#&$$%##)'&KGH$ '##&#!%#!&#!#>::0.-#%!!$! $!! 745754 # $ $  =89'%%!!644)&&%!!-++642@=>MJJ977401%!#522%!!'&&1//:87fjji,()1-.% /,)OKLIGHFBB<77511=:8!&!!'##%# ?<<.++($%(%%(%%$!!A??410'$#)&&)%%(%%)%%GCC(&%(%%(&%)&%(%&&$#CBA/-,'%$)'%)&&(&&'$$511EBB%#!(&%(%%(%%(%%$!EBA2//%##'%$'%$'%$'%#)'%HGF$! &$$&##%$#'###=9921/$ %##%!!%!!!400:87# # $ 977-))!##1//1-. =8:(%%521:98FCB=:<)&&0-,$! ecc×%! 745A>>EAAA?>JGG&$$$ !521865&#!(&%(%%'%$@=>(&&)&%)&%('&&$#GEC/--)%%)'')&&(&%)'&B@?$ & !& %% @::' %&('&4',A69&+++ +!'F9>4!+)++(((H:?%&%##5,/1), !!,&(986# # $ ! 6220-. # !!.++664!!=::$!!(%%?<=745<99<99+''×,A?>(%%:87QOM744'$$+''>:9%! )&%%! ?=:2/.'##(%%)%%+((B@?'$#'%%'##% #C<>'&(-/#4#+KAC:04A::CB@FIFJUMJ[Q_i`PbXRn^SubX{eXiXmbqjr[t\y\z^|]|\~jx^\\~ZX}XZ}euUsRnRmQhLzaIu_Rl_Tg]B`RA[MCMG?E?:96<66G:?')$!-!&/)+!(%%<99!!967,)) # #855$ !522GEE1..%!!<::,ë-++@>>612745# %#!855845%#!)%%'##A>>+)(&##%$+#=-4'1%7(.<9:BLF\h^Mr_QmWxZ[_ca____^i]\[[XWbԞgVXZWVVdZWWVWWV^XZWXXWZә]͕VVZWWݝWӗ]XU~SuOmIx`LhXKRL6<81,/.%($<051/.400$865(%% 2/0-))><9$#!ë6FBC966!2/.520%##%!!A>=.,+$!$$A27)5&)=99CXLSr_^zXaɓaٜaccʘ^\ZWW[\̘WWXZWXgXXXZZWcȗhVXWXXVe\ڝVVUWWWcWWVUUTXΖXĐSRRRPRVQRSRTUٚZTۙTˑUSLrWvdI^Q@FB812-#.%8.410/0-. 1/.'%$!745=::6ë$ /,,$ =99-+($ !B69-!8(.HFCTg\_tX^ڟ`\`^ZZZWZ_ȕXXZ\W[ڞ^˘WVXXZXiWXZWVWcʖeTXXWVVg]ݟVWWWWVcWVWUVUXҗ[TTRSRSXRޚRޜRݛQښQښRԕVOޙP٘MܚLޛMUR֔S֓UɏVSxWscC]P:98- %-#1(,-++0--+'(ë,-()0/.(&%%#!9/2(8(.JRKcp`bҚa_^Ӝ[XWX^Қ[ߡWZZZ\^͙XXZZW]ٝ_ӚXWWXWZjXXWVVUcȗeVXZVZWg\ݞXZWVXX`VVWXVUXԚZVUTVSSXSݛSޞRݜRۙPښQٖXPٗRחPזOՖMٗTOōLؕLהLٗMܗURۘUΒUTuTj\67Zp`[a٠b_ԛXWZ\Ҙ^ӚXZZ[`К[WXZZ]ܠ^ӛXZXZX^֝^՛Z[ZWZZkXZXXXVeŗgWZZWXWi\ܠW[XXZWaXVVVWTWٚ[TTUTUTXSڛRߜSߜPݛPܚOܚWPؖQؘPזP֗OږSRMؕMӓOӓL֓UM͏K֔LٖLޙTTӕTOnLUM1,.&##.,,×:67.))KIGEA@B7:a]X]ל]ӛWXX^˗\ߟXZZZ_˙Z[XZZ_՞_՜ZXXXW]ԛZVXWVV[iVWWXWUgƘaǖUWUWXUh[VWWXZWaWVVWVVVXȑTTRSTRWǑSޜRSQߞRߜQߝXQ֖QٙOזOזMږRTMٖLӒMӔLؖSOčMԕLғKוRM͏LܙQPy5#+><^Z[_ʖ\۟XXW^Ò\ZZX[aʗXWWXW_՛]۞XX[]ޟ]ޠedǘaןbϛa̚bʙdėhĕtjnnmklushjkkkivkgdcdecpaaaba`be\ɔ\Ē]Ñ[Ǖ[Ē[˔^ZǑVӗVԗTחSژPZRԔQPߚMܙMߙQȎSLܘMӕMӔLؕRQL֕MӒLٕQPÊMؖMٗQ'401E@@'$$iljk(%%742'%%%Iq]^ZXaĕZXXV^[ZXZ\e_۞aћbϚcʙdʙldcėbbe•b˗kja˘b˘aћ`֝^ٝcΛp[_ݠ]ߠ\ߡ[XheŖVZXZXUn_՜V[XZZWjZWXXWX]ޝgXܜX՛\Ӛ\ҙ^ʕ\˖d_]\\[[a\WWTSTXPΑOϒMӔKڗRQKۘMՔLؕQRMٗOՖTӔ465%!!/,,%!!ebc/-(('$#745&$$'St]WV^ƕX[]ٝb͘j`ϙaƖbŕbƗcėj`՝`؝`ߡ]Xc̙\XXXXVdǘ]WZXXV]ߡmUXXXXVjdɗWZZZZWobןVXWX[ViZXZXWVXdUTVVTR^X՚RRSRPXTːQוRΓRǎTV^yWX}X|WX}XyQQOΐOɎRKޙMؖRߛ>^WW]aћXXX]ޡb˙ZWZZ_ܡa֝W\ZZZdŗXXZZZXk]ZXZZVdԟmUXXZZWnd̛XZZWZVrb؟WZ[XZUi[WWVXZWgWXWVWS^˖]ΗSTSSRWǒZRRۙPژQٙOۚWQԔP֗MՕOӓOғUMӓMғMғOՔSMӓMٗLP0 '866HEEEBB-)+*j>99B@>A>=%##!@OE^ZZ^Ԝ^ԜXXW^ٝ_ӛWX[W`ٟ_ڠWZZZZeŘ[WWXZZk]XZXXUdОmTWWWVTobӝVVXZVSq`ڟTVVXXTi[UWXXWXhVVUUUT^˖\ɕTTRSSXɒ[RSڛOڛPٙPݘVQҔMؗMՕPӓM֕UMѐOӔOғLזSP̏OՕOٙSČ+$%!!:77:781..jëdba)&&&##<87(%&&JjX^Z[`Ι_۟ZXX_՝^ٞXZXW_٠\WXXWXeʙXXVXXXl[[\\^]kʚs^bcݡa٠eء`ݡunĘaۡbןcҞdϜgКaԝykŖdמcӝdҜeӞc֟aܠqb`_```\m\[XWXU]Й^ʕRRTTQU֗XQRPߜPݚOWOϓLٗMՕLԖMٕUMːMԔOғKؕRPōO֕MؖRҕ221 $!!400&##]\[ë/,+,''/-,:77(%%'Qk]XWa˚[WXV_֞]XX\[c͝cӝ`ߡb֠c՟gНi͚pc˘hșgėięgėgėztuuutpzuzzzzvsl™mnmnkrllllmjƚ{]TVWZVX\XX]XZ^XZaXX`Xs|hiihjhkl``a^__dZÎZVÏUĎRϔ[TQВPѓOӕLݕTOˏLۗLٖLݖRPMؖLԓQژ8E=!522% !&##'$%4&!!+('521744'$#&S}XVXe•`ԜaҜd˚gĕpigƗgĘiėhǗokØdϜbНcןbؠc؟k[]\\\[lZZXWVSgǚkÖRUVUSQo™bܡSUUVVRs_ٟTWVTURo?'02,,5+,4+,2)+0').!epXVUVVU[؛^ĕUWVߝVߜWؙXϖ_UДWĐXŐWU^\{[~[~Z}X~^uZ|VTSUSOՔM֕Q=\I200'$$'%%4bvtu$%!!510621511A27eg˜ihphdŗcК^ݡh_ZXXVdΚ\VVZW\e͚VXXXZWo[ZXZ[WmĚnVXZZZUrcءVZZWZUvcӜWZXZWVsG29955:65<55:548545',hq\WWWWV[ٞaŕSUUSSUۜ\PQRPMVËSǎLߙOٖL֒MՓUTQÌRTX}ZsVzWyXPh[1(-)''1..'$#!srrbàOLK2//@>>XTTTPPJHHI6=`\[WcŖVVXXdŖ\Z[XVgƘ\ZZZX]g˛VZ[ZX[nXXXZXUnƙlŚVWWZZUscڠW[XZZTvb՞XWX[ZWtI69964<76<66<659647(,hp[WXXXV[۝`ǖUVVUTVܜ]QQߜQޛRۚPߛVUOܙO֗OՖMڙSRLۘLٖKۗPˏRKٕM͏QҔM}d6).?==-((%! 1(]՛ZXXeĔX[XXe[ZZXXję[XZXX`d͛W[ZXWZoZZXZ[Voƛm˜VXXZZTsd۟XZZ[ZWvc՞X[[XZWtJ6=:65>77=76=65:667)-io\ZWXWXZܝaÓUUUSSUߞ^RSޞSޝQܙPޛTďUOܙOוOՖMؗRSLٖMӔMӕPˎSLהMғOGl (&&5211//B??HFF/,+0-,& @<<.+),&%8.4_ޡZXZdĖZ[[Zeė[XWZWhǚZWZXX^dϜZ[ZXX[rWXZZZUoƜlɜVZXXZUveڡWZXXZVxd՜WZ\ZXVuL7><76?97>87=87<778+.i}m\WZXWWXݟdSSUUTSߝ`RTߜSݜQܛPߛUĎVOޙO֖O֕MٖRTMږOӓMՔM͏S~K֓LғOޚOt% (%&2/0)&&(%%.# 500,''B?>-)),%%?8:aXX\dƘWXXZg–ZZ[XXlǚZXZZW^hϜWWZZX\qUWXVVQoȝi͝SVVUVRtbߢUUVWUPu_۟SWWWUSsK2:822<55954:249422&+gzk\VVUVU[dÖSUUUTUbSRQݜPݛPޛT̒WOޛPוP֗OٗQƌULٖLӔOӓOϑT}LԓLӔOݚP|' %$$200 -)+.P% !40/.+)B??-)),$%EFB_XW[a˙VVUWdʙWZZWZh˜ZZ[[Zbݠh͚[[\__aڟuĜejhhjgzĜvhӞkϞkϟlОkПhӟtʞnܣo١o֡oסm֠j٢skɜlślęmřmĘhɚ~eV[ZTTZTTXSRXSRXSRSHJrscݢ_מ_ל_ם_֛]۝^՛h[ݟ]ڜ[ٜXݞXޟXܛaSSݛSۛQܚRߛT͒WPPQߚOPϒSJLۗKٗLؕR}LؕL֕OߙR( %!!522 ,)(Pvonn%#!.)(,''=98+&%,#%JLHc^_ߡcќmdѝiƙkŘlØqaehge|vqšnĚnÙqoěqÚynoloĚnÙr{g\\j``i^^h\\hZ\aSUyik|nʝoślƜmɛnɜiΞhMT]JM_KP^JO^JP^KOXCG{kmrʟkОkΞk͞j̞l̝iӞ~hX\]XV_ZW`ZX`[X`\\]QTuveנdћb˚bəcȗaȘbƕogÖebadbk_``]]bb}m[m\r[sXyZy_xVWWTZxRQQ͏S+ % 1//(&&rpqvÐ]\\845GABPJI]ZXSOMVOQhlgmɜjřgʛkĚodΜgΛbԝd`mc=+@+2A+2@,2='bx\XWVV`iӠUWVWV^koh8+.>67?67?77?77810bRVjSVVUVQuL7>=76@99@98?98@98911n`bcSUWVVRtL6=:54=66=65<65:657(,gvi\UVVVUWbĔTUTTTTbSRRSߜQߙVߜ?B@$'((,VpRčRTT[xU~V~U}ZxJBFFAAB@@LJK=9<:98+'&^\]ÐÝiegJGGB>>B>>FBB1.-.#$M\R^VV\a؟UUV]Zsc9+.>98>98?:9>+1c|X\XXVbۡl̞W\XZXbnpj@46E>=C>=C>>E???97gX\kޤW[[[[UzR>CB=>E?>E>>E?=>76pcegXXZZZUvR=B@:9B<?E?>E?>E?>?88hZ\lWXZ[[UzR>EB=:F>>F>=E?>F?>?87pdgeWZX\[VxS=C?:9C==0-,/ &Rqa]ZWaޡcӞWXX_Zk]=.1@:9@::@::A+4_ZZ[XVdסlʜVZXZXcmog?67F>>F?=F?>F?>?78gX\kߥWZ[ZZWyQ>F>>F?=F?=@87qdegVX[ZZUuT>C@:9B=02kxk^XWWWWZe•VVWUUTcTTSSߝRߛWHTK$'$$&##%#!'SnOߚOՓMӓMוS~MϒOԕMؖS̑1//!642%!#%##%#!977þ>:950//++<87A<<2--0!'Trc^ZXaݢb՟W[Z`\i\=.2@<9A<:B<F?>F?>F>>@77gZ]iWXZ[ZUzR=CB==E??F?>F?>F?>?77reehVXZXXTxT>EA=:C>=B=87@99@99@99@89912oacdTVWVVSuQ8?<65?98>87?87?878,/kuj^UVWWVWdǘTTTSUSaTRRQQXITJ$! # #!OlMMڗLٖKޗSOԑLۘLۘQژ060/,)# #)''-++ICEMIHEA@PKKTPPJGCJ>@dxkgӠd͚dϛlęnęhӟiНhҞm֢ipgQFGTOOTOOUOOVAHniiߤiߥhhpѡsśi֡mӡkӠmӡkӟqբyysZQR^XW^XW^XX^XVZRSujltɝiҟkџlОlϟkϞhӟeUZ]WV_XX_ZW`XX`ZZZSS|rrsȞjҠj͞kΞkϞj͝gӝgW[]VU_XW_WW]WW]WVZOPvuh֠aӞbӞbҜbӜbќ`Кpa۠bמbמa֝`Ԝ^֚k_ɓ]Ȕ]ǔ\Œ[Œ`ȔX_X<56><<=99=:99-2XkVUTSZ{TTUXAFB400512B??865755=9:=98JGFPKKICCQMMVRQMIHLBCg{miўg˘e̛mngϞi̝i͝kӠpypVLM[UT\UT]VU\WVsklZKM\OQ\MQ\OPZKPjT[všhѠjΞlΟkΟiϞqСzzt^TTa[[a[[`\[a[[]UTvklvǝiϞl˜k˝k̜l˜gџhW[^ZXa[[a\[`ZZa\[]UT}tstśj˛mɛlțlȚlǚh͝iZ]^ZX`\Z_[X`ZZaZZ[QRyvgءbӞaӝaӝbԛaӜc٠hrjJ5>K>CK=BI>@==?=<:05[lWUVSZ{UUTWCGC612744CAA:87977?=<>:<844:56-'(<76A==1-,0!&Uve\ZU`ߡ`۠VXW\bpd:-0?99@88@98C>=d^^>66A99@:9A:9>87U@EkۡSWWWVbkme<02A::@::A<9A:9:44dW[hSUUVVRvM7==75?89?98@:9@98:00oddcRUVUVQtQ:@<77?99?98?98?889-0kvk_VVVVV[]td7'+8427116/06//1%U}hVRRROVJWM &##%! ##QmPLژMږLߗRLԓLۘLܗRۘ061.,,$ # +'&-)+B>=8442..A=:FA@7226(,Xvh^ZZb٠cӝX\Z`grh@46E@>E@>E?>IBBhaaB==GA?GA@GAAC>=XEJnנW[Z\[dnnhA68G@@G@?F@>G@@@99g[]kXZZ[[VzRC?>E?>?77qggeW[ZXZTvU>FA<>E>>C?=E>>?45mxl`VXXXX^`vg:,0=88=86<65:545$([jWUUSߞSXMXO' )''(&%(%%'SoOߛOӕOԕMٖUPБM֕MזRҕ451 4//&##&$#)''0..ýB@=:76510A<:HCB8217)-Zug_ZXcءeϝW[Z_gviB47E@?F@?F@>IBAicbE>>GAAHA@GA@C==ZEJoՠVZZZZeooiA68F@?G@>F??F@?@88i[]lWZZZ[VyQ=CB=E?>E?>F?>?77qghgXZZZXTxU>CB=:E?>F>>C>>E?>?25mzl`WWWXX]`tg<.0>88=77<66:645%)\jWSSRTZLXO( ,(')&&(%%)UsOOՕPՕLٖTOВOՖPؗS͒4./ !622%##&##%!!967þíJGF9544//>88IFE8428).Vpb`[Xcڡj͞XZ[`i|mC27F@@F@?F@?IBAkecE>=HA@HA@GA@C>>ZEIqӞW\[\ZdppiB78G@?G@@GA?G@?@88h[]kXZZX[VyR=CB=E?>F?>E>>?76qhggVWXZ[UxU?FB<>F>>E>>C?>@46m{l^XXZXX]`sd>.1?97=88=76<656&+]kWSSTߝRZKUM(!,((+'&(&%+ VtOߜOՖPԕMؖUMёMՔOؖT͑1.- 511# %##$ ?==íÝliiRKLIFEJFEMIH:657+.Ud[\VV`eԟUXX_ipA27F@>F@?F@@IBAlhgF@?IBAHBAIBAF@>[ELsўZ]\][dprkB79G@@H@@GA?G@@A:9h[]lߤX\Z\\VzS>EC==E?>E>>F?>E?>?77qggeVZZXXTxT?EA=>F?>F?>E?>@47m{n]XXXWW]ase=/2?:9?88>77=769(-dqXTTTSZHSL(#,((+&&(%$+VvMOٖMٗMݘTMٓLܗLߚQҒ-')# 8660--756:88a_`ÝÐdbbF@@RMM[WWibb_[Zb[\rtorÛoÚlȝpxÙlmikq{K>@OIHMHGLGFLFEleeH@?IAAG@@G@?B=:V?EpӟU\WZW_nri>02B::A::B<:A<:<54dUZiTWWVWRvO7@@88A<:A:9A98A:9:11oddcSWVVVQuQ9@=77?98?98@98@99:.0lzm[VVTUU]]n`8+.:659528429426$)crVRSSRXISL-$&1.-0--0,,2#']{WݛW͔Zɏ[ō]}VVW]{LCGFCBB@ALKK@==><<,((^^^Ðvuss1--954954JEE854<24X[Ugbbޢkۤmdd\GLeUWh]]jdc}vukddqjjrmltonton~tonxrpuposnmrml{lnsžxvxtĝzğ~jbbnhglgejbcicac^]{op{pʝoƝoȜmʝl˝hԡhV\^WW_ZX_XW^XW^XXZSR|rrtӣlݥmܢnڤmۣmۢjhW\_XXa\[c]\d]\d_^aXX~{m̜mĘm™lřkǚkĘlǙrxq\QS`ZZ`[Z]WVZTTWKMrzeŕhigcigbcWRRWRRROOOKKPKKXUUCAAC<>@777!)SraUƏRQΑU.$'! 20/(%%qpqvP5/.A<<>77QLK=77=24UTPbZZ`]e^@45E>=C==F??GA@IAAG@@mheKEEMGGOHGPIGMHGZGKvadeݣgܤgڣjzxWMM^VV]XW^XW`ZX\UTuhk{ÜkОl͞l͝o͞m̞jѠkZ^`\Zc]\b\\b\\b]\]WV~yxk\_`MR`OU`PSaPTaPU\HM~qsked_XX`ZX`[X`[Z`[Z\QSzzgߢc٠b٠aڡ`ݡ`ޡbgqgH=A.5cuXWߞUߞUߜR\ޜECF(##+'')%%%! 1--?<:## HcPLٗMߚR+ !%##522!,()P.5..C?><77RMM?98>57RLKd[\cdtjE7:ICBJEBJEBjdcKFEKGFMFFMGEKFErmkPHGLGELFEKGFJEBWBGvĚ\^^_\bttC69FA?F??F@?E???88eSWmUVVWWTv™O9@>77A99A:9A:9A:9924ojhRKJ=66?88?98@98@99911mgeQJI=75@:9@98A99@:8=/1op]WXVUV^bmb=.1?88>87=76=77:)/eyUUTSQ\ۛFCC,%'/+).))+&&612A>>%! '%$'$#&PjQOՕOߚQ(#&$#200 .)+.?98A<<822TOOB>=@99PCIe]^ad~qH7JEEJECJECJCCE>>hTXoܥX\[[[VyT@FE==G@?F@?F@?F@?@:8smmVPPB<:F>=E?>E?>F?>>78pjiUOMB<:F?>F?>F?>E?>B46qs_XWXXW`bj^>24A<:@:9@98>88?,1gTSTUQ]֚G>@-''/++.+))&&955?<<%!!'%%'$$'QpPOՖOPx&# (&&2/0)&&&$#c__^XWKFCUPOA=<=86L8@gڡ]_ajzI8=MHGMGGLEFoiiRLLPIIQJJRJIOHHupoWQPQJIQKJRKJOJHWCIv^bcaaez|J=@MHFLFEKFCKECF??hTXpݥX]\[\WyUAHC>=F@?G?>G??F@>A::smmWQPA<:F?>E?>F>>F?>?78pjiTOLB==F>>E?>F?>B46qv]ZWWXW_^d[>24A<:@<:@99>97?+1dTTUSQ]ӗE7=.)(/++.++)&&<86?:9&#!($$'$$)SyMߛOՕPKp)&%4100--A>>HFFà_Z[JECWSRnhhicca\[`MSnėba`jH4:KEEKGFJFCnjhXQQQKJSKLSLLPIHtnm\UTRLKSLLSMMRLKWCKzaddcbgzL?BOHGOGGMFFKFFGA@hTXrإZ][\]WyTAGE?=GA?F@?G@>G@?@:9snmWQPC=E?=F>>F?>?88nihSMLB<:E>=F>>F?>F?>C27ry\ZXXVW`\`X>45B<:A<:@:9>:8@,4eTUSSQ^̖E6:.))0,,/++)%&?=9=98$ &! #'QOPӓQ٘Pi7'.?=G@@GA?GA?G??@::smlVRQE==F@>F?>F>>F@??88ojhSLMB=>F?>F?>E?>E48q{[ZWXXVb^^W>26B::@:9?98=76A,4dSSRRP^̓=+0,''.)).)(,'&E@@A??401:76?<>PJIRLKE??G/9g_ceueQWhcanhgqml~|{zts|uu~vv{ts|uuqmlokiniglgejZ^oolkjg}P@EPKHOHGLGFKEEE@?bLRt٤V[ZX[TuʟR76A:9A99?88@98911ledKFE=66>88@87?97?86>-1ozXWWWWVa[WT?67C>>E@?F@>HA@J8?i]ڞ`Ϙ_̙aĕ^Ɣl^PSXTTWTTTQQQML_][TPPHCCB?>:77?58XOוLזQ?_K50/(&%(%$4HCCGA?MHHXRRICAK8?jgdcpȞWBIRLJSMLOJIjdbc^]VQP\VU_XZ`ZZzsrsnmjedpjjtnmvqq{tszzv~|}vv~xx~xx|vvzsrsnntuuŸxÞvÞvÞuqĝsdgg`_ia`haahaahbac]\|{pjie_^ga`g`_g__g_^b\[{zmhgg`_ibaicbicakdbk^`k˛l×ljĚmnrqkke_^c]]c^]`[Z_XXcTXsc˙bǖ`̗]͖WؚdE6::665110.,)&$FBA0-,$ %!!#7//WГPژOٗSݜ:I@# 622&!!'$#'$%ëurrGBAHAB\UUKGEK=Bisjhgsإ`PTVRQ[UUXRRnihmig[UT^XW^WWZTSrmlmggXTS[UU[UTZTT[UTzyXOQXOPXMOWKMXKLUGI{sr[TS[SR[TS[TS[TSVQPjZ]~ʡeiߥiߥjޤi٤eޢ~iW\ZTT^VT^UU]WW]WWXRR}uuga`[TT]VU\VU\VT[UTTMMyrr^WWUOOUPMSMMTMLQLJP?Ct\]\[ZWcVPO=54@:9?88>77944C.4b˕QRRRQ^9$+1.,1,,0,,,('JEF1-.)&&+'&%>??U٘MٗOٗS՗466 %!#511%!![ZZëj^ZX_[Za[[KGEJ>Aeqemijvh[]ZTT]XW]VUnjison^VVa\[b]\_ZXuqouoo`ZXc]]b]]b]\b\\b\\_[Z`[Z_XX^XWZUSzz]WVXRRWRQVPPUMMPJIdPU{Ϥ^`__^Wv͡XEJC=:E>>E>=C>==77qlkTOL@88B<:B<:B<=A=87M8?e̘STTUS^8%,4//2..1---)(LHG0++,'&+&'%BSISޛOחPܚSȎ.$'$!!966976400j)MHGZTSupppikc\]iddqjjtojj]TVa[[`[Znhg|uu`[[g`_g`_c]]vrp}xuc^]ga`ga`ea`c]]ga`c]]b]]b\\a\Z]WV||b]\[VT[UT[SSXRQSOMeRV}ˣ`caaa\y͠]IOG@@ICBJBAHA@GAAA<:tmlXRQC>=F@>F@>G??G@@@:8qmkMHGC=>F?>F?>C?>G48rWXXXWVbޡRFKA98C=77P=Ac՛STSTS`{6#+40/4./1,-/,)OKJ.)),('+'&%HiUSMܚPS1 '755GCCHFF0,.!)lheHA@[VU`XXg``xlná~Ч}׫|u}z_UVb\[`\Zibb~xxd^^ibbidbhbatqp~}gb`kedjdcjdcg`_mgeha`g``e__d_^`ZZgba^WW^XV]VU[UTVQPdRVʡbdbc`]yΡ_KPGA@JCBJCBIBBIAAA=9snmWQQE>=F@>F??F?>GA?@:9slmMGGC==F?>F?>E?>C??G4:qXZZVWVgנTAI@99B=66SEHcڞTVUTU^r5$)5102..1,,2--LHH'#$'##'$#&Rh[[VzXqcA9<42040/)%&FCBÀJFE^WVa\]TOM[IOy̡s|ܬخy{{z}yxojiojhmhgjdcrll}hbalgglgemggjdcrmlkddkddjdbibbc]]mgga\[a[Z_ZX^WWXTSeSXɡdgedc]xСbMRIBAKECJECICBICAB<:smmWRQE>=G@@G@?F@?F@?@:9rmlMFFC>=E?>E?>F?>C>>G49qW[XWXUgӚR65TKMaRTSQUW~g.#1.,4/.40/=87UQQ@<=E>=E>>A=86?98>88?97:11UUS_WXۜ\֛]ΙaΚj{nUJK[VU\VWTQPWRR[VV?<<:661-,0.-=77 $! (&&<:9$ &#!521(&%/ZTThaa^ZX_QT{xxzp^dnjiojimggsnmrnmvqq{utzy{xuxsruooqlknihp`eoolkgbz֤cQVJECLGFKECICBIBBA<:smlUPOB=:F@?F@>E@?G@?B<:qkjJEEG@@IB@ICBJCCKFFS>Eu_cbbdޢcqcQUa[[b]\a[[a\[^VVppmmǙeÖcƖaȖ`ʗaӜ\d]=25<5660/-)(=87B>>'$#+'&(%$855:87%!!'$#.,+754#'%$1..$!heeie`_yzked^UVt}v|zzծxglrmltootnn~zxyssztsztsytryssxrqvqqvrpsnmupp{ut|vu~yv|vv~yy|{||}}~}z|ǥãâ} vxtnnuppvpptootnnojiyrrojjqkkpljpkjqkjlgeojioiioihohinigoihsklzxt[`W^]W[TSXRSVJOP?Fj[_XSQOJHKGEIBAE??>/2]n_\STRQZOOM2(+50/50/0++GBB@<:,('.)()&$<88621&$#%#!5110-,41/FCB+))ilgejdd~~xv~svz{txuooyssysr{uv~yyzy|xv~}zyzyzy{vuvsrztsyqqupopkj{ykdckddhcbga_c]\gUZklkjhbz٧jV[LFEPIHOHHLGFLFEF?>snmWRQF@?IBBG@AG@?G?@A<9snmH@@B<66]WUH@?A:9A<.2aziXUWTS_ڝLBB5./61050/0++JEE964-((/))(&%C@?0-,%!!!:55<88A??JHF'$$977×]VVqmknjizz̪ulm{ut{ut{z}|~}||}}~~~}{z|vv~yy~xv{vuvqpplkqmlojinhgkedm\apqonlg|۬o\aMHGQKIPHHOHGMFFF@>tpo[TTF@?GBAGA@H@@H@@C>G@?F?>E?>C<>F?>E?>E?>A::`XXGA@C==C=>1..=98EAARMO<77+''1..×,kggtonnihnjiuyzho~{z~~~{y}|}{{z{uusonuposmmqlkniho`dusqoni}ޭq_cOJHRKKQJJOIHMHFG@?tpp[TSG@@HBAHA@GA@GA?F>=uooIAAF>?F?>F??E=>B<:WQPd]^@99E>>E?>E?>F>>C<<_ZZE?>C==C>=B=IGFZUUHEE=:92./724 ,''-+),)),ëoihuppqml|vvysr{pr~~}{zxsrytsvqqtonqllobexuspoj}sceRKJSMMRKJPJIMHHHA@vqo[TTH@@IB@HAAGA@GA@F?>vpoHB@F?>F@?G@>F>>A::ZTSc^]?88E?>F?>E>>E?=B==C?=C>=B=@>99?<<$ % 1//622% -++ë6{{rmm}|~zy{{~~~{{yss{utxrrvposnmpdg{xutqkyikSLLUPOSMLQKKPJJICBxrq]VUHBAJCBHAAHA@H@@G@@yrqGA?F??F@@G@?F??@:9[TS_WW?88E==C=76>88?99@:9@:9G19i\]Ԝ_Ϛbǖbʘo~`RV]XXSOOKFFHCBMJI+'','&'$$<87:77(%%'$$865-))#976B@?6ë{z{z}~}~zyvln{xurk|xjlPIISLKPIHLGGKFEC>=C==B<=E??C=<]VU^UVF?>LFEOHIRLKUMM[TSojiXSR^ZXb^]d_^a[[dUXqc͚b˘]қ[֛Z\l6&+50/2--/))B>>FA@.))0,+,''C??20-)&%&$$7450--C?>,((ë,|{ztt|utxrquqotoooiiyqqmhhnihnhgmgenhgnhenihpiirkksnlslmqkj|uunjhd^]c\\_[X^XW[SS[UTibbMGFOHHKFEFA@@88K9@`֛RTTRZXi]6)-9447221-.LHG>990,+0,,.)(C@?($$+''976PLL:88+('>=<,×|{~xx~~{{~yx|vuuppxloocgpadn^cl\`gTZtdj|{^ZWc]\a[[_ZW^WVVQP|vud_^UOOUPOTOOSLKQKJOJHyqqICBJECHBAICAHAA@98^WWSLL?77A:9A:9A::?98HBAWQP?76C<>GCCGBB4/0$ #×{z~}|{uv{zsonqmlnjikddd__snl}|XRRZTTWRQUOOSLJKEEzsr\VUHBAICBIBAIAAF@@JCCvppC=F??F?>A<9d^^SLLC=>E?=A=:QIIXRR@99B===45Z[T^UVVT`לK>B7007224/-2.-PKJ721C>?KFGURRMIJ611)&%611)''gedf~yxuqptonqlknhhhbbsnm\VU^XW\USXRRVPPMHH{tt_ZXJEELGFKECJECHBAMGFvqpC>G@?A:9gaaRKJC<E?>E?>B<:UOMWQPA:9C==C>=C>=?14_lb\TVUR_ƒA,1:65B>=KFFVQPda_PKKIEC722B??0,,(%%0,,976#B>=fü|{xrrxqqtompkkjddsnm^XW`[X]WUZTSWQQPJHzts`Z[LFFMGFLFEJECIC@OHGtonC>F@?B<:kdcOIHC=>F>>F??A::WRQRLKA:9B<:@<:@:9<)/]rXW\^\؜m^MS]XWVRQJEFOJIGB@-''.))0++HCB.)((%$642<88-))ý)|{xsqxrqtooqlllgernm`ZXa[[^WW[UTXRRQJI|vua\ZLGEMHGLGEJEBHBAPJHqljA:9F??E>>C>=C==@88jcbIBA@:9A<9A:9A:]OR>978215//0++LHG>981--1-,854@<<(%%510MJI'$#jhg)k}|~xxxsrztsea`ga`c]\_ZX]UUSML|uta\[PJIPKJPJIPIHMGFTPMtomKECQJJSLLSMLVPOVPOsnnXRR[US^XW`ZZc]^b\\snme^^]VU\UUZSRQKKRLI]QT=&/>-1=.1:12A<:VQP821:64954711UPP6201.,,''A>=E@@B@?GBA0,+865kï~}|{zztszyvppvppupouonqljsnl~~kedkecjedga`d]]`XXxrpVPOULMPIILFFICBE=>b\]E>=@:9@:9@:9>88KCCUPP>87@:9@99=76ICBPJJ821:65821<66KGF0-,>97HCCZUVA=<0-,1.-% ï}yv~xxzttuppqllrlle__d`_a\[^XW[UUTML}vva\[OHHMGHLGFJECG@@SMKked>76C=:B<:A<:A<:B:9jcbB<:C==C==E?>c]]C==E>>C>=C>87A:9@99<65SMLFB@600721944PII[VVPJJJECB??A>=)%$1,+-)'>}~}zz{uvvrqvpqkdcibbe_^a[[^XXVQQyye_^QKJQKJOIHMGFICBXTRnihC=>E>>C?=HB@`[ZA:9E>=C>=B?=@99WRQKEC=87?77>76:54XSRMGFRLKZTSTOOa\\C>>500-)(B??501.)(.)(>h||}xxytrxrpmhgjdcg``c]]_ZXWRQzyg__RLKRKKPJIOHGJCB\VUmggC==IA@G@?HA@F??MGFmhgB<F@?C==LFE^XW?88B<:A:9@::>77[USHCAKEEOIITOMRKKibbSLKJEE>98842PII4//50040.FBA:662/.rpphÏ}|~yxztsxrrpkikeehbbd_^b\[XSR{zga`SLLSLLQJJOIHIBB^XXlgeC=B=GAAQJJ6/0944721FA@KFF0,,2/.JEEQLJ+%%ebbÏë~}}yxtonoiikgdga`b\\XTSzyga_TOMTOOTMLQLKLFFd__niiLFFRLJTKKSLKSLKc]\ojiWRQ`\[`[Za[[b[[mhgga`VPOUOMOIHHBAJBCVQP>76?98?97<65PJIKFE:44:554//MJIC?>GBAKGFRLL!VSSëû~{zzssvqpmhgnhgmhgkeeg`_qlkuood^]e`_a[Z^WWZRRc]]e`]PIIQKKLGEHAAA<:WRRJFE@98A::A::@99PIHTPM@88B<9A<:>87UPO>87:55A<:KFF`\\KFF?88@:9+&$VSTû|{}xvvqquqpoihkddhaad_^]VUzutb][VOOTMMRKJOIIHCB]WU\USC>=C==F?>E?>B<:_ZXJECE>=C>=B==@:9UOMKEE?87?87>88B<<]XWPJIWRPOJJSMMHB@1,,50/611gdc|{ztsztspjjmhhidce`_^WW}xvd_^WQPUPOSMKQKJKEEa[[\VTHA@ICBHBAHA@C><_ZZVPPC>C>=`ZXE>=C>=B=<@:9?98WRQIBALFERKKQKK`ZZ_XWF??>88711QJJ844842610vttû~}{uu~yxqlkniijdcga__ZZ}xxe__WSQVQPTOLRKKLFEb]\ZTRHBAJCBHBAG@@A=88E=87@88=54SOLVRQKFEOIJQKK812E@@Ïk~zy|tpotonqjjlhgg``xppjdc^XW\VUXSRVQPPIHhabUMOJFCJCBHA@F>>F?>c_]B<=E?>B<<[SSMGFC==C>>B==@98\UUF?>JCBPIIRMKgb`IBB@=:710?97pnlk@~~}xxqmkpkjkgdhbaa\[toog`_XRRWQQTMMRKKMGFidbQJKJEBJECJBAGA@MGFb]\C<F>>E>=A:9ZTRE>=C?>HABKFEUPOleeUPMTMOGAAMIHOHF8215.,VPP@ë~}|vupkkojileehb``\[tpog`_XRQWQPTMLQJILGFiccMGGHBAHAAG@?B=>JCBPIHRKJXSQjdbSLMXSRUPPLGF`[ZSML>77>77<66[UUA:9<64vrrëlxrqupprlloiiibavrphca_WX^XW\VU[TTXRQojiVQQWRQWRQZTR\VTkdckcd[UT_XW]WVTMM`[Za\\B<=C>=B<<>87^XXMGF?98C==E>=F??F@?jdcMGFRKJUOORLKe`_E=<5.-FA@h×|}}xx|vvojimhgicce__^WW}xxjcbUPPUOORKLOIGXRQpjhHA@KEEKFFLFELGGqlkPJIVOOXRRWRPa\[gbbJEBJEB@:9IAAJBBTOL×.è~yx{utxrqsnmleesome__e__c]]`XWkdcvqp]VU`ZX]WVXSRc][oiiLGFMGFICC@:9_XWKEE=66=64KEC{zè.;ê~yx|vvzuttonuppniilgekddb]]~yxlge]WU[UTWRQQKJe`_d_]HBAICBG@?@:9]WVWQQC>=IBBHB@LFEXRRE>=a[[ê;2Ö}}}|}yyvqqysrledibae`_^XV{utibaVPPUPOSOMOIGleda[ZPJIQKKSLKPHGmgeLGFE?>E>=HCBxss×2l~yyxqqsnmqlk|{~yxmeeidbjdcgaa{yojia\[\VUUPOSLKpjjTMLIBAE>=A::RJJkecc_^l1Àvqqsonjdcd_^ysrica_ZW]VVb^^c_^~~tpoÁ1+iêêi+6`àà`6.OuÏÜíüüíÜÏuO.??????????( |||{{{yyxzzz~~~yyz|||}}~~~~~~~****************& }}}~~~~~yyyzzz{{{~~~ Ӽ̺ɮˈEEEEEEEEEEE):VhnonnnnnN'Ȇ)Ãƌ ǚƏċ& y~~uss[YY|zzPNO977B>?936)%%)&&.*+-**+*)'$$ROM656*(&,**.)*-)))%%*&%733?=>945jgfkhiWSTspq}|}(dT(Aȗijxwwgce[YZFDD988+*)$! .*+ZXX%!!&""%#"&$$+''+'&,'&,'',)*'##VSS965'%#*)'+((*')*&&*&(&$%%!# @>=PMO!# +)(745DA@YVUcbbăMLLLLE"sǧnnmPMO531>;:NKL!%# *'%/,*311.,,PNN`]^300755744:88?<:;?;;:88845422A??hee4113201//-,++'&%##,)&OML'$$211KJJiggvE{ŢƱhfgHEF20/%!!!]ZYA?@3//<::>;:C???<A?@:88_\]UST;89956846;79<:;;996334335212.-[ZZ@??301532421742=89=99:68945775?<<;B>?@=>C@@?<;@>><:;<891,,^Z[@>> " /-,BAAba`(`wuv:97&"#% %#"-*)621;::=9:MKKfdd<89>:::887446254//2.00...*++''b`_><=)&(+()+(),'(+'))('+('+'(*&''"$XTT966)&$+('*&(+')+&'+''+((*('*)()%%`]^D@B(%%/++0.,21.2/.623735;68975LJJcaa=:;?==<99522-++$""!#FBCnnlwvv7QON,))MLK<:91-/<89A<=@==:660,,MLH=99'#%IHGvvvŸ.ZZY856.***''MKIWUU854:78633/+++)(,)'.()+'%--,bab856+('+)),**.**,(*,((,')+')$#!765ebc-)**&&)''))&*('+(')''*''*&(+&&'##XVV:75'%%)&')('+''+&&+'()(')''*''&! KHGWUV! )'&+'(+((,(',)(,)),)*.)*)$$TSTNKJ#!!,)(+(&)(')((-++513944>98_[\>:9,))-(+300PMO}|{m TSOQ7440,,311<98622522\YY/*)+%%*((*)(,+*.,*.+)/+*%"!BAA]Z[*%'&$&%%&)(%+))-(),**/*,0/.+*'GDEdba732964965767887=9;=;;=;;><;<<;<99b__JHF=9;?==>>;>::?:9<9::76966865521LHIb`a.,,20.0...*+-**+()(&%)%%)$$&"!<9:^[\&$%+''-(),)),))-)(+((+&'&"#B??URR(&'635;894/0.,+2//IEEţT|ī|z{VTT+((0*,7244100++,)($!!B??FBC*&'.++.**,''(&%(&&'$%)''$""VTTVTR502:58>;>@@@CCBD@?IFFGEEDCBFCC_]^eaaGDDJGHEDD@=>A>=C@ADCCEBBEBADAAA?>dbaOKLAA?DBBDABCBAFBAC@@@>>A=?FBDHFFRNOkiiHGFKHGECBGDEHEEB@?B??A?=>;;865;99gde834+#%*%%*$$*$&(%&*)',))-+*-*)SPQ.,,)$$)&(+**110534.++/,-QOOddcŖmĘ][[HGEJGG*%(-),.++-('-)(-*)-*)*))VTU501&##)&(-**3//<87@=;=<:984494642320.,'(WUTTRS*&&,)(+)*+''+&&*&&)'&($%)&&)%&$!#XWV865'$#(%&)$$($%*&%+&&*&&*&(+(),*)733gdd5320,-2/.422755743<88>::C@AA>=EC@gdeZVWB>?EABB?>>;<9672/.-)+)&'$ DBADAB("#,***)))'(+(',**)&'2..HDE966TRRŨ^zQNN2--$!GEE521)&%.**-)).)*-))*((%#!=99b^^A>?DBBIGFKIIIFGFDE?>><:;521867^ZZ967*)(,**+)()''*&&+&'*&'*&%*&&# YWVLKL'$$,(&-)(,)(,))-*)-))-))+*)+))(%%[WW=98*'%-)),(*-(*+))-))+()*(),('*''/--fcd432%$#+(((&&*&&)&%(&'*(&+((+'(*((ROOVTT,))532;97>==FBBGFEJGIGFFC@@MJH[YX)%&('&)'&*%),''*()+&(&##D@A:88! /*,GCDyxxWOPNN)%%&$$$"!D?ANIJ*%&-*)/+,40/633856B@@GEEdbb[YY@==:88522/,,-*+**)+*(-()(#$844VTS0/.*'&-)),)(,))+**-*)-)).)),((($$`^]GED'&'+))-*).))-**+))-*(-*),)(,*))&&ZWW<98)'',))-(*-))+))+)),)),)(-))-()-**dcb>;<%#"-)(-((+)*+*)-))-**+)(*'))&%DA@VRS&"#+''+('+'(+&',(*/+,501966C?AcabRQPFDCC?>7243/01/..*)+%%/+,SQQ--,'&$&$#%##FEE3-55Qhgg989&#!%"!+(('%$411\ZZ976;89FCCHEFDBA=;;646623:77][[522&#"+)).**-))-)*-**-*),))'$#DB@QON-)',('/*)-*)-)),**,(*+*),***'',*(eab?<>*&&,))-**.)).))-**-**.)*-*).***&%ZXW:98)''-**+*+*+)-**-)*-*)/*+.)*-)(+()`]]FCB#"!-))-()*(),))-)*,()+)(.(()&%965VSS-**+'(-))*((,((,((,()*()*'&&$$KGJOKK,**735522:9:B??FCBFAB843GDCQON&$#)'&*&&'##"411fcdB'rB=>#!!+()0,*534643ZXWXWVA@>><=:871..+((*('*(('""B@@XVV-)+,((.**.**-)).+*.)*,)(+)()%%NLLMJJ)%&+*).+*-+*.++,)),()+(),))'$$/,,fcc855'"#)$%(%$(&$&$#(#$(#$'#$&$$'$$" YVU744"!!'#$'"%'$$'%$'%#(#")$$)$%($$'"#YVWKJJ")('+((+'),))-))-))-)+-)(*&'3/.WRS500)%$,**,*(+((-)(,)(*(),)*'&%=88ZVV,(*%#$*('('')&%1,+755=9:A??_^]GEE735401/**,&'$!><=nlmD|{{JHG;77"/--:67@=>EDAA?=LJI`^]421*(()''('&-*(.++.++/**,('RPPLJJ'$%-**.*),*(-+*-**-**,,*,((+')XVWHFF#""('&)%%'#!'##&"#'%%*&%-'')%%:66ief<<:3/0733964;:8<:9=99=::>;;>;;?<<<89b__JHH;99=<:9<::<88;878765332//[XXUSS)$%,)))(')'&($$&"#&#"$!"%"#'""*''SQQ<::&##-)),*)+)*,)),)*,)(,(*(&&1,-\XX<78(#$,))-)*,(),'((%%'$%*%&A?=[XY=88B@@DAB>:<754+)))''735611mllȅoDCC$!!EB@>:<=::B??D@B>;;733,(&KHHHGF)%%**,.+*.+*-,+.**.**+((3//\Z[<::($$-*+-*),)'*)))%((%&(($%"",)+a`_IEF1/0>:9B@?DA@GCCLIJMJLNKJTPPPLLXUUpmmVTUQOMOKKKHHNIJNLJOMKNKKKJJLJHIJHGFEgdeSQPJGEJHGKIILHKNIJNJKMJLMJKJJGLKJPNMeccfddJFGQOOQPOMJJMIILHIFCCBA@@=?867432XVVECD# '$"'&#'$$((&)'(+''+((+'((%&QPPHFF'%%+(),(*,)),()-))+())&&/,*SPP410)&&411;88?=>?<<965GED=;;966|}|Ʒr_]]'### NLLZWX>;;:650.,-+,-)*)$$3-.ZVX965)&&-*,-+*/+*-**-))-*()%%<99^[\*(((%%0-,300523642;87DA@JGHPLMXUTpmnXTVOLKMIIJHFIFEA>=@=<;:9832854.,,ECBecb412.,*/+,.)+.*)+*)-,)-)(,)(+)),+)(%%ZYY;99*'&,)(,(),*),((,)*-)*,**-)*,+*-*+NLL^]]+((421743633;98?=:@==$ #QOOų!ȩkjj875432=9:MKKQOO0,.,**.*)-*+,)*.+++('IFEROO+&',)(,))+().*)-)*.*,0.-511VRQgdcIEFQMORPPLJJEBC=;;<;:==<<:;744FECeac2./($%+((+'(+''+)(*((,('*''*('# GEDb_^,)*)%&*)),(*+)(*((,((,'(+)(*')*()&$%ZWX;87(%&*'(*)',((*'(+()+('+'(+('+)(($#HDD`]]($$*&&+''*(()&&+'(*(&)&&*&')&'%"#KIH[XY1/0644:89>;;<:9<8:B?@KHIPLMLHHSPPffd@?>21/0+.+)**)'+('+('+'('$#510WTT5/0(&&-**+((-('+)(*&'2/-VTT;88<991000.,[XWŸ;+ΘGDD321@<>754300VRR4.0,(*.+-.+*.**-*,,()/*+XUU<9;%#$//-422;:;B?AKGHQNNRQPRONkhhSOP945532.+**((*'(*(()&(*&(*(('$$HDC`^^+)*,((-*)+)*.)*-*),(),))-))-**&""LIK_^]-***'(-***)+*))-))-*),().)(.)),)*(&%[XY;77*'',*),)(,))+)*+)),)),((,)*+*))&$B>>dba,'(*%',))-(*,'),(*+)*+))+)',()&$#BA?`^^,**&$$)'()%%*$%)%&)'')&'+))2//955b`_WSSKIIOMLLKJFEE@==:663.0,*)($$PLLB@@'#",)).))-(),))+**)%%=::JFF'#%765?<:2/-622~}}gIzwv521:799560++$"!MJJJGE,*(/,*/++-()(%%)$&,&(>:9gdcDABECCMJJQMNLKIHFF@=<9760--/,+a]^200$!"-((.*).)*-*+,+*-**.)),*)*('TOOXVV&$$+*)-*+-**-))-*+,**-*(+*)-)(%#"QNN[YY,''*'',))-)*,*(-))-*).)),(),))*))'&%\YZ<88)'%,)*,))-))+(),)),)).().()+*)(&%=;:fdd/,,'%&+*)+)),)),((+((**)+(),()(##;88cba412'%%,))*)),(),)),(),)),()*&(!PLLHEE'##/++543<99DABHGFLKJIHH?==TRQYWX0,-)&''%$(#$,'',))+*),))QNP965%!!.**744:672--liiĎ\fbc51/0,-/-,,')+((633XST622+(&(&%)&&1./;89EABMFI]ZY`^^B@AA>>;672//)'%(%%)%%)'')&'?<=a_^*)'-**.**-**,*+-)*.+).))-)+-*(-)(ZXXQMN%"",**.)+,)*,)).(),**++)+))-))'$#XUTXWU*&'*((+(*-)).*).*(-*).)*+((+*),*((%$[ZY<98)%&+(*+)),(*-)*.)(+(*,)(*)(,))*''<88fde1./(%$,)*+*)-)(-')+((*)(,*)+')'$$420cbb;87&$$,)(,*)+((*()+)(,)).()++*$#!DA@XVV,''*&'(%&'$#&#$)&&/.-654;88FCCebcNMLGDDC??965/,,($#&$$($$@<=PMM)&%+((*'&,()/--511PMLĦY ˖|z{SPP544*%%/*-.-+0-+,()KFFFBC*&&721A>>JHHQMMLHIDB@:96SQP<9;&$$*''+'%+('-**/**.*+.*+(''LKKXUV("".++-))-(*,**.)).*).**.**,'(.+*b`_HCE%#".+*/*),+)-,+-)),(),*),)*,'('%%ZXWUSR)&'+(*-))-)(/)*,)),)*.*(-*)-**-*))%%\YZ;99)''+)**()**)-(*-)*.)*,((,((+***'&743fdd633'$$+**+)*,((,(*+()*)),*)/())&%-++a_`A?@'$$+((-))+))+*(,)(*((*)'+*('$#743_\\.+-(((,(*+)*,)*,()*'''$%'$$$"!OMMA@?753A==GFFKJJFEC>::0--.*+MKK644'%$,*)+**+''($$;89><::A<>+)'.-,/++.*)+('300[XWUQRB>=DA?GCD;8910/.+,-)(0--WUT/*+,)*/**/**.,*.*,.**-,+.,))'&\\\HDE(#$.*+.+*.))-**.*).**/*).+*,'+20/fee>::'$$.**,*)-)(,**,**,)(-)),'))'')'&\[ZNKK&##*'(,(')('+')*'')&&+&'+('+'')&&%##\YZ986'#%)&')''(('*%&*&'+&&)&'*'&)('($%200gde976%""*((*((+())((*'(*((*((-((+'&(%%\YYJGG(%#*))+)*+'(+()+()+)'*)),)*,'(+()^\]977)''+**+()*((+*)+()+))+*)%$#>;?p]|||)$&0,,NJI+&'-))0-,401>:9EDCZXX_]]6430,-,)*+)).**.**.***''CAB\XY*$%/++0**/++.*+.++-+).++-*)--+fcc855+((.**.+).)*-)*,()+((-&)+&'(%%744iff312&%%+*)**++'*.))-**.,+1-/10/0--530fecTQP532;79>;<@>>C@?C@?CA@CABCBAECCEBBC@>gdcOMMC@ADABDBCDACC@@AA?B@@B>>?>==:8953==?:660-,*)*($$0,+JGG%"#" fde/a^[[$!(&%LHK622/-/=9;HFDGHGB@>852SQPB?@'$"/,+0+,.-+.+-/++/-+)%%YUVKGG*#&.,+/+,.,,.*+.,*/+)/*,+)*855d``,(((&&*&&)%&*&','(++*/,-2/.212512IFGnlmA?@C@?JFEKGFPKKPNLPNMSPQUSSSQPRQMUSRmkk_]]QMMSPQVRRUPQPNNMIIJGHIFFIFFJFGJGFGEEfcbPNOHEFIFFHGGIHHKFFIFFMHHOMMTRRURRPNNSQPkii^Z[RNNSPQQOPUQPSPOOLMNLKMIJHEFGDC=;9ZWW^\]6545102///-,-**+('(&''$&&$$&$$"IGEUSQ%$$,)),*+,))-((-()*))+((,((+'&\ZZ655*'',))*((+))+*)+((+'((#&NKK>::2//=<:DBAA=>975,)'<98DA@&$"FDF3 ʐB?@ '"#DABLLL?=>FCDJGFMKJOMORNOTQQRPO\YZiefJFFLHGFDCC>?C@>=:98456353.0/,-,*'0-,[XX=99%! (%&'$$'##'##'##'"$%##&#!&""%#!"UTT3//&!!&"!%$"$##%!"&$#&""%#"&#"&%#%#")''VTTA>>'"".++--,100644544:78?=>?==DA@FBCWTTeedNKKPLLPNMOMLLJJIFGFDDD@A=:<9671.-@>?^]\'##&#"%##(#$)&%*)(*)(+)*,)+&!"PNNGED'$$-()*)'*((+(*+))+))%""A==OML'$%'$$-))967GDEGBD>;;TRQ421'#"200G³1.- .*+;66]YZFEC><<634-)*-'&.+*-*+MJIQPN)%&1-,0,*.+-/++.,+.-++''>8;a]_(%')%&)&'*&',)'/-+633=;;E@CHDE[YXdbaQNMRPPPMOLKKJHEEBC@>=<98955310.*)HDEQMN"&$%&$$'#$'%#)%$(%&*&&*%&)'''%%0-,\YY=89)$$,)*+)*+)),*+,)*,)),**-+*,))-*((&%YWW956+'',)(+)*+**-*)-)*,)),(*+(),))*('+()VRSDAA$!!+'&*'&)&'(%%'$#&#$$#"$"#'"#"633WTT.+*-+*2/.523956>:9@??EDDJEGLIKLJJSOPiggJHGGCB@<=9662//,)))''&&$(%##=9:YUT'$#,)++()*()*)(*((*()('(,*(XVT412+((+')'$%+'&2/.977JFFSQP311.++ $ {{{S(%$-((=::E@AZVUIEG.+*,((,**.++1,*0,+/++][Y967-)*0-,/,+/+,-**,((+('#QNMUSR512D>@DAACAAGEDNKKRONQOLLHHC>@TPQB@@21020//,--)*+('+&'(%%)&%)&&*''(%$PMLLJK&!"-*)-)+-)*-)*.*(-+*.+*.+*.*))&'31/][[:58)$&-*)-)*,+),)**(+,**-))-)*,))-()(''YXX854)'',))+()+*)-))-()+)*-**-))-)*,((,(&WSSHEE$"!,*)-)*-))-)*.()-()+*)+)*+()(%&301[WX0-,'%%('&&%%'$$(%#&$%(%'+((,**/--0..PNNA==A==FCDJIILIJHEEB?@>=:@<:<:9966`^].-)%"#(%'+((,))*()**)+)*#""JHIGEE(%%+)*,()+)((&%)&%-*)KJJLIIA<=766*&')%%}||Uhfe.))@=>YVU&#&.*+-**.++.+,332@>=401($#+('+'(+**0.-0//321<86B??IGFdaaUSRBA?=;:400+((*&&*&&)('&$%100WUU+)(+)(+((*))*)(+()*&%<:9GCD,))301D@B=::)%%OMMU\ZY><:B@?977-+*+&'B?@KGH+().**1-+.+,/+,.+,&"#XTTDBA+*)644?==LIJYVW_^]YVUJFGGCBXUV0..+)',(&,()-**-))-)+,))-**,)),)+XUU5//.)*-+*.*+-+)/++/++-,+,**.)*-**+'(]YZ=;:(&$.+*-++-*+-+*-**/+)/*+-)),**)&%966a^^612)%%-)*-)+-*),))-*++*)+*(-*(.)*,(*(&'ZYX745+))-)).(',)(-**-(),*),)*.'*+))+('+('PLLOKJ&$$+(**((-))+((+(),)(-))+)*-))*()(&&XVV;98)'',(*,))+((,))-))-)),((+('-)(&%%==<<9:'$$*)()'(()'*''*&(+(()&')%'&"#@>>HGF532ECBJJIMKLJHHA>?7540--($&VSS866&$#*((+)),()+()*'&0,,LKH410'%%+((623>;=?<;BA?U!QOONKL=9;/.--)+-*+1..PMO:76*('0+-0*-,()*$',*)412kfhPLNUQQYVVRRQJGG;:90..,%'$ <98NKK,)),*+-*,.++/**.*+.+*0++0+*+((631ZXX0,,.*)-**.)+.**/*+/-)/*).*+/**-*).**a\]865*''-)+.*+-*).**.**.++.)*.+)-+**(%<88^[\2./+%&+**+*).,),)+-**.+)-*)-)).)*+)*(%&[XW654*((-)*-))-*'-)),*),*)+)*,+)-*)+))*''LKJONN'#$,(*+(*+)).))-()+)(,)(+)(*)'+))%#$VSRB?=)&'+))+)(+))*((,)(+()-(),))*)('$%=;?GEDLIIGEEYWWSPP)'()''&$#'%$*('+()($&DBAGDC*&&+())''*)):66EAC<88V#IGGLII612*&'.,-0,.-)*>;;QKN+&',)'+&'.*+734C@@MLJb__a]_GDF>;;2./*&&)&%+().*,/-,)&$JGGGBC,**.++.++.*,/++/,+/+*.+*0*)*&&>=>B@>,''0,-/,,/.,.++OLK:57+((<96ECASPOURROMK@=<\[Z:87(##+(&-+(0,+1,-/-,0-,.-,-)(QNN<98-)(/++/**/++.,,-+,.,+/**/,+($$IFGONN+))-++.+)0+)/+*.,,/,+-**-*+.*+-*)654a^^-)),**/**.)+,))-,(/+*.**/**-+*.*+)&&A=?^]\1/-+''/+)-**-)*-**.**,)*.)*+)*,*)-**(&'[XX776*('.+*,)),()+**.)*.)*/))-**-**-)*)%%JHIXUU)'%*().(*,(),(),)(,))-*(+*(+()+**$!"MJJNKL)&$,(*+(),)(+)(+()+))+))+*),(()&&2/0USR*''*()*((*((+)(+)(+()+('+('*(&+((MJK744&#&,()*)(+)*+((+())')&$$$ HDDDAA:77JGHNMLLII?=<522(&%BA@:89*&'-)),)*,*))&&A??410:77W777,*+HEE/,+.,,/,-/+,*'(967dbbMLLURREBA?=<=:9522+))2.-PMM1.-/**0-,/-,.++.+-.-,0-,-)+521SQQ422,)(/++/+-.+,/*+.+-/++/*-/++(#$SPPGDD+((-)*.+*0**0**.++.,+.,,.**/*++')><<^[[)'&.++.)*.)*-)*.))-))+()+&'*&()''#! A=>ZYX)'#'##)%%'%%*'$*&&+&'+'')&'+((,)(,((("%[XW754'&&+(())')(()'(*(&*'&(&&)'%(%$(###B?@URS'"#(%$(%%(%%('&*(&+'()'()((*((-*)&#"ECCSPQ*&&-))+)),((+)*+))+)*+))+()*((*((.+*USR0/.)&'+)(*()+((-'(,)',()*))*(')&&CA@B??%!#+')+()*))+)),)),()*((*'&866GDC$ ,&'0--756987@>=JHISRQWUV+&(($%+)),)*+('.+-EBB%"!,**zyyU+')#!C@A:76-**-,+.)+523JHGgee\ZZ><;300.**.++-))-,)'&#FABQLL0++.,,/,*.,+0-,0++/--0-.*('=;9PNO0-..++/-,/,-.**.+*/++.)*.+,.-+*((VTU?<;,)'-)*-)*,'(-((,()-')-)*,)(,)(&%%DAAYVV'""1,+0./00/311956;97;87@??GEEFDCC@AWUTliiSPNRNMQNNOMLOLLOKLSOOWSSWUVYWVYWVZVWVTUnlm_\\YWVZWWYXWYWWZVWXUURPPLLLMKKOMLQMMPLK`]\geeDBCC@@EAAFCA?<;:669878463/00--//.(%$><<;;999568567454135333325315220.._\]?==400533532633622613743754955=:9=;<=;:RNOba`AA?B@@IFDJHIHFGLHHQOMROONJJQMMTRRLJKVSTlijKGHIEEHDC><<;^[[))'%"!(%$&##'#$&$$'&%)$%)'%,*',*+-+-:77c``<99>>=C@@EBCLIIKGHNLMLJIMLMKGIKHFFCCXTUTOP5226535003/.0,,-))('$%$#'#&&"#+''NJK965'#"*(*,)(+((*)(+')+'(*'()&'@==EBC'#$+()*(())(**)+*)+)(-**VSS*(&)&%876JIINLK?==GCD:65%"!,&'%#"Vī856&"!+)):77b^^SPQIFE756,))-()*()ZWY><9,+)0,,.-,.,,0+,/+-,)(743GEE3...++/,-0,+0,,/++.))*(%&$#+')SQPA==1/0:99?<<;_]^1.-*((/)*,)).)),**,)*,*)-()*)()(()%&-+*]ZZ,)'&"#'"#'##%$%'%&*((-**1-/331966<89QNN`]]DCCLIINLJPNNPMNQNONJJHDE@==7560..MJIA@?# %""&"#(%$*'&)))*)*+'()%%734HFG*'(*'(*()+('+))**)+)*'"#KJHB??&"$'%$(%%3//A??PLOVTT0--)&&"!,)*Q ɉ=::!A?>JHHYVWOKK30/,((,**0...*,845VTT/,+/,,/--0--/-,/,-/,.,)'><;HFF/++.+,-&**('*&&-('411>;;EBBROOgedOMKFCDKIIIHHIGFEBDA=><8864430/)%%B>@QNM(&%($%)&'+&(+'),+(0**.**.+,0+-/,+)&%\Y[B@A*('/++-++-+*-**.,*/+*/+*.+*.**,*)*''RNLSPQ(&%,)*/++.++.*+/+*.*+.+*/*+.+)-*+.++*('\Y[966*('.*)-**.)*/*+-**.*).+*-+).*).**($%:68][[2//('&-)*,))-*)-**,)*,**.)*,()+**+'(+((^\\652*'(-)).))-)**)(*''*')(%&'&%&%%$""733PNO'##,))/,+1/0743<88B=>HECJFEHEDA?@VRTZXXFCDD@A=;:3//+(('%#%##'$$&$$.++DAB/-/)&&+)*+('*('+((+((*&&643PLM(&%+)(,)((&%($%/,,MKKLKKA@@;98 2//DKA>@,((HFFIFECB@RPO1//+('/--0--1-,+&'B?@ECC.-+/-,0-,0,-/.,.-+.,+*&'IFEEDC&$%1./<8:FCEQNNWVU[XY[WUMLKQPOXUS31/0--2,-0+,-+)+)(*((+()+)(-)+($%LHHNKI.*).*+.+-/++/*+/,+/-+.**/*+.+,/*)+(&a__<8:,)(/+*.+*/*+/)+-+..)*/+*/.)-**-()*))PNMOLK(%$.(*-*).)*/*).*,.*+-*+.+-/)+.**.))+'']ZZ866*('.**.*+.+(-+*-+*,*).*,-*+-)),*)'$&956^\[411*&&-*(+*(-)*,(),((,*+-(*-*)-)),(*'%%[ZY<:8)('+*)+)(,*)+)(-(),*),*)+()***+((400TRR-()'%&(&%&$%)$%($#'#$)&&+(),(()&&<9302.*+CAA2/1$#$,'(*()())+((*((-(),''IGF.-.)&(+((+**+)*%""201JFH856CA?CAA,))3005/IGG;88MJJ@;;-'*GEDHFF+((1-.1.-/--1,-+&)PNP@<=-*,/,*.**.)+/**.,+1..=9:a^_YXWQOOZYYXVVPIJC=>64730/-,,,((DA@LJJ*&%-*,/,,/+,.++0,,/,-/-.0+,/-,,('ROOJFF,((-,*.+-/++.*+.+*.*+.*+/-+/,,.)+-+*ba`966-*(.+)-*+-*+.)+.+*/*+.)+.)*.**-*)+**QOQNLL(%$/*+/++-)*/)*.++.+*.++-**-**.**.))+''\ZZ856*().),-*)-**/+*.*)-*+/)*,*+,)*-***%$955a]]623*%%+))+)*-++-*(-*)-*)-*),*),*).(*'$%YXWA=IFFOLLROOa^_ONM322.**+'''&(('&)&&*''+&&BA?:88&%#**)**(+))+'(+)(IFG745'#&977GEE<99833xYWVMIIC??0,,,)*302TSS765,)*1..0..0+/.**410[XY511+((0,+411=;:LIIWVT\[Zba_ihfFCB6352/0,*),)(.)).++.,,-,,-*+JGFFDD)%&/,-0+,0-,/*+/*-/,,0-,0-,0,)-**VSTC@A*''/++-+,/+-.+,/+)/+*.++/,,.+,-+)3//ebb300-**.*+.+*-++-**/+)/*+.++/**.*+-*,.)(SPPLJI(##.**-**.*,.+*-+*.*,/*,,++-+)-++.*+)''[ZY966*)).**-**.*+-)*.**/**/**-)).)*-),)%%845ddb854($%-)+,)*,*),**.)+.*)-))-)*-*(,))&#"VTRGCE'%$-(*,'(,()-()+()+((+)),(),*)+('.,+SQQ877&$$*()+()+()+))-((+)())(+())%&.,+MII410(%%+((*')*)'*'&'#$&#$(&%*('IEHba_USSURTQONEBA744/,,*'(&##<::JGF$""+))+))-()*)(&#$?<=GEF+(()&&*));;:ECDA??p vvtQNM723+''0,.-,,B??QOO+'&1-.0./0-+*&*#!B?>\ZZ>9:HCDTRQ\YZXTVMJIB?@200631JGG,(*,)(/*-/-,1--0++0,+/+--**-,,JGG?;;*&(0+,/*+0-+0,-/,+/,+/--0,,.*)2.,XWW==;+((/+,/,,0+,.*+/++/++/,-/++-++,)'632cbb0-,.**.++/**.+*.++.+*/+*/,+.,+.++-)+,*)VSTNJJ(#"/++.++.,,/+*.,+.**0*).*)/)+.*+-++,&'\ZY957+().**,)*.**/+*.**-**-++.**.*)/*))&&633ca`:76*&%,+*,**.*)-+*-*)-()-().(*.(*-*)(##RPOKGI'$&,))-))-)(-(),))+)(,))-(),)*+)),((NLM?<<%##+))+*(-)'*()*(**)'*))+(()%&(('JIJ856'%$+((*()*((+*)*'(+((*)'$""865IGF)&'/,,?<;LIHUSSVRRLKI@==@=@VSR)&%$""'$$*(&*))(&'.+*LKJ0,.+'(,()%#$533CBAXVWp˅|<::>;:*(%2./0-.0,+QPN<:9,)*/+**&'/,+<:9HFE`\\ZXXPMNRMNFDD:88.+,(&&*&'*''?;;JEE+((0-,0,-/*./,+/,,/,,/++--+/--HED833,(*/-+.--0-+0++/,*/-+0-,/.+,'*533ZXX766*)(0+-.++/,+.-*/++/-+.,-.*,.+++('<:9caa/+)/**/,*/),/*,/+*.*,/-+.,*.,*.,+.++.++URQJEG)$%-+*-*+/,,/**/++/,*.*)-)*0)*/+,/-,,(&]YY976*'(.+*-)+-*+.*+/+..**.*+.*+/*)-**)(&20/_[]<98*$%.+),)+.)*.))-)*,**-)*-**,*).+*($$MIIQNN'"#+*),*(-))-(*.)(+(),(*-))-)(,((*((KJJFDC$##-*)+*),((*((+()+((,()*))+(((#$EBC<:;(&'*'(,)'+))*))+)(*((+(('$$2/-RPP2//%#"&"!$"!*((723B=744(''&##)'&'$#C???;<+(&,))+))'%$856/+,fbd`b-*+?==//+0/-1.//,,955SOO&%$+'(833KHGZVYYVWWTSZVV946/,,-**+''-('.--0//0.+/+,JFFB>=+(&1-./+,-*,.-*0-+.+*/,,/)*2/0LHH31..*)0,,/../-,/,,0+,/,)/,)0.,+&);78[WW412+()/,+/,+/-*0-+/,+/,*.+-.++/.*)&$B?@`]^+((.*+/*+.*+/+,.++-++/++.++/+*.++-**.*+RPPE@C'%'.+,/+*/+..*+.*+/+-.*+.*+/+*/*+/-,*(&\[Z976,*)/,-.++/*+.*+/++.*,/++.+)/+*.***'(2.0_^]=:;($&,*,,**-*)-(*-*).)*.)*-))-**.+*'%%FCDVTT%#$,)*.)),*)-*)-)),*)-().((-*(-)))''FEDLJI&$$-)),(),()*()*((-)(+))+))+)''##=9:>;:*((+((,(()((*().((+((*((*'()%&QLM;87(&%+(())('&&&"#%!#(#$+&'IFEWVTEBCROOROOA@?0/."!-)*QNN,****),*))&(0-.=:9# hee^F*%&:66FBB.**1--0-,+((A=>EAA@<=ZVW^ZZQNN=;9../;86LJI0*,.**/.-3/,1..0,.1,/.-+1..QNO957-**/../-+/-+/-*1-+0-,0--.(*524PLL0,*.,*/-+/-+0,-/-,0+,.*+/++0+-+'&@==ZWW2.-.++/,-/,+0,,/*,/++0,,0,+/,+/+-($$GDC]ZZ*().-+--+.+*.+,.-*.*).**.**.*)-)**((+((RPPA?@$""+'(,((+((*''+''+&(*(&*(&*'&*)'+'''"#\ZY643($%*&()&&)%()&&+&%,(%+('*&'*%(+%''$$.+)^\Y?:9&#$*()+(),((,)(+*(+((-()-)(,)),*)(%%B@?YWW'$$-**,)(+().()-)*-**.*)-*(-))+()*%&@>>NKL(&&*()+(),((,((+))+()+)**))*)((%$655=:;,&'*('*('+'(*(),)))((+'(+'*%""HDDCA@(&%*'(*'(+('*(()()*''%""854NJK+'*-)(945IGFSRPPNM977HFF/-.*%',()+*)*&%D??0.-urtůɠ:66%!"MII400-++.*+.+,322][ZcaaTQQ@>=3-..**-+)+)*GBAIHE+')0-+1/-1.,/.,0-/0.,/.,613RPO1../--0+,0-+1+-.--/,,1,-0,-,(*;89SPQ+)(/-,..,0+-0+-/-+/+-.,./-,/-*+'&EC@TRQ-*)-((.,),*+.))-*).,*.++.+).*+.+,'#$OLL\[Z,*'0-+1/,3/.500421733974<:7<8:@<;A>>`\]URSC>?GDDIIHKIGKIHMJHNKJNLLNLKMIJMKKNLKLJIlihWUUOLNPNNNLMNLLPMMOLLOJJLJJJHHIGGJGHGDCIFFjfhQLM>;9?<;<:::789675244014010-./--.***&'?::^\['#%,'(*(')'&,(()&'*&&+''+&%*''+'&&#"<::SQR+)))''+(*-((,*(,+),)(+('**(*(((%&423A@?+)**('))'*)'+())((*''*''*&($""=;>")$$vjOLL!?<=@<<,''2..<;:OKK`^^hgg300,)(-**0+,0-//,-0--NLL><=,')1--0-+0-.1,.0,-0.-0--<:9QNM+)(0.-0+-/,-0--/--1,,0,+0,+.+)E@ASPP*$%/*,.*,.))-)(,()+(),(',)(-***&&LIFVSQ0*)2..311423854<:6=<8B?=GDCKIHNIIKHGgfdjggPNLURQWSSURQWSRYUVZWVUTRRPOSPPVRRTPOSQPfcdVQRGCCIHFKHHJHFHFDFECEDCDCBCA??=<@;>@:;9677353100..1--*&%855RPP.++'$%('&'&&'%$&$#&$$(%%('&)()'%&20/IGG-++*&'*((+((,))*((*'(+'(+'('$%522RPP-))*&&*('*('*''*('*(')'')''OLL=;='%$-)(*()+(()'&$##533a]_QNOIFF753-,*&$$B<=511 :66<Bzyy! .**JGH<;:?;;NLKWSS=:9JGHIFF+'(1..0,-0--0-./**643TQQ511/,+0-.0--0-.1,./-./--.)*GCBJGG*('0.-/..0,.0-*0-,1-//---++)&&IGGEBB"+((.,*0..633977=;8A>;B?=A<>?>=\YW_\ZIFERPNSONVSSXUSWTSVSSRLMQMKOLKIEE?<<`]]SPO975<8876520.1-.10,/-*.(*,((,)(+(((&%+)(QNN:55$!!)'&,%&*&%*'%)&%)&&*'&*&'+)&+)',(('#$TQP521(%$*'&+)&*'(*%&*$%(%&(%%)'&'%$)%$&!#)%$WTR;::" (&%'$%)%&+%&+)(-)*0+,1..11/755866@==iggIGGDAAJHGPNONMMQNOVTUTSSYWUUSTRPQKHHPMNa^]BA?:87;9:;89;887554220..-*))&&$""'%&JHH-)+'#$)'')'(,((,)(+'(,)),*(*'(+))SSR1/-*%&*()+)(+((+(%)'(*((%"#GCDKIH'&&*((,*(+((*))+)(('%JIH200:78NKIFCC944A<=`]^VSRFDD968.*,'##XTT<66/,,0./2-,1.-0./0**B=@RNO,('//-/.-/-.2./1-.1./1--,)*RNN?>=,)*1-./..-*+,&&(&%)&',()1--421[YXUQQHDDPMMUQQWSSWRTVSRVRPQOMMLJDAABA?^[YOKI854:989447222//0+-.)+,()*'&+''+&'" RPPFDB(&%+()-*+.*+.++/,+.**0++2--/-,0.-.,,402ZWW>99,((1-.0+,/-./.,1,,/+,/++/+-/-,/.+0+*-()WSS965-+*.,,0--/-,0-+/++0,-0-+..*/-,/-,-*(0-,_][EAB)%&0)+/*+-*+.)*-),,)*,)(-((+(()'()&%*((^[\**(#!!&$#&##'"#($&+**0*+4//732764755=<;^]\DC@:77@=>GCDJHGNKJPNLOMMOLLLKIGECDBC_\\=;<0-.-))'$%%"#&""&$#*'',)'*)(%$#QMN<88*&&*)&,((,)'*'(+%','(%##936TQQ.++(&',))+)),((+)(($%B@@A@A +')4/1@>=OOMXUU0-.$!#~|}Ġ͝:77& CA@a_`NKK712.+*-*+*')=99USR0,-0--0..1.-1/./../-+LHIFDD)'&0.-/..0.-1.-0--1..1...-,TQP1..)%%-)(1/-977A>?KFGPMLWSRXTUYWWqomWSSKGGFCBB?>=:98534212///,,/*++)(.,+VQQ=9:&##,)(,(*.**-*+.++0+-/,-/-,0..0..*((VRRA@?.,+0+.1,.0.-1.,0,,/,+1+./,-0,+1++-),422\YW976,))/.-/,,0../,.0,./,,.+,.,./--/,.0-,,()VRT966.*)/-+0,*/++/.+.-,/-*.-+-+*0+,/,+.*)-,*ZYXGBB*'%.*+.*).**.+*.),-+*.+*0*+.)+-**-)*,*+\[[765*'(-**.+)-(),)**((-'()&%)%%($&%!"*''WUU;87$ !(&&*(',))-)+1.-500853;99?=;C@>a__VUUMLKMKKMKJGEEA>?:662//*)('$$EAAGAC'##+)'+)(*('*((*&)+'*(&',*)UPR504'&'*)'+((+)(*('+''20/NKK)'%*''*%'*''1.-IGFXUV;99# ,()św^Z[*$$LJITQRJGG.+*.((1+,0./*&(LIIJIH/-+2.-/.-0.,1,,0--.,-UQQ<88,+*0.-/--/,-/,,-,+-**.**643`]]FBANMLVSRZUVXUUURQOKKFBC>;8732754da^41.+)*.*+-*'+'(,(*-*+.*-/,,/-./+,522ZWX;88+()1-.0+-0,-2--3,.2.,1,-0.-0-.0,--)*[XW?<;.,,0-.1.-1/-1-.1.-2.-1--1..//.2--/++642XUR943.+)/../-,1..1.,0.-0-./+-0--/+.0,-0-,,))WRT:56.**/,,.*,/,*1,+/+---+.-*/+*0+*.-+/,*-)(URPGCB,'&/++.++/+).+*/-*.,*.**.**.++-)*-)*+)(^[[=:8)&%.++-*)*)).+*-**,)),*),))-(**((+((TRRB@@(%%+))*'(+'&*'&)&'(&%'&$'&&)&'# HGEGEE,(+1..644<;;<)%&+()+(()))*)(*'(,()OLL432(%#.*++())##.**IFGIFFFDD'##KHG=:9NJJ><;?<<><<.**0..0-//,,/,*UTQ>=;0,,0./0,./.-1--0++4./VSS/,,,+,.,,1-,410:88EBAPNL[XVc__kggLJJGDC:864012-,.++.+*1,+0,,-*)865^\[++).,.0--0--/.-/-,/,,/,/2,,0-,-+,735[YX653,(+1.,0-+1-+//,0..1.-0.-0.-0-+1--/+*a]\?<:.+*1.-1-./.,0/-3/03-.3.-2-.10-2/.1+,732VRS833-+*0.-0/-2-.3--0-+0.-//.1.-/.-0..0,-+(*UST867/**0-,/,,/,,0,+0++/*,0,,/,+/,*-.+-**,'(UQPHGE+'&/-*/-*0-*/,+/,)/+,/**/,)--+-(*-)*+('^\[@<<)#&.)+.**,**.*(,(),)*,))+*)-))*''*%%QQOFDD*$$-)*+)),)*,*(+))**)+)),))+*)%"!DA@KHH($%)(()&%)%&'&%(&&+((-*,312<;:KHHkgh][[ZWWRMMFEC:670.-+()+''" !AAAIGF)$$*&'*&)+)**((*(()&&EABA@@$##+))+)(,()*)'B?@854855GFE531lllƫLjWVVCB@2//0-,LHH544/)*1/./..,()975WVS541/,*0--.,++))+((-()A<=YVV2//>=]YY+'(0-00--0--/../.,1.-/-./-.0.+.+*;78_[Z60//++1.,0.,1.,1--0-.1.-1.+2.+1..0.,0.-]]\<890,.2..2..1..0//1..1,.1/.2--1--0//0-,733XVV733-++1.,0,,1-.3,.1-.0.-//.1.+1.-1..0-,.*)XTT:66.,*.-,/--0-+0+,.+*0+,/.-.-,/--/-,.*++&'UQQLHI+''.,)/,*/,*/*+/+*/*).+)/-+.,*/**/++*(&WTTA@@'#$-)*-**-**-)*+)*-))-**-*)-()-())#%MKJKII)'&,*)+))+)*,*),*),**,)***)+**'%#=89ROO*%&+))+((+))))(+((*()*&'*'&'#$($%VSS20/753GCBQONXWU[YXVSSLHH978DBBVTS-())&&&#$'$$'''+)))''865LHG*%%+'(-((-)*(%$989FDD($%-+*?=>JGH&,hgf411-)*-*+>;=IEF-*)/.-0-,0..,()HDDPMN-)))'%*&&1.-=89JEEVRSkgg\YXB?@KGGLGHB>?754/,,+(&,('(&"SONB@?/-+2.-2..2.-0/-2//4/-1-.2./.+(NKKWRT,''2001.,1-.1..1.,1.-0..1..2-.1+,?<;[WX1++2,,1--0.,3..2/-1-/0.00..3--2./0.*51/\ZY8642-.2-/2-.3//2//2/-1.-3/.3..0./1./.-+744YVW734/++1./0-/0./1//1/-1.-0-.0/-1/-1--1.--+*XUT;86.++1..0/+/--/.-0.+1,,/...-,.,+/-,-+,+((TPOKHJ+((/++/*+/+*/,*.+*.+)/+*.,+/+*.++/++,)&UQRIGF($#-**-*).)*-)+.+),)(-*)-+*.)*,))%"$HEGPOM+'',((,*),()+)),))-((+)),)),)()%&502WTS,((,))+((*(),()*()*((*((+''+))(#$SQR856$ !%!!$!!'&$0--=::HDCHFEJHGecbVSSLJIA?>612*()&""$ "-*,OLM4/1)%%+)(+))*(',,+JHH622)%%)&'0,,OMM"40/(&%0--/,.B>@<78+((1--0,,0-..,,PLK=99,')A?>USRb]_d^a\XZNIJeba=:9/*)-*)+''+)(.,+/-,2/-2/..-+XVT9651..1..2,.2/.0/-0/.1..1-/1//,)(VRSMIK.+(40/20.10/1.-0.-1--0./1/.1..1,+FBBYWV.+*1..0,.1--1--2./2//2/.1./2//3/./,*831`\\8630.,0--1..3,.4..2..0/.1..2-.4/.3/.0,+843VSS8430-,3/.1..2/-10/2/.3.,3.-0/-2..0-,0--.(*XUS<870**1--/.-0..0/-1.-0-,0--0,,0-,/.*/-**('QNMKHH,)).,+.+,0-+/++/*,/,+.+,/+*0*+/+*.*++(&VSSONL'$"/*)/**-*+-*)-+*-+*,))-**+**+))%"#EBCVUR-)),'(,))-(),)*+(*,((.*),)(,*())(,*+YVV0--*'(,))*((*)'+)(+())()*((+)*%##KHGEAB&#$,((+)(*')'$$##!$!"'#$% !VQSLIIECBRPPXVUVTSLII966('(C@@<99$#"+)**(*+)*'$$=99965,((,)((&%/,,~~qhKJG-)*0,,/--1.0@=>3./1,,2,-/-)*&"400b```]]]Z[_]]QNNB>?855/+,-*+WTS4/./,,1--2..1..3..2-.2.-0-,4/0YVV3//2-/1/.2..2..0..2-.0.-0.-2//-**[YYEB@/,*4/.2/.11/2//2/.2..1./2/.0.-0-+KFGTQR,((2//1.-1/.2..0/.20/2/./..1//3/./++754^\\5320--00-0..0/.3..2/.1..1./3-01//2./2+-734TSQ5431--3./3./20.1..1-/2/-2/.3..3/.3/.3.,-*)XVT;770++1-/0../--1-.0.-0,.2.-1.-1.-1.+/,+,()NMLKHG,)(.,*0+,/,.0*,0*+.-,/*,1+-.+*/**.+*+&'ROOQOM&%"/,,/+*.-+.**.)*-**-**/*).*).(*("#?==VUU-,+*'',)*,)*-)),))+)*-*),))+))*(('&&WUT622*(&-)',()*((-)(+'&*&(+)'+((($#B??MIK$ "+)(*(%*((+)(+((*(),)*# !GDED@@!,()3/.;98IGFUSRSRR][[PLL(%'&"#*''+)*)'&30/876+))+))+((+((4003lll0/+1//0,./,,845IGG-))-**-*+>88RNMhggolnLII9771//-++,)*,+)-*(<88WUT-,*0/.2.-2/.3..3.-2--0...+*<89WST/,-0./1--2-.4.-3.-1/.2/.0/.3../,*a_^=:90--3/-3/.3/12./5//3//3//3//40-1,*NKJSQP-)'2//1//1./10/2./2./1/-2..1..5/00*+:76WVT4103..40/3/-3/.3//4..3./3-/4/.2//20/2.,855VUS521/--3./2//10/3/.2./0..1//1-.4./4//1./.,*XWV;890--3..2/.1.-3.-1--0.-0-,0.-0.-1-+0-,+)(LKJKHH.*)0--/-,/-,/,,.,+-.+.-+/--/-*/**.+*+((KHHSRP'%".++.*+0+*.*+.**/)*.**/**.*(-**'##><;\[Z0.,*''+)),)),((+*(*()-()-)*+)(,(*'#$SQP:89(&&+'(+((+()+(**)',((-()*))('%966TPQ'##,*)*(')((*))+''*'(+(('$&<8:TQQ'$#*&&)$&'&%)&$-))2/0JEEeccYWYJGG643)&&)$$-,,CAA.*))(')('1./,(*LIKɲ966A>=-,*0./-))B?@EBB1-.JFG^[[b_^MJINMLNJK)#&.+,/-*0..1.-1./-)*@>?)$$-)(+()-)(*()*((+((+('+)()''2-/WUT))&*')+((*((*'(+((*('*(('''1..WUU*')*'(+((*(),'','('#$+))LKI;78EAAWUUTRRBA?/+,B?@2/-''&+))+'(>;='%#|zzZ=JHHA<<632+)'+('2/-]\\TRRTQQWTR@=<-'(+''SQPFA@+''1-/1/.2-.1--0.-,*(CBAC?>/++2-.1.-0/.0..1..1-/3/.,)'MLJKIH/-+10-30.4//20.3/.3//20.10./..:76eb`30/3./4//3/.3004104/040151041140/1/.XTSJGF*'&0--/-+0-*-++-**.*)-()/')0().))*#$<66SOO.*+/)+0)*3(+4*,4),8+.8-/8+.8+09*09,0:+0D8<^XZC47>04@25@26@16?17@59E7;E6:E8;G:>F8=G9>E6;f_`NEFD8>E:?G9=F9=D7=D6;C58A49@48?25@47@37<.3UNPTKN9+1:,08).8(.6)-4',3)+2&*2$)/#(/#'. )* #G@B\VW% *%&+#$+##*"$*$$)$#)$$*%$)&%)'$%!"2./][[521+('-+*.+)-)*-*)-*).*).))+((+**&$$JFFJFF&$$+))*()+)(*)(+((*)(*)),'),'*-((WUT11/(&&,)(+)(*((+(()''*)(*(')((QOO0,-)('+('*'(*''*))*')'%%HGG;89$! )$&:56NKKKIHQNNIGG.,+'%&&##534<::20/ nnm.+)EAB'$#521HEF\ZZgdd@;<0,,)'%-()/)+312[[Y944.+*0.-00-2/-0..0..-*(MJI><9/,+0,.1/-1..0.-2.-0-.1//-+(TQQC>?1.,3..30/4..2//3./3..30/200/-+C>>c`_2/-4023/13/.1.-/--/+,.+).)'-((-&'-'(\VVE9<0#&;-3>.4=-3A/6D39C4:F8=L?AM?DOBGRFJ]UVjddVMP[ST^XX`^[_b^cd`gjehmhinikvmjzoi{pnusw~~qxoxo|nnkmproqopp}ojmpnmkjkiiklkqq}g|eyatbsas`o`|l^tfZjaYh^Ye]X`[RVT__\okkRPOQMMKIIJGEGCCI15<,17*.2$(5'+`XY703$'!"'#"#""%%#'%$(&'+((+((-)+)%%B>@QNN'#$++)*()+()+((*('*))**)+&)-(((&&RPP<87'#",((+('*)'*((*'(*((+))'%%IFF623)%$*)&*((+)(+))+)(&##?<::YWU.*(1+.2..2/.1/-1.-1.,/+(YUU;770,+1./2..2/-2--4/.2/.0-/2-,YVU=9;2.-4/.50/2/03/04//22-5.-2//'%&EACXVV)$$/()0()4**6*-<-1@.4F59H9?M@EQHKWOQpnm`icbogmtkxgxjjilmmnn×qxmmřlȚjҡiաiסhأhؠe٠eޢfdcgƘw_ݠaa````^^\[]^[r`\\^]^_]\\__\[bg`_aa`bbcd۠eݠeܠdמaӝgpfȗe”dĖcŕchfbc~e{`u_}o\ugluoaY\QJKMEGF9;;'""-((,')+)(,((+)('$%634ONM-*+)''+))+()+((" KII@?>FDESOQ<79432551$ ̴]Z[$ NMMUSRPMM856*''NKK644/--0/+1.-2.0/+,GFDSNO+&%0.-1/.2/-3-.1../,+311[ZY5210..1./1-.1..3/02/.30,/+,413YVV7351--1/-0+,,)).)(0&).(+4*.:/2<.4\SUjadQKKZZW_hacvjfpgyi|hgihȚiȚrfНfgdbbcaa`^`^d֜l[\\]]\]]\\^^[c̙s]^^]^b^^_^\``]s_ߢ^]____]]`^]^[cēe^_`]^]][_\[\X\͖iYX[YZ\[Z]\]\ޢ\cge”edcdbwap_sh\lcW]XQONRKKc]`<158,12&*-$&(!#&!"%#"($#)&$(''(#%FACLIJ$""+))+(',((+((+(')('*((($%?==HDD%#"*'),&),'(*''+''('(**)PMM2/-)&'+))+*'**('$'?;;=<<%""520IFEQMMIIGDA@džW.))JGG]\[<<9.*++&'634TPQ.+,/.-0/,2.-2..0**IEDDA@,))00,0/,0..1/.1//,)(>;:YWV2.-2.-1/-1.-1,-0,,0+,1*+,$&911TMN4,.5+/;37F:>PGJXUU`ebftlkwnlxmg͚fןbߣcc_`a^bb`la`_`^^``a_`a^f˚m__`a`__b``^^^hĖv]_aa_a`^`_``_\saۣ^_a`^\]__^^`^d“c\``_]]][^\[^]_˗i\][XZ\[[[WY[Y\\ǐYZYXYܞ\ߜ[ۜ[՛]ј_ʖ`ēanydzazar]shZb]TVSMIIE=\YY2//,+*1,.+&'C@?KKI.++0.-0/,1.,3-.0--KHH854-,*1/.30.2..3-.1./)%%HDBPMN,&&.%(0&(2(*5*-:/2>47C<=CGCSZUkxphtkool˜kןgݤedd`kbњbab`a_`^^__aj]aba]`aaba``_gʙk__`aa`ac``aa_hĕu_a`_`_^____a_\tcڞ^_^_]]]_a^_`\eǔf^__^^_^\^][]^_ΗgY\\ZZ[Z[XZXYY_`Z\ߞYޜZޛZޞZߞYݝXޛZݛ[ݛXTڛe~V͒UޜYיXӖZ˓]ő^`bbx]}matigjhLNLE?B>599/36*/1')-$')#$& !1,/WTT'%%(&#*(&+()-)(.)(,')%!#A>?;88*%(+)(*('*)(*)(*((HEF0-/)(',)))$%743XUV:76ZWWWIEF;98EBB0++/..0,-,))NKK?<:0.,1.-1-.0./1/,4./YVW20/1,+2-/.,+.)(+'&-(*+$&RNNOCE?37KFDTXT]qgfwhhgǕdݠhѝj̛e`_]_`aa^bamc֝aba`a^a^^`a`ޢn]`a`a`ca__`_`iɗk^a^__`b`_``d^g•w^_^```^``_aa_]taۡ^`]^^\_`_^a]]fʖia__^^^\]]]\_[]֛g\[]\^Z\Z\[Y[Y_cXݞZߛ\ߜ\ݞZޜ[ߝYݜYܜYڜ[ڙYڝTۚdYVXؙWؙWڜVۜVۙUܛTۛUۛUڛXǑc\^_ayctcul]b^TPQI?D@6;^WZ6.1(!&""$"!&%"('%+()($$776B@?*&%-('+()+))*)))&&EAB?<>'$#-)(+()+(*=;<2/.957ľmkkB@?A<=0++/.-.+*41/URR4210--2.-1./2/.1-+;77\ZY'%$*$%,')3+-?04K&#"5 ^\] ;99HFE1.-1,,1..+((IEDHFF0++0**,('.(':.1L793(+<15PKNhpkoltf͙aa^__a^bΛhaa__baa_c`kh֠]^`ab__`cadݢk``aa_aa`c``agҞk^bc`aa_^___`^mja`a``````_``^kx^a___bc_\`bb_]ubݠ`c`bba^_abcb^aϘg`\^`]__`^^_\^]e_ߠ]^^Z]^][[Z\\[՚a\ݠ]ߠZ[ܟ\۝Zݜ[ݛZݜXۚXܜYܛWadWYٙYי[ؚZٚWڗU՘X֚X֘UטXՙ_XTۛUՖV֗TԗUԘTӘUҘWӕWԘYa{SՖW֘WӖV՗TږVڗXיTؗab{`d~q[c^EAC6+0.%(A:==::%!!*(),((.)'A?=865*&&%! ]Z['!#3.0KHF;66*)%,*).,)<88b[\gjfjyifӠca^m`bb``da_dÓiba_ba`bbcajfܢ^]`a`_caaafқj_^bb``_ba`b`hћi”`ccabd__aaaa\oka__bb___``aa]my_aaaab```a__c_vcܢ^]`da`_`_``_`cϚg`__^^^\\^^][_]b^ޠ][][\]\\\_]\[ٚf\ٝXY\ߜ]ߜZߟYޝXܜXݛYݛYښUݞ[fUޚWښYؙXٚYחX֙W֚XךWؙXחVՖ_\TܚX՗U֕V՘UԗYԕUӕUҔUؖYdxWΓUטSҖTԗU֕UӕUӗVٙY\PۛVҕZ͕[\z^xl_b^SOP1..*&')%&)$$654@<=*'''#"EBB^50.0-)+623><:,**20.GECVTSf]btjca_a`cܣm^c__accagg’a`ccaabd`cmbߤ_cba``caa_j˛kababa`a``ba`hΝfƖ]b`ab``_a_aa\pnĘa``a````bb_a^myZa`aa^^_^_^_c^uaߢ`_^aa`b_`db`^cМh_``a^^^\a`]]]^a[ߠ]\[\[]^\\][[]ܚh^۝[[[ߝ\[ZޡWޞWXޞYڞVޠ[Ñe~SݚYܞXڛVךX֙XؚWؚWיXזY֘Uח``TښWՖU֗SԗWӕWԕWԗWӗUזWŐbwUĎSۘRԕWҗUӗTҖUҖTטVa|TӗWוV٘TۛVܜX֘`gtkXNQOML?<=-**,'(745-,*+)()&&Ǩmll*'&-**2--FDBONL_\\^[\ICCIADbÔ`cdcb`f͛j]a_bb_`^jg˗_`a``b`b`blb^bca_``ba]kǚj`bba`baa```_gʚeҚ]`^b```^c``c\rnƘ_aabad`aa`^a`oyZ_aa`^^^`b_]_]wc___`__aab`c`^eӜg^``_^c_ac__`^^_\ޜ^][\][]]^^[[[d^۞[Z\\ޞ\ߞ\ߟYݞXߝ[ݞ\۟WޟZ̔h}VחYܞY؛YؚV֚WיYؙXיV֖X֗Vܚ^_SٗXӗXԗS՗TԔTԕTҘWԙS֘T̑byYRؚVӖXӖTԖUӗUѕS֗SȓaxSђVטTԙU՘W՘WݜYSi8)/C??VRSVRRKGH@>=)(&)&')$%USSoA==)%$0++TRQlghSPP?>=0-,'JMIk٣abeda]jg]aa```_^idӝ_ababb`cacۡj```ba_b_ac^lhŕaaa`^b``b`a`fɖbӝ\`aaaba`__`c^ri̙^_[_]\^_\[][\mxUX\[Z[ZY^`\Z]\ߞv`ߢZ\\^[[\[[Z\][aםdZ[[ZZ[\[\]^^^\__]^^]\\\\\]]\Zb^ٛY[^[ޠZޞ[ߟZܝZޝZޜZܞX\ДhX՘Xޜ[؛\ڛZٚXٙWٚWؚVטWזTߙ[b~V֕WיW֕V֗UӗV՗TәUқS՘Tѓa|YSܙWԖWҗUӔVҕTӗTԘSіa{WčTٙTԗV֖V֖SՙYߜ\}7,. ,)):66LIJa^^IGH*''%!!201V+'&A=;_Z[gedEAA+&&-)*0+*1!&QfZh^abcd^mf˚`___]`bakfڞbabb```c`hӝj`a_a``babb]lhə_aba_`^`___]cȖb֜]`a___^_^acdbwsjɛmnrustutuyzyxz{{{||{|}|~}yvxxttstrssstrvynmmnmkklkhgeǔdǔdg`͙\ڟ^ݝ]ܝ]ܟ[ݝ[ޟ\Z[ZZ\Ya[؛ZX[\ZZX[ZXߜXZԖh~YΓX[ܚZܚYڜXڛVךV֛XՙXטUܙ[c|TҕUٚVԘWԗYӕXӗVӖUҕSԘV՗_~\TۘVԗWєUӓVԖV֖VՖRט`[TܙW֗W֙XԙV֘Uߞ]?<;(!#)''(&$&$$C??[WXUQQ:88&$$tttϖeccLIFOMKA=834GFFFCCUSSĕ0YTS:66,)(953LHH/,,0..1../++5(.^|eae``ccnba]`_`a^c͚k`cbb_____]h͚iʘ`abcdݡfٟeМgΚkʛnp|pntrrtrorsnliњurgǘgɕhќfӜd֜bڠaߢ``__^^iʙ[^_`^_`__^`_\q{[____^_```_^^\}cӛ^]_ac_^^^^b_ZdΚp^\^]]^^\\][_a_jhƖZ\\]]]\^ޠ_ܜ`ԛbԜaқ`Ǖqfdggfhklmkkkiq|h~b```[WWǎX͓VϔSיWŏdzWɓPߜTܘVܙTٙUٛWיRԘVӘUؙ^`zSҕTԘTҘVҗWՖRӕTҖVٗX`|TؗW֘XՙVԗVӗVٛ\֙F`R*#,'(*((*''.++ECA.+*'##634FCCp3/0*'&/.,A<8;($&-)(-()*''0+,GDC.++*((-*+2//CAAR><;:550++0-+A@?LIJ.()2/..-,.*)/')`tbbݣgŘntvt{lbӚba```__meמ^`cbb]`_`aqf_a]_^_ba_]fڟoaaabbccb`a`_`te`_aa``a__ad_fءi֝]baababab``aaz}\ba^]__`aaaa`agΚ_a__`d]__^\`_eΛrb_^_`_]ba^_^^`nn\``^`^_\^_]]YfaŒ[_]]]Z[\^]Zޠ[deV[ݛYܜ[ڜ[ۚZٛZڜYٙWؗWڜUݚ^`YٚYיYӗWԕWԔW՗VՖWӗXזUՖ_}\UܗRזT֖S՗TіU͒VčXaxhsdxguex`}]WƐ^IKH'!'&%*%&,())'&FDC3//+)))''846*&'ă,}||644956/++.+*IGEA>=($$0+*421=::NFJs}qspkeЛ`]la_`a`a`__lgݢ`__`bbab`aqb`bac^_aa`^fءqaaaa```a`__aaxd`ad_abdcacc^i١jן_baa`_`aaa`a_{|]a_`b`ada`aeb`fΛ`aa_]ba`a_^`]dЙsb_aa`____^_]]]jo^``]_]]^^`]\[icZ[\]]\Y[\ZޡYߡYbfYZݝXڟ[ܞZܛXۚZٚ[؛XٙXؚSޝ_bWۚWךWՖT֗VזVԘWӗXՖW֘Tז`}\UؗVӖWԕT֔UԖVԙW֙Tۚ[[SؕWǏY_e{fwi{`caA=>534.+,(&&"A>=977+)(*&&310.)*[[['lRPQ=99410/--)%%LIF;77A=;WSRebbhcckbdudٟ`[^^beޤmcabbbacccofcab`_bca_dߥn__``dba`b`_hӝoa^baaabc`_a`c{b^baa_acbcaa\j٢h֟_b_``aababc`^~}]bbbab`_`bcba`gΜ`cbc`bca^a_`]gӛr_]``_a`^_]_`^\ln]`]_`__^]_^_Xgg\[Z[\\[[[\\ޠV`iXYݝYڜ\ڛ[ۛYٛYۚYښYٛY؛Uݜ_cYٙVיW֗YכWךWӖVӗVԘX՗Wؙa\RחT՗UҕUҕUҔVӖWԖVט[^}V֘XٜTژRۛQטRӒYfyoXPS[YZZVWMJI743>;;<;:$! +('1.,;86534.853?<<*&%/+*>99ifeeccfbbXVWGED610E<=iʙ]bab`ag՟lda`aba`_bݣpddb``_ac``fڢra_cddca_c_^l˛o^^aacbab``bac{aabbb``baa__]j֟fנ]a_`abac``bc`~|]cba^a^^_bbb_^hΛ_ab`_e``ac`a\dНt`___`^[^``a`_]no\a^b``__a`\[[gÕg\\Z[][\\[\ߞZW_ƒiXۛ[ߝZݙZܝYۚYښYښYٚYٝYٛTݞ\dXԘW٘W֙Y֙XԗWՖWՖWԖWՖSښ^^~VԘUӗVҗWӕWҖTӗWҖVחW_{UѕV՘XҘWҗX֘SۚTZp,"%/-,?=;PMMZWW`\]ZWW623'&%&##?<<'##ö|{{0-,>:9?;;[WVjhfgdeB?>634.*,-)*+'&PQMhأ]``b`_gΚkc`a`_`_aeןp^ac_`acbabhןpaa_bbb`aa`_lɜm–^`^^c_aa^cc`a{caaba`_bb_b_[lМfڠ]``a_`^b`^_da~|\baabcc`_a`cb\gϚ^__]`b`bbb`]\b՞ud__`___^`bca`^mpZ`]^]^]\_]]]]dŕeZ\]^\Z[[ZZ][_Ȕi[ۜ]ߜZޚYݞYܜXݜVۚXٛXٝXٚUޞ[eVԗYٛY֙VԙV֘T֙V֗VՓVҘQڛ[a}UҖT֗WӗWҖWҕUӔUҗW֘YÎ_{V˓W٘XԗXԗW֘VԚTݜ^5,.'##%#$(%$2/.<99a^][YYOMM855966&$$[YY kIFGMIIgdbVSR>;:HDCIGF*('/-,3./4010()[h`g``baa_iŗi^ba`a^_`fѝn_a`__ac```iϜo^`^`_a`bab_kʜmęb`_a_`a__db^d|ba_bbbb`_`a_[n˛fݠ__`a``c`a__aaz[bd_bcbdce_`a^hϜ`_^`_^_`bcc`_eםvc`b^aaa^_```a_m–q[`^]]^^Z\^^][fƔeZ]]^]ZY[Z[]Y`Ɠk[ؙZZݝ\ۜ[۝XۜWܝXٜZ؛XښWYŐd~XЕWښWؘSיWԘV՘W֘XӕWҗSۛ[azTϒSؗXӘUӗXҕYіTӖTؗXǑ`yXĎVڗW՘U՘WԘXӘVݚ_?89($$*)*+(()&'%"#IFF744967MIJ_][DA@1,.XUUe``=99-+*,('GEC@<<1--40.40/3/11'*a|mdacdbbbijė^ca``cb_hɚmZbaabaa_^`h̜o]`bcadcaaa^oŘmř_ab_^__bb_bbfܥ_aacababa`_`\m˝fޤ^```cab__``a`}]cb_`_aca_]^`]gЛ__```b_acb`a^eܞya\a^_babba`__anÚqZa_`\\_]__^][fȗiZ]]\][\]\[]ޡ[^Иi\ԚYZݜ\۝[ۛX۝XܟXܛXۜYښUݛ[͕eV˔UڛXיUטV֗VԖWؙYԚYԘTۚYbyU˒T֗WӕV֖VӗXҖSӘU֙U͒`{XUٚXԘTטXՙV՚Sڛ]‘HGE(#"+()+()-*))%&ECB976&$%(%'634]YYIFEOHHDA?=-))2./.*+QMK=993./3004003005).ezba`ace`lkȚ`a`^ab``jėo[bb_bc`a`_i͙mɚ]`a`bccbc`asĘlɜ`c^`_`_ab^bagס_^^^``^]^\]`WmΜaY]^]_][Z^]Z^\|[_[\\\\]_``^\]cј[__[]`^^_^[]\cߣy]ZZY\\]]]^`]Z\nțsY^Z]][[\_\\_[dќmZ_^^[]`]]]\Z`ҙi[әY]ݜ[ܝ[ڝYݞYۜWڛYښYٜT]͕gXʓUܛVؘWԘV՚U֗U֘U՚WԗVۚYƒexUƏS֘TԕXԖXҗUҕTӕUԚSғ_|ZRٚWӗXӘX֖U֘Sٜ\˔OUP)!#-(*-(),**)'&?==A>>($%-(*'%&;89>::^[Y20-DA@/,+1..1--USP7643/03//3001/-;.1ia`_a`ccngЛadbaa`^bkjȘ^c`a_``_`^jŘj͛]bb_a`_`_`_pǛhН^_^`^[\a_\^^f՞`abddcܢgۢfۡiآkڠkڡm֡iџzwsȝuƝvŜvŞvyxy{|z}|x{yyzz{{|}~|{{{}|zzyzzzyxyv{tśtϡrϡsӢqӣnբmբoנnաnաp֟n֡hۡgs{fқhϞfϜfΛfКb՜a٠`ܟ`ۡ_ڠ_ܞ][c̚lX[VXYYZZXYWX[כi\՛WY[YX[ڝZޚXܜWڝXZҗf~YÏUۜUؚV֙X՗U֘PԙTԙUԗTטZʒcxVÏV՘VҖRҗUҕYՖUԔWԗTؗ_ZSڙVԗVՕVՕV֖VؙYԘTf[)!!+)(+)),()*('866IEE($$.)**&'<:9$##XVUNGEC=:8>::0.-2--744SRP21040/40050/1.,C6:j`b__^_cpdמ``bababaniʛ`ba`__b_^]lěgѝY\]]`badeegvn–cߡiѝl̞iΝjȘjØor˜qqsv{y|}}|{{zzyyzyy}wyxyyyzzzyy{y{tgknfgohhqijpjkpkjqllqmmsnnsonrrorvptwrsyt}uxyxyxvvwwvvux{qojhhjgeddd`Ē_oc]՘\ә\ՙ\כZٚZ؜XܙWߚSSTߛdWǓUUߜVݚVܘVٙU؜XטW֔T֖WєdzXW՗UӕWӖUӕUՖTԖVԔW֔]ZUٖV֖V֘TӖUԕUיVٙXwf*"$,)),((,(**)(3//JGG*(&,)**%(;782/.976ʣ966A=<714300/,)@=1//400/+*GDCLJG20.40/410631/))SOPhԟ`_`^`\dr`[`_``dݞeӜkȚ|pmsuyxxyxwtvnƚmșiӝhПgӟdܢcca^cvg՟]b`c`_acc_`^mП}[^`^^]\_^]^_Xr^]`^^__^^^]^_`y[_]_`^]aa^`a_`fǗ_aa_ab`^`__^]aOBF?9:A><@=<:>;;?=;?:8=:8=88;66923ZNRy]_^_\]^^\\]ZZ`ܟlY_\_^[[]\\\Z\ܝjaœX[ٚYҘ[Η\З]͕]Ð]\__n}kufziwkulvjvlvkyj}h{c}lwa}]XXŒVőS˕RҔU՗QܜZ^~UטUיV֘V՘U՗V֚Vۚ_z6,/(('*)(+*(+((+()IEE4//)'',)(/+,?<=! poookl0,-HEF0.+411.)*LHGFEC200400621540-&%X\Yga\]^bajșulqvvz|~z{slʚl̙gқeܢcߢ`bb_^thܢ\_^]^ba`_^bqe٠]aaa_`a`ade\pǛ^dcbbbaaacac]tca`_a`_bba_]a`y\aa`aa_aaca_``hĖ^^^ab``aa^^^^eQCGB<E?>C?=C>=C==B=>A<=?<9:;55^PTy[_a___^_]_a^^`ڟr\^^_\]\\\^Z\[ޝiaɗXXXYޞ[ߞZߠYޟVߝWޛWߜTc]SؚUԖVϒV̓UĎVZ[]^|mujvgwhvisgugxezd|^c{bxXWŐU̔SѕTՖTؙQ[912%""*((+(),)**')DAC966('%+*)+)*BA?# RPPeRON40.D@?2..610/,,NKJ><:/,*.)).**1..3*-bkdk̝kΝlqtyx}vspjÖhϙf۟_ߡ_^q^^a`^`_cc_`xgۣ^c`_`edadbdp˜hڞ^`_b`_b_`bc[rÙ}`dba``_aabcc[w`^``_aaa``abb_yZa_``b`^_aa`^_jĕ```bb_^c`````eSFIA==F??D?>C?=D>>C=?C>=B==B==A=>::(&",)*)'(>==&&%:789ӓ;;9:54B>=0-,-)*)%&OKK>;:<87HDDTNP`\\idd||ttrolgΚbߣiƕm[]]]a`aacubb``ab^`_abt``cba^ba`accpÙhܠ_`_aa__cb``Yt{]cbb`a`aa`b`Zx__ca_`aba`bb^^xYb`aa_a`_```_`hė_a__a``baaaa_bTHJD==E?@E@@D@?C??B?>D>?D?=A>=B>=A=<<88]OTx]b`__aa`_`_`]`ߠs]]^\_]^][\[[ZlcV[ޠYZZߜYݜYݝ[ݞW۝WܚVgaWڙWژWטX֙XטV՘T֙V֗X֘Sݙ_]TؚW՘XؚWڛUښQܙTݚPR˒]vSTX\~_zcwetjsgdeXUUQOOGDE=::300><=@<=)%%(&&>;;20.)''ťϥ-**?<<331/.-B??WTTnlkb]\]YX_[\_\[WTSQFIl}a`_]^\^jΟp^a`aa`c`cv`caaab`___bva`_ba_b`b`_cqeޣ^a_bc`_a`aa]ty]aaa_bb_`a__\y_`a``^_``b`aa`wZ``cdca`_`aa]_fƗ]a_a__`cb``aaeVJJB?G@?E?>E?@D??D>?E>>D??C>>B>=C>==77\PU{^____aa`_b^\_aߟq^_^]_]_^\]^][idW\ZߠZޟXޞZޝZݞ\ܝXڛXڛTbcXښXٙYؙWؚVךX֘X՗W֚WՙSܙaaTԙSҗVԗVӖVӖWԖWӘTٚXɑazWɒRߛUٚRܗPڗU՗SѕYXWU=9:LJJQOORONQLMXUVa^^JGG<9:)('200875{zzșzww!OLK\[Zhffgeeb_^a]\C?=856734511.,+8(-f`^ccb^_lŚq]]`^bba`eߢt^abadca_badza_bc`aba__afp—d_`]`c`aa_`b`ry_aba``bb`_``]|^ba```a`bca`a_yZbbbcb`bbdaba_fƖ_ca`bcaac`abacWIMB@C?>C?>B?=>:8^OS}[_a]^`__a__a``p^_^^^^]^\[^^^hfWYZߟZXߟYݝXݜWۜXۜZڛW`aWڜYؚXؚWؚV֙XӘX֘W֙WҙSۜ^a|VՖVӖTԗTӘXӖUԘSїW֘Y̓axWU՘WӖWҖU՗V֚SۜW͔MYQ!'%%*(&-*)/+-99;USRQON\[Z^[\USTFBC[Z[ŤSlkjPNMsqpWTSA>>2//:66KHG6001-031/6302/.C38ja`b`^`_mǘmș^`bb`_bai١t]abbd``abae}`]````a`aaaflb^bb_aa^a`^_]uz`b``c`aabaaa[{^a_`^^_bbaa_a^x[ccabaabdaaca^hĕ\ab`bb`_aa`cbcXIND>>HA@FA@G@AF@@E?>E@@G??F?>D??C>>C@?>:8^OQ|Zab^___`_^`a`^r_^\_]\_]YZ\[[ggÕY\Zߡ[ޠ\ݞ\ߜZZݚ[ܛYڜVceUۛY؛XؚXיU٘W֛XՙWՙVՙTݜZb|UԖTԘWӖU֖TҖWљWӗW֗WӔ`zWS՗WԕWӖXҕV՗W֙XіTi^("#*)),('*''(%&.+,A@?+('.+):67MJKgddFACQMOcovtsIFFMIJ/,,2-.1,-<77GAB7335216217320--G:>k`ac`^``mƙlǙ_adb`_`aiףu]b^`a^``cacޡw_```bb`_cb`fk×aabdcaa_`_a_Ywx]a^aa`__cc`b]}b^a`ab]_aa`_`_w[_a^bbaa``_cc`jĖ_b_abca`bbb`_dYJMD>FA?FA?F?>E?@E>?F??A::\NR\`c`ba`_a_`_^]t^ߡ`\[[[]^Z[]ZYhf[\\[ߞ[ݞ[ݡZܝYܝ[۝XٝR_eUښXښWٚVטWؗUטVטUԘWԗSܚ[e}UҗT֙V֗WԖVәVԗVԗUؚTӕc}ZSؗTԔUғUїRӖX֗XҔVk`,!&)()+)(*(()'(/.-@=<.**)(')''*&&@<>@=<`^]ps;8;,((HEB40/5.14--=87D?@64151/5328241,-M?Bk_ba_a`amhʚ_aa`dab_hעt_a````bb^agڡu[a^_`a^`ca_bk•aab`a``_`a_b]zx_a`aa^aaaa``[|_abab`_a_`a`aaw[`abb`_`a`abb`iĔbcb_bbba``bb]cXLOE>A=:]LQ^^^]_`a_`^``\^y`ܝ\\\][\^_][\ZhjX[Z[\ߝ[ܝ[ݞYݝZݛZڛWahY՚XښX֛V֚VؘVטV֘Y֙WؙTۙWezWҖWטSԖWӖWѕXӗXחV֗U֗_[SՕWҔTՖUԘX՘W֘Yך\p2$)(%%,)*+())'(.)+>8;0--*(&,)(,)*754/++n&$#996<885/05012-.DA?HDE4237438348432+,WPSkӟdb__`abl×fע_a^`_ab`kΜo_a_`cb``a`jԡ{]aba_cbbab^`ocabd_aacbb`_\}sŜ]aaaab__ba__^`_aa`ac__^_`_au›]c`_b_^bec`^_^hȘ\_abcbbca`_c`b\NPF?>ICBHBBIBAGCAHAAFBAH@@HA@HAAF@@E@?A<<\MQ`^`a``]^__^_`^w`۠]]^`[]_^\]\\fi[[Z[ߠXޟZܞ[ޜWܞXܜYۛW^ʕhX՘WܜYڛWטXחWٙVיXיYיUܛWʑe|WіY՘VԕWԖUӗXԖXՖVԚSٙ`]V֖TҖV֗VԖTԙVטWٚZs7'-(%%,)***)*)'-)*?=>30/*&%-(),(*6331,,pnm,3srq$ ;76;874006134..FCCHCD7336357538642+,[UVjԞca`abb`jfؠa_``__``k̛l]bcbbca`aaiӡy\_`__ca`_a]dr–ba_a__bd`bab^s͟]dba`_b`__``[]_``^_a^``a`_atĜ[c`]a`bc`^__^^hƙ^`bac``_bba_^a\LPE?>IDAIBBIABGCAHBAHBAH@?GB@FB?FA@F@@A:;]MQa^`b_^]_`_]^_^v`ܠ]]]__]_\]\^]e”i[\Z\VܠVݞYޞXݜXޞYܛUZɕgWؗXݜYۛXٙYٙYךXכXיY֙UۙWΓg|UϔTՖT֖UՙS՗RҖUѕUҗUڙ]YU֗VҗUӖSҗRԘVՖUڙ\|;-1&##,))+))*(),'*A@?524)$%+*)+)(8543/.][[JD`^^$C>?@<<41/6112./MJKHFE4217559339543)+[c^fߤ`ab````hbߡ__ba_bc`l̛lƗabaccb]]b`iНv[`a```^]_`^eoŘ``]]^^`a^a_`Z|rС]^`_a^__^]_^Y~[]]_`___``a^^at›[acbbbcaa``_^^i_c]^baabac`^]`ڞ]OSF@AHBAHCCGBCGAAFB@FA@FA@FA?EA>E??C@?@;9\LO_[^^^^^__`_^_]qaߡ[Z\`_Z[[]\^XcǕgWZXYZXXZZ\ߞWZ̔gW֙WޝUٚXؙYؚYؙY٘Y֚W՚WڛVʓg|U̔TՙU֘T՗TזVԗTїTԗSۚXWV՘VԗSԖSԗV՗W֖Vۚ^=16&##+*)+((*((+'*BA@:67($%-+(,)(:86752MKLEIQNP$##DBA?<<71271120.PNMKGF5118348538546).blee`a`ac_ag”```^_^[^\jўiѝ\__^__^bb]lϞtZdb_bbccfcag֟tfܡgܢg۠iۣfۤd۠g٢jڡk֡lҟjϟm͞j̜áwУyȠ|ǟ|ȠzǡzŠzơ}Ơ~şĠ~Ÿ}}}|}|z{y~xw}xx|ww}xw|wv|vu{wvzuuysryypooononnkllÕjǗjȘdŗ{niɛhǚjƗiɖf˗eʖb͛cӜbҞaҝbҙ^Ԛjj\ٝ[؝[ל\֙]՜]םZךXؚYݛ\ݛXZɕi}WԖXXޜXߛWݛUݛWޛXۚUܛWߞTӔe{WҔUܛSژVۚXڛWטVיSژUޜZYV֖V՘XחV֚XՖX֘Xڛ]?58$$#+*)-((*'(+'&CA@=99'$$,**,)(:88964# <9;EUCAA)'(GDC?<;630542511ROMGCC5127438435212&*cofe\^]]_\`lecceehhߠfۡdޤqnʜdgܣhڡkՠlբjϝmȚnęoØrÚ|w{zy{~|rvsvqu~pv~puos~mp|kq{kqzjoyhnxglwej~{|{|zxyxxxxwvvquhZ]k^al^ak]ak^`i]ai\ak\aj\ai]`i]^j\^g[]h\^yp͠rʠuʜs˜q̟sɞrʟrʠs˞rɞu˝uʞq̡rŝwnojeclggmifngfmggoignhhoihpjjpkkokjpjknih}psoĘoțqřoÙoonqoqooom|xxwtstsrvuvtwzomoqrnjighhju{igffeccb__^jy]YYZĐ[ǓYʔY˒W͓Xי[YUՖTؙRחRؖSژSۙSY?8;!('&*''*'')('C@A><;(%$+)*+*)=;:>:;$!!2/0Ey8640,-IFE=994101..0--OMJ<98.))50/844;96A69juonʞlПoĘqquyx}{||z{zy|joi_i`_c_]][^XY_ZW_WX^UV^ST]QS\LPl]aoԡpўoҢmץnעlڢk٢kܣlڤkۣdkآ{hڡegݦgeceeba``\dWYF>?HCCFCBHBBHABIAAGA@FAAFB@F@>F@?D??C=<{glW[][ZXZYZ\\[Y[eZ]=96E@=EA?F?@F@?F@>FA=E??D@?F@?E?>FA@D@>E@?~~fӟ[[[YY^[[ZY\\[^WJO?98D=>\LQ`_a_b`^_`a_``[td۞]`^`\^^]\][ZdhYZ[WWXZYWWVVds,$%)&#*$%)%$)%$)$%+$%+$%*%%+#&' X^ZZÑXːVƎUVYWYZ_|aw[}]{a{bzbvcvcvi}sieh_\\`^__[[\XYSPQYWXSQQ;78412-'*21.=99%!$ 2.-OLKmkkokkolkpmlpkjwrsgccYVUVPPPLLHFEK;?n|ga```]^_nʛ]]_^_\]^^iM@EA?=FA?GA@GABHABGBAGBBHCAGCAE=>dX[v͞]a`bb__```_eޣwdaca`aa`abaa\dWZHCBMGGNFFLGELFGMGFMHFMGGLGFNGGLGGLFDKCC~ms_bcacbb`a_a``bj_aFA?MGGNHGMHFLGFMGGNHEMGEKHGLHEMFFMIFKFDKEFi̛_`aa_`babbab_`_PTHC@LEDKDGKDDJCCKDEJGBJECJDFIBCIDAIDCF??^LSc^_]`__a`__`^\ud՜^__\]`\\^^\\fk[[[Y\ߟ\ߞZޞ\ݞ[ߜZޛXZߞfv4,,/,)/,,/,+.,+.)+.)).)(+**++)( !V^XZϕTݛTښRڙRٙS؛TژUחSߛUVT֖UڗUؘWԘVЖWДUѕYOMM1,-=88A<'#"qnpe`aheffcbOIIA;<:66<;7UQQ>7:20/632841630>,2kvb_`_a``bqřa_b`^^`cahL?DD?>GAAG@AGB@GBAIAAIBBHCCHCBG>?cW[t˞Z`ca_``ba^^hݢxc^`cba_^cab_^bWYIDCMFGNGGMHFMGFMGFMGELHGMHHNIGMGHLFEKEC~ms[`cbc``_`c`a^bi_aEA?MIHMIFKHHLGFMIGMHHMHFMGHMGGLHEMGEKEDMFGjΞ`c__`bba_`_c^b_SVIB@KFELEDLFDKDEJDEKCEKDCJDFJCCJCBJDCG@?\LPa___a^^`^``aa]vfҜ^^_]_a\Z\\]Xcl]\Z[[ߠ[ޟYߞZߞ\ߜYޟYߞ[ޟgv5*-.,,0-+0*,/+,/*+/*--+*.**-*)'#$V]Y[ɔSؚX֙WԕSӗVԚWԗYՖVښXZWԖV՘T՘UؘW֙X՗Wݚ[̒KRM#*'&*'&(%&&##955EBA+((0--523A?@VTTZXVWTT~~,()500B?>5224/0500>99WUT?<;842;66<75753B16lwcba`a`_bqÚ``b^aacdahN>BG@>GB@HAAIBAHBBGCAHBBJCCICCE?>cY[s̟Yafda`]`a`^hۡwa_bac_`bbac]_bTXICBMGGMGGLGHNHFKHFKGFLHHMGHMGGMHHKGEKFCot\d`_b`bbdbbc`aj^`FA?MIGKGGLFHMGGLHGMGHLHFMHHNFFLHELGGKFGMGG~jΝ`b`a__``_aa`_a`QVJABKFDJFEKEELDCLEEJCEJEDKECIDDIDCKEEF?>\NQa_aa_^^^``_^`^ueѝ^]^_`]\]^\^Zdƕi\^^]ߡZZ[ݝZݟ[ޝ[ޞXZܞgv6*.0**0,-.+*.-*/+-/+-.-*.**.**(#$V[YZȓV֘W՗WӗWәXՙV՘V՘UܜW]XәT՚VԖU֘X֘WԘVڛZ˕OXS(!+)(+))*()'%&744FCC+))*)')'&.-+<;:'%&&"#fecvss& =:9LII:65642511?99YVU?;<834=77=76:42E39g~cba`_`_eu™aaa``^adbmO@EF@?HBAGAAHBAIABIBBJBBHCAIEBG@>d_^oԣ[_bbdc__ac`kסxc``b_]bdabb_`bUUJDBMHGLHGMGHMHHLHHMGGMGFNHGLHHMHHLFEMEDps_cca_abcca`aacj^`GBANHGLHEMGFNHGNGFMGFMHFMHGNIGMHFNHHKFGMHGk̜`b``a]_cdcbb`a`QVGDBKEDJEEKFEMFCKFDKFCKFDLEELFDJDDICCF??\LP`]_a___bb``^a]ueќ^]``_\^]]^_[bΚh[[\[\[ߝZ[ߞZޝ\ޚXWܟiy8-0/--/-,0-,/-+0-+0++/+*/++/++)$%UZW[ɒUؚWԘT՚VԗWӘTՙVӗVۚZ^~XӗUטTՖTԘTՖWՖTڛ[ɕQZT'!+((+((,())%&736HED+**+)(+(&21/GEE/-.!QNMmkk'$#A<fc`mޥ]^a`bb__`a_kؠwbb```]bc^dea_`TVIECLHGNGFMGGMGHMHHMHGNHGNGFNGGNIIKEFMDEos\``a_`ababba_bi^_FAANHGMHFNHHNGHNHGMFFMGHNIFMHFNGGMIGMGELGFj̝^`aac`bdcc``_baQVIDBLFFKFELEFLFEKECKFCKGFLFDLFDJDEKDCG?@]MQ``b`a_`ca^aa`]ueЛ[]`_]]\\^]\[bКg\\[\ZZ[ߟZߞZߜZݜXXޞjz:/30--0.-1.,0-,.-+/+*.++/*+/***#%SXTZɐSښVՕWיV֖V֖V֗UӖRښW[{VҕX֙VԙVӗT՗UטTؚYʔS]V)"*)'**(,)*)%%843GFE,*)*'(,('0-/C?@0..$ URTYWW+'(@=>JHF954855532C?>YVT>;::63:77=78844I7?lb`a```aev`cbb`aaa_lL?BGAAIABICAJCCJCCIBBJBDICCIEDF>?fdbkܦ^cbbaba``__iסyb`aaa``a`bbb``SUJFEOIHMHGMGGNGFNGFNIGMHGNHFMHGLHHKEEKDEps_b^a`ada`abccch\`F@?MIGNGHNGFNHFMGHNGHMHGNIFNGFNHFNHHLFFMGGk͛``````c`aaa`^_`SWJCBLFEKEDKFEJEFLFELFEKFEKEELEFKFEJFEG@?]LPa]`a`^`a]``__]tfМ\`^\`_^]\a]\dϙi]Y\[[ZZݠ\ߠZZޞYߟXޞl}<230-*2.-1.*/,*/,..*+/*+-++.**+"#RUR]ǑVښXӘY֗X֖V֖UҖWҖVܘX[|TϖUӗVՙX֙WטV֗VؗXʒS^X)!"+(',))+)('%%733HEF-***'(,((/+,<9:/..&""JGHYVU+('@=LIFLHGMGGNHGLHGMHHMGFNHENGGMHFMHGMFEOGGm͝`_^_`cd`b`aa`^bTVIDDLGFLFFLGFJGELFELFEKEDKFDLEELFDLFCG@>]MPd[_ba`^\_^___\tfϝ^`_\`]^^^]_ZbЗg\[]]ߠ^Z\ߟ]ߠYZޜ\ߝZݝo}=262,,0.-1.-1-,1+,0++/++/++/+,(##QRO[ÎVڙVՙVוUՖWԖUіWҗXٛZ\|UЖTӗWԕVՖW՗X՗W٘[̔T`W( #)((-))-***''542HHG.,+)''*)'.,*=:;/.-'##<9:^YY,''@=;IED864844822EB?VQS=77;77=77>98944L262,-0.,0.,1-.0-,0+-0+*/+).-+'$$OOMYŽUٙUטSؗUԖXәUՖUӗTڜWƐ\|UЖW֚XԕWӔXԘY֗YؙZΖTe[+"(('+*)-)(*&&311IGH.+*)''*((/+,@;=0--(##522[WX-()A=79;76=97>99844M;Bocaacaabft›_baabcbc^nP?EJBBJCBJCBIEBKGDKEFKDDJFDLFDI@@igemܥ^bd`^a`ca_]i٤wšbbaa`b`_bbb```SUKCEMHGNGGMGGMHFNHFNIGMHFNGFMHGOHGMGDLDDptà]aa``aab`cb``cj]_GA?NIHMGHLHFNHHNHHNHFNHGNHGNGGOGFMHGLFEMGGm̝a`^^a`aa_```^`cTWJCCLGENHGMHFKGFLGFKFEKGELFFMGELFFKEDF@B\LQc]__da^`_``a`[vhϛ]^]^]_`]___XaΘi]]][^]ZYߟZߞ\ޟ[Xݝn>470-,1/.2/.2--/++/+*1,-/**/+**$$LNJZWݛWؙV՗W֗X՘WՕVՔSؙWǒ]W̓VԘW֖U֘WՖXԘXיYјTl^,#((',*(+()(&%2/.GFE0.,(&(,'(/,+FAC402&$#966TRP.'*D@@MJI956966762GCBZVV>:7;66>88><9973N=Ap`^aaaa_es]a_`cbacapPBEICCKEAJDBKEELFGKGFKHELFGLGFH@@jgemݥ`b`ac^`bb_`kעzÜdbaacbbc``ba`_SUJFEMIFNHHMFGLHHNFGOGFMHGMGGMGGNGEKHELEDqtĠ_`a__cdabaacabh\_F@?NIFMIHLGGNHGMHHOGFNHGMFHMFHNGHNHHKFENGGiΝ`baba`abaaaaaacSWJCALGEMGFLFGMHGKGFLFEKGGLHFMGFLFGLFFGB@^MQe___`aaac`aac]uhϛ^__^]\^^]]_[`Ϙg]^\[\[Z[\\ޞ\[ݝo>580--1/.2..0.-1-.0.,/,.0+*0,+)#$KLHZWۛXיW՗WՖV֘VәUӗRؚXȒ_VёXחWԗU֘W֘W՘UחX֘Srb-"+(',()+()(&&1.-HEE1-.)&'+'(.++GED633'$":87SMM/)*EA@NKL965;85863HDD[VW?:8=86>:8@;9965P>Bpa^b``a_gtě^aadcdcdbrPBGKCCMGEKFFLFGLHGMGEMGGLGGLHGI@Bkifnܨ]a_bcbbaacbm٠zƜdabbcbccbbda``TUKFENIHNHFNGFNIGLFFLGGLHFMHGMGFOHGLGEJFCptŠ\`b``ca`ba`b`ag\^G@@NHFLHGMHGLHFLIHMGGMHGMFGMFGMHGNGGKGFMFFkΝ^`a``ac_^`aa`cbTVHCALFGKFEMFEMGELFEKGELFGLGEKFDLGCKEFHAA]LRf^__]_a^a`__`\vgΝ_^]__`]]]^\[cЙhZZ]]Z\Z\ZZݞ[ߟZޝp@581.-2.02/./.-1-/1..0--0+,/+-)$$KJI[XݚX֙V՘VؙTؘW֖W՗Uښ[˒_YѕYژX՘VԙW՗VיVٛZՙUsa+$*('+))+)*(%&1.-HFE1./)&'+().+*FDD422&$"985LHH*$$C==IGF41041/3/.D?>ZTS865721:64;463.0J9=l^\]\[^\csÚ]]^^]`][\pM=E??F@?E@@FA@G@@F@@H?@H@?E;;efblY^^[\^\[\^[fܢuƛ\^]a`^]_aa]`]^ORG@AIEEICBJCCJECHDCICCJDCJDCICCIDDHAAHAAos|V\_]]^__^^_\^_fZ\C=;JDDJDCJDCKDDKEBJECKDBJDDKDDIDDIDDJCBKDCiΚ^]^]\^^^[[[\[^^PTE@ZINa]\[[]^[]^\[[VsfќXYZZ[^[[YZYW`ӚfYWZYYYXUWYYUߝo=13,((.**.*(,(),((,'(,(',('+&'%JHFXRܘRדSזT֖S֗Q֔P֔PؗVǐ[QДSחSחTחSחU֘VۗYטSqa' ##!&%$'$$# "+*(ECC,+)$!!%""*&&CAA.-- 3/.rpoeaapkmtqqnkiolkokkuqq}xxroorontqpuqqson{tu~xpotqovqpurqvqqvrpvqpurqvrrxqqwoo~~~{zzzyzzzyyzxuxzyxwwwututtw}wuuttstqrqoo{mhhhdegfegecfcdfbcdbcfaadbaca`a]]ljinzjzkxlyjxixiyhxfwhvmugyhzhzgzhzjyhyizlsn^Y[\[[][[^Z[\YZ_\]gef^\\[YY[ZX]Z[fec^[[WSU\XWa^]LIG[XXc__XRRWTSTQQa[ZmihZVVZVV\XW\YWYWUg\^{oØmn–npoo–toƙq›oěrØsĜpĚrřqÛoǚndfhcaieejdekccjeckedjedlfdkffgba|qtgY\k_`k^`k]aj]`k^ak]`k^`l^ak]bi\_xfksȝsĚtĜtĚtěsÜtŜtěsÜsÛtÜuŜt™ypplfenhfohfmghoghoigmhgmhgmgfmhflgfnfdkfdrÚuÚttu™ttuu™tutšrv}uuidclifmggnfgmghmihmihmfgmggmggnhgmhhnhfmhg|stsvuuuuuvvusuyqqjeenhgmggnhgmigmhflgflgglgfngglhglhfkddvjmm̜fӞiΜjΝiϛkϛiΛh͚kКiϛg͛h͜gϜdΚ}eUZVJLWKNVJMVIMUILWJKTIKQGJRFJSFHRFHNAFYHOoj̜gƖgƘeÕdÓeÓdēfdccatYQSOMKPMLOLLNKLNJKMJJNJILIILIJIDD]\[d_^^^_^_[_dw]\]]]][^aphG=BEBCGDEGCDEABKFGYVVIFFEBAECBHDDWUSHGF@<=KGHNJH,&&B=?LII8527214//DA?YUU:55:54<76=87741N;?pa_aa_^]e۟v[]a^^__^YrP@FE??HB@GA@HAAHABJBAHA@I@@HDBB>=wqpg``C<H@BGCBHC@HAAFBBHAAIB@HBBI@@JA@GAAB=>YINa\_`]^^___^`_XvUFJ?::B>=A<=A=;A;;@;;@;:?99>87=87=88923G9>a]ZYYWYYZXXWWo=25-))0+*/**-)(.))-'(,)(,')+)(#HIF\ǒXUޛUܛUۛVܚVۗUۘTXϔ\T՗TܜVٛWٜVښSܙUݝZڜTqa'!"!'$$($$$""-++ECB-+*&#"&$#+''E@C1/-!303TPP0-,JEERKM=77=67;54IFD\XYA;:?:8B=;B===98RAFqbcce`_bi֞w]bdcbbc`^vTFIJFDLGGLFGMIGMGHNGFMFGMHGNIHICBytskddIAAOIINHGNGHNHGMIHOIGNHINHGOJILED_RTa`bbcdbab`aacaTVLFGQHHOJINHHOIHNHIOIJOJHOIHNJGOIGMGGMGFru¡\`a^`baa_abcbbi]^IB@NJGNIGMHGMIGNHHNHGMHGNHIOIFNGGNHFNGGNGHkԞ_ba^b`a_abb`^abTWJFDLHHLHHMIGMGHLIGMHFNGGLHGLGFNGFMHGIDD^OSd_bb``a`a^^`_\wXILC>>A>>C>=B=67;65KED\YXB<=?:;A==<99Q?Etcaacba`g֠w`eabeca`^uVFIKECKHGLGFLGHLFFLFFMFGMIHNIHJCAytskeeGBAMGGNHFOHHNHGMJIMJHOIHOIGMJGKEE^PT|`aabd`cbcdc`aaTULFDOHHNHIOIIOHHNJGOIHNHGOJGNJIPHHMFDMFDqt[b__a_`aabaa`bi]^G@?OHFLGFMGHMEJMHGMIGNHGNHHMHGNGGMFFLEFMFFkҠ]\__aba`aa_`^`cSWJDCLJGKHFLGGMHFLGGLHGMGEMHGMGFLHGLFFJCB^ORg``a_a`_`___a^wXHKD?=GA@E@@E@@E@>D?>C??B=>A==B<<;9R@Erb_dcb`bhءya`adbba`^vWFJLEDMGGMGFMHGLHGMHHNIGOJHOIIKCCyttkfeHCCNHHMJHOJIOJHNIINJJOHJPIINJHLEE^PT|aba`baaccaccaaTXKFDPIIOHIPIHNHGNIHNHGOIGNJIOIJPHHLHEMFEpuž]cdba`bcacba`ei]_G@@NFGMHGMHGNFGNHHMHGMGGMGGMGGMIGNHGLFFMGFhӟ\abbbca`a_`c`_cSXJDCLGGLGGLHFMGFMGGMGGLGFMGGMFENGFMGEHCB^NQe``^`a`a_b`bb_xVIMC>=G@@GA@E@?E@?E@?D@>D?=C>>A>@h^\[^][]]ߟZZޟYߟXޞqA6:3//4102/01//3./2.-3..1./1/.*%&NOK]ÐUښU՘VԖVӘX՘VԖV՗WٚYʓ^UЕWיXՖV՘TՙU֙TחWәSo_+"('(+)(,(*'&&20/HDE0.,)''+''/.+DBA300&$#;76_^]3-+E?@KIG=:8>:9=98KED]XWB?>@<;B>=C@>>98Q?Eqda_`db`h֡w_`bdcacc_vVHKKGFNHHOIHMIGMIHNHGNHHOHHPIIJCCxtslfgGACNJIOJHPKHOJHPIGOJINIIOIHOHJLEE^RTc`b`ababdbca_aTWLFEPHINJHNGHOIHPJGMIGOHGOHGOIHOJJLFFLDGquŸ^addbbbabbdbadh]_G@?OIGMGEMGGMIGOHGNGHKGHLIFMGFNHHMHGLHENFFjӞ`bdca`_`_a`_]caTVJDDMGFMIHNIGNHHNGHMHHLFGLEGMFGMHELHFIDC_OSb^a__aa```b`a\xWJMC?=HAAGAAF@AFB@EA>F?>D@=C?=B<==77M@Bj^\]]]][Zޟ\]ߟ\ߠXݝoA7940-6015/130/30/30.2/.2../-,,#&RSR]œUٚXטX֙XԘX՚VՖW֘UٚYǒ_~WДV՘UӘX֘T֚X֘TٙXϘSeZ+ "(('+)),(((&%411JGG0,-+'&*('/-->=A<=E?>A;:S?Drc`aa_abgףy_`bcbcab`tWIKLFFMHGNIHLJHOIHPHHOHHOIGOJHJDByutmihGCBPKJOKJOIIOJHOJIOKIPJIOIINJHLGE_PS~`aabb`b`abbcabTYLEFOGHOIINIHMHHPJGOIHNHJNIHQHHOIGLGFMFFquŸ\abbaabbbbaabdh\`GA@OJGMHGNGHNGFOHGMGGNHGNIEMHGMHINIGLFENGFjӞ`abbdbaa`a^^^cbSVJCDNHFLHFLHHNHGMHGNGGLGHMHGNHGLGELFGICB`PRcab^^`_^_`__`\wWIME@?HBAG@@G@@EAAFA@D@?E@?D?=B==A==>87M@Bi`][[\[Y[[\]WߝqA794//5014003114/04//1.-1/,0.,+%'TXU\ȔVڛXؚWזX֗YיW֘T֙Uۙ[ő]SҖWיV֗UטZՙ[ՙTؚXʖT_X+ #*)(+(*,((*%%622IGG.+**%',((/,+>:91--&#%A??gec2,+GBAUQPA<;>99=89IDCa^[E@@?;;B>?HCBHBAF?@F@?F@AE@AF>>F?=B==C>>?78N?Ch\[YZ\[YZZYߠZZp?795007105115/130/3/02//2//2./-%)V[W]ʕWڜUיW֚X֘W֕W֖VԙUۚY]VѕW՗V՗XՙXәU֘UٚYʔT[V*#*()+))+)(*&&654FFE,+(*)',((.,-?:;0.-"! PONzwy0+*HCBZVUA=88GBA`]\GDB@;;D??E@?A;;O:Bmfcbaab`gݢzbbcbabcd_t[LNLECOIJOJIOIIMIGOJGNIHOJHQKHLCCyttpkjIBAOKIOKINIJPJHNJJPIJQJJOIIOIILGD_OS~abccccabccb__dWZLGGOKHPHIPHHOIHNHJOJGOJGNJHMIHOGGLGGLGGpt]bcaa_ab^_abaaj]_FA?MHHMHFLGELGFNGFNIFMGHMHFNGHMGHMFFKFFNHFkԞ`b`^]`aabacb]`cUWIDDMGHNGHLGGMGGMHGMGGOGHMHFMFGMHGMHFKEB`QUa^b`b`_b``aa`]xWHLF?>IAAIB@F@@HBAEA@E??E?>E??C>=C=>>88O@Di\]]Y[[]^[[Y\p>4642062342041/52/4//2//1/.1//+'(W]Z_͖XښT֚U՛XךXՙXטV֙TܚY^UіS՘U՘V՗WԖUՖWڛ^̒S[V)#)((**)-)))%$743HFF+)*+)(,)(0..ECD0-/"XWVxuu,&$B=A<E>>C?=@88PAEja^[[[\\\ߟ[Zߡ[\n}<3552174252141052050/4/.2//2/-,%%Y_[[̔VۛYՙVטW֘W՚YיWԗVۜZ^TҖV֘U֗SחW֙XԘVښ\̓RYT' !**)+)),()(&%634GDF,*++((+('300FDD,++PMMKFFIDDNJJ>99:65;54D?<]ZZFBA@<;E@>C?=B<HDBGBCIB@HAAHAAF@@F?@E??C@?D?>>87UGJn^]]]^][ZZXZ]l{=1552274253351050030/2./40.2//,&&Za\\ΕVښX֘XזW֗Y֗XיV՗VۜY[WӕXՖU֗TחUՖU֙Xۛ[˓OXQ'!*))*)(,')'%%633DBA($$'$#&"#,**=<<302:64zxx"õ`\\mhjupqgccc`^a]\b\]mhhTPNIDBFDBEAAB>=K8>r|b`_``c_bsabbcccdd`uęaUXKGEOJJOIIPLIQJJOJIOLIPKJQJJLFEwqrvqpIDDRKLQJJPJJQLKQKJQJIRKJOJHRKINGG_PUeaeeecaecdba_f[\MHFQJJOIHNIIPHHOJHMKIOJHOJJOHJPIHOHGMHFot`a_bebacdcbcaak_aGA@OHINIHNIFNHEMHGMIHNGHNGGNHHMHHNHFLGELHFjџ_bbaca`ababb\bbRVJDDMIGNHGMHFMFFNGGOHHMHGNHGMHGMHFNGHIDC`SVa^_a_`a^^_ba_^zVHKGB@IDCHDBHCBHBBGBAFAAG??F?>C@?E@??88YILs\\]\]]\\]][[k{<346238436335134314/13//4//2//-'(\c]]ЗYۚVؚVטXיWؗVטXٙUޛV[YטTڗRؙWڙWٙTٛTߜ[ȑKOJ%,''-,)/*,.,-DBBURRFABLIINKLQPP\ZZXUTLJHȕ3/.@99]WWVQS[VVfabplm}}}{}ww}xy{wxvsqxloxrĚo̝o͞jӡjڣfۢhӟygcb`aa`_^tȜ_RWGA@KFDJEDKGEKGFKGELHELGFNFGJCCunmxrqIB@QIHNIIPIHOJIQIIPKIPLKPKJQKINFF^OQdacfdcbcdddc_h[]NGGPJJPJHOIIPIJOJIOIIQIINKIOJIOIHNIFNGGns`aaaeccaadea`ck^aGA@QIHOHIOIHNIGNHHNGGOHHNIGNGGNHHMGHLFENGGj՟``^ba`abbb`aaabSWKEEMHFMGHMHFNGEMGGLHGLHFNIHMHHNIGMHFIDCaRVa]_aa`_a_a`ab`{VHJGA@JCCHECJCBHB@GA@HB@F?@F@?GA?F@>?89YKOq^]\ZZ^^Y\[W\m{8/14-/3.021.2../,,0+-0*+/()-*()!#Zb\]ҙUߛQܙVܚTۜUڗZٖZٚWڙY[VƐXÎXY]^_f{a^^URR[YY_^]a_`a_ahggfdbWUTNLLEBBDCBGCD'%&}{{͉=::=87PLKB==<75:54<:9_ZXRMMICDRQN[VTa\[kab~|ʠ}ϣ|Ҥxmpc_^ea_e_]c^]_[Z\XXZVU[USZUTVONvqpzutNFFSMLRKKQKJOJINHINIHNGGLGFMGEJBAZJM~^\^b`]\^`^^\[eX[H@@JCDJCDKDBKEDJEBLEDLEDKFDKFDLFDIDDHBD}lrZbb`a_`^_`a`^ak]bF?@MHGNGGMHHMHHLFGMFELGEMGELGFLFFMFFKFDLEGl֠`^]b^ac_^b`]\abSVICAKFGKFELEEJEDKDDJDFKDDKDDKDDLECKFCGA?_OT_Z___^[[]\Y\][xPAEA;B>=D=;A;:@<9A;9?:9?::@;8?98912TGKoZYZXYZ[YZYޟWܟ\؜pyB69=9:>;;@<;A;=?<=D?AEBBGABFCCF@Ahmhifdgghjiizmvlvhxjvjwiyhxh{d|jy_^]JFFEDC?<=8561,/><;?<<# &#"&""20.>;;(%$'#$uGDD834VRQJGEA>>EA?_[ZPJJ@::A<='$#%#"&$$'$%@=:@><(%&.**,((966<9;&$$)&'^SON521TNNLFGD==D>>B><^YXWROE>>HBBIBAGCAH;>pyribdcc``aiK8=GCBIDCIEAKDDKEDLDEOFFKCCicbkhfPLJWRQXSRZTS]WW^ZXaZZd]\e`^d_^}wwhdcpjjslltnmwqpxrrzts}vuwxyyzy~}}~~~}~~~}~~}~}}~{}yyzusysszss}yw{ww{uu{wttonpkkoiimhgkddxprroonmlkkggdÓiu|wRJLMHGKFEHCBEB@B@>?<<=97953722733a^]613.((.((+&'+&&)&%(%$(%&":33ZVUݝVۛSܜVښXٙ[ޝ^B=='"".*)-*)+)(*)(BBA>;;'%$-)*,))=9:<9:#634νQb^^30-ROMNGHB>>E??B:;^XWYTSE>?FAAHBBIBBF8;nxpkabcdcaemR@ENIGPJIOJIQLKPJJPKIOLJLHGhbbnhhJDCNIHNHHNJIMJIMIHOHHOHGNHGIDClfe~ywFBANIHNHIOIHPKJOIHPKIQJIPKKQKJOHHYJN~hceeggefhgߤjޤhcߣukkZTS]YW`YX`XY_ZY`ZYa[[a\[d^\e^\b^]e]\c]]y}oÙqƛpŚqÚq™rÚs™tšu™utuštuwzlfeqkhqljqkiqlkqlkpkkrklqlkrmlsmkqmjokjqllzopo`cpbfqbepafpaeqbdobepaeobeobeo`do`cm\apaczvtlfcmhhmfflddkedkedjecidcjcbicagabfa`b^]uimf٢feݢdۢeۣdݡcߡdߤccecaa|WJNLGGMHHPHGMIGKGFKGEKFCHDBFAADA?F??A79XMPn[[[ZZYZYYYV_۞lvp5+03//41/2./2/-2/.1-,1-,0,+/+*4/.b^]522/**/-,0.+/+,/+,0+*0+*)##>9:ZYܝXוWיV֚U՗U֘Uۛ`@68'##.))-)(,((,((C@A<99(%$,))+))965744!B@?՞$vqr5.-KGFLFEC>>E@?B>=YUUXRSF>?HBBHCAICCF:=lkfpߣbbdccafpXFKLHFQKJQJKQLKRLJQLKRLJNJIhccsmmNGGRLLRMLSMMTNNSNLTMLTMLTLMQKJnih}OIITOMTNMTNNUOMSNMSNMRMLRLLUMLPJIYJNjdccfdededdc^mabKFEPJIPHJNHIOIHNIGNIGNIFMIGMHHMHHMGEICCzfm^a`_]_a`da````l^cD>OFF_XXGA@IEDKDCJEAHEDIDBKDAJDDJDDLCCJBDJCDF@?bRW^\___^^^__``]]|RCEFA@HBAIAAHA@G@@FA?F?@F@?E@@E>?E>=?78YOPo×]\[^]Z[]ZY[f֝jqk90275585584373463371150250/3/-622b_`532/--0/.1/,0-+1-+/++/***!$E@A[WܜW֗XחU֗SיY՚Vܜ^>14'##-+*-(),(',))C?@947)&&-)(+()976522YVVþ5//HCDKGED@>F@>B==UPOWTSF@?ICAIDBJCDD<>ibcpףabccecht[INLFGPKKPLJPLJPMLSNKSMLOJHicbsnoMGFSOMSONRMMTNMTMNVOMWONUPORMKmgfPKJUNOWOMVONVPNVONUOMSNNUOMXONSKJ\LQmdfgfffjfffc`rdgNIGRMLQLKRMJQKLQKJPLKRLLQLJRJJPLJPJHMGF|ipabda`ab`abccdcm`cFA@MIJMGGMHGOIHOIHOHHOIIOHHNGGMIGNHHMEFNGF]XWJECNHGNGHNGGMGGLGGMHFNHFNGINHHMFGNHHJEDQKJaZZJEDMHGMHGMHHNIGLHELFFMHENHFOGFMGGNGEHCCdUZa__bb`^_]^ab]^REGKBAKCCIBEIBCJEBHCBHA@HBAGA@H@AG@AA:9[PRp]^[]^\[\[[ߠZdםhpj80185585574485273262150151/1.-833a^_6311,+0..1/,0,,0,+/++/*-(!"IFE_XܛXיU֙W՗UיXיYߝ[9-1'%#-*(-*(*)',**B=>401(&%-*),(*7130./ged_ ˨;46IBCKGGD@?E@?B=>faanեc`dfcchrYGNMHGQLKPLKQNKRMLRMKSNLQLKgb`upoOJHUONUPNTPOVNOUNOWONUOMUONSNKhcbRMLVPNVQPUPNVOOVOOVPOVNOVONWONSMJ]PRmcfifgefgffdaseiOIHROLQMJRNLSLMQKLRLKRLLRLLPKLQKLQKJMFEzgmaaa`badca`ccacocdGB@NHINHHNGIOGHNIHNHGOJHNJHNIHNHHNIHLHGMHG]WWJEDMGGNHGLGFMHFMIGNHFNHGMIFLGFMHGMFGKDDQKJa[ZJECLGFMHFMIGMGGNGGMHGMHENGHNGGMHFNIGJDBeUZaa``ca_`_^_`_`QFGJCCIECICBJBBJEBIBBIBBGBAGBAHA@H@@A9;aVYrƜ[^^Z\^\Z[[ߞWcכgoi:32965835944742732713632510/.-<8:c_`6002--1/-0..0,,1+-/.+0,** $KIH`XݛYؘUכXՙW֗WؗY؛^v5(-*'&-*)-)(,('-*+?;<20/)''-(*,)+7530.,}z{3я?:;E?@RMLF??E@@B?>QKKXSRIEDIECLFELGGF?@cXZqʞbdefedds^LRNGGSMLQMLRMMSMNSOLUNNRMLgaa|wvPLITOOTOPVQOWPNWPOVPNWPPXQPVNMe``RMMUNPXQQXPPWPPWPPXPQXOPVOOVQPSML\MQoehiheffghgfcuhkPHITNNRMMRMMRLLRMLSMKQMMQKLRKLSKJPLILGFxfk_dcbbabbcaaa`apdeGB@PIGOIIOIIOHHNHGOJHNJIMHIOHHOIGNKFMGGNGI]YWKEEOHHMGELHGNFHNHGMGGMFHNGGLHEMGFNFHJCCQJJ`[ZJDCMGHMHGNGHMGHNGGMIFNIGMGGNGFMGGNHHJCAfU[caaa`_ba```a`bQDFIDBIFCIDBKEBIDCHCCJBAGC@HB@I@AFB?B::f[_qɝZ^\[][\\]ZWhΚhie:12;66:648548547435436435210,,A<=d``2/.1..1..0///.-1.-0.-0,+* #NKJ]XۛXؙTؙV֗UטVיWٜ]r3%+*((.))-)*+)(.+*=8:/,-+((-)),)(855,*)$}_ZZB;GBAE@@OJHVPPJFEJFFKFFMHFHAAaQWwÛeedeeefwÝfUYNGFROMUOMTNNVPNUNOVONRLMf``|{PLKVQPWPQWQPVPOXQPXQPWQQWRQWQPfa`UOQWOPXQPXRQWSRXRPXRPXRQWQPWQQTPM\MPpfjghghhfgggbwjmPIISONROOSNNSNMROKSNKRMLRMKSLKRLKQKLNGHxfi`bdbddccbdbbacpcfHCBOJHOIHOIGNIIOIGNKHOHINIHNIHOIHOJHMGGOIJ_YXLCENIGNGFNGGOFHMGGMHGMGHMFGNIGOHFMHHICDQKK`ZZKEDOHGMGGOHGMHGNHFMHGNFGMIGMHGMFGMHGKEBgW[_aa`^^_``d`a_a~ODFICBLEDJFDJECJBAHCBICBIBAHAAHB@FA@C:;e\^pʞ[ZY\]\]][[ߠVjșfbb921:65;558447337427437326110-*C@>c``3/.2/.2/-1-.0.,0.,0+-.)*+!%UVT_ƖVڜYךVՙWԙXٗTךYךY~j0$'*)(,*)-*),('.,+;79/+++((-)+-(&966'#$>;;;||idctonNIFD?=D<=vqp{xxurob[\[WVd_^KFFHAAJDCKFEIDBXHMydgiffgfxѤm`bOGGTPOVPNVPOUPPWPOXOOVNOc^\~UOOYQQXTQYRSYSS[RS[RRZRSZTSXRQd^^]XWXRP[US[SS[SQZSSYSVZTSYSSYSSXQQ]OP}~rghilkiliihkc{pqQLJXOOWPOWPNWNNVNPTLMTONRNMRMMTMLRLLMHGxeiadeeded`bddbbcqciGBBNIIOIIOIIOIGOHHPHHOHGOHINHHOJIOJHMHHNII_YWKGEMIHMHFMHFMGGNHFNGGMGFMHHMHGNGHMGHKCCRKK^ZYKEDMHFNGHMGFMHEMFFMEFLHGMIHNHHMIGLFGIBChY\\`cb`__`__`a`c{MADKDDJECKFCJDCIECIEBIBCHBCHBAGA@GA@D99f`_qѢ[\^[[Z\YYߡ\Vjș]YZ814;76<66;55964753743743631/**LIH][Y3.-3./2..1--0-.1-,0---*+/#%VbZ\͔VۚWיYؘX֘VԚXך[ԘUiZ) *(()'&)'%(&%1--EDB765GBDYVVba`YWV%""SPRe̶>66TPOOLJ_ZYrml{zupogaa_YZXRQNIGQBGubdcehhhz֨shjNHHUPPXPQWPOWQQWRPXRQXQPa\[ZUTXRQZTQZSS[TSZRTZSS[USZUSZSRaZZa[ZYRQ[VTZUR[USZTTZUT[TTZUTYVTYQQ\NRugkiklkjihjjd~rvSMKVQPWPPWPOWQNVNOVMNTMNSNOSMNSNLSNLMIGxejabedbcbadfca`ardhHDAPKHOJHOIHNKINIIOHHPIHOIHNHHNHHNIHMHGOII^YXKDFNHGOIHMHGKHFLGGLHGOGFNHGMGFNHGNHHIDDQKJ^YWJECMGHMGFNGGMGFLGGNGGNGGNIGNHHNGGMGGJCCjY]^_ad`a``_[_`_cyLABJGDKEBKEFKEDJCCICCJCBICBHCBGC@GC@C:;f`aoϟX^[]]Z[\\[UjØ]YW924;76;66:65:54743854623721.*)PML\YX2..3/.2.-2--0-.0-,0-,.*)3%*\ndZӗWܚXכWٙXڙVܛUYѕOWQ&!0,,531>;:HFDXUShfe_\ZURSB=@756977mkmDҫIBBTMNQMLD>rnmnҢY^^[Z[ZZ\\WqWLO;35<78=77:76:64:55843731510+&&TPOPKL(&&-'(,'(,'',*).++0,-1..?38bwjbacg~i|iyfzl{a]]LHHC?@833/,*&#!955@==#"#-***')><oqnjآZ^[\^^\[]\WrPEG6//73140/4//4013//40.842965966c_^`[ZNLKUSS\XZ`[\`^]^\[\ZZXVV`W[lvedb_\ZTј^?6:"%$$'$$)'&+)&DBB>;;($%.*(+''><<&"#CCD؇ IEC^XWKDDLHHIBDc\]b\ZOIHQKJQLLQLMNFGpolodggiihs_QU_ZYeaakfdqllyss|{}}{zzuutoo}vuc^^e``c_]`[Y_[Z^[Y]VV]WU\WX[VU\QRyy~שimmjjljlmkie˦}VONYSSYSQYSQYQSXRPWQPXPPXQOWQOWQPWPOQJJtchicegfdddbdcbabvfjHCBNJHPIIOJHOIHOJHPIIOIIPJIOJHNHHPIHMGFMHI_YXKGCOIHOIHMHHNJHPIHNGHMHHNHGNGGNGGMFGJCCUMO[VTJEDMGHNGHNHGMGGNGFNGFNIHMHGMGFNHGMHFJCDl]_~Z_abc``_`a``]fyyH>?KEFJDDJDDJBBJDBJBAGDBGCBH@?F?@C==F8;otmhߤX[[[\Y[ޟ]۞\ڝ\ך]ӚubWYQMK[VU_[[a^^ieekggmiiqnnpmlolkzwvqmmeaa^[[XUVRMMJFFB?=>982./A48czWܛTۚVۚVۚRښUڜU^:02)&&-)*.*)+*)-((HEC644*'&,((/))D@@$!eccTιKIHVSRMGHMHGKDE^ZYhdcOJIQLJSMLTMMNIInefwӦhjkkljr^NQWSRZSUZVSZUSYTS[VT\XU\WUqmm`[[jedmiiuoo{vuzz}xy|֩|ܫyݮzެwttrspnh˦WQQZTSXSRXSPWPQWPOWQOWPOTPNSONTMMRNMMGGq_cd`bcaaaacecdd`vdiF@=NFEKFELFEKHEKFGLGFMGFMFELFELFFLGEKECKFG\VUIBALEDLEELEELEELFDLDFKDCKECKCCKDCKFBF??QJJWRQF@@ICCJDCICDIDCJDBJCAHDDJDCJC@JDCJDCG>>j\]~\b^]_^^`^___[hv|vH>ALFFNEFMGFNHIOIIPLJQKKQMJVPOXSRXSS\QT{~xxmnquwtw{uux{uvroonjiieec_`[XYTRROLLHDDB=<:53b`^GCB1-+2,,2*,0++0,,0-,/,,*$$D7:fWߟVٙXؘWؘTؘVؚWݛ^y5*,+*(-++,*)-**,)(KGG1/.+)(-)(0--;89&""2YXSRYUURMLMHFKGGZTTmfgQKLRLKRNLTONPKKi]`z̡illjlinbQUZTS]XW^WW^YY^XY_Y[_[Y^YW}xrqZTS`ZY^ZY]YW^YX]WX^WX]WX^XX`ZY}ywa]Zkhenjjronuqp|tszz~~}}||z{yy|xvyuuwqpsnnqmnnhiwyxɡtϢvҤs֤sפqգr֣o֤qץn٥n٦mڣkܥlݧ}mqSMKYTQYRPVOOVQQVQPVQOUQPTQNUONUPOVPNSNLTONc\\SKKUMLUONTNNUNMUONTMNTMNTNMTMLUNMUOMSLK]WUb\\VQOYSQ[SR[UT\UV]UU\XU]WU^YV`XU`YZa]\b\ZzppjӞmЛn̚pȚpǝoŜněnǜruwyy~xqr}xx{z}xv{vv~xw{{|zzutyut|vw}xwzst}uqomjǘfΜdϘaϘ\י[ڝZqI?A823954722312321420410632500400db`EB@3/.50.4..3//3//3/.1.--&'F<>cYߟXؗXזVؚWڙUؙXۜ]p/&),+(.)*,)+,))0.*JGG-*).))+'&744744/** /^[\UONZTSMHGOIJSMMpkjTNMRMMUNMVPNQNMbUY}gllilnnhX[YTR^YX^YY`[Z_[[a[\`\Z_[Y~}|vu[VUb^]c^]d^]c_]d]^d^]c_^c^^c]\{y\VVa]\a[[`[Y_YZ_XX^XX]XW[XW^XW\WU~xy\VXbZ\d\[f`^g_ajaclcdpbeoefrgivgkudi}}}wv|{~}~yyyyxwussurÜrǝnΛtǙ|{^XVb^[c][^WVWQPTPNSMNRLKLFDHBBG@AC>t|`UXYXZYZ\Z[\pH<@:65=98=77;67;86:65965854633843d``B??4..51041030.2/-30.1../&'LEGcVݛYיYטXؚXٙXؚXٜYwf,"&,*)-*(-(*.)*531JHH(%'/+**%%;78-*+A??ՇSOM[VUMHGQLLQKKnihXQRROMUPOVQQUQP]PS~kknonnon`aZUS`ZZ`[[a[\b][a]\b^]b[Z~yx}|]XWd`_e_^eb_d`_e^_e__fa`e`_b]^~`YZga`fb`eaag`bea`ga`fb`d``e_^a]Z}_ZYb\\c\\a\[_ZY^ZY]YX]XW\WV]WU[VTUQPnjiVPPXRRYSQXSQXSRXRRXRQWTQZRRZRRXSRZSRTOMoadohkllkllnަnۧlؤnעo֣oաux^YXe__d^_f`^ha^g__g`_g`bf`aga`gaaf``ha_hbaqlld_]gb`e_`f_afa`e`_e__e`^e`\e^^d]\a^[_WVhabhca]VU^XW\WV\VVZUSYSSYRSYRRXQPUPOTONSNKQIHreh|ƟY]^_^\\]Z[[ZWhmsm@86D@=C?>F@@HB@HBAF?@G@AG@BG@AGA@C>87<88<77<65;54846844600>9:fbc=993-040041/50/30.2/.2.-/%)PQObÒVU٘XؙXךWؘWڙ[қTeY*##.+*-*(-)),((=99GEC)%%/**,((867))'mlk\ʘtqokggIEEPKINIIjgf_ZXUOMVQPXRQYQSZMP}nonnppoɥtgk]VV_]]b^\a]]d]^d^_e^^d\\ztu`[Zf``ga`fa`faagaagb`gcahcbd_`c\[gcahbbhbchbahcahbbgcahbbh`ac_]c^]e`_f`_d``f`^f`^d__d__c^^d\[d]\_YZqnn_ZZ_ZZ`ZX_YY]ZY^XW\WV\VU\UVZUSYSSYRQQLKk^cofiedddecda`b`wgkE>=MGDKFDJDEJEDKDDKEDIDCIEDHDCJDBICCHCBJCCZUSE@?ICBIAAJCBIDBIDCICBGCBJCAICCICCGCBD<=IBAIBBHBAHC@HBBHCBICAICBHBCJDBJDBG>@lady̤[a`a``bb``ba\lߧprnI?@LGFLGGLFFLGELFDJEEKECJDEICCJCCF??O?Dwd\^]]^][]Z[cnzE7;>76?89>87=67;66;6585695540/A<>daa;774.050040/4.04//2/.0-+1%)W`Z`ΗTߝVڙXחVؚW֚Sܜ\ʕNRM)#$/,).,)-)*)''D@@?=<)(&,'&($#KIHMKJ%ifa`}xwwst\XVLHGd^^c`^TNNWRPXSRYRSYMN|snpooqpӨxop_XXb_^c^^d`^d_^e`_f`_d_]wrrb]\h``gbbhcbhbahcbicbhdchdbfba{ze^^iccidbidchccjddicdhcbidchdcc_^f_`ga`fcaecafb`f`ae`_f_^e`_e_^d^^`[[rlla\Z`[ZaZ[`[Z_[Y_YY_ZY^XY]WW]YV\WV]WVUQNo`eohkgfgfhgfddff{lpKFFQLKSLJRLKPIIPJHQJIOKHOJIQJIPJINJINIHOII`ZYKEEOIHNHHNIINIGNHHNIHNIGNHIMIGOHHNIIIDBXRQZSRMEEOHGNGGLGFLHGMGHMGFMGFOHFOHEMHFMHGLAEnefw̠]cb`aa``_a`_^kܥkkiG?AKGFKEELFELGFKFEIEEKEBJEBJDCJCAG@?TCHz`Y]_[[_^]]ZaߣmxE6;<87=98=87=86<77976;659552./HBBc`_:555/.5004104/04./3..0,-4&)Zka]ԙVܚW֙WؙVלWؙTޛ_FEC*&&.**.,).*+)%&IEF422(&$854USSZWV844˫AurrWQRljh}yxxrrokkokjQLKUONWRRYSSXOOy~xwmoprspܮ}zybWYd_^c__eb`ga_fa_fb`ea`tqofaaha`idbjccidbkeeieeiedjfchda~zyhbbjdckedkedjeeleekefidekddiedf`_gbbhaagdbgbagabhbbg``f``gaaea_ea_b][rlkb]^b][b\\a\[a\[`[Z_[Z^XY_XX^YX]WW\XWWRPn`cqhjjihifhiigef{kpLEERLKQKJQLIQLKPLJQLJPKJPIHOKIOJIOJJNIHMIJ`ZXLGCNIHOIGNIINIGMHGMHHNIIMGINHHOIGOIHHDAXSQYSSKEDNIGMHGNGFMHGMHHNHGMGHNHGNHFLGHLFFLCAoggz̢[a`aa_b`\``^\kڤgebI?@MDGLGDKHELGGKFFJEEJCCJDCJDBICBG=>UFIx\[][Z[]_]\WeڢmwpC59;:9>89=88=77<66<56;669652.,MHFa^\7446/06104114/03//2../*+4(,_}l_ۛXۙXՙXٚZؚZךXa>89-''-))*')*(()&&LIJA>=VSQZWVKIH0--C?AΘUPP[VUOJIkef~~uoojbd_XYYVSVONpmkyޫmrsqqnfX]d__gaaga`gabicbhbcgaatmmkffhccjdekeekfelffmggkfemggidd}xwlgfkedmfgmhgmgfnfgkgflgfjgflffg`a~~jedibcjddjdchdcgecidbhbbhcahbaga`b^^oiie`]b^]b^^b]\c][b\\`\[a[[`ZY_XY^XX^ZWYRPm`csejkihhhfghgdd|lqKFERMKRMKQMKQLKRKKQJJPKIOJHPLJOJIOJJOHGOJH`ZXMFFPIJOIHOIHOIGNIGOIHOHHNGHOHJOHHNIHIDBXTRWQRKDDNGGNHGNHGMGHNGFNGHMHGMHGMGHLHHMGFLBBphiyˢ\^aa_``a_ba_\iۢba`HBBMGFNFELGEKEEKFDKFEKEDKDCJBBICBF>>UGJv\][[\[Z\\\Xfءhph@35<88>:8>;7>88<78;56<65:643/,OML\ZY82251/53051/5004//40/0,+8+.as\ݝVۛVךW֚XכXٚU_}2++'$#*''1-/=:9NJJgedZVWDBA(%%975'%$nmmmȁa\\c\]TNMPLISOO|vw|uu~xsslgfxopΥnmqssq{i\_f_`hcchbbiddidciedhdbrljpmkhdclhhmggnggnhfoignhgmhikfhzutpkjlgfnihniinihnihniinhhligmhhhba}nhhjfcmgfkefjffkgejedidcjechbbhcbea`mhggbbc__d`_c^]c^]b]\c]]b\\a[Z_[Y^YY`YXZURm_bsiligghjhfhfgd|msKFGSLLQLLQLKRMJSKKRLLQJJQJKPKIOJIPJIOIGPKI`ZZLFGNIIOJIPHHMJFOIFNIGPHGNJINIINHHOIHJCCZTSWQQJECLHFNHHMHHMGGNHGNHILHGMIGNGGLGGLHGLBBqhhv͠Z_a``da^^_`b]lآb__IABLFGLEEKGEJFDLGDJGEKDDJCBJCDHCBF=?XIMv[__^^[[Z]_WiӞfjf?26>77>;9>97>78<78;67;65;564./VSRZWV50252152150/41/30/4...++>25e}ZYٜYٛWܛTޜTVavA7:@<=KIHZXWYVWXSUPMM'%&&#%,*+B?>+(('M~~_YYZUUXRPUPOohh_XX]UTleeqlmwrrɨ}ڪwsntl_afa_jdckeekfekfelgejeeojjxsqjeenijpiioiipjiokjpkiojinhixtutponigpkjpkkpkkpkjpjjpjjpkkojkkec|{qmlmgeoihnihmghlgglefjeekfeieejedhcbnihieee`afb_e`_e__e__d_]d^^c\]a][`[YaZZZUTk``vjjjkkikjigghfotMGGRMMRLMPLMSLLQLKQLLRKKQLKRJJQKJPJHNHGOKH_YYMHFOKHOIHOIGNIGNJHNHGOIGOHHOHGOJGNJIJCD\UUVOQJECMHHMHGMHFNGHMIFNHGMGFMGFMHHMIIMGGLABpijvС^abba`_^^_a`ZpΠd\\HABLGFKGELFDKEEKEEKFDJEEJDCIBCJDBG==^SUx[]_^[]][\\Xlʛa\\<35?99?9:<98=98<77=67<76965400\XWTPO51072160061051040/3///*)C:;9>99=98>87<66<76;65744732`\\OJK2006116014011/-/*+.((-&&MHFiaĔjlh{p`caOGINEGRMM1.,.))*&'*'%'&"GEC735+(),''644*('{{yjʋoml\YWXSRZSRgb`too[TWa\[a]]`[[aXYxrux٪ͩ}wwwpqqlloiinji~}kddpljqljrlkrmlrmksnnsomqljxrs{yqlktootonupnuonsnmtnntomrnmojj~zyyurpkiplkqkkpjkokjqjiokiojinhgnihkgfmhhrljicbjddhdcicahabf``e``d`_c_^b]]c_\^ZXk_bzllmnmkkihkjgcpvNHGVNMTMLTMLQNMRMLPMKPLKQKIQKJPKJOJJOIHPIJ`[YLGFOIGOHHOIINJIMHIOIHNJHOIGOIGNGIMIIICA]WVUONLEDOHFLHGMHGMGGMHFMHGMIGNGFMGHNHHLGGLADuootڥ[bbb__``_a]^_nŗ[OPLDCLGFMGFKHFJFGKFCKFDIFFJDCJDBJEAH>>aWYvÜZ\\_\[[Z[ZXo\PS=54><:>98=98<77<75:54953531831b]^GCD1,+51/:44>::HDAPLL\XXebbrqomol[XWODG>6:4,00))' !B>:442-..,*,((0/,ZVT;87.,*0.//.-0.-.,--**QNM;;9-*(/+*/+*)'';87B?>,)*+(*/--.*)Wt[VV]XX`Z[okjlih`\Ze`_eaaf]]ukm̪wwxz|yqgirlmsnmsnorlmqmlpjjmggvpo}xw}|}|somtpnrnlokknjiojhojhoiinihojimhhkgfzutkedmhflgfmhflffjefjeejdchdbhbaiaac^^iad~orrrolnlkkmjhƤtvQKIWPPTPNWONUOMUNMSLMRLLQLLQKMRKKQKKPJIQKJ_ZZLGGNIIOJGOJIOJHOJHOIINJHNJIPIHOJHOJIJCA^YX~~VNNLGFMHFNHHNHHNIGMHGNGHNHGMHGLHGMGGLGFOADxxtnݤ\`afca`cdaba[sVILH@@HBAHA@GA@D>?D>=C==C<>C=>E?>G<>lliqС^f֛iϛg̚kØm–pqqoo~tjlgcbiedgbad`_b\]]WWUQPLJG>;9IDDd__643.))2+-1..3/040.3103//985[XW4111-,0-.2..1.-/+*3/.PMK532-)+0++/,+*&'FCC<:8-))+*),+)VTR!+qnl[VV_ZXmfgwqrc^\fb`gcaga_pdfyz{{thksmnuqourpvqpwqpvrrtpnysttppvqouqptppuqpwrpyts|wv|wv{z{wtwsp{ymhgnjhlgfiddhbafbaga`e__c^]c]\b\\_ZYdZ^~mpqnmmokkmjihɤtxQKKVQOWQOWPOUOOSNMSMLSMKRNLRLMSLLQLKPKJRJJ_ZZLHFQJHOJGNJIPJIPJIOIIOKHNJHOIHOJGOIIHBB`YY|}SLMJFENHGMHGMGFLHELFCLFEKFFLFEKDEJDCIDCK=@vztk\a^^\[ZY\ZZ^YrZKOSJKWPQZSR\WUb]^f`agbalfhqkkqlkwrqyqquwvrrnljřjǗbКdӝtRCG@;;A;;=77:468226206116112.,KGGc`^95473184363153242152/3./@<:8?98?88>98>98=88<77623SNM^[Y7206337357417205015202..IDCUQQ,((1..2..0.-0-.-+*745C=>1,+-**.,+,)(410DBA-)(2-.KIGRPNEZoji{vu|utleeeb_jddkfdmad}y}}}tvvqpxsryttyttzuu{vuxtt|{yuu~xy}yy}yy}zy~yy}zz}yz{wv~{z}yx~zy~zy~zy~yy}yw|yw}ww{wvwrswtrytsyutyvtyutxusyttxutzus|vv|wvzut~yz~~}}}|~~}~}}~}~}zsspspnsomsjjmcdl`aj^_h]_eY[aSU\PRYMPUIK|tt[UUOJGPKHNGFLFEKGDJEBJCBIBAGCBG@AF??I=?vzfZ]\]][\\[Ybޡm}tF6;?::@;;@;;?:9=89=78<87;76942YUSZWV40/7538447117116016100,,NLMMIH-)(2..0..1.-0--,*)>;;DAA/+*/,,-**)%$;74CA@ECBZVX<::baaa[[f``|{|}jeekfchdcl_bz}̯z|wqqztszttzuvzvw{xxzwu{z{wvzzzzzz{zzz{z|z{xw~}zy|{{{zz|z{z|z{z~zzzvu{wv|zx|ywzyxzyv|vvzvuzvuyutxtsxtrsomojirmlqkloijnjhnihlggkgfjeejedidbfbbhbbگsustsߪuݩsݪvݧwܨvܧv֤yѤvХnhgskksmksmlrnmtnnsonsnnsoosnntnntpnrnosnn|wvslksmlqllqklqjkolkojiojhmihmghlfflfdd_^wrqibbd^]c]]aZZ_XW\WV[TT[SSXSQWPOVOMSMKPJJSLLxrrTLLH=>KABHABIBAIA@JBBICBIBCJBCICAJECJBCJBBuqpTMMKDCJEDLGFKFEKGELFCJEEKEEIDDJECIA@OCCza\\[_]\\][Ze֟jokA49?::?;;?;;>98>:7=88=89<76965]XWUQP4/.9437346226206215211-,XUUD@@0**20/0//2./0---+(FC@EA@*(%+''-)*/,*OMKdbbNKK.,,($%ṱ}yy_YYa][xrr}zxpeh~{y޵}۶yrszvu{xv}wx}yx~zy~zy~zy|zw{{{|||}||}}|~|~yy|{~}~}}}}|}|}|}{|{|ww{y~zz~zz~zzyy}xx}xx|xw{wwzwv{vswqpsmmvrqvqoupntooromrmlqmjpjiojinifkfdkcc߳tvttqqqppljkgͧvzOIHSMKTLKRKKPKKRKJPIJNJIOHHNHGMGGLFFLEDLGF[VUHA?KDDIDDIEDJCCICDICDHCBHEBJCDICDHDBB<;a\[||NGGHB@JDEJCDKECJFBICCKDCKEBLFDLFFLDEKEERIJyutWQOKDDNIHMIHNHGMIGMGGMHFMGHNGHMGFLFGKFELGEvrqSMLMFFLFFLGEKGEKFFLFFJFDLDELEDJFDJABOAEx]^^]a^[[[][iѝfec?45@<<@;=?;;?98>88>87>88;66=88c__NKJ30.843744833730540520400]ZY:651-,2/01-.3./0-.0,,IEC965/-+DA?OMKSPP_[[?;9'$#(%$C?>)Gd__iccmfgrnmrpm~ˮ}|zss|xw}yyzz{zz{|{~yx{y}~}~}~~}}}|~~~yx|||{}||{zyyzyy~yy}xy|yx|xwytstnnxrsxqqvrpuoqtpntonsnlrmjqjkpijmhfkedڰtuwttvtqrpppk̥{WPQYRRYUQYSQYRPXRPWOQWPOUPMTONSMMTMNRKKRLK`[ZNIIQKJQLJQLJPJJOJJOIJOIHPJIOIINKJNHHIC@fb`}}RJLMGFOIHNJHOJIOIHMIHNHGMHELHHMGGNGFLFFQML{wvVONICCNGGNGGMHGNHFLGGLHGNHHMGHMGHMGEKECPJI{utQMKLGDMGEKFFLGFLFDLGDJFCKFEJFEJEEH@ATGJzZ]\]_^\^_][nɚbXZ=56A>=A<<@;9@:9?99>98>98:64@;:fbcEDA31/93383272464373240.967_[Z40.3003102.-*))&$#1.,YUSVSSZXX[YYHED964956,))-(()%$vuuӎ Ǯwrsgaaojj{xuokjjfeqnm}zx­ܶ}vv}zzyz|{||||}{zy~~~~{z~}|~}}}|||z|zzz~yz~zy|zyzvuvpozttysswsrwqrvqotpnsnnrmlrllplloiikbd۰xxxwutvttqqqkΨ|WPQZSSYSRZTRYRQXPPWPQXPOUQNVMNUNMSNLQLLSMLb\\OHIPLJPKKPKJNKIOKHPJIPJIOJJOIIPIIOIHGBAgcb|{QKILGGOHGOIHNJGOHGNGGMHGLHFMGHNGHOHGMGFSNK|wvTMNJCDMHFMHGNGHNGGLGHMGFNHENHGMHGLGFHDATOM|vvOJJKFEKFFMGGLGDKGDLGELFDJEDJEDKCEH@@XLMyZ][^]]\]]\Zn˜\QU<56@==@=;A<:@:;>98>87=97954DA@hdd?;95319547438337436313/.DAAZVW/*,0,-+('0,+=99NLKb``khhRMM?;:0-.(#$20-?=:9=:6;55IEFfbb954943;45744633632430/+*LIGLHJ/+,C?;;B>=.)'#" hhfîtppgca|wwzyrnltpovoqton||uppzsu}~}~~}~}{{~~}~}}{|z}zzzvu|wx{wv{vvyttytrxrqvspurptonsomsmlngfֲyzyxywuttrsqpөZRS[VT\WSZTR[SRYRSXQRWROWPOVPQTOOTMLSMLSMMa\\OJGRMJPLKPJJPKJPJINJIPJIQIIOJGPIHPIHHBAhdayyQJILHENGIOIHOHGNGHOIINIHMFGMHHLIFMHGLGEWQP{srNFGLFFMHGLGFLGFMHGNIFMHGMHGMFGMGFMFGJABZSSuqqMFFMGFMFFLEFNHGLFELFELGDIEDJFDKCCH?@d[]uƟY]]Z\YY^\Y]mSAF>66A>=A<;?;:?<;=;9><8>97<55PNNb_^2//721621530720741955>98da_khigbcebbWVT@>=2../*+GCCB?>*''0,--,,0,,FCB965'$$/+(yuf`_voqupntpnvrquoozwuzxx{wwzxu~xw{}}}}}zz|xv|yy|xx}xw{vwzvuxtuxttwrqvpptppsonnihбz{zyxwututsro֬[RR[WV[WU[VTYTSZSSYTPXRQWQOWPPTPMTNMRNMTNMc\[PIHRLKRLKQJJQKHQJJPJJPJJPJIOJHOHHPJJICAjeb~vwPHHNHHOHHOHHOIFNHGNHGNGHNGGMGGMHFMGHLFEYSR|vuNGGKGENGGLGFMHGMHHMGFLHHMGHMGHMHFNGGGAA^ZXvrqLFDLFEMFFMGGMFFKGFKHGKECJCDKDDJDDG?@g_`t̟Z^`]_^[\_[[hK9?>:9B<>A==@=<@;:=78:76862620XRR[WU50/B?=GFCMIHSMMZXVc``heftppRNM>991--.*)1,*0--3/0OMK;77-)(0-+.,+20/JGE1/-cab¹||jddzvtvqoxttxrs|{~zx}xxz{}|}|~{y}|}|{{~{zzy}yy~xx|xxzvvztuztrwrswqqurqnjiί{z|zxwyuvutsqڭ\UU^WW\WU\UUZTTZSSYTQYQRXRPVPPVPOUOOTNMTMLb\\PJJRLKRLLRLKQJJPKJQIJMJJOIIOJIOJIQKJHBBlff{uvMJGLHFOHIPIGMIHOHHOJGNIINHGMGFMGGNGFKGE[VU~xxKFFMFFLHGMHFNHGMHHMGFNHGNGHNHGMGFLGGFA?b\\ojiLEDKHELGELHGLGGKGGKHGJFFJFCKEDLEFG??pnjmԟZ_^]\^^\[\_e{D4:=98=97;65944:54<77B==GDDPLJnihqnmhccnjjjgg^Z[TOOJDE=88;87YVV/,+1.,50/5//4/.2.-:64PML.++0,*/.-/+-;77A@>! :78ngwqp~ww}xtrzuvzvv{wu}~zy|{}|~~zy|{{zzz}zx{xvzvwzvuytsysswsqpljͮ}{{zzywwutsrp۫^UU^XV]XW^VW[UVYURZSRYRQYRPXQQVPQUOPTNMUOMb^]OLISLLRKKSKJPIJPJIPKKOIJPJIPJINJJPJIHBDnghyutMJFLGEMIGNGHMHGNIIPJHOHGNHIOHHLFFMHHMEE\VV~yyKFDLGEMFHMGGMGFNHFNHFMGHMHGLIGMFFNHFG?@g``nihKDBMHFLHFJFFKGGLFFLGEKGEKFEJEAKDCG=@rsolۡ]^]`]]]\XX[bo?.3B=?KFFUOM]YWgbbmjjsnnrnmplkzww_\[QKJFA@:673/12--2../+)@<:RQP2016105/.5.02../,-CA@LIH+''1--0-+/+*A==1//-)*~~xttzwv|xwzvu|z~|~{|}}||{{~zy}zy}xw{wvzutzttytrqnkɮ~|}}{{yyxuqus۬_VX^YX^ZW]WW]XU[VT[TTZRRXSQYRQWPPUQPSPNUNNd]]QKIRMKSLKQLLQLKQKIPJJQJJQJHOIHOHIPJIHCCoji{uuNIFNHEMHFMHHNJHMJIMHGNIGNHHOHGMGGMGGLED`YY}vvJDCMFFNEHNHGNHHNHGMHFLGGMEGLHGMHEMFFF>?kfelgfKCALGELFGKGFLFFKGEKFFKFEJFEKGEKDFH>Auxg]^ZY[[\^ߞbלeΗn}ulnxttyvtvrqojie_`[VWQMLHD@D@?ife:762.-6107128438549553//DA@HDC2//4004.04//1..0,,MJJA=;,)(1+.1,+0/,EBB<99SQPi[~}}}yvu|xx|ww}||}}}}|}{zzzzzy}yx|xvzvuyutqonî~{|zz{xstsڭbYZ_YY_ZY^YW]XV\WW\UUZRSYSRYTRWQQWQOVNMVONd]]PJKSMKSMLQLLRKLQKJOJJPKJPKHPHIPIHOJIIDBqkk{tsNHGLHFNHINJINIHNHINIHPIIOIGNIHLGGMGEKEDc^[~wwICBMGFLGGMGFNHHNGGNHFMFGNFGLGFKGEJFEE?=lgfc]^IBDLFDKEDJFEKEFJFCJECHCDHB@IBBH@AH>?xcbߟfћiɛostwwvrvzvvWRTTNNKFFD@@A;;>78<46;74842DAAhee954:659658548448548422-,NJIDA>4//40050030.1./30-NLK3/10,,0-,)'%@?>a]_:66nmk !~xy}}||~yy~}~~~~||zzzy~yv{vvzvuxusxtsqmm{~}||zxzyywspޮbZ[_ZY`ZY_YY^XX\VV\VSZUSZTSZSRZRQXPPTQNTPNd]^QJJSLLSMKSMKQLJQKKQJJRIIPJIQJHOIGNIIIDCrllzstMGHLHFOIIMHHNFGMHHLGFNGELGELGFMEFKEDGBBd_]}wwE>@LCCKDDJECKDDJDDJECLEDMFELEELFELGEIA@qmlc_^MGGPJKQLKRLMUPPYTS[XVb\\f_`kfetnm{st{yvunjřg͙`כ[۝ZYgϜh`a:22A=:A;9?::?;;@;:?;9?:9<67PKKb^]621;76;5695495384463330/XSU@>;30.4/041031.3..:77KHG*&'0++511HFEb__824,((gXwsq||~}|zwuuso}aVX[VT]VV\VTYUSXSRWQPVONTNLTNLTNMSMJOJJQJJ_ZZKEEMHGMHFLHELGFLGELEEJDDKEDJCCIDCJCCD>=qlkvqqHBBIDBKEDKEDKEELFFMGENHENHFPHIRJKRLJPIImgf{zNFHVPOZVS^YW_XWa\\gaaibaiddojipiirmlwqr~}xtsvrpupmqljoihmfghcdgcbe``e^^]XWcVY{Z[[[ZZ\[\[Zm`TX=77C?>C><@<522OKLNKKIFECA@!lkkˣ(~{{­ìíĬˮЮЮүǬ|}~yy~xx|wuysswqotnmsmmrljpmjqjkpiimhhmhhwrqkdekgfifekeejfekedkddjdcjedmfgmhhoiioggtolvonuonyqp{uu}xwzx{z{z|}xuq~zy}{{{ysswppvrookingflffg`_a\Y^YX|wwe^]SMMRKIOIGKEFIDDIBAF@@FA>E?>F>@A;>A==A<=A<HC?tnmTMMF@?KECJDDLDGKFGLGELGDLGFLFDKGEG@AaSWt[^\^]`]\\X[tO@D?;:D?=A>=C<=@=7::56`][D@>:65<77<659759449342..OLJPMK5011+--'*30/FCA]YXhbdIFE722*'&.,-HEE)%%Ư}~~}{{zy}xxvrrzvvsqospnqmlqljpkiohjnhhlgfjeejdciabf^_rllhbb`]\c^]c^]c^\b]\a\\a\Z`ZW_YX^XW]WW[VVZVThccWRQZTSZRSXQQVQQVQPVPPSNOSNLSNKPLLOKHJECwpqrklKCCLHEMGFKDDIDCIDBICBHDBIBDICCICAHBAD<=qlktnnA;;JDCJBDLDCKGELHEMGGLIGMGGNHFMGGICDSKJvqpTMMKCDNFFNGFLFGMFELGGJFFJGDKFDKEFF?>j_`p˛Y_]]^__][Y\t~J;=A>>B><@;=@=;@<9=99>::gdc@<;<75<77:77964;54824610XUSB>>/+*?;;SPPa]]WUTWSRC@@+'(/+,/,*@<<943PLMhU~~}}}}xx{|zuvyttxttvrqtppsnormmpkjoiinhgkfeicbsmkjdd_[[b][a\[_ZZ_ZY]WV[VUZTSZSSYRPXPOVMNUOMc^\PIIRMKQKJPJJOJJNJJOJHOIINHGNJGNHJMFFICBvqqpjiKCCNHGNIGMGGLFHNHHOIIOIIOIGNIIOHHNIFJECwqqrmmF@@NHGNHGNGFNGILHGNGGMGFLHGMHINGFHCASMMtopRLLJECMFFLFEKGFMFFKGEKGDLFEJFCKEEF=?mefnҞ\`]]^^a\\Zbܟq|sD8:C>>B?=B>=B=;B=;@;:?:9<77HCCife:77<88<77;468437123-.:55][YUQP`\[ebaROP@::1,-JFE7342-/1..2/->=;400ɯɐ~~}yz~}ztvzvvzutxssvrqvoosonrnkpkjoiimhhkedunmmgic]\e`_d_^a\]a[[`[Z^ZY]XW^XV\UT[TSYSRYRQf__TMLWPOUONSNMSNLSMLSNJSKLSLKPLKQKJNIILEDytsqjkKFFNIHPIHOIHOIGNIHOGIOHIOIHOIHNJGOJHLEDzusmgfF??NHEMIGMGFMHGLGGMHFOHGMGGMHHLHFGBAYSSupqPJJKDDLGFLGDLFDLFELHGLFFKFEJFEIEFF=>suqfݡ\^_]^^]]^]h՟lki@79D>>C>=B>=A==C>=C>::2//20.2,,.+(]\\zg~||yw|xx|wxyvvxssxssvrpuoormlqllokkkhguonrmle^]fa`f_ad^^c^\`^Z`\Y^Y[`YY\YV[VT[SRZSTgaaTNNWPOTNOVOOTMMSNLRMLSMMRLKQLJQJJPIJMHH}zxpkiJEDPHHPJIPIJOIHOIHOIHMHFNIHNIIMHINHGLFE||fa`GA?OHGNHFMGFNHFNHHLHHLHFLHGNIGMGFGA?c\[qlkMFELFDKFFMFFMGFKFFLGEKGEMGEKFDICBNACya[\]]]^_`_YqYMMA=>B;=>88<75;53?9:HBAMIHurqpljkgejgfb^]SPNA?=2-.3//VTSHCB3-,6245115103+.LGI>=;1...,*+((JFD̸ȶ~~yy~zx}yy{wvzusytrxrqvqptpnrmlokklghtonvone_^hcaha`e``c]]b][a\Z_[Z_ZY]XY\WVZUSYTSgbaTONWQPVOOUONTONUNLSMKSLLRLLQLKPKJQIHOIH{zojhKFEOJIOIHPJINIINHHPHFNIFOHIOJINHHOHHNHE}|a[YICAMGHMGGMGFMHGNHHMGGNIGMHHLIHLFGH@@e`^kfeKDELGEMGENFFLFFKGFLGFLGFMFGLGEGC@VEJx_^]\^^\_][XtJ>?<55>98C?>LHGZUUfbaojkpklqnmzwvXTRHDE<9862131-731723A<;\ZX;7760.6226403-,:55TQQ845,&(521B>>spoEQ~yzz{~zy|xw{vvyusytrwsquqpsnmpkkohfsnnwrqe_`icahbafa`e_]d^\b]\`[Z`ZY^XX]WU[VSYTSgaaVOOXQQVOPVNNTOMVMMSOLQNLRLKRMJSKJPIIPII|zoigKFDPKIOJHNKIPIJPHIOHGNHHNIHNIHOJINHHNIH~}[TUIBBMGELHGMGHMHHMHGLGGMHFNHHMGGLGFHB@hcagbaKDDNFFMGFLFFLHFMGFKFFLGFKFFLEEE?@\KPu[_^^`]^\[Z[w\PSgabpmmvsqvqpnjic]^VPPF@?TOMeba841733955=76;67;55752IEDYTS4..6206305102--FCBJGH.*,B=>IFFYWU֍szy{z~{z~yy|wwzvvzuswstuqrtoosmlojhtpmzstgbaiechbbgaae_^c^]b^\a[\`ZZ`YW_YW]UTZTShbbWOOXQPVPOWOOTNNTONSNNRLNQMLRLJQKJNJHRII}|mhgKEDOIIOJIOIIOJJOIIOIHMHFOIHOHHNJINHHSLKZUSKEDNIGNHFNGFMHGLGGMGHMIGMGINFGKFEICAmhgd^^IBBLFGMHGMHFLGFLGEKFFJEEKEDJDDA=;?9:>89620[TT[VV=87>87<78<76<66;56843USQNIH3--84373141/300KHGEBBIDDIFE<77<}{}{|zzz|xwzwxzuuztrxsqvqosnnplkton{uugaajeejdchabf``d^_c^^a]Zb[\`ZY_YX]WU\WThcbXPNYRQXQQUOOVPPUPOSNLSMKQMLRMKRKLOIJQKJ}kffKEDPKIPJHOHIPIHNJIOJINJHNIINHINHILHGUOMVOOKGFLIGMGGMIHMHFMHGNIFNHGLGHNGFLGEJEDnih^WVD?@GCCICBIACJBCKECLDDLFENHFOHHLEFqjjxm͛qtsqwmqmebbZRTRFIG8=`TVga_@:9@<8@;:A<99fca]XWD<C?=B>>B==A<=C;<=87E@@igeGB@<75=:7<88=96<86953FEBYVV2./2//30/><:QOMfbaMLJ2..%! \XXҝ c~yz{{|xw{vvzuvwttxtrvqpvoosoornmojiqlmyxfbakfeidchbahb`fa_d_^b\]b\[`ZY_ZY]WX[VUiccWPPZQQXQPXPOVPPTNOTOMQNLQLKQLJQKJMHGPMKjddHAAKFFKDDKCBKBCJCDHBAHAAG@BGA?GA?D>=WOOJDCKDCMGEOIHRLKUPM[TS`YZd]`jdbmhgnhhsnm~xvunowppvqptooqljlgff`_a[ZZUUTMLOIGtonNEHA99D?=F@AHA@IBAIDBHBBHBAGAAB<;migRMKC==C@>C@=A?=B>;C<=:66RMLgbaA<;;96<:8=77<67<88832VRRFBB/*)B>:;( Ř~|~zxzut{vukfdligjeejdcgb`e_^d^]c\\bZZ^YY]XW[UTYTSfaaTMMVQOVNNTNMSNLSLMSNLULLTKKQLKRLJOHHUPOojhTMMYSSZTR\TVaZZf__gbaidbkefqkkuontnnz{pkktnnwpnwrqwtsyuszusxtsvrquoopjjgabmhh||b[YWOOTMLPJHLFEIDBHC@E@?E@?FB>E?=MHFojjOJJHBBJCFJDEHCBJCBJBBH@BGCAFA?JDBpljJFEE>>E?>B??B=>B==A=?GDD.)(+'&X1|{zx}ww{ttsmm~zx`\Y^YY]WXZTQUPOUNNSLLPIINIHMHFKEDF?@WPPupoLDCF@>JDBJCDJEDLEFMGFKGEKGHLFFHBAVMMjdeLGGJDAJCDKDBJCAHAAICBH@AGCAC>=RMLmihFBAD?>E??C?>B>>A>=C==A;:A:;c``QMK:57>98;75632864A<=UPOtrq[WWJED;7640120.NII945$ `^\ׂA~}}}}}{{{{zy}yx~xw|xv}xxwrq{tsztsyttyssxsqwqpvrotqotoosomrmkqkkztslfhnihlgfjffkccjccgbcfbae`_d_]c\Z^YVc]\oijTPOVSRUOOTNLRMLRLLQKJOKJOHGNGGMGGG??ga`}{HC@LFDKEEKFEKDDKDCLEEKDDJFELFFMGFJCC`[ZupnLEDKFDLFGMGEMGFMGFLGGLGEJGELGFGBBVMOc\\JEDHDBJDBIDBIBBICCICDIAAHCBA;:^YXc_^E??F@>C@>C@>C>=A>=B==>98ICCe``A==845?99GB@ZUThddXUU]XYKFE82273263151.FCBEA@& #VSTѕ Ƥ~~}|{{|zy{xxyvuxssvrotopkecnhimhfjfegccgcaf``d^^a]]a\Z`[Z_YX\WVhbcWPPYSSXQQWOOUOOTNNSNNSMKQKLPKKPKJLGFWQQe`_IDBNJINIGOJGOHHOIGMIGNIHNHGMHINIHIB@phi}xvICBNGHNIIOIHLHFMGFOHGMGFKHGNHGLHFICDd__qjjIBAKFEMFFMGEMGFLFELGELGDKFFLGEH@A[TT`YXJDBJDBJDBIDCICCHBCIBAIB@GA@C==hdbZWUB>>F@?E??F?>D==A<?644[WX>99744853842844NJJ-))JGG1Ǿ~}}||{{}zyzxwzvvxtsvpqmggpkkojhmhglfejedicbh`bf_`d_^b]\a\[^YYlge[TR[VUZUUYRQWQPXRPXQPVPOVONTNMTNMOIJYUTf`_LDEQJKQJIOJIPIHPIHOIINIIMIHNIHPHGJBBsonwsrIDANIHNHIMJHNHGNGHMIFMGGNHGMGGMHFJFEidekceF@AMFGMGGLGFKFFLGFLFELFGLFFLFFFAAc]\`ZZICCJDCJCCJDCJCBIAAHB@IABF@>IBBnihRMLC==E?@B=<=98>88A==PKJlhgFA@<65@9:HCBUQOb\[ifdjgflfgzvuOMM:77943:44=78?99831VRRHFD8349557414/-GACEAAΏH~~|}{z}yx{ywyvuwrrpihqllqkkojimiglfejddhbcga`e`_d__b[[_ZZlgf[UU]VW\VTZUSYQRXQQVQOVPOUNNUONSOMNJH]YWc]\KGFOJJOKJPJIPIHNJIOJIPJHOJHOIHOIGHCAywlhfICCOJHNHGOHINHILGFOGGNGHLHGNIFLFEOGGuqna\ZG@>MGGLGEMFFLFFNGELHGLFFLHFJDDLEDoiiZSSGBAJFBJEDJDCJBCIA@E?=C<<>88WQQnigWQO`[Zmhgqmkojid``WUSJDDMIIe`a:55=76@:9?99>99:65A?<\XZ=99832601743HECJFDP¾~}}{{zz}yx{vvytrqkjrmlrlmpijmgglhfjeejcchbae`_d__b^]`[Zmhg[WV]XW\WU[TSZSSXSPXQPWQOVPNWONVMNOHH`[[_YZMGGRKJQJIPKIPIHPHIOJJOJHOIJOJIOIGJCD~}gb`KCEPIHNIHNHGNGHNGGMIHMGHNGGNGFKFFQJJwrrYTRHBALHGLGFMHFLEGLFDLGCLGFLFFHABRLKpkjRMKFA@IABGA@F@>HBBNJIWQQ_YZb\]ytuvqpa[Z`Y[XTTMIHGA@B=<>;9>98VQQZUU:65A<;@9:?98<88842SPOQLM720954HEEMKJHEDqoŏ~~}{~{z}yy{wvyusqkmtnmrmmpkjnihlffjfekddhdbgb_d_^b^]a][ngh\WV^XW\VVZTSZSQZRQYPRWRQVQOVONVOOOIHb^]\WVMGGQMJQJJPKHOIHQJINJIOJIOIHOHHMIHNGGb\ZMFENHIMIGNIFOHGMHHMHFMIGNHGMHGKFFSMMxssSOMIDCMFFMGFLGELEDKEDIDCJDDJDBE>>WQPpkjPJHPKHWSR_ZZhbblgfjeef`_[VURLKjddUPO@::D>?D<=C==B==A=>A<;[VUJEE=88@<;9:76?<:YUUB==E@>XUTNJJ;75kij1î~}|zz~zy|xwyttrnltpmslmqllnjjnhilgfkeehcdgbbe``b]^b][lhg]VV^XX\VU[TUZTTYSSZRQWQQWPPUQOTONMIId`^[VVNHEQLKQJJQKIOJJPJIPJIPJJOJIOJHNGFOHH[TSLGENHHNHHOHHPJHMJGLHFMHGMGFMHFIEDTQNuppIDAFC@ICBIDDKEDMGEOHHQLJUNNZUS`XXton{ylgfnhgidbb[[YRRNIGGAAF??B>=ICC_YXKGFC<>G?@F??D?>C??B?=A==E@>d__B<;>:9?;;?;9<77642KGF`[[UQN\WV>9:.*(liiP&ĵ~}|{z~yyzuttontomsonrmlpkjmjhlhfkedjedhbbf``c_^b\[mig\WV^YY\XW]VTZSSYSSXRRWRPWPPTOOUNNPJJfaaZUUOHHQLKPLJPKJQJIPKKPKIPJIOJJOKJMGFTMNWPPLGFNHFMFFKEDKDCIDCHA@GA@HABIDAICB^YZ{vtSOMYTS^YYb]]hb`mffmhhplioihkeff__ztslgfIDEIBAF@>F?>F@>IC@JDAICAE@?LHIa[[GABD>?G@@EA@E?>C?=B?>@:;SNOe`a<68@=;=79944>99LFIkedd^^EC@711,%%`\[| 4ø~}~|{{z~yy|xw{vvwrqsonunmrnmqlmoiinjgmhgjfeidcgacea`e`_b]\nih^XV_YX]YV[VVZTRZSQYRSXSOVPNSMMTMLNGHhedTOQJDDMGGLFFKECJCCJBCIB@HCBIDCIEBGA?WPPOJIMHGRJIRLKUPNZQR]WWd\\gaamggpjjqkk}{piiojimgffaac]\_WYWQQRKJLFDF@@E>>f_`YUTD>VSQgb`B=E@?F?@D>>B>?=77fcaQMK711=86DA@TPP]WVa]]b^]70/:33/**SONӨ4Ųxutwrqupqtoorllnjhlifjeegbcd__c_^a[Y]YWmgf[UU[VV[VUZUUYTSYTTZTTZUSYRSYRSYURSPOpllaZ[\WWa[Za\Ze_^jcdlfemfgmihojiojilfdwrpicaga`lffoiirnmsmntomsmlnjileegaa_YXupomhhKEDOIGLFEICBGBAHA@HBAICCJEDJCCQIHokjTNNHAALDCLEBKECKDBICCIBBHBAHA?c]]^YX?::F@@F@>D>>C?@C?>A<;GCAgdbE??WSRWRPZUUZUUJGEWQRC?>9543,+MJIҡ=IJ~}~~}~{}}~~}|||}{y}xv{ut{z}ww}xv|wvzuvwoprlkokjkffha`d_^[UUidd|{WQNTMMRMMRNLSLKQLJQJJNHEMEELECJEBGA@plk\XVD?>KEELHDMFELGGLGGKGFLFELFEJDCVONojiKGDKCBKBCLECIEBIECJDCIDBGAAJDDlgfPKIC>>FA@F@>E>?A>88a^]sood_`ZWUHCBB;<=65GB@VSQ7310,*OLKШ C¼~~~}}}}}yx{y|xw|xx|ww|vt{utzuuzvu{vuytsxssxrqvrpokiicdhccgb`g``d_]c]\`[Z^XX\VVYSRWRQSMMf_a{vtTNMQJJQLKPKJNIJNHIOIHMHGNHGMHENIIH@Ac][xsrLGBMHFMGHLGHMFFMHENGFLGFMGFMHFNHFMIFvqpWSQIDEMHFNGFMGELGELGFKFGKFFNEFJEB\WUkdeGB?LFBJCCJFCKDBICBJCCICBGBAQLLnghB>>B>=B=>97?99>:9;65UNNA<9-(&UOQί{~~|}{{ww|wuuppvqpvoorllpjjmhhkhekdegccfaae_\c^[hca^ZY`ZY_XW]WV[UTZTRZSRYRQWQRVPPSPNPKJgcbzvsQLJQKJSLMQLKQLLPKKPJIOJJOIIPIIOJJIAAlfetnnLGDNIGNHHOHIOIHNJHOIHNIHMGGMHHMGFQLLxrqOJHJHFMIGLHFNHGMFFJFEJFFKEFLEEKDDf_^b\]F?@LDCJDAKDDJDCJDBIDEICBE>>\VV^YZ@<;LHGUQNa_^kghidcSNNYST`\Z>99?<;A<:@<<<87E@@TQQ3/-eba}}}|{wwyyvsrwrqvrpsnnqlmpkjniilihjgeiddhbaea_ifd`[[aZ[_YY]XX]VW\VW[USYRRYRSVRRVQNRKKmhe|vtQKJQLJQMLRLKQLJQKKOIIOKIOIHOJIOKIGD@plkojkKFENIHOJGNHGOHHNHIOHIMHFLHGNIGMEFWQPuqpJDDMIGMGGNGGMHGKGELFFLGEKFEIDDLEClffWRQH@AKGDLECJDCG@@F?=G@>G@@H@@pkjjedfa_mgghca^XXNHH?<:933a]\RKK@:;A<=A<;=8:=78WRS@<F?>F?=JCBRIJVPOVRQ^WWlfezxc^^YTUKFFB<9:PJJgcaE@?@:<@<;<87<88PKKSOMjhh1FĴ~}}yx}}wqpytsvrqtpotnmqllojjmhgjgejedhbbe``jeeb\Zb[[`ZY_YX\XW\WU[UTZSRYSRXPPWPPSMLnigsnmNIHRLMSLMRLKQLKRJJQLJOIIOJHQJHOIHJDD{utb[ZKEEOIGOIHNHGOIHNJHNIGOIIMHGMGGJDCa[Ze^^IB@MHGLIGNHGLGGLHHKHEJDDJCCGA?WPOhcbF@?UNM_ZXibckedkdeb\\VOPMIHsmld_^@::A=GABG@AD??E?@B;=>:8OIJZUULGGPKKϯSIJ~~zywsryssxsrvqpsmnpmlnkinjhnggkfdidcf`akeeb\\b\[`\[^ZX^WX\WV\UT[STZSRYPPWPOSOMupoqlkNHGSMLRMLRMMQLKQLIPLJPKINIJOIILGGRNM~yxXSRNEEPHGNIHMHFMGFLGEJFELEFLEDKFEH@BgbbUQOLGERIJUOMYTSb\\ea_idckddgbb^WW{vv`][LECJCBHB@IBAHBBICBJBBE?>XTRojkF@?HB?H@AG@AF?>E==A;;XVT[VVOJIYUUWPQ>86MII͵DŶzywtrzutxtsuqptnnrnmrlkojimhglgfiddf``lfec\]c\]`[Z^ZX^YX]YW[WV\VSZSSYRRVPOUPOwrpnhhNHGSMKSMKRLMPKJPIJOHHNIGMHHNGFICAWRP}xwQKKJDCLFDMFEOHHPKKRMMWRP[UU_ZYe^^f_]{{iddgcakdcjddda_`[YZSRRJJLEEGCAKBCuqrLFEIBAKFBIDCKCCJDEICBJCBD<;mgh]ZYF??HAAF??E>=E>?KEEheeb_^WRPE@?1,+QMMϬ3ı~}{|wv||topvqpsonrmkqjhnihlggjeehccfbae^^a[[hba^WX]WX[WVZTSYSQXSQVQQUQPTMLSLLQIJPJJtnmfaaIBCNJHNJIOHIQJIRKKSLJTNNUONVPNRJJb^\~yy]WU]XVb^\jaanggqlkrmmvonsnmpmlkggkge||XRQSNLPHGKDCGCAICBJBBKFDLFHIDC[VSrllG@>KFBJEBKDBKDCIDBICCF@>NGFupoNIGD>UONniiF@?KFEMFGMFGLGHLGGMHDLHGMGHG@?kgfaZ[GBAJGEKDDKDCKEDJDCKCBC=qlke`_^ZYb[[YTROJJFBB>;:[UUPJJ500PLKFv~{z||wstxuuxsruqqtonsmmqkkojimhfmgekfef`_{zngga^^b\\`[Z_ZY]YW\XUZVUZTSXSRXRPUNMYRS|wvbZZOHHQLKQJJOIIOIJNIHNHHMHHNIGNGGHCBpljjccMGEMIHOIIOHIMHHNIGOJHNHHOIHOHFIAAnhi^VULGFMHHLFFLHGKGGLHGMIFMGGJDBUPOnhiKDBJDCJCCIBAHB?ICAPKJ_ZYrlmvqoYTSMGGGBBFA>E==@99SOOZUT811c`_BI~}|{zvszwuxttvsrtqpsmnqkjpjjohgkffjede_`{zmhfb\\a][`\Z_YZ]WW]WV\WSZUTXSTYRPVONXST}ww`YZOHKRNMQNKQMLSKKRLKPKIQJIOIIPHGMGGtpoc^]JGEOIJOGHNHINIHOHHOGHNJGOIILHGLGEsllTNMLGFMHHMGGNHGMGGLGGLFGLFGG@@ZTT\WUJBAMFEPJIZSSf_^idefc`[WUkff^XWA:;H??FA@FA@D>=HDBZUUKEDɧ+5ǻ~~{zyvtzwuzttxsrtqpsnmrljpjlohhneekeef`a{zmihd^]c^]b]\aZZ]YX^XW\UU[TUZTSYRRVPO\WV~yx\VUPKKSNMQOKRMLRLKQLJRKJOJJOKINGGQKJxts^YXKEEOIHOIGOHHNKINIGNIGOIHNIHLFCVOMqklOIHMGEKHGLGGKDDHDCIDCLEDLGFHBClgfkfde^]kfenfficc[UVMHGB>=I@@FA>E?>?99TPOmiiԇʙ~}~yxzut{wvytsxrquporolqmkqkknihmfgkeeea`{{nhgc]\c^^b[]aZZ^ZY]YW]VV\TT\SRYSSUQP`ZYyyXRQQLLTMLRNMQNLSMMSLKQJKOJIOKJLFEWQPzuuYSSMFFOIHOIGOIFOIHNIGOHHPKIOIGHAA^ZYgcaJBBFBAHDCMHFQKJWRR^YZ^XVWRQa]]}|mff_YXVPOKDEE?@D>>G@AF@@c_^hb_B::D>?UPNTOOJEBeaaΡ)1Ǖ}}yx|wxzutyttwsquposmmrllpkjnihmggkfdfa`{zmhhd^]d^\a\[`ZZ_YY^YV[WU[VUZURYRPVPOc^]|vvVNNSMMSMNRNMSLLRLLRLLOJIOJJPJIHDCb]\slkMFDJEDKEGMHFSKJYQS`ZYf`_lffqllwsppkkc]]a[ZZUTUOOQLJMJGJFEIBAJFCtpn\VUHCBLFEKFEKECIEDJDDD@?d__`ZZQLK]XVOHHOHHw c~~}}{wvzvvxurxtsvrptpnrnlqlkojjmhhlfeidcd_]zylhfb][b\[bZ[_YZ^YW]WUZVSZTRZSQWQOTNLg`_zttPJJQLLQKLQLKQLJQKIPLIPKISNLVQOUQOoihztvd^]lffrmmupnwqquqptlmmghe_]VROe`_|zRLKJCCLFEJCEHEDJFEKGEMHFICA\VTuqoNHFJCCKFDJDDICCICCKCC\WWzuuZTVOHGD?>ighȼOO{y{{|xwyusxsrvppupouoormmqkjlhf~}ojjga_gbag_af`_eb_d_]c]]d^]d]]b\]c[\rlk{{a[[fb^hbakedkfcmihsmmsmlvqpvqpsmm{ze^`c]\^XXWPOQIHLFEKEDKFDKFEFA>jccuooKFDKGEMGFMGFLHGMGFLHFLGFJDDkddd_]C?>KDDLDDNHIUOOXSR`[Y{utMGF<65OIHԙ%l}}~xwzzyx~xw~zx}xx~xx}yx|wwztsvonmhgmhekedhded__`ZY]WWWRRSMLNGGLFEvqoe^^E>>KEDNHFOHFNHFNIHMJHOJHMHFMGGxqqe`_FAALHGLHFLGGNHFLGFKDCFA@QKKxrqYSRTNNVPR\VVd_`_[YPKJXSRRMKVPO~{z̲h%˅|{z~xyyut|{yuszttzsrvsptppsomrllojhnifnhfhcauqpea`f`_c_]b\\aY[`YY]YVYUUYSSXQQSLL|{yrrHBBNIHNHEMGFMIHMIGNGGMIIPIHMFFRMMyus]YXJECPJIPKHOIHNIIMHHOGHNHJJFDWSQ~xxWQOIBCMGFKDDHBCHCAKEDOIJUQPqkk{vt_ZY`ZZTOPQKLMHH@98IABiff! s½}~~zz}|wrqwrquooromqlkqjinihkgejecidcc^]plk`ZY`ZZ_YY_YX]WW]WVZTSXSRYTQYRPVQOsklNGGTOOSNNSNLQNKSMLSKKPKJQKJNGFXSRzutTPOJFFOJIOJGMHGOIIOIINHGOHIJFEb^_vppG@>GA@KEESJKYSSc]]jdbb]]e`^}ywUNMMFEIFCHEDE?@>85PLKϲ:&ș~~}|~z{|xzwrrxrsvqqtpnsmkqkjojjmigkffjdeea_rlla]\b]\b[Z`[Z^ZY]WX\WW[VUZUSWQQWRQlggOHIUNNTNMSMKQNKRKKRLKQKJPJJMHF`ZZzusNIGMHGNJHNJIMHIOHGMHEJECJECKEDsnnrnnXSSe`_hcaf``bZY\VTUPOJDEjddd]]D=F@>SMLΞ5XȽ}}||~yywsrunovpptnmqkjojilihlgfjfejcbgaab]]pji`YYa[Z_ZY]VX\TT[SUYRRXQPWQOTNN[TT^WVQJHSONRNLRMMTONTOOUQPUROVSPTONyst|vvXSQea^idbmgelfemffgbaa\]XTQgc`tppD??JDBLGDMGDKGEKFDKFEGAAc\\VONLFGe__λST}|zz}yw|wuzutwsqupnqlkokimhgicctpofb_gbae``e^_e``e__e__f__e^]b\Zmgfhbcg__kedkdcmhgoiimhgokjojhhcaf_^lgfZUU_ZX\VUUOMQIIKEDIDAICDHCClff]WVGABKFFLEELEEOJGNHFLED_ZZrljzz̠\ Z~{|{z{|wv~yts{uszssxrqwssvqqtpoupmskloih}wvhcchcbe__d]\aZZ]VWZTSUONRNMNIFZTROIIIBBLEDLFEMFGMHHOIINIILHGSQOvroID@MGGQJKTOMTOLNIGSLKsmlWi}|{yy}yx{wwyvutpnwqrtppsnormnqmkokjokjoihmigkgghbasnme_^f__c`_b^\_ZY^ZW[VUZUSZTSTNNpjh~MGGPKJNHHNHHNJHNHINGGMIIPIHMGEjdc}xxHDCPKIPKIPIIOHGMGHKFFLGGGCCpllqmlWUR^YXSLLMHF[VT{xw[-xĬ}}{{|z}zy}xwxss{zzuutmormlpkkmjhnffkfeidcibbg`a`]Zohg_XV`ZY^YW\WU[VU\VTYTRXSRXTRSLKysr~yvOJGVOOTNMPOKQMMRLKRKJQKIRKJMFF{uvjccF@@MHGMIHOIIRLKXRQ[VU[VUfbb~xxSMNLFEUMMlihk`ư}~~}|||~yz|yx{vvxtrxts~yxqmlqlkojiniimggkfdjcdiccfb`a\Zoih^YX`ZZ^XX]VV[VUYWUZTSWSQXQPRLJ{zsomNIHUNMSMLQMLRLKQLJQLJRLKPKJTNM]YW[UUa[[a[[e`^^YWWSRQKIKEEoji_YZdabɨ] Bh}{|wuupovppsmmpkjnjinigkgfjfeicdc^_okkaZZa\\aZ\`YY^WV]WV^VU]XW_XVYSRpikZUT`ZXc]\_XXc^\d_]a[Z]XVWPOsmlyy\VTYTSRMLKEFJCAKEDUPQlihҀN\˾}xv{vuzy}|}|~~||{~yx{|{vuyutytt|xw}wx|xwyss|{vqpxrruposmmkffjdchccnhhqjhmfgpiihb`c_^b]\]WV]XVXRRUMNLDFJCCztsOIGC<9MGE[UVmhiҙ` Lԑþ~z{ztuvqpsnnsmlrmkrnmnihnihrlmqjkpkinjhlignhhnhimghicbsnmfbagbae__c]\`YY^YV]XV\UUVPOe``QIJPHHLGGGBAE@@D>}4Zec[ PQ* 툪莎(]4tTT]AuS@7clIdI7g읙+9O*":*{{NVo} G? a^,G#߇ Voz37_K ;Ik_boK& VrP8 \ڈ7j {y>k8Q(GJ:{dJ0/&*8Դz߰)o {=)7I98'=׿|ZߔqzV 7IEŁɨvݼ,*bb7Q1h;|G:Ns,k鉣ΥXhiy*Ϝ`w^ֵ(D5 @34zy} 6 9&^oگIϞt?x3Ƕ&Jp!Iژ7?#I+xOk8h6@!V3Tz 66"'U-e|;o}k|թ 9t TpbS==Y1^{\(̵@OGn{;J}0~ó5/kT߼qԧ~gj S 0%lΛhw->d%hGo!Ov ldMvԳ0>vG@ƠbD\ohj;%i]Gz=SLn !{8 2V dfkoO?t@SVt ?{% :^ 8Uq[:'Ͻ~zasluۓ?!*QD%9̿GLPvt%}$nVi?)Ism@*>l,gfގ" 5Zwm%R}ȞsBLt>C'bS[N;{=>dW1̡ V@<jtnj%;˚D\"._wDBC@J DZk( Yή;' ;?s1_y>)B'niyf6U%h1:پun[@)PH e!Lttygx]G *':MPF>hG~Q4. ?Q(P#lΑyդfm:ՕI #"SŰ\'8Bag 8}k>G,nzߨήxf~7WoӢ\OT,X`Ȇ K@HQݜ윌{x8!%&0K{>>[},؃[ w[3߻b}^G?vr|7;3-l zj9p':`YF@ϴɴٿ.-% [:iCGkg.4}_xKM/魏_Hwiw:oD>3l8GxӰ'gx`0c.㿼6#h=&C'_Z<.Sk-9m!Z/]O:_.Lqo3ɸB##aR{ᮛ(?G`m'7ޕڧ7AJ8t[ |S|1+{Ɣd+Çvk}'ꬩE_*` 'p! &)P~ SێZ2p [[,W_e֏w*5~k{_nyD @VRN VSpϝ۶gW"Z% )eJ7AXR6Tm|3Dt#8 N"bw( 5rCb+H$5nE1 #?g; ` A 5LwUIiNA %= e0 :vțSDYWuMun<9z3L3La6ŔwNmz(A$($$H„bc*]}$[ TBͯl%-(p<\67G8HAf`& 8C$La;O 5 z |Ɩg @P+ D&\kPǟ/Ow79%%%H*VIgU}@(r&% 8T@<%p*_ȿHH V Q+ɬxâۻ69 (H{Q`}H$B@ Hl/`/b 6* }`¡D@+$2dJAz-Mp7dwcT$K^ iFB4X@F =YK@HHF"4?gmwojS" h''n>` TaY`tJ "م8..4~vmQYqnj:1NF%"C>:EB^6}rn +9xāڝP(n#˻''1\c}܀^z$$Xמrl7FDeFj)2O@5@m "<#_3Q &3J ax_{nڢy'?NuxۙpN0X*N&뚡5ax~vigXA^<mg_֚{Y>"_7@$B@ 8]30;#%`pkB FYDY(a6@5 eFJd3[JAh0£///=򼘼0~vyqBȖkNYSByn&DJ9X[ЉdtNVˇW]luZkǒ1tP iU ;iϾ0.}|yۊq{ pxs6ks:"_[=96A-hdf*IZۈ:bDa?*r<]Ժ|עzۊ{*Ա0lN}x^:)3S@B8Qq[]"JPjF CȲn6U{=oVU(؀=,dYIrQ첰H+h.-KsC޶Y[>9vVy{s~|$ bTg}m ߔl@D[_,DπV8bP`>E*GFnT0T>qv^P"ti ] o1Ve9`2tyDB - hDY^5AŰ A3V?"]REAF.a^~tr0Ki:G A 1pۆ)ޟ pz^',{;=BHDQ+$EO/9%H c;d06G\Enyɬl ',C,QюPi9>uۄApG(\0XΘLDzPVP`1 -Ap5/x%oɉ^OA`88ɷ l;y VB,2}) zO,pfjtkS#Aޛ>@(`iW[BX?S~8&,4m$F慗ԑpݺA]Ce  "fNr|rkiR1w./)K}Rw; .-rFsKFw%KJ`o%wۻAk:hjEkGb Darl2럠d)z[#Ȍw,ƩP]qQ؝p)(i-TF6eԜ$v=` ٛ*W/a Ǩ~OOD6%9b8~K]~=ݽOPj\1 l 6B\};h,q+A p "ㅐ]e7!)vA `1 /ZP c~66;"USD%J f|qݕD%WWKΊ`E.ۿ0B $Ho*sy KH]0CHk ؐA$?Rh9@"P8j1tihxơ)诒:E89BL KpJɖOq \X6dAp0_}(AUCӬc!|A]-b#ODVG_ٶlOËo - B9.43#,v"wq{]u3UFyk>6yԠ6dZh@"ŌfKO9Y'bn(vbWhD8|VYd\l'4DQd#VTh)$V{;qm$9M>LzOuUi+#ccU hϙeڔp)t=5vh#j1ֳ;LuCؘdq)B@%SvC"0H vrfW. z/ /n 2J@یAF)ơ>HZ| oarž:6ul1 f6HȘB~S 3=;t yߣ{kViF$tζ( ΊF>"1AE8ia1UC/EU*-'s$sƳfXw:mmt͏^kl )bZ$"@yeKdmⵘJ-6.6c]CϓFXE** *#cWh7c֦eeZ )Z,?ù6Gf lJWQߕ(ڵʪ,!( Xo齅Tbc[9KمﬠQ!h)e5KuY250ХFN#:rGN "F#Ukr_rloR89,=Z[ZFQA)s Gr9'zVX h *ƽn[hᅈ /ǮG!O'r ON$ QT"Ӭ5`3TCsc@w_:2"vF2v" RcpEcĎjyf55:2R)LSz[*p`)gH^i?ȁ)KdUCȧ`;TV_6$f/Z4[ !@_F$jirEDwdC+**(Qcv[m+M16EnNBJU8Yr#XE!4\Ҧ}0LTWfࠤ?Q2a S°Yl؈sIˑc~RX>\0R#XWԗ"' ̎b sig1\KBT\6ĭqT"/E,ҠՂ+VI>^ghKj+++P3i]ID'Fռۈ̑3NYGE$փ+ ҝ>^P#"NȈaHy/eƮf -s/F/{j{\)85`2?| R/Sš^[- z\S=iGPTzn-IK ;`uܬuugJg]_JBodPOQa"p+P L5SЬol4RH @^p*@DUBjr Wp64K;7>{t/VՋ!K^DP*kmH_?ʛ,.i%/}呇~ꩧ,'x/屧?H` "G.M`<ҰO]d2 w-$R I~ٷ81 WOFg[k/=x?nY$p:0P(5Lsrk]*ݘ}]t2+*Kg77-񝝻Ɔ{G?+WO  AvpR  Zo{ݓC* pF2;ϟ}_kk%`^Y% M:qy腌$AG&(Ͻh0CjǞo|b8<<ƶ= [|{0/ 5pEZC^4EvW;#*ٴsѤPY-Byj%6o]wqwM&DG>pSD'/]^pP( HJ J m3kSVUFT̙%}X,uP?:u[vO|;~3o_iL79|^$r6/?޹-XLs\_I_VnQuW?[1̿9mo^\ʿ%p90Y,y6, drteZgCՄ`p\hi=͐fZĎ|rdtn#~o)mgֲO_8;x_uؾgJ"[$Z1 1:x$[Zz)w nzg~5{Q[~etP'`$`޳r[f?-ah~t̎HO ~9 Y:5keY=jb2|a>Ln_^/;ؙ#aZarT]}WN{h/g\a[NǯF0+8zÉsfpwg/<5Ɠ۩L{/{ S mdK]*Mg=Q=z/ލ٤8{޾lt͓gv^|O۰// 87؍'/(_I{=כ~M{az>2%KQ^y0XG!l66 7uLι[[1xMwu#~v]G%;qD''/0cIs(ښ%^|3-,@ EcYD .\=N#qiKt]ko/٣on`&/ G uwɍ?74_z]/h`lhSǍХ҂?G3k' HъJNOGE-֬<ދVuZ @>a2;,% 5N]kgO 0RTjݍ廢'kI&~v}C@ 070ZKx}6aXe  )gVpsW{[_ۋH"(r_EǞ{_^{t-T̋}T[x?,TQ9{;֗?ן73׽ebkmuCkY9L2tPj$Mqo3ndBְ;4.%Vzo UQHdI:,?8Ri2lVq*^w:xGl( aىQ"=xb i,_Y_O$4 |E¦7H?OҼ[~SaD\+'mh4ӪX8ƛJ-Kxch(#y!bxlXC'IJYA x3dr Ѓw\_lOrqyU>b}\v|"P`H;%D@\H/Ga572~5+E(gB l4̪* Avaп2\]nȘt^x2J30DK9{Aٞ䃎^ TK;uC;&d%@٪uK x^en JzlsÀRuTੀkQ6>nd(SHJ;9tW?9I: Qw-Ȉp;0A I=eD %rʻFMیgwWt]'<=b/0, ^_'+tX11L=Q ~Q$M^@ڌ~k DKbE'ؖ!6lF6mE=eZlRJJx-Z Vnw'a$:rv&-E!DVwp]!߮K$zi"M;RJ(N"55U Nprp"ĐINvDs]j!EYeYJ)DGzf8m2l-㙆>])V@5B_ Q%A+Ecl>O'n+pXv%B*SK O;i UvYeb2[IQU"łv;TV9F0M=z==8L4U$V  ,FqJ(P+DA(ZIk</ u|vӈrܴxD\"RICY,( Ny"#2R*a+>mm8v;,Ez]TR%Qr˟p%pX zyH)ֆ`2U 7? pt4ORQ9I)%JYM\V^h,@Aߋz?):"(T Jn 4׍OACQNhDiFҺpUلb}}G1$H(&}ٸvaJ9`nvjZBH`b !>h<&I0(UPjpF]-3IV$Iye@yIdy61A?"c:˲bQ`c Aĥhy27p$@9ZVe('IN[)|NdBauKӔcxQu0H!Rpfh7^.j6_0MM&m+GF>ЅHAB0poɉGnAAae "G$.[zU0d "% d|@/L'=y%eAc.#k"ĕ071jȶYȱ~#]  e) sD\$e)8LcZeyD 3*`Đ;*`5$_cqCǾ ;&cCG@\i1יZ<0:d]†#67ʐ4CfՓq*0"%-p%[ my* u֐pRS 4w܊`vsA# &H,ϑGXAs`[9uM,1StBc_XH=.em ͽx'b50ZVWc(fj 8?AN(x'Pe !.pe/!f[lmn4mwIDƻо)0@0ᅤiL'ňnRv(ƙd"iz"L'^[=) ǂЌ/E^DXD|wjmA#ipgBd>qoc,"/f.x|BKr5^M%_JI!ő~FU[ DJ4@$@TQ: K=_,bmm *m` ֐y`D8 [v1 K[H(uR@5L:6IEZy6~ݙEY9,&'&?0u{Y!Y>C ANa1zvڝCcnZ/ ]h4R?q|<DwJ @5}X"xVԇ_H)-YurjV_ZCb(7R}b1 {^jEaf!dZ-0>n`gP.@@o_ ~:Q3~"~ ǣuNETm*+aN+кYEQJ T^o>˅TewZ5 @˝DYKyh8VVt{v^ Le Rg4"R2|~xxz,Kh kbWnU%,<[X13x+q6Q2Ч5VWB Cq6hHP(FD'& /BރSv&dĮERIJFY0pIo?`!Lj^d:ibE<(v6|["Wymt6lQPȶYgD#V:%ɑ$;}fǒ3y@ᰗ%<|`LUռQFKFd2L[|>o,2OO//b@mAֈ3\۠M>[ʡz0ńX|QcqIkOtv:nuICz~^ɤ ~m;dQf]m+iXm?Y%~Q@5"%x\79mTt-u# JBH+|nOOv~~La۷?آa ˗}ƀ8|NYxwg'fL e%.?yQR i81,p!k1 BA=:lTl5ia9`ׯ?^gC)Hr/^/ #R )!$Hyh:FɁvY\mii>~v~=oybBH0Oo|{3d !F Bbitn&.€Tը̪Ύ\6-8"0@rG8rzZ(d@!ƚv>hǟn~Q23$E#BrZP"4C_GVC/1ũlҒX[0&7`ۼf'P }VqlL`&xRR6 4LX8Tz'w3TDn?[*iGǛe;2Œv-|U {hJ&>dP3#Fk+ 縘I|neEP#5*8ʋnSI%SB+(fJ TPʕk:*EOwIY;#9/Vv-ۈjyVimSGnK)q8p<9/!D8ܮ4gRX2jM@q*Ѧ[j\8ρ6\Zê( }O'!8m/| b֎:dUA/P<^!r\i^\X^]bu}Q:$[Λ שt41yi?14 ̜"˲L`bCAو#;HZTݦ?J")F@r%~_8ħ 1 eq3#[CcNlFCsOl ]+mÐ(grYAB 61F @p8||yqNwRO(InYt"Q(YֱcDcq]#w.o?e!:,`Cpm˒K5COq K^BL0Nӽʡ!%C:M*:E LAcOud1T.]d[WT-6viH"0<-˲tçÒsi<a2 2!ߖ9<$L(HjS mħ%m)elmKF@׷!=2(t8(ieӂ@Bg<~gə%1ȼd8D< BKޤ4<煿OǧCi~DcJGs jե:8:A%LJ,ttsL8 iHߧp[b)xc^ĝ΂eVۊRӺ^W!3d$Ñ֦Ma!NN1 )q@9 ZHoT8+6búiÚy\>uBz+0>x24F0D]m%^UMԀM\ 5 TvfRb2O8߆ܧC8>4rMR2MeSU1-3ժl mg Һbٽ4Ͽ)̗姟^*_R3rfsQHShtƂ]L)e'M&3zR<1& 24/[zQB4-{[!ZleP/!p<xnr_Ӈ˒]^e}vZp<䗗I)h6 N򽖑! }.%*P[ */P59ke9xq8>=>.|^!ioJ͙3D0k^BHUFBTaRD6&[)ALOy$"p<,yY6c yɂ$Ĉ X5Kg9IM2hqLOt>ȐLJ^xRP%#YbpΙ9m-5c%\਀&D@N珏aAvudY3q(uVNY;(kjMXN Y8rZ $!aH+?9`v I@!$03"2-4.6ci I=7/5)/"0BBaPg3z>/%6-) !`8a WŌ  E ,30Xt;<ͬp9 >9Ti`sW IDATRhZ0T PKEX$-Vd!Hփ񓈽:3M[}'/>!I'*C- 8ayo/3öa}Q]Qnz=rw4Kt]H(!&>|Kpxǔ5t5RYɻv0 4Ur)жxmb-3`Ш[.NHD$|({wADq8nŶěnЌ|m#H~XIު,Bd|h8B |WΪςЇ(q?2h*#IwqaXŝ^J[/xV+@8kKi;^%4PW/뮛]T.qǾ݉Sn3f+;\%((.1_v${n竇?۰ AY/_E5| W2C+Âʘ>X^Y ˙NTԮ#n23[cCzͶd:[caǶ( 0 i|Dt*꣣ѣ5 C(n 7 ҇ pGpg'Jz Ո\-pr3,3/BK!ZL){G46fV&H_m hN2BUOs zKiE:f *< *k}گ`, Ѕe69W^Z* #o8 q cұ v2K1c&flՕ XHufeBYrS>{8Β[[2x}'F5L0N9 .qe|5+ʦjϵK!g 54K Zs|ET&ۮ"9( -^me&)$c֍.5ps !! 潆! Z8 nu(3 $_>| oŒ\*T}%޾O)O??tzopd 11S}g.xJӗo_5/O`Y`u n/1e˒qa@H(NntFWj4歵q<?}oOA *o˸-OO!/K)>JL1ʫ1'pɋW9f aq)߾ 0t yx||8>2nׯ_sƔdыutacy9Q=סpĺ5f4y~݆4<=??bz "LJpDEnDyxbdx(XQ`SFE"XGpc!Ϗ< _$$p<u,rN<<"hnVnH gVı]j\iV8F0>¶l֓tZBBL헗Nh|YqA=!כV iP[3)iNK^d0*̘ |>߮71'! ZP,Y7NM=ER帄1h{H(mbq&%\Hɔv.2/sienxV}qW/eti<!t˒yxy9.<~ c q3"NA6;ն!f,M:dg'Rtʈ8~i@;l׈f[OpXqb8>ˌt\^1@lJp :Q='jVk`Mg%B8<,t)1A}+@%"U VSS̨)UF9> G9~@B*%ج8ȳ=>_>,^.T|Ea>({y :H!_5kie~o!!_B|׽18M1TΪ]h҆.lv^#L-^U18 cen'ݮ']10MV'SUJTSI̊zms\RC 4+:n VPE㴕E[QOj]1R# }VwU$"u'+VO4\e`NqXbGؚQ}A6fSJwXp$-H*so߫h%ع'5[t~Ti2Tnt6uqv:i8 kC :S71n?4*?6f%+‘&n٬B}`F\ژ{Ü P:yi=qPZJ߮UxvԕB3Jo(6%H8 ]q^52jl1aޙ*_&+XmQ`]ġ>Ƙ$qsZ A0G-A:Ahx0Lagl+"4 㴧k@ÁEV70}kU7;A-[FLfl;Zj1I udŝJw;偟Q8M [_֌ g={K*Y,=9Қjd뭙#ڷ$ a5a؇jI-ޤ热 5fyXs2_G'q\?.?ipw1Lm|wDh_Z_̹GGmL%#ţǮ"D >AF0CY|6"F0C~AR3;a'KN)  (ZMԪE ytB&~`ЩZ :G_1 gPk&tuۈh3`@3'y2dᳲhdv:}arM1[=Xɲvuց0Y0 ,t8gjwgֳ\XcVߠ*UD=C'$e1j# 4)GiZ趭zR }̅ÀnPXVWcvA]W؎M(%l;^%en5í{@"l>Կ&WH;4bwU 3RGo8Zn{|YdvC1h7e&<ᵛ`K=mTOq#(ۆZ lY~Fg~PݰΉͱfOr~ZBu#B gu4$ons׿nlUawdQM[D:+K+++wXզ FkGJ`!͖ͬkZGԾo) W=lC9.agVZ36_lҌ#`T;U{2QgQuGOl JlK6 #'qSX:'W(iG{/Zn3k6yݭbГ;"26ɶrsZ;6ƁVإs8 f4^I m[vPHİ_|ϴgڜ*+zޱөugj'CwzNT˴c?˝;˽!Uy:hKӽ m[~ij˻O˱)"z`:HCobCFOm Sè8A[YCFDx=GA͝,}:% s מK שu*A*ûss5:يnS޶۽g=Zlؖ ٭rJXP"0N@f􇺘%$4=c8&WN^ V)Ӥy?U`mn,%"xN))*OWp_,[KeM&=Ȫ6[қ0v<_]6S_X>uv8|JB6п6sV^_{~:n967uwhl-0]=4 w}~} $mm +G۠QU mu}h{F">ᴿxO޿q ;'5O~gwW$*pN +ާ؝;-CSQEm=~_3 N}玼X1#xik!حF;VQ}cf~zrx} mogN n}{3{ n gsl~tצl6#iN\wBnEf:hfoNnlv6_# {'htpJLֳ~BK9x>52ӎ|TCGedh|Qʳis.4qԃe(@ɶch:[f}U0CijDV%L Sw.f5_ښ4P.rhY;TwUӑ6KL?df|E 7uc ʆsXTi9_E? }Ī+2]"lPofE/qޟFXM`!pV\EtS=MЀKE߾V:IGia^%E( T.h7L_~j.-rM2ǵ)P@,3_k|qKm 3[*I#*s=f_ӈ7Z8#lv/]Jxf [I, }Ho tݭfۙeuV nYT^ӻV]!*׏hY59SʡY-X>hod*l 7P(YQb7u@[IϢG膃zK?L=*xy-yNE&q -Eȝy/lAa@W '1 (k6%CVaٷmbVklƅaһYSLVF'\796\8[ώ>ۤUyǂ&$Z:@V\8z4~HGAYlŜy"o@]&Uݾ͑ö@g^H&z/dI] \XL``OV&e3)aW]~U{?R75Ip _:h4<3*HC<ؔM6OO ar4R6nfulO+΀3{8kԙߐ|1 :8Tv^\=Y* :봞8NŖ6d[?#T)C9@1 hQG$TKT ]h }vSW3gΘoqU|5xCȚ8TvG%7*%MAk)t Mt{pCݍV1sOz2ji ꠜ ljM圛E i#d^VHu-.6<-/RQjPZPJ؉ъB/Sϲ%US28{9[8[v=[im{W(N 5`aAm+ QoyNBx`^HT,|Fb3{36ց8kN` U2c!!`k :tÆb>MŌ=PM4]5(E@ś0Ц`w ^_rIKѣFVg4t8oPr4ό))f6 WT `WSCYlq#ޓͺn.b+"m|{]&C4mOB8::@/U*t  {ES{:y쯟g;/R>  Tcmho=r_T\OFT1f|vh/zt^P`} bM KmQ5Nw#{]Z.h]vb ˞CnפG6%di`1%ϣP+vErguAM8o&!& J'A9͕gTV,;i%$ ز jR5;,%@Hlʰh jRBLZ4P5RPE+MժЌ}X5vla<%Ή^V7;Ozԗl4CMdņD@wSI*Cy,Ğ (Ɩ2EJMSiۍ]Ҁ6A4&YyËQzǮ6 FqaMϮ8Zڱ6nN~z`BȈw[i&Qm?6p$!ONu4 &Ҙ~z-fOw,<ڝU@7X &j Ht&[գFJ uifcIo>5+-şGu(& u+LקR j˪ m?BĎB@ڪq'sB,mV B.kOW U6<-ߛlh*]l9ithF`͛%A4L{ؚa1<(a+eALΖ4V> c&v mн*I+h66A#=F*C]KKq7{OVV Qj vBc)3* 6\fQEM SvۃXGK0f^7q@bAV;0۶=XvCq܅ijVi?iPQ[Z|oI_J~ꫪ*ɣRbΝV>|E nCz[{Tw˟X>.g%8piZfktyΧ(BIDAT&ު@ƨ<(zBYiBalfgΛgVTmPL+{lx޺Cl^lwr -(K/Q:Rװ*֪ƙP葠Wj GF:.t5ln5^ĆC3) `9ВzCuVhS :)H[]ޥykAchu2`SŪcQ'qL-s~TPue0uά=(4ŢT$.@6d]Kг:Cef\vU^.St !)%P;sx@wVtZhتc9'X,nS-jU4PmPP_hA7(J2Hi`ءTMp,w-04jeTn50gĚ2k:-`TzU뫳"좬gq.Xd8^?%E X@R:mT"jo]~Uh zzp( Ue R鞳m$w%G:'`Z b:",OvI)twvTp-|i)ä݌%Q%X't7,M%.WDK$oybeU]~K,1ic6W:Qe# 1]w7҂4eϼi&P ͧg.0}oڈB܃>Y(Wi.dIax[}eCq@Ď-1;_MB;n;6JXdwsf (bww>~Nξ<&qFx7uAvM(ņ͛l1oi.i/]pn)RI> {T޶wyhŦޮG4^q4D{KSpZ9RF$ ټn'1:{*/*^e{734q|ivxo]cWJ/*҂]IENDB`jajuk-1.9.6.orig/src/main/resources/images/src.png0000644000175000017500000014522511720500104021754 0ustar drazzibdrazzibPNG  IHDRZ=gAMA a pHYs  tIME 2 tEXtCommentMade with The GIMP.6, IDATxy|7ϒ=BܰjG[;]F۩N7&ɡ3y_yo]+n($* ; a 圜\?^|>ɳu/r_bKx].^E\.^u/^ןo?.RuN\D-0ߟ+eS晩\6`[adg[1]&􊖜vMYu/f#R`eɄ矓~e_PhQ_^>'|6%en!' SeNneض;Ϧ|rmOEv2lb2dF I/͟3$QjJr9|Y'woFCCf,=+ݎ6߄u G(pkutce]QPuyN}XfD(;yCYǺ{1(?旡V'l6n&X݋ʂ7]{;4 WOP7Br>$Oc8u^Ơ$7-qv_i΀rJ}s ajύ`׆wq8a3s43D嗔jvw?Ё8v`hA;1cnZu}0[:[9`NރPzc̀r"޺ʟzc;۾و1FtfVb"W&e<^ <3V={WQG:\$v}T6 N(3?fN(a0{9W^+GƝ+ҜONP:W?-wmny ySĬL'v""oX.~,tG\4!$owEc1iT%cQP$!uHEeDJy*_GR8d4M0|Zuv Wv %X~.C@o7:;Ga|jL9qb1 2d NGm/.6"lt%bX~z4Wn, bQ 2ޣ/&OQ4+W2ђJwP߀c8(pUVt7t#+(.Jǣ(sJRu"'!l@\l.tw.,v#oDfMz=q1{;ia4X|dŗHTܢ L88, '{v; $i#]G{7Bɱ@ =d+J}Z:ѝ1O!wʤ1{DJ~`(=G}Lk~hGK}'g~tjK"|ByU2])<ŞI╶I?<q̺ VCQ3P|1hR* Krfz2w\}Uы݇0zr^Nc.Q] 9jSS #=mauE1@Oඝy:KxI%&ǹx.`Uvg]}{oiI1!'Mܓ{{IlG_ *bHv\œs]yj1&1 ])}Qzw# 7qgSg  %+Ɛ8MwFt֮ oBGnYi?é3&֓w!Žw"JK듻Rm'/5?B}2)̙#zfTI{ń#t`ԅ{+bfIc!OM=w#o,JcLj(2N^E[=҅y~OCH3 ʠ4ى3i >8{whv;|ݽFWD}Eĉ">Yٍ4F`;>TD:w^4>dڂEit8SIrUӽdK)xh?DayG(DצoWGفS鄍*aVtA~˯(c8A70G(6>] (ӋΎ3 j鴅HR&̍dO@NJep:AI^B$h?DqY|{hFQZ$2=8U9say;o.} Lo"B{K7yS}S"n܈+ykW8C˟datwO?=/{t\mr_ڻl(lJ}Fԓ3h!r #NĞ.d!Di̷Hc'+ }ȷ]7G KJ1qjMf3d±T ĮX>*W#xbn8rmjB"((o6r$|{܅пg'Nb۶c*Kиy=>y<5Au. YE, %cUN_]cGsSf6^bR$IUcrY~L_}IL i?Ɯ@=/O|"\nMbLzU쪖Lcu|ݝ9G=7<'m%ASDsx2xb<7ttS\H} x8$zeFA&_P?@444 WNAa=eqLnf=/Ҍk[>DhNgƾm(k.߬JoͬS>Qp EFKAowDTgB}$">&m@"pO@A8.('J?s:q@̽$сƂ>qyITAZC018ݴEi[!_fh']d*BK&a$JP$-+gPh qC}gp" 2$?i 5l!,"^Ċ$y-`}\z1˟]fwVa_O O `I!,.edawJtgml}qϹ}_,v;X(;nڟ=+@Ai:,c D:A^a F_&z;cPi l<%jj' J:藲U}80nQ ?w]F_bI%[P nso? `!lN̹`yb9j:;fc[uWM:&HxN,s+Ӂu/dw9nG" |yX;ۍ*\wǝ<_Рoԅo3,[?x?x^o݇%<-i_C=+Nk(Nl^$X1 ߹/DxH>|wQš 4!㫛pW5ԀkPMDw$^Ot ߽c 'tt=0$8& o~:wê7WJyž=?4҇ƊM2Hd'6[0"]R4u*ӕbP^n/pg#S?'1q4,U\ ]ҵ$3Ä"UH4kq;4^GK$Wcoy`f$7b0sٛ ܺxJsg܂KQV-[=hK0kG000 Z\|͛ #zkbC3Qio0VRֹȍ!{ȣCŠԥȉ`bطF*@(N=9cR,7ߛ"| rLyAP+%`*!cx{w<4%y @f.u0˭4jzs#! Zi,z`hq!Z([EiNęzc[8?C(ҡXtg{qsy>8DDWx4q%Ӓ3h*V>41^dI\[Tb{?01crJGdf AtvX{ct!De7]4,m;8ۧ__CQeÏ'ޮXŮ^L*Cp K)r"8Lcdn2=s1=P_E3b 9!?[Խ 1X@d6IB^Y)R긏Zhij/|#!9,U(Rp1aXFg@Eȋ=ˤIfy )J"XDYpˆ܈yќqȀDx(!U9:EwFuIY̮Ct,"1@G`|hޚWVoq Xhij)3:OǺ0fD?UCW6E?=KTW;7F`<)1y/RB46?8x7p}.T'vzF} c]BaA!rtU@X8w$^+w42SBA6jrfM>ͫ^AI5# R!d6a]c.X]RWWD4 S xysi .lX[<߁J[Ȥ{"9^7,įW‰ ҆7~?%!R]I4njBƌ\ŊͧL[HƆU?nq}4}PD-ޓA;W5z8wyzEs'wW݄G{,waӫy^SWV5BoOnBq# ߍ;=x&ߎ^ ӛqNڳ~0zsD`°k@I z,l:Ǡː_ʪj| xύ+OC^JXp;E^? .SkY2Fyr"~lu4mc`Bt{ v%~?/un/_e#gcn /5?هV]n nx#8%uze=+'~}amu/*y&28nU IDAT_V^??ZXW߈]D(7C{\?EceDGƀXs29Cr̉?Ϋ}s5o^~Mc3_wpÓ?A㘻r&ըJ޸\I'ZDj/1}NFK\4 w> Iu^kl }p%[OJbӫQˍ3B!gSRo*V̾φ߻mއq%xpאst1iH$xt亴HG[Da.xjC䂄:?'o,V d/؋mQ'5A&o@A{)$ 0a_9BA+ Ƨ/a֮1"qW3~)z2IcL i1"T'Ÿc MÇ_G1 SsnEd@~>!.ѠP,C"d2KMġ6rzoB޵Nξu ȂH4&.0ց3 4$?~ҧTkn@ vG_ n\N@)};xM8D4ժe\=gMv~ 1՝uvZ Hfr(v]xl!yBxVk}vՠAa|&~g(^\$}*|r~I8&N_10X VXω/|PghX W~aׇ̪\ "э O Qu7aϞùY0ʲoiWΥϯYDp; 0MK" h]6D8XN+Ee˲bXaz !iI.f HS[\X8\_ Vhǔ;H[+.B&R^a8?Y(Pؒ,;miփ.1zmaPRd0ىe r=hc _0rmg \wcaQb:!刲W>x:;`uUX \hllDB@7(KyQwZe mŨs7D]Bحl$u :fq'߶SI;^J~`vq8*78)ƍ_D}׆=!,9y]Z:`$F.C]]}0+ݍ:brښZT!&wɯSt+;,D' Hĥeܖ?Hn+p@?Kb ,q^ZE qI>M{.lCMՓjMLKr Xθ L SBHmzs:4|)ni ˉj9:GZXt׷1x@n} =X/81ȅ%R8e]Jx0sAb~>;⊏< }M<+bJ*Gbpi"YV%%_F\3 o|r30Ww͗p l[2HFK#,2rpw)9 ]hCdQc8kGk{O.9Ǖ+mra﷧¸r-'m| ]s>;[IoQ9<.zJJ}:]`,a^6"x$ic2` ‹NHCFѝcNcF19p^$R`JQ?مG.FZ}͗ӿ5c-[ឥ 'NTbƵ~!(LX7'͐v+ēpRD-q:~6O1d,1!μnı;V[SIN/~,Yp oFW)|] z0?|L|A+&^"$H$y/ƸSN#HNxW0l޶Q0j'raʾG* Rd(v ;?%c/\L0MOw[`B іAPzi@ ov@FՀ+pڒ4%B ]Vj1R4O 3w\f:es]B{h3OדE}o=Y}2un!6P wfB]p8bU5|6B. D!Vm8xk"҆jS3i.Fk1 3]( tNι*F7]xFtJDf P5ctZEnMadqJ4x[HAg<ՆάIb2%Do?Н@ 0Mp qcQN ?‚[%Ļ#~ /o g:0k0CxG azyC倪 !3 .J-/1#3ڮ``dN%zUٕyIɵM"E$XK!dzp2i8XY$9BXM:Ev\o q tig,~Yq`lq$cY \7\8r@oIHI%@1@Cdt8xHlSXe3d&g ,ũ,?`NN]u`X e#>/yJZ!:fX@î,xqnw7Ag "sЖ€?Ƃ?*BNƤqZMW8רjryavbm 539 0<0J䖩=!PC},ӤEkSG'-maRya_WaqaQ#LY 'J weX3\YΞHd֑f |.Џ ϿvyksqI`=XxdBRUlsW⁨[#&ˍy!CDd (XjɐRZAJ, #XBUutbd<Хɯ%|K}76coԁ ʾQ(+,vP8[bGbFMw@4~5섈liygM5 (=Ů0.pEXsB:<;dLC^9 ]zsh:LJS.sKEo@~Ca!ߟ!|+Ȁ.*6L`Ƨ̼0Fōs&= 3VsNQ%HX1m<-|K1L$&ѠB"a H8$xҋ}?=\t{j8s͚p;SZH"my2j<4e)ȎZMAVcI+IuWRwcL<0ҼoJaeLcKDv2K%I B`D4@0 凴z>\Q2I|fMRZp9y僼ԭ!: I:Ia~IV ky:A%]ar$ $)HBT@ &*rx~6K q9DZ 4%5?&qyEݙ8z;u6MARt?oTH/.L> 7b3G1{VAVFEmi'3נ#y3+]]+2dU\+ J`G[p eBƢ]욱Kz;4&NlrŮ]4$i%}CGA,_R2ϑӠkAT8h1KO=CkZ9#0A'"]R$;:2OL\PY8&Pu7<3s@KY"Ĉ2L{醙3ӟh@~ٟo "Er&θAH@+h?x77ǐp0I$_%/RFƵq'a{#3b4A96Gli *>9K/F8;-Da!{W̗IMOθ)QCut2&|TmV1LA*"Oz qҰFs2kR6tc|^^W19tHf󩇮} T )PN6zd!E#kEXG`l$*.cyua@ʪ!zb|(H"lTͥ?Nr P[!VA4L G HeiY6z!8&$T]D_ޞ83IZoQ0SPk4KQC,}̎FY.RahRp]<4:|Mvjnk|HwNzUڌvd0$@gKAZ\"0 Y Κ;`aS)F$XUT aFwSț9/al;A W`PjdADQI⹅CL)EȞ8aa)OM4̅,5 HvD$=̢h> Mef{QhY& )W&,dY"K-2h6J xP^DL\z3< Nz4V(D1aѓ1qpM :>}Y 'ڻa$N_?g]lXD"q^}r% y?ԣ=n|mΠz-7V7Fz Zű]_u C?3x/ޗ$柁gesDWx8KSQ4)yN} 2x_D0ճ)c<:3z~\gB0;2s=dE55Oݞn;ؘXH-}*$˯ǘuuuY)#o˂z}7оoz*yVWg{a}ucqCyVoזm?O*}'6>^.sB=2dH.XwU׏3ZRdؐz"@A WG j-L:/80GzmVPå5Ǻ=NFյBu̦ 1(߁tޒcU}0^wVyM-HR$'(W+|*? M}{[*S'55B6w|omI3 峯ŜIV=Ȼ{".*ӃOG~x]@ɠ>Z̞4؟^Nɶ&7p}watqiC^wAG 2v.>o(_~AEo ¦W>YI<_KXtt mxC#EaOuX~o%,:z[7&N,r@''ƻi؂ o~ os؛6?2z4{A:OVM|_,щT!pBBH0d\`MHqp@"@K ^G.1.\@|0^ <*sqR첰^'Efn> JUcᗾdbP8֛^O'Vwth5-^MwbkCpGqҹ(+A$^ˮ]>wOa{^߃Q '%/x]ԁoQDq\vxݳϣ]XdJbyrX~*Xqo!qH#Cw[/s'GTYn@{ҡX˅u_Oݼ9T[k?\* @&f[J @80m pzOuA T\,@;0Pv @NL|H=Hj!!@/%9:d{${!cąR  >x@*zUM0$š4|p"zwɽw`ݻP{ NB*R©Nh?4*}bXs;Uǻ;PScƢhjG'9aygXEsK¼ WyZѝ\.>yOĺw[Q(Nu!EaCr"8ԓƘC?qHh*ccq$d揀77'T Iul2 V]y+5?yf "9C$RrC*$oC mBgI)Ip0G IDATI8O28ˁ2 = O)c]3XW)⑿@j4Zǯ^x |׫hĢxol !?E畉77_x {7!'y)~oOA/{(2 @h^/0 Go"DW8* {2P1$3\Gˤ:8_7bX2 r(ߠ]NNDlfR,5 J Ɨt># K+{Ci ̉:S@a\q.٧[MW6l mn<ݳɸ5a:vˈpA</6DfGJq QE44AMkphMpm/rG= vkAwoV&L: -6^c ǽ_~2:3'6pE~=oeq^ڞ+?\d:%PWapE~N²,=7f &aժfɠ^iD)E4BVT щw(1\k;;h?ӄkXiH7EH_IF`87gwYPPEA'տ l4w+3 u>dB#i! ?\ht˶E^ HOJCkEw̎)VuCN GL*܋#nBމs2 E*p3amXrH.ʆ~I | W/wJ+OŠlH|!}@Gۧ w/4s7uP\>3ެ`_0zAIy1~~q3~%9w騛`]G#4go U~ Fy"Yu=׮E 5ҳxP@x!p!1J8({A󞥔&@-D@{7{{tihy!H I{q? o.hIcs F!1n&[Vw\磫J$[|1k+Ci%i>T-&j1 td%ѩX Zj(dz&OXZ a֐KDՙU뒉!'5$X+{WCFZE6LUA) \?zѲW^T`8&'J%USQ~B II0plc9ח|kTK2ݖǓOt 5:xgм@5[g&8 |N|N]?)҆BmfW "@`5IuLJ$As1x<}=c1$H gwh| YSeHu{ѯ4!@`?Y^ t0ЁA/H[DtH]&#{S͊p s}<hɧMcH(n3 } 3@L2j>AY&#!4<4 *@c 5GjtsCs4BYĕ̪a`?MJ%8f;Ҝr,NYc J̴f PR4}/nڍLعаJW=bYVվç4hRGXaREԤei&,KiK}+G#yjG!g5adѐp d[IpIȆԷ }Beݍi¤"h=Zy)Y4 m96<{G#gyX }&CT-T#Ϊ&$2ELT6'Q$QEP!^]MD-0~붂0KeDlg1Fz 5"lё&yo^/Pº`2!}k,%ۇlفCRElO'hΐ 8ZC-vd͓Dצ/v,v|Ů p!LdL7oLVKs\$=߅LBDH,Ko~ס,$Bk$ñxSp~~h Ѕx^Qq݄\po@rݜoim$<܆ㄘl`Eo, {ź:21$ rNIL9Yq;0iN|^F=%8fA;.: !0w,(I͝킟IX SBnhNĢ?~[ókMڬW74Fj(xFٙ! &}q־CZ蹝#2f_5P1ic_ZC:~WY9( R8צW#.kiј0Dx1&b\09_h#9jJmD1|Bv7 auwb#u>ţ$և"!|A!ŀC H%$E[N- 2H\D&PQP1Qp/}4+m|<~.Һr;kȨ|#&]8 ل2dj[ \]tQ?ʨ;ŎŮcnn h ͚4l=0JTŮM؃6[20@MPkN<-vLҠH 9L0:58*Q= $)"~ǔI8~"!.\(qC&짒RR VAxםM͇͛ YW]vok ,rJwt݌fL uiG HD0/tXK9:y&AM$8882o͆Jo9D۫7?DRPlqi9j&c<(<{R*hC<_w9DSIIvf0(泘1Dx(,ڨkv VkU˽Q^=bg9ӧ@C=U+t `8v}6piI"$i6pyZLc[Є sAkl7Y Mgr%| rNs^;׃eBH`b;1dL:(E  gfDrnmBTLP>A>v hE!`LUhxEP*5ElwD.wy.ґk2}҅:NM *7Ix\Ja~| ! D'^p7@SCڹ+߄θIi- # Ւ^\b w1Y"B'0B5Fd3wT& }X&3(qG)vw/©BoDQd"^cr q0Daf@XE1T4T9K" yV"˞q ,ˡs2-JOd'Xcod;oNb'Y|jrc-NiÜ9N7D~to2˩!FZ! [H'>ƥ9q ` ƞ¤F#!]1;!ør9BE+KD3B_ g&FXOSPY/IJP1ٟZR6 't^Q Y|+\,+ZRd{1Z+vFx9aIٶ6V6P8CՋОd]N_MФSg&c<L&:~8h>v\McfEyxń?aYa4ЖQ`p10u0XȄLIj6q6}VB w,vupcy~I(;ӽ/>N| XI_-j˕Ԋ'tޙ.G@;A|Iؚ/^ 2 n2:#r\7;k%2@9`[ p8GdK\ eAq;!vgǁF_.l^Lvt ]G7yf(ЇԂO+>6VeSb. " y;frwxC\J 0$-`-"O9|R`Ӈ7 ie.z._L;9(ݲlāIUa0{R% G=\Wgc~S|`PD?o8k~A9i(rt4|i}}I%rZD {[{]X)nk cjjD`82! iI"ǒ?*BvN:1.w)a( ιw׿gc;qrAH) HqEB6%Fɔ-ҒRY*־ȻkZ},+ TfH#A xg}}t; ;z6|Y~wiG#<6E?3͗8}RV<854Nh(= ?, +JId cd0بmz ~zsP,lTXQ,קR~̺K>Z~BP@ɺyɽoׂb֐AW+my&>p5xEɦ&|^F(9!$c+῿*f%mylWTT~:/jIwH`̔|Ֆ[WlmE*1p%s96I xIM8Wu%uey_?~:^ (I#,c|pe751ӘQV~Q)t__6|F1IR2&X֏TUYS+fkUBZc0jH\'X|W OPƶ1ɘ)s IJ|sMdLЌ+ `Д| AjTEG*CV! 3>H旫AX_8 CXQdt:>r5 ɤS IF&5>}J_e$us]-dZs}{#(uI0*Zc!DzEOvdLA2 +Zŏpg'YPq"Kە=yK֯_HEyV建dda8xFꕴT1x+wnɝ(}Rnno9߷(mx{7q+?́,G΅cw=m~19K7ގ|k&)\H ˰S6v!0{V NJ|L7MK}e<1^m{ʖ?-SZ[ ,jRڙ V{g{MJ!\.9$8t\2R2Z6a~IC6u)xwdV {*>^*;'<'?Il433CXUY-h }}O Z֖vMmA^=ĕub xW4W7H _y>lXo̕GwխiJ4D %Af&wBϹ~g3kj} 枰d2ft/T*iya TUmMΩh{|( å)TD$Tq^Cˉ#\^ p- n]u|M/Z3R9!fwiʕ+Yfoߠedd;v0::4Hh4z(1<ЫJ1p!2b\ᠨVV~TrWZIK^ ۖSa8T[V ~WET0,aq>߬nNh^0缦9dΣ?XiH5B0d2R)Bz jar0ȯOW@+Q)1gu* n.?uU: ;oyuO6߳tiQ8~ܶXV** 0CjYC9vK;t@D|)SD[}iRiXD I5W~ʐuhoMp5{3op C}4圦5eOI:\BZvNAsKyl. 羾l߾G!\SiӀxv;^&?~ _8Y|#b)@"o!u ugm,pr%=1DhkIǨ 8gl`q+hRV35k6v)zK_ 3͏?ܱ`s?&e]&tN 4njM,n _ kňISEqL)$Q{?jP#( >t\ sX%_mz\> V}]0&6H_߮gWK'!#9|MH~r*M`s/:$/05~mEmx="ݭ zZ#Lg ɑI (sblDhtD-a^.s/qz11:⚥\JHɫOWǙ. ;Ѡ[hRn6ǣSyv>xWK %GgyH<:=rmK׼HAnrw-cy|(s⟟KF{yASEwwe}{-G7Sk^V++,??;Dy]y2#"Ђ;7 }xyN + ;zNacdQHgcFGOKf& hj0%\:^Ft5ktF82X``(MynQb8,kkqDJ,8e_ͭ[i3>g5>^ZbϷ~6(t%E Ўy5]בηn೷8KeCJ!?q'ױ(y)2#1Orm",:'G4>Д/gVpѽS,=֏WVZOƮ'Z9n}|[h1^Dw\~_bCKi%OYրn~hkЫUZK296#486Xp)IM\ciG| N `l`pҠQQ':[`ߩ< ɂ(M nojр05inamr^ᎻV#bQ6x #QJB@J[|7;nD+?'w[iHhD e'<çwr8B"&wNұŚ.cOx[iteWvfg'd~pe׷]g_;VERGN8f^juh>9)K.+Lcg9=0H*[{%׺U}r:SH$3Y NKxOIhY35Y(P[㎫vDi9>RbSڠF`|Qr$Ɠo3 Ot|&.[`'G K]뚕:C|֥<:ӏM0216߼mՖ57)&d% U*EKY$IOŬbQ"#yJI5P*]o='ynYp'N8I^f=As9)*y#͒s-Wdu)9?7n׊"IUJ1y m݇^bb|#Ye_΋U@-0$&Yҩ#M2xLF3c fvk.O>^4-m<-5:o)/JFS&F"&~]v¸]_B%ha (Wf8>jdJH#9qD`Sh\m13y% ȧ#5.Õ|r=םsSg*|/R$<;UbKcĝ0<".uDWTp:o$!D""^Ɲ_B&p2DDo]Vt^4cbn<|i210ɯ~,UVqْ7,cKn>&a`9)2M=YyK(WƹH(SDʜ[n}ᚦ-VwPVwvyV\.*1$&!CDqJ&C*&ioVzD%R!TKTqs=[i&ϚG)ݿՏoe%+Q!7Ixh MzZ n]G?a"mRU׭ƃ?|_g /欄v)m_ʊm>NE+2a'u#~&_+k{.!AqU-3|!}Y.L*-03mk<jC `ɶlqYoJoVa% ïl&޳ezA}GW]pG^+?-Y'۷<--C JFʚ^rNvz0mKYq{<{q~fLNNi&6l0g cļRSU*K `|lX,A]}a9dPҮz_xNVX\f[fMDj#UJ+pkƢqbgϞGW_eڵY{2mt7x~[|jﭺͣK'*!Ke~`s !?.;aFk-bH\i,ΔׯRBW%.Z9,P;a<@@pҟ]uaU܇K V}*$B38J5!|nakYŢ)O*iĢ[l iVMv%X&;J)y Ji;@ꇾrKk)(Hؾ9{fgv) Zu[Vˈ0#n+pg+Z_ϩj3btH#C)rDXzEl<zV/P11^?[YF͵_O%]|^/Zl舔)<țFc+ Q)y_UFF,Z_h{y%Dv` !fN/1Mv׷ˣټ]TA6NCŧ?yqkb Z|Q~!po<3rx- LJ|P!i9_>ȏs_XGZ{~ݧѩp.OƮF/k\c!gN'ѻ,.{<죶=\4A}1Cs%7BKt 3=6f묵S :M X`>㍢@^pˇєЉ$\yJpne;Z" 1 0% {K.;fnh΃1FcBw.j[2y_,}j?s-H lؓ Or-hβͫ)9>1M&x+H&%:-cÍrɱ|ݳ'z0S_$ M]Q[uXHPj` (Y?%2 <Y5@V!T GxG @ +lA% YgE_$1i[OX,\,mwIê>zlUJ`i.O|!Jl97 K2YΗ mXr\.4_SȂz, {>B0iBYB;5ɀ!fhnEIg[NWʄt4NM%4rS]_zͨxBvu/cֺE/rS)iZ O#"#39x | )#;WϷx!|\ onO˳S%4EU/ewis$,,#r)P#˜e|K_RJJҜ&U |!xks>Q\0=)P|o٠$oB&O7˭Mv2P飇}}is}ݺ;L) &/[v,i((믻y5G /غwG_ܲ 7Y $9km Zo[7L|:V-r )YqNE|!tzVT%,fCۻ@3;Һɯmk28>wF6x뷬2Bq"z~/{1h$j~:*W$!D"M}?m~>% [/x)dv\r R\pC+}}E!Z; 2gvY {26'BUJ?7`P3BQ9"PN"ijkx<^[Qo&bt)%BBhjjje.V޾0} V+~4Cey8wEpT1 xz"c=?Pʙ^>w'N}]$X,:jШ滺DQ'쀠 mllt|jZB=^rGyaF'AJ3|*9@nB5HMfl4ADq |{u|]SG4lt:M&!R*%NiD'L<9m)Bfb־m\2Yaem~C3_m]e~zgۍ:kg1'{le#>oN|w"(hB8LMM166$T 0$ $I:YV|>iNN% =[#uf_w Iγ9Y ϣyYs>sa0/Vve||!9s D"illdQ__Omm-H) )grzL&Ԕsr i\gp.Q}Q]vy'OoߩBfΗm-G;88ӧ9~8CCCiii9R,5 IDATZBl6[Qk8RJT*dY<E333,Zz' ~! [ J拑JZG2*)n +EILs惷ΧU6xŕX/^YIZ8;CB0::ʱc8|0cccreMOO 3==0\|>O.sL]VcVu'gnGd2d2 ǎСC,YK/ŋŜBU VrUω3 cx*8l${|V9|Y><3,(2LVCjvّjwNyX۷Akeifgg aa:F pv;uoSFwuuY`'N={5kְvZZ[[f%a˅Kz٩ٿ( ,`cm Oҕo*L8jJ5*H=oƆ] պyTYTz.DTf>66޽{9pXK/Vi㌍111A:hcUm_&9s W^y%˖- A?WPJ+!IB`ev|~4p7%vu;#XP/(yӐ*6h@-ٳ\~\uU$IR/2'O]GhH,%d>4 E ēD"Ya FPU[屦ing_UV͋)d(YM,]7(-'#}tUkz,Lbwj#k5TG" ޖwUs"8!X5Z޾)}z[%; >ɰ:9^\!OӼ+?~7zgNZihh2!䧇ISӺƅZ4cL05>Bc[7M7w`*Z&TS,-䀴b444puבfyihh\.wNV.$2A_aer>Qrn>M>miTY.a~X~|@=[I'GJT(aG).ira:ҥKټy3di}Y?𳫋IA!Cv &^0zF M4 jZф DD`HY&0xq &%5m4/d ^^( d쪵H$B]]W_}5ٻwDb>Z=E3jZNQ*QTn]ja>lnD*Ta]m-++m(fYBߺ<y&< T;r8^yb:|B?zZ^DJ8~8B֯_OSSB}q '&:z=0~W9Lqz$HPE=^K_=^ENMX{ =L&C.czza^{~'5w<@e{ϵl}-\J|BHvH]]]_={pY֮][vOJ˪Ȑ< ⃑y|pg; IPˊC2~ee!\TB!SRZg5^c)J:uVXAOOOرc+D&DcdN0cQ^F4QC$DcHL b]ZRc̎P8 5AӠ.Z:{YbSSS= dO'?.D.la_d G%KT>>`+`,e5&UW*ߠ!fe겠J9OU oe'ʍ B4U^U{a:fYK쟆-͐H$kYԻ=<3?2\{V(BPWWt:iS6]_A@~_5BX?ѿ#a}!D{(UB YݕLfjSJLr L  ,a7L!J@1z{{'O_֭[RYW)! ߅,~I%t/*v 7d$_z~5Kf&&& _͍#{zCJJ%4-5-#0@ (``S2\ndP,BPSS67\q Fu)1Y󇩾t~$ڷWV +x񗾾ݡz4oO15mguٲda%Ijkk9sLYF$75Djl!I| t J4Rޖ6e 3szU,a-kjĚLjvRX;S !-uc?M74R:-T2ɋT򴥄9` /!(mayPo µ." D  _N/_=ĥ7PL x# ? J~?R8bl)$ {PS Z!@7%Bh@ YuftSboKkB&zIMI,b67Ѭ@ K&R\Abs:jjj( 2::JMM x܉E>^eU).[N Ju.<̚!gpCܫ4K^LY!+zV;?: dzfpDʠ =w /:%/(To g99!_F6];!~ut;ӠKG}rC?9Hn}fn)k (ouKcLf` r5͞q8DV˲'M?CMg%f||íto۷_ZU(#*zWRt(j!~~6G?y%m^J_9OG'-Y+г)aO*l&MHRXL&Ǹ֏1>6ާ@N[l#0|S(addēVv:;;ЎMm¿$.¾qKN6&`L~74@A I[nhFO={{Uؘ5|TjkckK Sv)}3a5)kՐ 8&iYiqѯ_?H[\:oGlԠXѤ=N9N)w𬓒;o北| *o;p/^saV8984MAjڸ{cȬS)'ʓ f/v)B^ C]`m/^{-_%FWWH) d2d2R)Μ9éSRҥKvx.+B0-%Z ]mhRA`"lG0aBp)҅t:&t'\ 7yM;`X;5L(YK)61LQvWUn8T,cGkx!vdbU?ʛZ <:[|pHz+IG}}J-{g$ab=wӕuF- ~YODU=M23$e@N'l9RmCXY ,DʝLlu1 f榏нd <+N~$2_DDZ\mKՔ3\$SEix}]k׮;dUNÇbv:.16Sm$q?s饗O?W&xAw룸v)yS#v޻&fA ̌ "X5a!xdI TFedb&!_C}6/p{a~IC6-B]cW‹ i\]x?Gh_ȇ]­fa~HԷ7ru*oZ?x2%uiSYOϿa&gP-+?::6?bxtx-Nĭn$˓eؼy3i:6M Q '6YĖgϞGg&d̀o3H]B2q |9$?XYIx`x 7/.?(T?ype !Ub _HmE{B&8: "YmŤT9zуm[لacGFtwwٳg$rz.YpixIMMϐ̐OFLAI*e-ni個%kcPS_GG]# -tvtZ9Ӥ񣇆Fv~I['%hJ%uYw!&1+cFd d9aIC%X{d‰ oB!t SQ"(hX"AsK;={YRt9W"§vr0fcwme͑65Ms@1YゃVEzhߣ/ZbͰ*W -MT\ %zd5U(4X_J%-*}j*ەku"ek IH!P!Y@$pnޙYB-Jl -ıXt:]Tud2%K]T*Ec⒵ cLO3$ɠE"L3P,ڱD"i$7EmC=Mw^D<f r9':Rp[Hd2p'I>Wɹ deet|7PVIl8hz* # *AcU"A $ 4!"fD C&*!͑l_wff|>;6ilH&&&#NJT,Y̯NךLӰ^LyDH$OH 055 X4rTl6pYSSC" 8HTracl4 ќo`ƎWhJQQ-Ϥ:^j`#B(F9k@v9D0GzxTךsijG+g*)FCCwC ")lPL}V||ޡ\;ؽ`]oG1Տv[Kv?L&XGΩvaRL&D"LMM144ę3g8y$iE{{;B'"Ji&bE"yQhy:\MYs8JΧ0EoW|*)U(m켏'0YY^鶰o+ F+danoכ\ss3mmmDQ'ǙK$9z<'ؾ};֖0M9{,ɋTr.<|H,#J9cۚ֬&v z.K9|*"J9_T0 fC8=[yqWo0NnfH7|w$ˀG?B^7Rd a}r%hlq:gW?hG W,;Ѡ+"`Zۓzƥ;`ρ) Z[Vc}VgOЮԷ5r]kY <_W5M}=(w:֭Lw%r;E]]Ì[U!S5-,]diV?O{>wcXI:::ӧOs fffذa_~Bdb/ZnnV.ꢔoۃ<Cn%! x qmq6'LJ305U[+[3Mvg*rc3%&;Rpi',J_qvooA1KȮfۦO;1TRP̞=}}}8q)˦-3f3 rY<'㕂[UU% ^g?ҥKQWWuLv~x9\*7}O@BWmx^W܅` `AܽQ>PF<)p/* \ !KvcҐN ѐ\`*!ٟ58s(.Śo"ɥx6ޞ!0pC?[TYhʤ ɕz#Yg|"Xq&… ܵn!62,Rwzݹ! GY$z}MXp!2㣖˭Ukod@~.X.]ɓ'1sLMXɦ,|9(1LbppPx\cڴi())Ü9sd̘1C7Or hOp9¬HZ!DխFk~25ܬ"[j“&HEdߤ~kel?+QęwÚ 7Rxm))}`>K0aA0^"B[Bt_5OO [k)޶dOaW23FPRRŋPRR"/˦;O鴼.| F,C? @0D <Fq b||eeeXlΝP($s7a茌 !f&b20= =q2=0C\x10 \g?}^ߏD"!,###ٳhkkC{{;PQQ+WD]] M{'"3^|d cC}xI^+9Aj8Xɱ!i؅r Ooh$^y 51oMy&mEv@"EHFQC遗~Ӊ3#g:$`G<ͫa8bdr+ߛI`q2߇k9 DRHpRDP'Z"{ZG,#ɤ' [RMa|,lV@qdٔIɏD"0 sA,Cgg'ߏ˗&[x.&QRs !9 97y6aŨBii)ov%k͢f]]\;V>b ?[^Ǿo/8 P]0_`INufgT'}NyP2wIB1mw( @'B8Ў#H\(0۰ [q#I+Bk"*I@͍ ?~~%8~[q{C^Y$ |c1ljr1>cxtE}} A7m>%0{m}W^Y$ /\4c}:fXI<(矣F(BAA(23[ޛ?d"{ ?%_,5yrNY9dGhnG8\Lw\UH-cӧ+H3EbM$@ŝ9g*4rİrKPiPs!U6 ^;wNc֚Ր; U[DqVf &ꚩ7`ˬ0qY)ob5,=, _fO8Ak֒8>3{ 7 _8W2@h%VSu )Qzh"1>>ǃjÈbAii)8IY- 9YpI|BӇa,X(RTTt2`\Fkee8VJ=Jfݎ+N4VIqf%G˺ YIfLǷ(,2#qjd?jV o03[ z!Dx\@RUԠ===(..FAAzzzՅ`0JTTTX(@s[x*FjpE9sVXXǃ3f`ƌb9Y  >cRA:Hʎ7qB$?#P{Y,g:ŵ*;3ΔISK3; *QEųKZ4QiY̖*)pj63Qt.RسBt^sB_o0T)uq\ڊEE 'g|:Ywq\r<###H񍣬 ϷԷr!6L.2!ץuS`~$ j8iϭhw[Lzu͛Pz2& 9r0ml:zkY`&KZ ?3o55ꡓ'OsAUU lڛkZ.T HW\4ͼFo@Q D<_oڴiXd |>#Œh]r .X$7͋wl盐BP,rHeX?υCw#_},l$N`uut2`4l6GB9v0x\mm-с'O3f@8(1FD"=appP̬EEE6[r- FD0}t}\WԵv]cǎaݸp}=h rxrilI&F9ΞFI%(ۍY;9nTC92[|r ţsmaF ɓ'qetuun-Y-g~n2rCS^XX(_r;_}`0`0  bhhW^E,C4vx _K@LnZcȵ.dغu+i؅P0o/--E Cs(. P:|q xlOV7AV|ˇ _.Ce:faɩCh]/Sf/' }͛䊛u7mj3QϮL1|v"7fVE+B#0;\qO 'oA]y)r2g/FA,yL ՚6Ju1\'Q*;Yb>?#fLƭhюkssrhha;(O!6'yqyw\|B> x6a&T*-owFhZ%=N .O3{25O?=W?U^za-,ҬkX<cx!z4쨩FK>!sw<=MhMUG y~36Kw3QR}vK6.Oexl^^#-w-FK>-Þ?U`(ZchMMf |Hh<{1HNO Մ:X.͸f nfw\ H|,T3>awR]Z;::ow()CY%[0_~^7ݤ7`βG1?tDO3M>EKW%8֭FckBߧGϙ%iY)@5#wİG3,0VOOP*JnׯF7wg-b{`.✗P>e3K[C l(Z"Ys/)Fú3,4#Tz|Mv9%;3- ہ7NypcccFm`C[ 1Gǁ'_ڧR) &ً`t-c,<\!Gk;(=#*iJSVšQo߂N!&_nJڽ'܂L`l.~ÀP)oM&F)Lb coY$01{΍0@ p2,snN+ŚK3y DZR"{ȴT1Vf-00e+axY= /֊I r.tA!.{.<󡼼Fo80%zZZZrKl6ۜ>-'N`֭8~8b~ H9#9 ZI b#}ucB$?9 |ܰE"T0&6m$RtVj2®]14xl GDI\1[ CECy 0>w:\8ḍ.`aUʉAz;1%$ͱ92t:7 u% QqME6 exZ#)P84;8q۷o{ԄףUB?u<:ͿغUEa\jzNİFxb`ۿž|Jzg?7)LdG*#x~qso t ^֎7PKXWaǾH2O"s@O/^{|^x3V>5݊ouq^XjU,OUk [z5VXl|S+$p +r՛ILdc " qaF4Ça֮]+?Brى۷hTTDSo>.螙isR>ƠoPՠ]tW[[[coiX,ߗ0r e",fɰ(>"7ar3{[ZDjG I"aҔkK چqn V(M+FAB`J`̂pZf67_L`\3s>r'0¡tx zjz>$d*F@Z 0]+bnY=c~.g)l ?Dr" }d{_FG8Ö I$WFOPhKZj*''"a׮]h9ނ^p@^7+keu^9q 6Šr8(2&|v+Bb2Gd`jIV ;CZ#[^KZVY3>oֶVz K &lUlXkЗJiTx>5^[[vލfI() g8`p04 :Љj$WȂᄆ!o"eYR9l*h8w/i4iqD ị㺭 ѳ\={D-  u ;iD[| IDATֵPpY4qhj-&hAKg&m&B[+KDLΕ ˮj~}9p>=7 *<ã3Ka;~2%rU~nkk 9{W<_BF9mĮwn'2nh?**8p1:: ߏP(P(5hIܞp=rrCRΟoMy=Sumt5j.]N>sǏȈCaѡ`.4dY9gE")m\ZQkZ5#y>f<31 YI5뤢ud|S6ǾyJOΪxNaWȾLqf{WW$#I)4ߗc,X&DckEdCmH>ɢe˃*M `R31e 3/+aUBhCfPZ[ON­u&Y%dWX6=߯[9O({ww7:}r.>_1KMP sIl5}^mw)&n ]8::4Žl®]J'Y^ :%p֮.Xatt~_\u#fL#dnR\QjƭR0ktJ?;T &'aؕArt9b/CV2)#`Fӕȷ|آɃ`'3mt)kF ,1P>+>Jj檉3ٔn7ev2❫^%Gd)V"0) rx< 6JDc0aB vK7+Lg >a&m)J ܀5I #lB+}EJV*! 45`6hkfatHX2ieV,VyXP m f3%e`梂WM.bLV,D"ak:mrpi:u G0C!MvK0vȮɶs#;!G>lGS{kZX`Z,-HkC(ێt([ NQemsh}t~=0ڊNYۋ3g`xh>f(,}I$d\{M%=dZ(\SA='I`+!e& ]eYh0W@:9}0*R% ʼ SH  k_'(q !RgR J8#Rw~mS#{jԩS8q℅g}ȞNzPFyZ C$KUOdg۹>nI&]8KHGgRB rypsYOLi#sBSKf"$)A㐱~EE|b i%?UDйQ~Z?.3VLӝ" UѮja9ey)NѥrjAkReJ?C0 1B2c˖.z 3n 3 ^[w6;]mB׳`9xs?SO'[?Y^/**a5 q) gg Dtۏ`͊',h{#E9r}$^^Wd+e|EOn~moJKk9'I=2g`<6W?#LV۝8 JG07eaVyy#]p=b]5 ^%L67T>)'~:nqS{zF3S,TL'qj姎&7/PVRZc급&,LrIENDB`jajuk-1.9.6.orig/src/main/resources/images/border6.png0000644000175000017500000010255711720500104022531 0ustar drazzibdrazzibPNG  IHDR@X]wV pHYs  tIME9P,tEXtCommentCreated with The GIMPd%n IDATxmqVUk恤hٲbeQA%lq8@, Hp?4$2AFXHFl 1("{w8]a^{Gw+*S!~W~;`ߋO;?b}}_`?7O0IS=?2? dQF?N9_,Wd@ጳ?*> %7­m~/yN:;Լ߈ioQ=kT/쾚=2]oޙ>~_tؾcK |fkTh?/r ŀF~ ߑ٫(1?}._ܻ=,IgH|eso?oJHp =@ m@dswH?1xAz~` \w!ˆI_K]K>o*% b;C_hc#"/>/M~xzP὏vt/?= l _&fzQ<ԛo5-}$k{b"ݶwC/Ru*ɀҟ:zo~{` pۀi|1_+磯ӽ#,WR![>6nQL6}.k. t N?)g`p_QC$ @v-ib[alPVa.?ogS6@5}~W3=]0?6?Bp]Q+sQO_ ^/i2^6~$-M܀i;*X.oV_) {Տf[/5Vf@*_hcy_06 vb{3?~ >w4le6[ *61~s;OjesnE"wFV&*JnlS-+@Ai%l(m?prRufu>F> ۫b!")Il/]'ū1(YRJDD  Qf\}]{R_c̛![\x0HG@eֺa_|eJ~zoڡϠ5!1H1y _?:W߳O0Jx0St9;!F9c~s_o/E@"@y fs,~㧯>8>LƇ5O޶G yQOp_C !!n ! jy~1[eN}}p<$sֹ('twpfw[( >:}?_."!) j7j6}S7hY ^4k޲ 7_SYx.p, Ma |ep1Y /oҿpOgPD}OZ8ON7yz٬;n]Q&Bhh?n /ӛ>K3Ucl릞׫ْ{5"oL?؞]"Eo]w߻9~g,7{ml2:nG.!X2+ٝ_w+/7W) /ᕏM~nی7{@.۟}썻N[m_ꢺMӓvl %>ztc 2,A>ƇxtNFnH _gI677{pOӣd8& G|2/O~,` X z 0 LF`y }a_8#"x.2@W5 [`|͛GYǃI>/7ߘ7TetrT#)q2g>8iGs?3ܮja:pFZ%Çǀy9 ` \5_ڔf-Vk|چ1i~x'lE_>` 7O^a0 DA+P 93ݿ[^-|xwfɉ~ffϫtJ1*akbco&f5j%aAdOyy axhH~DJtt_x2Dn8s #0 09aXPV!I`A~8s" 9 .40UyóSj45nV02Ψ]<^ Tuuvmܓ+g6BƳvBC0"1/JsP0L&3d)d 譧gß8fY\R}Lc>w {NE@nyG>6%KXm@4,G? 73΀ibM_?~ta\3Fw4n?* T l+0,;o~ ;@ B4(_8|lnK_ #epkBS~ZfAT+Iy5k% J0H 'Zg_Iv}/ͽ`42]xi |旿My2?8Q@Qr n8I~_+7.2 `:\1>|kwV\Zx])y 5| _|[]jptT~%wTn~vUy;kfOö<˝PlޛOw/[ˋEO= s—ټxY}hz?|.[d3 g߁]BG̦`y*M/2W0 (B U {Ϯ}{=Ozųx{-g,e=P"Hd Qqܗe!X.7uQ ɣ;wyK>\fݼQ~pT6BBd6ب/9yqWXetvg'ͩۜ~s_!3kZ^rYzTz9/ovA2:H'GhF:E$rUG}co=yqLI:9٨}݆ecu?󷿄 2XkT[Sbk60#)J3`%*ծble9(F'D.e/E} Js!pm4WFga7zI|!A{HM9J?,3=bp)QݩRC@NV?;L8T`iy(}b\#G0{S0r!"wP(]6?~FZOV4T 0O<KW?pJ4]0"bǘ7|HDwPAֆ"3#oD+ d͡x̭#"7na|8{/ˍN4ƮGV"#@$CWhn uLa:ApT@A{yĦۑSXx}\F1ƀ2 p%My"n!_=f |0 b8I~m¡Gr`>1 ȌBX4'8y@2&`ء0e4̺ ak;ݔv>BiM@]]w`9#˹ewR$%Ƿ 貿@+]Α`c`ȸ"sd}mXL&l|l' P!mk n$m:`ĠacejedF@P3*ו96w=L %Ey{}d7x`5|n2 8"ct #oUy sT?{"Q={t]^" }n\Pѥnp쁍oq9pl9BcYZYJh3lߋn=vJ§0);~OȂȰhC-MN2GxY*> ő[W}@.?+$&90\p+=w-ya".k(;!ߓ@>9{&;qNb82JԁG$8,1وtyheƣ):ExD8BL q %8'd8{..SGd at Coo?GgQ㠭W]v1\i!`I0"<9 Apϑea+#x㠒sB.0P([o:K 0|ekD-xi nWRf CMvY7ߟL'53[Ͳl<?|\]^-dn!P=aݎIe0;.4!D!i8%D D|nyGHts}3_,90 MYf4M9ף82c,"25IX~=Q=t|A{Œ4@47Wi=@ib`ZCJ3W+v:'turyyiƖx.JΆ,ƽaX9{%HX0SZry0!0(,mie$Z;w.,<չ=9hW M,:󰑭9<.m}p~y$&)*HkD#ڲ4MNOO$KYoL)DQW/a1AS2r~}5_9e-3t Hu3 ,פi-3)fXSHTecjƅftb34ͳ%u;@I `0h fk%E -8&j=yz|T&fQR8V +}{nǒ:@QOق-qm 2aI%i*!0%Fh eH6^Frީe;w&Y^]^t6 Ͳ޽{׺HUI԰#^d;4Ʃ7^7"` ԤP3}NM.4"BAgtb͞+$`69R?ShZQ: ".цtķj*t1?b؎U;W=v9ލe69`)P!!ZnA/f _]F0H I<ЀE 6znVni|JEH81lV-\8>Ch/6hNnfl,Xy [p^9Q!D}B&V WKA$" N!Q@"źer#1:(e`Qyuf'cL[l MSS*)R#&NW8,DᥠfJYH6 &/-3wNNNʲTJi뺮v~ sPHhq#g:8\8~n @*d<.ΐRm`S HwKaa(Ea@*%!IqYRrX"{CDFϸJt8zȒ#N䗧1ӎ IDAT$aGc!꓅襴2+H_Y3T5#F9K&>GY0u";`DE:hPv肄=-`ȨR=P1v o^+K > 5G.G!IH䣠 Kʎ>=,3 >cJ (n4r!=!D:v@cԉ`Tƽ o2]ҦHnG%1G|LKDȝ>ؗgq`z!H1I>,G!-3=^ 6JȠرGJ9^2Oą7@5%o""77Ks:s'2 ^+=}y@hvڮEQ"E<& 䓋]^KJ~w`Pt\ʛ}H*$0X׋zXp0&P11zS\'&Q-J#qo;v\~/0Ƚ ţ 썝;A!HO^I)fFzvxgQ+D.+0dG~zu"_2ճwZ~t:mשiiȲM'uvQEMf+܌ ܥ<_{;xptvzf11!a>==<~'* >9=~ٳz *{I?Ւw4(!XY:0*QDb iƣk?.vJV}P%V&  2Kgut(Nlۭ1v<!aQ ;Zdzuy9vFJ">> #JDB#vƚѾֺRdnEQ 1= H.pUUuS"B)ZLOpeE}N!Ļ$0':ij/ck= W7k11MY4 Rv HhHoiobA63\!i`QULc*"$f>?hilQc"ussYJ{";:)[rMMwgE (\jki1MS[k:^8öf4Qy:g{3FjT z;X,jV]Lhtzzyi][{QfNĔH#tJrq Ča'`q.x<iABDcWp tRW%QGF '8L^cm\ vDk,! A\d)ߗDQ.Hu] J)kmnir.w>0ؑP١#?GFiiPw˶n Y@+y0HdCg`08TNO^6~/:[ # atcP#"!ɮUl> Ml3ԝGV;oM46"RqvFpC|K@WRvpTR< kh kEm41Mڽ D"BA3oNZVl^^D,\,he0#+ja\Sd vKi gG;J)դSJc0 xCp0t:lV~@-H5HZ~!sCJUe5='i^jl0ȭc#"N,K&UY&|u@S]ݣbHH!aQxd-ky{щb R]\`;Uz#M C$'抾%6[ d:y]7muDu ̖P%InMU/$=_+ǘ*?wY(p? ܯU]N&$Ii mBTrAJ-tNd(: \2B(E DEv{dlDV'u$H) mTPeUm"b2QEiiGM]=e$wγzx6$PeUW@0ں62"l2^V֢ Y9)ȄA/ѽ|Ύ$rmk% cR*3"@Qj[6;"aa\˥C&b;|?5PY 0T9IIsP{Կ3qMmpUΉƠ їtaw1P%%e(>KlI|)b%r,W5L'/FY `d J2A Sq#-,!ZJ׆`)dXE]p-*IG ]ITgdee *Ncn;B7˷8ߗ(QrwyR@e&r1K#hɘ,zyW##]@Q3+TIms#$ 鶷̚me>BdvT}`/VA.݂xUESj 'Pv b&`~6XhGZ*n,!R-~CPsPuW& (t2 ʪ",˚0pUUU@&{,eUD 2! MFazZm[i3f_ `-'I҂\Hh%4I$1PY,BY.oc_+dbז?H8ykSbX\>Nӧ-&:M/GB@jr,OTvaB=}}QtGh8F:~G>~:z; uCD0(T_s7,z;Gh4 N!dww PB v$5u1Q5'bt)55;P;fB^ #5H,EG*om}47QE'4p(kє l!"Q |2FaA usyy=h'?~ы/;|71[Rˎ^+3Z%eYtcMcJ/h -oBU+K|4ƣ4Mrm<{£G\dk5m"j'?Rڪ#h? B9s0ãK^q>~,Fx8i믿kJo|޽טXk;iS2((\1B}"F9ђ9AVr늦P*>{ҋ/5iLѣpX?'ƶ| Xfl ιc۝ocm]S42Y EyoErb(J"iS7}Rt]$l677NzZ,l5k5Xf0enZ[7MJ^a31AsF=RE+9cbqUp4Y*0_ѱR*It6 ZKZVT5FmGe`PG΃mK*9Iwn]7v2Ll֑/8DdK[/Sf|Xk(v (C^%]#EiZk$1N1RJˋ˪,k,22NeYYjLe9É2! Xrqx?eN)"U>ț 77uU#ǣlvs{cٶDf:M,K(sAQ(EթE+.ѩG:c )lF)c'}oIQ$d:,b-Xf6;8==L+][EU~~Vt{ w)x"0 b4 J1$1Mެ,o&Iwl:ͦU]-+c u]"Jt86R=[{b=x>jQC&뺩3 pxuy1MӜ__$iz|t\7MUMLcDTHy5MSUY4*DU u X,<dxOs;11gQ_\a'.&W[tۖ4/ÇYuzMq6H I RTY髲4z(_'B⪍Шb]d 8p,S+Dti|]խF^,v'vӒ`Gx2!EfU+&Hp_("L44T "!mh:LeQ(V'fy[3#$%@}4;mpoKkTQ`ܟ.w`jP-N0Wz6mDJ bGH,^(oψ8j!W=(EaX :r:nK DnsUv=ג#aC~1z%{RNHi}w{8oRCF*fkpߑ =G0zF{3ޫoR~{Z{eQ(?S@l d9 d30J ؃\_B-罋+>vH C#ݔ̢@P|H/K :ݸKdz U'=Aƨe[ˑ \ 1˙hWDow❜`sǂoO yQQ.Cs1(9^Uc^e(n IzdJ\w0ݰf9z*`Ats :t<iVjWzAR r7hG,04<Wy2ľ(E0<6OUReA":NQ j3o҆rĿ\G(N'"'r3Ij) #ti*Y<F<MN8V7*X*CCj)D&W&6Op,Almz&eh4&2Kx墱%|DUkK{E!O;J!K` llؚƐiZ;Aidb 0ChQo4 JާMg@z`l a+>̊d:f_2bqOi`'ݼ/2yD}===dΚx} s4,bYU:I$BHkgr,­AAY[<~.^i܉C1٬aԖjkU(Jf&WeCڌǣzSEkZ"E+URYmRiR7RGh ?KRd ڢHOv\ `h\.VWR{B$’VK7S97^W `:IDzRtxp7ztJcRѾqlNT Mr $40J?!". kd.ɖϸwшa>^mkp8eYn6<ωTX ߽=DzEQl6cLUU͊t*UFH,#Vt`Ff$l>ߘ D'Ym/f2Kֹ)rXkgi$- ,ˢ(jL+L1JEߑ6fOƿU9{3S+fyr5 b2ۦ6a~s}3L֮כrQ`hI%?)*W!4~R!/zȚT-4M`Zc뺶ִ^x<>LZZoED"u QXJcFo@!+^{T,˦nHk٬P)2ִƓI{ʲ5F7Pe@̰(W:(.EO)v!ci$lip4TJUUi],UU8\N%W` XPǓGꋸ?V$I_2pӘmUW&xRC WտSX1Q?hՈp@@@P)) xQWpD݈0X/=8rE: I"a"h;BuoF۩hx* c(T4}! |NƂ{6ٛ f/ͦoH` ޺4f83A{VHf}{OZ͝| qh DaEmmUj69kRT,|RP!`y -Ln.Aq1IWU7f]Sި1zND1*rw>4Eث#8 Df[b15eHwACf"A6P8{jШ`:=8!bZju2@ Sލ2۾2V=0u|P=2V1f<VmTQ;tM cbXa}șF%6|IۏBEmNZq$uS܎% &{7A2 A#4fq_ц QcǽQ90X =y{~b>YҶ%"" Gm!,^5'K$9 N*0'%-p/[ xFʺbKIfa4P1=C5:z@W݇Ebeg%<ZGZiL,1S@W5Dt40-Tbۓ֚%6#:e CqlqH "\uKMZ\mtasŦnufADuC$BQ4b,E7");wBL%x08˪(z5 '9غV@{, -RDYDd\w^64w-$RU i꺮vkt\>~򔑀Lþƫ=^^(/Ro F L@mnu4>9D"ӘmQEqppWזMٶmMVNh":P*&ej ޲QgPھ]ud4ԫzmRˉ吪C1b9NGja+2!/nd$UZ誹R<h0xh8y~Ԧib{rn]v*` 2u}D"eAAZfD`H%Ij1[ffS7ãiV)έa ڂQbAaŒSq:C*MYŌAuvz(Ʃ;)fft2L&Z# B@APt5udDC %d㤜n@'IQA>Z"]kNk #fw?|hTG|0D>pJӤXCVi ud̆{R2j_JK~E2ʪ/Ҷ eYi&TZݽsf5Z1!f6KINJjS( #2U5̦Zo}, ltϞYnJSksĸ)Eþ;Or%r1 S>Cf;/1'֚.= biN4M:0hfIB)*MsvsPzN_^Zô*Ѻu_(b>OWh%d?n23m MИ\dMN;@(Bᭆ_nG4:Dix[-j!'c n1@&3č:N!`ByL;x0;7TT^پz#xZ)KY[h!G.NRTC9UWN%Vqґp֘6g[DY79R#JQ .tM &H4ZA)M5ZR&)j>H=Ka;6b6<աJ/<+VK#=~;+&4Q4wle_e.!Wċḩ6c\ ?O?tS}M_zffeo'ّYk>C?{[_6:1qJ`ي^~Gd34{#Vq.%5ff4;0ٗnn]5ai{+/_%4*۫ 12KJ6"o}¬5;23=%3sήw_>{݃kݫ Xw %bNl]-̞offS#fO6mO>Xޱ7/LcV72ISqӐrXE55|h'vla?փa:}=~ѧ۞m0M-}ߡi=Y1 %5ˑuRfw ymrC?}ڡٮ߽ox6#/x#O]:ZځfW y'gmdP)S{qb Ajӽ86vyWn_7~!?~~qd3kf;v;uQư>?NlJkd}=_m`n4;5[؏>40vҴf;;ww_<tkW۬K_` =Y` )GyĠAG̞4[G{~}r6 o~/\_Yf3=oO~z>G޵᲻>; +BHJxxd Nmvf'f #76l/p;G^حCO#۷^{Ͻ'[Rq2lg!sػ<G0?xmgnOqY flj.5/|+}/=ogo/hL/\^~ 6/L8L fb`DãO8 i?z[>{_{/|/f7qsa6qqjѯ+ꉯO'|liq8ﯞ|p*6bDR5m$ #RZ X~~7}Wm="}o633k?:g޷{޽N+_GZڧ<]N-?' x#p65ie ;s}K'7^|Ӎ/Gom:;fݑM4kNm@L;|_}8|o{3 rO7=xttunR'Xǰ9}:*GHp.efD-2Y2h̫8m |y̟?vhž^5O߭v _} EH؇ \%1deiKF 5f>3{ן7?WOڻmu3͝K7ً#'ǥ|-ܹ{//OJtjM7kҞNoP:LA\1=藯4M~O_|37_=zp}SǽkfAgIXfS(U#Β{C?]Lli˟ӿ3W_~G߾/Կȓj|ܺ5KW߽_ՙ"[TVPsi,6[YNvwyyuݗGl[M߿|_k&In2t9P0UF%hdgap/?/-{W]j[nʻ`y@c*;q`Oo׶<͚v|?uz: g_9ߣ gxg;WڹzdgH0yOĠ<5OˤA?BS'*';;7goa{`0k'Dzԫ#hu0Wm*אzv2?wwdm frmL?4NNȣ,!Eœf&͜)Dk1m8&-j^yyɷjK7˜S9qȷLݲRdAJMLfZL~ N*;M:zf.se&$$8)p4,̧;?}PZ`:l'=Ͱ*T*Ȯ% ,k!c\* R$ =,e4͙`sh ? Vӥh؀mYfG~$r`'c(sǗG@{A^}4[J+`G,I!B>pV|gZ4 ͈tcڈ PHDeṀ{ě" "a͔n5M aV _jUQ59@>^Qٖ&ӞUI0@(B`c2$k=?b_5EVnՇ0 4Lk_u*QpD[ Vdl>=N96vsr˗mD|q/==oRq /RE@9xkxwu f@8kq߳_VrYOf} _:1JLag"Cpw`.DF8}Yׯlb5 \:9}~:dk >۸d ׄ<4dDYsCџN׫͊TU;0q|ǔ`[8 W Fõب*ozY ;a.7v\ͷGf57f;Rlkom[ ryHp ({.Oº7ƾWE۴ }RZqO7ƚhGa%3!vxZ皆d#R@^׎C+6ۯܺyJg!f$]GM~K 2,$MvGqxܘ7>mW._L&/B@@&$-7}`ZoF]Wyepx9X;b@;}-f{{i} =uf}oM3Mb =B}O3zL64aV`tR>>==\#BaA 0&MId|yw߶bd(i[t]hj2L00Vftt72[Hm{|˛@Ew}װQ4{|/^>*p9v(8hD4H*bd|8{}tt]wrrz8}Uqb}O[t릙SΛl?,tELF@g[7=^m6['>ִ[qSt3/ڃFz̵0Q@cFfHRnqz0Õ˓tyX"3wִ!gȞ=P`mJe$|Bjc:@QmKƛI3Xu3\gf6NEdvwfXڭtA{Z@f$B88,L4RzKOQu~ho6Mg$$"f6u}]v0vzC,4 f;[-1k⽆>+q0ѺTDK&'{Gsm18izCZѮGzC۴g=vhDT3' CT/3*8*Lquhj8Nbշ}lMwzvywY~gvٔR t`SEt`?kɤݪ-$]B}` Zcױgh(:u^OΖLݫM;I ){_({=@|~دi@ , zсj}4Z0ɠȊ M ҆ &FțrvZ^/^oo'6ӰsD!Iuie IDAT;sT3NZb&Ɩ@XtFٞ(!`XJ^БMކ"E@$w9`w[$P ,mﺝy1B|-%{պPq'cAif'r Ͻx=.]j&ma;Db5l77OW:9񦗶2+ZCHeu2ZhZ;˯.ΦӶl3AF*]׭WrC'yB[%S>\j̀DYP]ѷUYhW?,:g I3=̛.~릭l~ŋnPF>U|~J,BtE{v^`T< BȠ$]$`c=+O #ohBf,%0/{.cu(5Sy8bin3Oɉe.WV /v8QrW {?9#*z̒| h^9%I*\a9ccB}>ٕ&Drfh8,j#n23[cCjvɘru@DCC.ܙaHjt(eAHmf\0!˾+t}#,pճy'!,Ɉ<[pD3,rC%TI1ab? "[ 7)j% !@Ue@9T 7{3moIj40)fQ)> a1ҍ#,sF.Oѝ7M{3mhV>c5fFB؈i$ mWf4n, eg9IL] K.]n:LB3 aUTe^ MhidiFaBAaqأOvY}fy={ח/_vr\9)ډ5-cͬ*-kg h!;âG`YQ؜7{~찙4a"z;1FA[TD:^+5]᥃;wۜ٠2~ZqX`wowww/4aXz啮ukM4 l c*Nrr!O$eH7S0]N.utrݓ~yC{[iwB/۷o= 6zM]Hs:/M:t">ь&s..IN)+Xf|6Gw-W"l&{ڦv\M J0`m|l-F=" CX.ncfv˓S+Z[|>σgjyr|҇i?EhC3AhfF"C>ZqHJV|Y$t:ݷS|' `=\NONfҷ{-MũtnNMnV0 堶g)tsz+7M&K fsvv\,Lv$-2Sn(ۦE,{V=lkrLZ}#.nMN iVtJ`s~9D(ffɽșΉf3[t{Z?\7}ߝ,Mk ͤi&=_JfD1`k:\ޑmxlĦ*ގv]ڹ5д@(13'pN@&]bMH4X]ٔ٣,dۑjxwӽ06$@9@@z&cH%X '2]YT54*okOOϺ4l˄31)~2ɅRц S^xS{;{w23\o[^lYNCu!6-'Σuq] vl G5M .@eJOVHG}1ZEtV5iGaNNҷwJ͘COp_Xpb8t֋s6NLCԆdT#*D<ǜIXK-"՛Jd[glgsiL򷧳@% W$VS̨(IF913m~ aX9+ ȳ'  !_|CVi?Is`o`mufA*t~!_?P,`ZB3|^ 4Mfo;3kb}{lUIdrU iÀa>V)C= -zpz|)eXL!InrKJղ ԧљz59.k Jzh Rqbiࢭ=x4,3utỪ*&~IVBJDO&ѕ Taᷱ28QMUC3h6'˃;\) Ђ$1}U8$ o<= Yd&#+O!J'S^nBNhStj`σfCQn0Vo G:@)!tf5ĈK7,3lO龂'<;zқBAoL2s ]8Y %%;\t- :22~Rf9-jDAe,"Fa ?d5|tULKQ5]9<͝]ڮ͜ +\+m !P+[E#GLE5Œ-G#$-Xk2H"3^YtcK-E- l$iJX0eL@jNe-K\gS^=R92WzCuW3GDouIa2a2T0e]V7I1K# 5(eyPGdl{MO >I] aj9?lMR='ȹGns%*j<IO1CùM%k|(ɒ}BrfJM&o٪E ytم @ЩTCOsI#фPBrŹ!2<""- !(AE҃aI }0J$Ni_(f _Rn~b@Պ&"ї.HS,>ϫm8AV/h'm5Gs)BSL `Rh˶"BR{L5(1AaTZ%_HQ<= ("(ۆJ O?ֳ!Ήű'Fp0N?Q<ΝtB .4&2ȃT~4Tod^lВ9nPO\}>D9 Ɓ6YM}RSn冱:BN}bA} + i@Q+Qr+ 3@5ŹC&]5PF$Zu,HoUw(lj(;/Kzy㶜Gjt@4x3rduR0>V{F;H(z~fAZ{ 15b"x)k!X,':VQ}apsyV_=9J ߅S[7[&t9͡r:]Mǃa 5 X;2i<N\ HC3k2 :[ *SaDCv!.P\to=QrWoB(?pΙ{p,O;S=(pQbd~0kMiIӓ:2ЈmedAKӏrE2]ĵ)P@QW`$3x,_\yUY]t>{ u#eJgb҈Z8#4pîLxαUC-E$FP^C_ $PK1}ruY5v&oSk6-*H5nrʪQfH O}o'CgⵕC|ȽUh7YV(,(1xPp**P3 RGb2G>ϣE:ϩe9Ny)rg -v((y2y[F>j`Q6i|A5CrRnf^u,O%r3c8ai̊/$#_TLh+|~bl@#Ȩ=M'SF%Zb`HRClsL@s4jo1p$,EC*[yAF(:ntuL-Nq(y90o l7J^wTrbTD40FS%(Fړna%AĔ>H)`HrH2C,(}Ґs./% ֛9cRu-";hr,hӸBle A J 4N+rESdĿLNhN^:Nu>5{@"H.ќ4kaAj⣵M;QCp}{!Q#F`90, l"8+N l:gj}IAHH.Xõ@_eg<tÂb}\a-+nM'cM*Z{&$Z .@qu@KzD,-L6qn԰ZYQ8I㲷=rK $~+7IdLI64l C>= Ę\ %J A 0؜a^:lNT zzA#XFu2#YkAG$#'i`X2c` U]DWҳB.MaYsYM(ZQqPgL+H%RwCY%=s0"$j|3 $$dʌh.>HQ faIN/&YbY$ $1 %9k揣w$K6@j$62L`/ fB60IRE!P.AF8cV~۸(cjRdQ*'n9;s_ :lBR; AQHgMc@6d8j&cÝiQک`Lb21Ar oxK֔wrR~ʞgCΰr3i/q0GVB{T_cRxVru^$^&9+Fr =&r] ʚG`VݗrsKI!< Qѝ,ĕAO eKL32Vz8peȜ,Ri* iCc<4:,D̀VٜE5KhQZlwP V&eR __m?с*N7 䫵ȨLĊ7CGMKQ'yfDk4V\-=EhKk7@L-DlMw˪,g%`3,0^WNCXLخ40Jccyڝ%@7 &jHl Q$:?KzV|HiPQ]qn0<9$f7MQ\ϣ:4 w]dAjMG(5Qk9l L>PViN^KͪA(em^ÅJӢ{ MW%@"`IC1ʀm7K8iY{ʰJ~ٲªXV0ک'Z*yΤT2rY1C(2ɿ4fy1wӹm:Xq*DGJ%T  R2* Z.Ce&R#n{0u1M.:p(.q@b V;{CȶKnUfҠc# Wz 3V;[R/,FbTeHe+{hx)S1Nytb+H! ~HoVzC03u98N¥i\W!-IDATtyΧ2*&i^UCs#*Oe&O(AN;*-Mg΃g&Tm+љ*=i,0K%"tґbHT3-}7G!1T ̏:.t<5L.b" =eAM1(yG.ri3Y)Yبe»cw, IUڊH)໐smF%[Ժ>Xiv1@4ÊQaFt"Q(rS8*&1ԇct?qƢd@Ȕx]Do \\jCm^M;LDxr\Ȋhq16+$Sd#FTp-׌|i)!ifv4cjeD VI9݀卄't.cQKXmvFwCRq>R* rq'X]+]؏de! 1U5ZlǍ;=M3owTC[Y3(_0}ojs !AFcx3"^a@ui#P&KÓՋ^X'\آn];Q$]`6[ۨ˴V7r=`p͙f2hQ%MǙwW>~N|[<"qF쒸0uFE(M -"8S̛fKidmFbRl})$چ}_b-<bQsl#SOh-R%F8V̍~kKul.mH˂1oV`}m{3q|)FxPo]cT1GV.֩IENDB`jajuk-1.9.6.orig/src/main/resources/images/border7.png0000644000175000017500000010260011720500104022517 0ustar drazzibdrazzibPNG  IHDR@X]wV pHYs  tIME9 tEXtCommentCreated with The GIMPd%n IDATxmqVUk恤hٲbeQA%lq8@, Hp?4$2AFXHFl 1("{w8]a^{Gw+*S!~W~;`ߋO;?b}}_`?7O0IS=?2? dQF?N9_,Wd@ጳ?*> %7­m~/yN:;Լ߈ioQ=kT/쾚=2]oޙ>~_tؾcK |fkTh?/r ŀF~ ߑ٫(1?}._ܻ=,IgH|eso?oJHp =@ m@dswH?1xAz~` \w!ˆI_K]K>o*% b;C_hc#"/>/M~xzP὏vt/?= l _&fzQ<ԛo5-}$k{b"ݶwC/Ru*ɀҟ:zo~{` pۀi|1_+磯ӽ#,WR![>6nQL6}.k. t N?)g`p_QC$ @v-ib[alPVa.?ogS6@5}~W3=]0?6?Bp]Q+sQO_ ^/i2^6~$-M܀i;*X.oV_) {Տf[/5Vf@*_hcy_06 vb{3?~ >w4le6[ *61~s;OjesnE"wFV&*JnlS-+@Ai%l(m?prRufu>F> ۫b!")Il/]'ū1(YRJDD  Qf\}]{R_c̛![\x0HG@eֺa_|eJ~zoڡϠ5!1H1y _?:W߳O0Jx0St9;!F9c~s_o/E@"@y fs,~㧯>8>LƇ5O޶G yQOp_C !!n ! jy~1[eN}}p<$sֹ('twpfw[( >:}?_."!) j7j6}S7hY ^4k޲ 7_SYx.p, Ma |ep1Y /oҿpOgPD}OZ8ON7yz٬;n]Q&Bhh?n /ӛ>K3Ucl릞׫ْ{5"oL?؞]"Eo]w߻9~g,7{ml2:nG.!X2+ٝ_w+/7W) /ᕏM~nی7{@.۟}썻N[m_ꢺMӓvl %>ztc 2,A>ƇxtNFnH _gI677{pOӣd8& G|2/O~,` X z 0 LF`y }a_8#"x.2@W5 [`|͛GYǃI>/7ߘ7TetrT#)q2g>8iGs?3ܮja:pFZ%Çǀy9 ` \5_ڔf-Vk|چ1i~x'lE_>` 7O^a0 DA+P 93ݿ[^-|xwfɉ~ffϫtJ1*akbco&f5j%aAdOyy axhH~DJtt_x2Dn8s #0 09aXPV!I`A~8s" 9 .40UyóSj45nV02Ψ]<^ Tuuvmܓ+g6BƳvBC0"1/JsP0L&3d)d 譧gß8fY\R}Lc>w {NE@nyG>6%KXm@4,G? 73΀ibM_?~ta\3Fw4n?* T l+0,;o~ ;@ B4(_8|lnK_ #epkBS~ZfAT+Iy5k% J0H 'Zg_Iv}/ͽ`42]xi |旿My2?8Q@Qr n8I~_+7.2 `:\1>|kwV\Zx])y 5| _|[]jptT~%wTn~vUy;kfOö<˝PlޛOw/[ˋEO= s—ټxY}hz?|.[d3 g߁]BG̦`y*M/2W0 (B U {Ϯ}{=Ozųx{-g,e=P"Hd Qqܗe!X.7uQ ɣ;wyK>\fݼQ~pT6BBd6ب/9yqWXetvg'ͩۜ~s_!3kZ^rYzTz9/ovA2:H'GhF:E$rUG}co=yqLI:9٨}݆ecu?󷿄 2XkT[Sbk60#)J3`%*ծble9(F'D.e/E} Js!pm4WFga7zI|!A{HM9J?,3=bp)QݩRC@NV?;L8T`iy(}b\#G0{S0r!"wP(]6?~FZOV4T 0O<KW?pJ4]0"bǘ7|HDwPAֆ"3#oD+ d͡x̭#"7na|8{/ˍN4ƮGV"#@$CWhn uLa:ApT@A{yĦۑSXx}\F1ƀ2 p%My"n!_=f |0 b8I~m¡Gr`>1 ȌBX4'8y@2&`ء0e4̺ ak;ݔv>BiM@]]w`9#˹ewR$%Ƿ 貿@+]Α`c`ȸ"sd}mXL&l|l' P!mk n$m:`ĠacejedF@P3*ו96w=L %Ey{}d7x`5|n2 8"ct #oUy sT?{"Q={t]^" }n\Pѥnp쁍oq9pl9BcYZYJh3lߋn=vJ§0);~OȂȰhC-MN2GxY*> ő[W}@.?+$&90\p+=w-ya".k(;!ߓ@>9{&;qNb82JԁG$8,1وtyheƣ):ExD8BL q %8'd8{..SGd at Coo?GgQ㠭W]v1\i!`I0"<9 Apϑea+#x㠒sB.0P([o:K 0|ekD-xi nWRf CMvY7ߟL'53[Ͳl<?|\]^-dn!P=aݎIe0;.4!D!i8%D D|nyGHts}3_,90 MYf4M9ף82c,"25IX~=Q=t|A{Œ4@47Wi=@ib`ZCJ3W+v:'turyyiƖx.JΆ,ƽaX9{%HX0SZry0!0(,mie$Z;w.,<չ=9hW M,:󰑭9<.m}p~y$&)*HkD#ڲ4MNOO$KYoL)DQW/a1AS2r~}5_9e-3t Hu3 ,פi-3)fXSHTecjƅftb34ͳ%u;@I `0h fk%E -8&j=yz|T&fQR8V +}{nǒ:@QOق-qm 2aI%i*!0%Fh eH6^Frީe;w&Y^]^t6 Ͳ޽{׺HUI԰#^d;4Ʃ7^7"` ԤP3}NM.4"BAgtb͞+$`69R?ShZQ: ".цtķj*t1?b؎U;W=v9ލe69`)P!!ZnA/f _]F0H I<ЀE 6znVni|JEH81lV-\8>Ch/6hNnfl,Xy [p^9Q!D}B&V WKA$" N!Q@"źer#1:(e`Qyuf'cL[l MSS*)R#&NW8,DᥠfJYH6 &/-3wNNNʲTJi뺮v~ sPHhq#g:8\8~n @*d<.ΐRm`S HwKaa(Ea@*%!IqYRrX"{CDFϸJt8zȒ#N䗧1ӎ IDAT$aGc!꓅襴2+H_Y3T5#F9K&>GY0u";`DE:hPv肄=-`ȨR=P1v o^+K > 5G.G!IH䣠 Kʎ>=,3 >cJ (n4r!=!D:v@cԉ`Tƽ o2]ҦHnG%1G|LKDȝ>ؗgq`z!H1I>,G!-3=^ 6JȠرGJ9^2Oą7@5%o""77Ks:s'2 ^+=}y@hvڮEQ"E<& 䓋]^KJ~w`Pt\ʛ}H*$0X׋zXp0&P11zS\'&Q-J#qo;v\~/0Ƚ ţ 썝;A!HO^I)fFzvxgQ+D.+0dG~zu"_2ճwZ~t:mשiiȲM'uvQEMf+܌ ܥ<_{;xptvzf11!a>==<~'* >9=~ٳz *{I?Ւw4(!XY:0*QDb iƣk?.vJV}P%V&  2Kgut(Nlۭ1v<!aQ ;Zdzuy9vFJ">> #JDB#vƚѾֺRdnEQ 1= H.pUUuS"B)ZLOpeE}N!Ļ$0':ij/ck= W7k11MY4 Rv HhHoiobA63\!i`QULc*"$f>?hilQc"ussYJ{";:)[rMMwgE (\jki1MS[k:^8öf4Qy:g{3FjT z;X,jV]Lhtzzyi][{QfNĔH#tJrq Ča'`q.x<iABDcWp tRW%QGF '8L^cm\ vDk,! A\d)ߗDQ.Hu] J)kmnir.w>0ؑP١#?GFiiPw˶n Y@+y0HdCg`08TNO^6~/:[ # atcP#"!ɮUl> Ml3ԝGV;oM46"RqvFpC|K@WRvpTR< kh kEm41Mڽ D"BA3oNZVl^^D,\,he0#+ja\Sd vKi gG;J)դSJc0 xCp0t:lV~@-H5HZ~!sCJUe5='i^jl0ȭc#"N,K&UY&|u@S]ݣbHH!aQxd-ky{щb R]\`;Uz#M C$'抾%6[ d:y]7muDu ̖P%InMU/$=_+ǘ*?wY(p? ܯU]N&$Ii mBTrAJ-tNd(: \2B(E DEv{dlDV'u$H) mTPeUm"b2QEiiGM]=e$wγzx6$PeUW@0ں62"l2^V֢ Y9)ȄA/ѽ|Ύ$rmk% cR*3"@Qj[6;"aa\˥C&b;|?5PY 0T9IIsP{Կ3qMmpUΉƠ їtaw1P%%e(>KlI|)b%r,W5L'/FY `d J2A Sq#-,!ZJ׆`)dXE]p-*IG ]ITgdee *Ncn;B7˷8ߗ(QrwyR@e&r1K#hɘ,zyW##]@Q3+TIms#$ 鶷̚me>BdvT}`/VA.݂xUESj 'Pv b&`~6XhGZ*n,!R-~CPsPuW& (t2 ʪ",˚0pUUU@&{,eUD 2! MFazZm[i3f_ `-'I҂\Hh%4I$1PY,BY.oc_+dbז?H8ykSbX\>Nӧ-&:M/GB@jr,OTvaB=}}QtGh8F:~G>~:z; uCD0(T_s7,z;Gh4 N!dww PB v$5u1Q5'bt)55;P;fB^ #5H,EG*om}47QE'4p(kє l!"Q |2FaA usyy=h'?~ы/;|71[Rˎ^+3Z%eYtcMcJ/h -oBU+K|4ƣ4Mrm<{£G\dk5m"j'?Rڪ#h? B9s0ãK^q>~,Fx8i믿kJo|޽טXk;iS2((\1B}"F9ђ9AVr늦P*>{ҋ/5iLѣpX?'ƶ| Xfl ιc۝ocm]S42Y EyoErb(J"iS7}Rt]$l677NzZ,l5k5Xf0enZ[7MJ^a31AsF=RE+9cbqUp4Y*0_ѱR*It6 ZKZVT5FmGe`PG΃mK*9Iwn]7v2Ll֑/8DdK[/Sf|Xk(v (C^%]#EiZk$1N1RJˋ˪,k,22NeYYjLe9É2! Xrqx?eN)"U>ț 77uU#ǣlvs{cٶDf:M,K(sAQ(EթE+.ѩG:c )lF)c'}oIQ$d:,b-Xf6;8==L+][EU~~Vt{ w)x"0 b4 J1$1Mެ,o&Iwl:ͦU]-+c u]"Jt86R=[{b=x>jQC&뺩3 pxuy1MӜ__$iz|t\7MUMLcDTHy5MSUY4*DU u X,<dxOs;11gQ_\a'.&W[tۖ4/ÇYuzMq6H I RTY髲4z(_'B⪍Шb]d 8p,S+Dti|]խF^,v'vӒ`Gx2!EfU+&Hp_("L44T "!mh:LeQ(V'fy[3#$%@}4;mpoKkTQ`ܟ.w`jP-N0Wz6mDJ bGH,^(oψ8j!W=(EaX :r:nK DnsUv=ג#aC~1z%{RNHi}w{8oRCF*fkpߑ =G0zF{3ޫoR~{Z{eQ(?S@l d9 d30J ؃\_B-罋+>vH C#ݔ̢@P|H/K :ݸKdz U'=Aƨe[ˑ \ 1˙hWDow❜`sǂoO yQQ.Cs1(9^Uc^e(n IzdJ\w0ݰf9z*`Ats :t<iVjWzAR r7hG,04<Wy2ľ(E0<6OUReA":NQ j3o҆rĿ\G(N'"'r3Ij) #ti*Y<F<MN8V7*X*CCj)D&W&6Op,Almz&eh4&2Kx墱%|DUkK{E!O;J!K` llؚƐiZ;Aidb 0ChQo4 JާMg@z`l a+>̊d:f_2bqOi`'ݼ/2yD}===dΚx} s4,bYU:I$BHkgr,­AAY[<~.^i܉C1٬aԖjkU(Jf&WeCڌǣzSEkZ"E+URYmRiR7RGh ?KRd ڢHOv\ `h\.VWR{B$’VK7S97^W `:IDzRtxp7ztJcRѾqlNT Mr $40J?!". kd.ɖϸwшa>^mkp8eYn6<ωTX ߽=DzEQl6cLUU͊t*UFH,#Vt`Ff$l>ߘ D'Ym/f2Kֹ)rXkgi$- ,ˢ(jL+L1JEߑ6fOƿU9{3S+fyr5 b2ۦ6a~s}3L֮כrQ`hI%?)*W!4~R!/zȚT-4M`Zc뺶ִ^x<>LZZoED"u QXJcFo@!+^{T,˦nHk٬P)2ִƓI{ʲ5F7Pe@̰(W:(.EO)v!ci$lip4TJUUi],UU8\N%W` XPǓGꋸ?V$I_2pӘmUW&xRC WտSX1Q?hՈp@@@P)) xQWpD݈0X/=8rE: I"a"h;BuoF۩hx* c(T4}! |NƂ{6ٛ f/ͦoH` ޺4f83A{VHf}{OZ͝| qh DaEmmUj69kRT,|RP!`y -Ln.Aq1IWU7f]Sި1zND1*rw>4Eث#8 Df[b15eHwACf"A6P8{jШ`:=8!bZju2@ Sލ2۾2V=0u|P=2V1f<VmTQ;tM cbXa}șF%6|IۏBEmNZq$uS܎% &{7A2 A#4fq_ц QcǽQ90X =y{~b>YҶ%"" Gm!,^5'K$9 N*0'%-p/[ xFʺbKIfa4P1=C5:z@W݇Ebeg%<ZGZiL,1S@W5Dt40-Tbۓ֚%6#:e CqlqH "\uKMZ\mtasŦnufADuC$BQ4b,E7");wBL%x08˪(z5 '9غV@{, -RDYDd\w^64w-$RU i꺮vkt\>~򔑀Lþƫ=^^(/Ro F L@mnu4>9D"ӘmQEqppWזMٶmMVNh":P*&ej ޲QgPھ]ud4ԫzmRˉ吪C1b9NGja+2!/nd$UZ誹R<h0xh8y~Ԧib{rn]v*` 2u}D"eAAZfD`H%Ij1[ffS7ãiV)έa ڂQbAaŒSq:C*MYŌAuvz(Ʃ;)fft2L&Z# B@APt5udDC %d㤜n@'IQA>Z"]kNk #fw?|hTG|0D>pJӤXCVi ud̆{R2j_JK~E2ʪ/Ҷ eYi&TZݽsf5Z1!f6KINJjS( #2U5̦Zo}, ltϞYnJSksĸ)Eþ;Or%r1 S>Cf;/1'֚.= biN4M:0hfIB)*MsvsPzN_^Zô*Ѻu_(b>OSڪ:twm6VFDC h_ c4FQL HGADQB@KwWQ]SԹZk^>cs͐be1..?C_?=dO7qޣiKcs55) F<`YKvut?9=kZϹ pc8\+s[^r>W= %d?jffp^TEFs\15:kk5qXCP&* m0s Hɨc¢`A-Ijű PݢpGϜ7 TLh8ӎ`>Fl U*ھߍz#XUԲrb)v-`PNT|䕓C Ur8 kvdi3+)yFfE0Gj$Pp5 ]&D$N )M5ZRMR>w$拥G6bDiN9ңP~YT@/s$~Fq86pz@Bmö;GzS%rUr=f06H[cpr9^\ a%.x֝ߺz= [~DZ8ϋTS!RK1J3Ay(Xã9?=?޾q6y?f٬7Nl)r>[q~J]zlU}H|5Y@4`a)t9,yBڜs>4Mu$ү 6a%;FW0=Y )y#]vE]:94bTjDZvCo;8H'ezO^H'a[AVi#6-)oN M-G,ۖqqԾqoG S;t; ЭV+ edw0|@B'8 U/1I3Z̡*34.yv.?>8;Hj+ q<;?F뻑lfն>?SƾNH31Q). L`vz}txΫz8©%w.8㸂HO,)V9lg)04|pS4xEFXyl\qzB;8p $j:OrNG+QQǜ53R|gDen@ OZ'@Cpƹ $ewݮ(#Gmڦ }?w8s ;|Ӷ#V)nSi,g(e:#`u32qzl {٬V5M[xzzzzvlO64I)~ k8:w̅Lb#JԺ(w{['ۣu{xt{^|Z;Exq~1uVNNFViڝb{?:ićӳa<%|r.pn(:XS "HT63:& u[(vsAvg=BU'9 -BcV?i՘9Z|ެB#8W(uV4.=JHB;q!B66G 08Ժ^-Բ ,$]G:ą/(]=w*B,+XJ"HBq8(6 LGD]E(3ODsQ$jjX4#0_8V92Ywmi< %8'S4c?ƄREjyٕa\и2^a0Ta :BI{`"Y T;Yire ??ǑQၖJ *)+qɴKZ1*#\ʁ$a?&i(yŠ,jj-Z4)ZsF`%]* 0e}G@EL?5qzD<bay14jR-;H" *dglLB0FN7}LUih{1j4^l!J}O-&\]1P$2,h"65R򞯌3Q67LMc&3\Y&^t;|53Z$)rm]]Sz9&b 4tiNQ!6>܅FLԾ,Tfx&˞񢨄a%a͔Nk afAy+`)T`jDaTɴgxլF0nҦ ErViX\,cwC9=UճxӵwbO]#oz&Lkz),]fSaL"k/fIq}*1 .~{]<GL>!5o^ C3S{Wi)ǎ?l8B6fﺿ_/[It~mW҉s:fͥ=p' y??={_}͇_|{>ndk 6 QAJ#Ȃ7d\=^Xr qNuK҆w]_}݆l [pm򦵾Q+H{;9e臾߅!yrW_ n"G0H7H?W<>zg[11 M஢gVf#$*\ݫ/[o]rwwWܽÏ?qx"9]FJˮǃM~{͢7$4$ WN|~o?M~Gv3/㏿OC !2B.F>M;ƏVuԉ5rufuҮ>Q%]8~<;7<?|ÕlVxb^D܈ tm54Kxep^B,*K^|w?HCOמȿ:^JVH7VsoVwMx"j 6u[_:zW|?&2 ~=O]y;4^ ۽]٬-HD&˥ YDȬwʯFGp3Oa~q|+^fu wnup_xsEL4E\4$ }♕.ί;m#!)RAη3 n1suuݚH5`yh/% M"!x7y2 qu7m~+§?BsCD՗>|__y0%13wkyuZUdAV}7m ^dq߾O죪f2c2ZšHɇ~ﻶ!(Mxp~?~g~4!~^+wvx͊E̩(IcR4|s?񻯽[ )=_OYЊg=_9zlڭk|8yXV^6ҒkaX@c?$)w|?/.?Ap) ~~9zŕ6s$8qA_'ߒQF}%*Z*>ksֈS}tbuO~y+[ad$_>_XΣó1e'n/^ܽz+h&HYsP†'\Juq}7ǛYO\R8N乧yt iH?H"(^O ][ϯ>5KgIUSfQ uS=uv7}x:{8S?qd?H7Or'@d Ҍzs`V>;wsC%[h^!5u PpW?-i!LVnfzGs?Јpׅ}7ݿ~w50ͦJ,\Oc,(]8tWnmj\<|cȮ&>xZ^fW~o t7|>T2Hٳ2~@3h dMNq_h^Dtw=񉛷~ߝι;3E NCcH D"hB@_5TY Z̒|Y+φZ(f޴^_B˰-1k;8&W,D0 ,'uYNfO"M:1f0mlH0SX-"jC.;53C ՀƹF=PdA$NmLNJhWݸsۇc,MhA8O>ydmݚEhxhrLYFXfk8Wma} t2 O8`w;]+ øƻ. z1lvUNE5RӤ1ϭ׮_rCwkˈ݉ppxpppooܿ?s@yy$+.y =LA\ݟ^m\9:yt:pu(ݩ۝9`8r#p(O$JTX; Ob">ь5w]Bã3p7ѝ"zZÁAv)P\UI0K LӐ/wn&'ӹv4=:侸 srl6:Evڱ9 7p^1:)FFK)Q9hdS m<PTU8uo-mۃ#9;;#ej7덛zrߟ!\>(ؤ_ Ee+ rP[3)Nqpp"2&\20H5z펾!|Bq[qb*Ѕȴqbj< 3RpIqn^v3l"4>{&ClB-Zlf܋2WH/B8v>_77R𕩉H"XG1`4 #ovXۇ Nl0 l)e|X~܁ dxޅ-VS6%k( irϋB}<l]s%JEG`%Kd.;Ѳ@!\'|GZ7 #fiJHfyR8mL3Q@.^ԑaN=q\KXa.,ϤƹEFhKI Ԧv]ѥjq觍ӓk.7`&Y~k)ojਐ7Hf v`4s~ߑwg#Jp-[sz+ 11*Pw=<ŀn )"i}*7sV-zEӴ2ta$h֠`!Y@yz`p82G#f*d IrchZTbR7ytE:9&k  Ɇ)4Km%J dg< JawH:,3u4jUL6։LSԎ 0 [M7?ĦSq*h܌4nc: vIbs=}FNvĒڣA:K?Mfi2\)Ddjt&irҀp֊`.{rIqڠL08)KA,9UgQVP`tqʥzuŗzv14?]}CeԠ+(U%fmFBΘ@2ILDW0٢]4gCB}1=bi+P#2ES&%c]L) $(.N3r?0. B8@agmβ-C-@I,&+!IegQ( 1+fQ`F\"$-Vi6$MTZL(Qt[WK)a+Ô1Us,XpDt]-R9R"Hk3Ghljlj$T?2"nv8PL27%oXbRA)C娓1|>?_____VuVAw0L-a I_j?ԹiG]Gfj+0I 54N "cVIZڈ(8a8` ى E=Y2O]XN$C-[՘!n"(t*UPZבz PB3Pm&tr(3@1P'Y2d2(dV:}rE1<Xf[R@gRBH`s1>Lvwϫ=+Hl褁TS2FMr"R&񈚐"E ]X/WTr300Y+1 +.yR Eb,ǦCSJV,Jr^eY0a L6v11V1,g >+8޺F"N!jhciW'MVMz 9}<kOȕ|DF:4}C7Ԥf"HVfцڧQi;1J[lB5MX`,R!TNNU0zRڞC6J,mCŃ O;ֳ.Q0JҋMUQ }rER1T#[߻t.~yꩲ5f(wӘH c ⒩D/N &8Ie9}>Q`6BuD5a%A[-i[JBdiq?PiKmuX!T(N: fy1UAܭ FSʨ4ʰŭD%INBGˑ8),# kC{ԣ%ј%+nB1hɉS} dtPɿI%}E@^@+RGy,9R`AI m[PHqǰ~j) 9 TW%cSNojNTɴc=I˅ ˥&U{PKo{ūO>XĔK=&743e^d`ꍁofxpqs P*"FPV媑%5?3eָ\]-)ˎLUhi}Y,+H\ ^^SFբ]L=I)U1@1fO Ru]>^~9colz؄syw*Gg.ǥ,<\Z:eO+ Z\Vv'dQDKSL,ʝL(a"6_jV^rE.CL V#ˉrѨupsyV_ =J ^L'KV?Wd%P ia#-?Иtr$/g$+|VN[?Յ}UtO.#/i,CĿ`c%SE =1dԬBT;5\10@ fR9zM벛t(\;fhfB Omo(fj+`y{#V8`cP(YQNkTu@ɪsIϨzK?L.=9zY-yN(`2DrJܘB:T%_Q?$e&gH #ԭQR! vѲMsbXdMAA2Tz7sJ>p9քy}s.A-/g``BÉۤUYł$$:oct%BEKD%.*g.eTiVGBM:e .iBJ$Ei`{UQU@f\ZQN_8khP1UK9 x +2v_u9/k`g)* >v((yjLUF>j`Q6J-oډ GطEK0B#,G3 {3e TYq;ΦgLͶ=6šMdSIʹ?eB_GH aAnbKYaV[RNdY45(Q@ośPЪ`HT3>#5Q^&NNRj~ZYQ8H㲷=r#TWn1%,Hp0d@9ʤA?ĀA?O8Obs4@-AO $;%NyV5U{d"vp-8hdd.EimK#HdP!Ex٪ԓ:DUQ*t KEQ[:l?vZHFL!'tTP{A=YLK*(*1)_r\NhBT~a1b\l]v(hPMĂI 5 *keFl ESXBV"%`:YEV+6SJf۠ D]YH44*"IEh:y^ :fA7tRUFjp6h4`0$A:HG(zhZl"@ahTjHJQ,P@*&wX 7'%|`BHiwYL~l`H,Cq:ki(UlWͥ1Z#y;K&o0fA NP%DhL &KG٥V5 !f1,i2ZYTUR\«tWPXJ WY5NMG(5XP@sv@YU>.+؉)Ҝ,KUW0 TKEK&-J~a[FQ4ئf c2 S|jX YAJv%U!ϱz˜ԝ:yCsTJޤ3h6AGF<7 w/Y^L4=E[[Q=X1*DCJ%T Ϩ <Ԩr)9$6X&+z@k"XpvD;Z1(\tCDl|om%n7UfҠK# Wz 3V;[R/,FJaf+[hX)S1gNy-f̭q?"@3!-[=w͟h>.g"SUIDAT90iZjtyƧ2*`&˕V͍Ry*Qf/΄ B-MϜg-͢M$љZ ٲ%u謽4?PzkPf_ԣt$b1$\U3-m7G*>s^-b&22R)t4㉭tUl2DYp>eAbP4jɀFNk:y@>kb…<(21n[E ] *љE}yS7H/W#7dMMg1fQG2ĶKp[: R [gwe N16X{Ή8ۤvZQhnȾ |E|=Cq̤9 HJtrJ͚DM@Rf5cpvWQ)*+iYzQ!/h0h%b&(ЀdfJic&֖swQ T5CLO P*隳$w"G:%`Z :"4O,rHfRd!ǒ EY+$RNVL4 ?K-ni[py%@볚ڋ.SJlZJaŨaF4"E(rS8*&,1Ǵ~"J ,EɀZ1t}@~!.|7,Ն ڼ꣋0eq#+ʯťȫ#|HXRL.1,`ZJ#Y\RZ_J3KR, JJi,/$,YpI{.GDI$/ybeIEzK,1iXbW_ɴB`X9Vhd8nii\yEweϠ\`X%-W2uCu) P&KÓB, m ._$zlQN.Xŕ(.t[حeǴVjoz ˿3dJrmF̜ĸsK.CEP0raĥ /B(:l^dEgy3LrYY W*b9 "SpWqQPA.z2ޱ^8 KzR=yq[DyIPp[X9RF$ Y\'1*K**_Res7q|);,X Ƣc__#B8IENDB`jajuk-1.9.6.orig/src/main/resources/xslt/0000755000175000017500000000000011720500104020173 5ustar drazzibdrazzibjajuk-1.9.6.orig/src/main/resources/xslt/report-print.css0000644000175000017500000000023011720500104023345 0ustar drazzibdrazzibbody { background-color: #fff; color: #000; font-size: 10px; } .notice,.jumpto { display: none; } h1 { border: none; height: 2em; }jajuk-1.9.6.orig/src/main/resources/xslt/logical_collection.xsl0000644000175000017500000001002211720500104024543 0ustar drazzibdrazzib Jajuk Music Report

jajuk-1.9.6.orig/src/main/resources/xslt/device.xsl0000644000175000017500000001162311720500104022165 0ustar drazzibdrazzib Jajuk Music Report

jajuk-1.9.6.orig/src/main/resources/xslt/report-all.css0000644000175000017500000000230211720500104022763 0ustar drazzibdrazzibbody { background: #d5eac3; color: #34363b; font-family: Tahoma, "Bitstream Vera Sans", "DejaVu Sans Mono", sans-serif; min-width: 720px; margin: 0; padding: 0; } h2,h3,h4,h5,p { padding: 0.5em 1em 0 1em; font-weight: 400; } table { margin: 1em; border-collapse: collapse; border: 2px solid #becdb1; } td,th { padding: 0.3em; border: 1px solid #becdb1; } a:link { color: #34363b; text-decoration: underline; } a:visited { color: #34363b; } a:hover { background-color: #becdb1; } h1 { position: relative; font-weight: 400; display: block; width: 100%; height: 3em; background: #f9f9f9; font-size: 2.5em; text-align: center; margin: 0; line-height: 3em; border-bottom: 1px solid #b3cf9b; } .notice { margin: 0; font-size: 0.9em; position: absolute; top: 0.5em; right: 0.5em; padding: 0.4em; background-color: #7e7f7f; border: 1px solid #b9b8b8; color: #fff; width: 10em; } .jumpto { margin: 0.5em 1em 0 1em; padding: 0; list-style-type: none; } .jumpto li { display: inline; padding: 0 0.2em; } h2 { font-size: 2em; margin: 0; border-top: 2px solid #becdb1; margin: 2em 0 0 0; }jajuk-1.9.6.orig/src/main/resources/xslt/artist.xsl0000644000175000017500000000533411720500104022236 0ustar drazzibdrazzib Jajuk Music Report

jajuk-1.9.6.orig/src/main/resources/xslt/album.xsl0000644000175000017500000001024511720500104022025 0ustar drazzibdrazzib Jajuk Music Report

( )

jajuk-1.9.6.orig/src/main/resources/xslt/directory.xsl0000644000175000017500000000736411720500104022741 0ustar drazzibdrazzib Jajuk Music Report

jajuk-1.9.6.orig/src/main/resources/xslt/genre.xsl0000644000175000017500000001005011720500104022017 0ustar drazzibdrazzib Jajuk Music Report

jajuk-1.9.6.orig/src/main/java/0000755000175000017500000000000011720500104016110 5ustar drazzibdrazzibjajuk-1.9.6.orig/src/main/java/ext/0000755000175000017500000000000011720500104016710 5ustar drazzibdrazzibjajuk-1.9.6.orig/src/main/java/ext/DropDownButton.java0000644000175000017500000001210511720500104022502 0ustar drazzibdrazzib/* * This file has been adapted to Jajuk by the Jajuk Team. * * Found at http://www.jroller.com/santhosh/date/20050528 * Original copyright information follows: * * Copyright santhosh kumar * * @author santhosh kumar - santhosh@in.fiorano.com Drop down button */ package ext; import java.awt.Insets; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import javax.swing.ImageIcon; import javax.swing.JButton; import javax.swing.JPopupMenu; import javax.swing.JToolBar; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import javax.swing.event.PopupMenuEvent; import javax.swing.event.PopupMenuListener; import org.jajuk.ui.widgets.JajukButton; import org.jajuk.ui.widgets.JajukJToolbar; import org.jajuk.util.Const; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; /** * DOCUMENT_ME. */ public abstract class DropDownButton extends JajukButton implements ChangeListener, PopupMenuListener, ActionListener, PropertyChangeListener, Const { /** Generated serialVersionUID. */ private static final long serialVersionUID = 9126200472940409277L; /** DOCUMENT_ME. */ private final JButton arrowButton; /** DOCUMENT_ME. */ private boolean popupVisible = false; /** * Instantiates a new drop down button. * * @param icon DOCUMENT_ME */ public DropDownButton(ImageIcon icon) { super(icon); if (icon.getIconWidth() < 20) { arrowButton = new JajukButton(IconLoader.getIcon(JajukIcons.DROP_DOWN_16X16)); } else { arrowButton = new JajukButton(IconLoader.getIcon(JajukIcons.DROP_DOWN_32X32)); } getModel().addChangeListener(this); arrowButton.getModel().addChangeListener(this); arrowButton.addActionListener(this); arrowButton.setBorder(null); arrowButton.setMargin(new Insets(1, 0, 1, 0)); addPropertyChangeListener("enabled", this); // NOI18N } /*------------------------------[ PropertyChangeListener ]---------------------------------------------------*/ /* (non-Javadoc) * @see java.beans.PropertyChangeListener#propertyChange(java.beans.PropertyChangeEvent) */ @Override public void propertyChange(PropertyChangeEvent evt) { arrowButton.setEnabled(isEnabled()); } /*------------------------------[ ChangeListener ]---------------------------------------------------*/ /* (non-Javadoc) * @see javax.swing.event.ChangeListener#stateChanged(javax.swing.event.ChangeEvent) */ @Override public void stateChanged(ChangeEvent e) { if (e.getSource() == getModel()) { if (popupVisible && !getModel().isRollover()) { getModel().setRollover(true); return; } arrowButton.getModel().setRollover(getModel().isRollover()); arrowButton.setSelected(getModel().isArmed() && getModel().isPressed()); } else { if (popupVisible && !arrowButton.getModel().isSelected()) { arrowButton.getModel().setSelected(true); return; } getModel().setRollover(arrowButton.getModel().isRollover()); } } /*------------------------------[ ActionListener ]---------------------------------------------------*/ /* (non-Javadoc) * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent) */ @Override public void actionPerformed(ActionEvent ae) { JPopupMenu popup = getPopupMenu(); popup.addPopupMenuListener(this); popup.show(this, 0, getHeight()); } /*------------------------------[ PopupMenuListener ]---------------------------------------------------*/ /* (non-Javadoc) * @see javax.swing.event.PopupMenuListener#popupMenuWillBecomeVisible(javax.swing.event.PopupMenuEvent) */ @Override public void popupMenuWillBecomeVisible(PopupMenuEvent e) { popupVisible = true; getModel().setRollover(true); arrowButton.getModel().setSelected(true); } /* (non-Javadoc) * @see javax.swing.event.PopupMenuListener#popupMenuWillBecomeInvisible(javax.swing.event.PopupMenuEvent) */ @Override public void popupMenuWillBecomeInvisible(PopupMenuEvent e) { popupVisible = false; getModel().setRollover(false); arrowButton.getModel().setSelected(false); ((JPopupMenu) e.getSource()).removePopupMenuListener(this); // act as good programmer :) } /* (non-Javadoc) * @see javax.swing.event.PopupMenuListener#popupMenuCanceled(javax.swing.event.PopupMenuEvent) */ @Override public void popupMenuCanceled(PopupMenuEvent e) { popupVisible = false; } /*------------------------------[ Other Methods ]---------------------------------------------------*/ /** * Gets the popup menu. * * @return the popup menu */ protected abstract JPopupMenu getPopupMenu(); /** * Adds the to tool bar. * DOCUMENT_ME * * @param toolbar DOCUMENT_ME * * @return the j button */ public JButton addToToolBar(JToolBar toolbar) { JToolBar tempBar = new JajukJToolbar(); tempBar.setAlignmentX(0.5f); tempBar.add(this); tempBar.add(arrowButton); toolbar.add(tempBar); return this; } } jajuk-1.9.6.orig/src/main/java/ext/JSplashLabel.java0000644000175000017500000000602311720500104022060 0ustar drazzibdrazzib/* * JSplash.java * * This file has been adapted to Jajuk by the Jajuk Team. * * The original copyrights and license follow: * * Copyright (c) 2004,2005 Gregory Kotsaftis * gregkotsaftis@yahoo.com * http://zeus-jscl.sourceforge.net/ * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ package ext; import java.awt.Color; import java.awt.Font; import java.awt.FontMetrics; import java.awt.Graphics; import java.awt.MediaTracker; import java.net.URL; import javax.swing.ImageIcon; import javax.swing.JLabel; /** * Extends JLabel to provide support for custom text drawing inside image used * for JSplash component. *

* * @author Gregory Kotsaftis * @since 1.06 */ public final class JSplashLabel extends JLabel { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** Used to draw the text string. */ private String mText = null; /** Used to draw the copyright notice. */ private String mCopyright = null; /** Font to use when drawing the text. */ private Font mFont = null; /** * Constructor. *

* * @param url The location of the image (it cannot be null). * @param copyright DOCUMENT_ME * @param text The string to draw (can be null). * @param font The font to use (can be null). */ public JSplashLabel(URL url, String copyright, String text, Font font) { super(); ImageIcon icon = new ImageIcon(url); if (icon.getImageLoadStatus() != MediaTracker.COMPLETE) { System.err.println("Cannot load splash screen: " + url); setText("Cannot load splash screen: " + url); } else { setIcon(icon); mCopyright = copyright; mText = text; mFont = font; if (mFont != null) { setFont(mFont); } } } /** * Overrides paint in order to draw the version number on the splash screen. *

* * @param g The graphics context to use. */ @Override public void paint(Graphics g) { super.paint(g); if (mText != null) { g.setColor(Color.BLACK); // Draw copyright notice FontMetrics fm = g.getFontMetrics(); int width = fm.stringWidth(mCopyright) + 50; int height = fm.getHeight(); g.drawString(mCopyright, getWidth() - width, (getHeight() - height) - 20); // Draw release g.drawString(mText, getWidth() - width, (getHeight() - height)); } } } jajuk-1.9.6.orig/src/main/java/ext/ProcessLauncher.java0000644000175000017500000003013411720500104022654 0ustar drazzibdrazzib/* * ProccessLauncher is a tool to launch an extern application * in a Java program with stream managed in separate threads. * * Copyright (C) 2006 Fabio MARAZZATO, Yann D'ISANTO * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ package ext; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import org.jajuk.util.log.Log; /** * http://ydisanto.ftp-developpez.com/tutoriels/j2se/runtime/fichiers/ProcessLauncher.java * ProcessLauncher permet de lancer une application externe en consommant les * divers fluxs dans des threads separes. * * @author Fabio MARAZZATO * @author Yann D'ISANTO */ public class ProcessLauncher { /** DOCUMENT_ME. */ private OutputStream out = null; /** DOCUMENT_ME. */ private OutputStream err = null; /** DOCUMENT_ME. */ private InputStream in = null; /** DOCUMENT_ME. */ private Process process; /** DOCUMENT_ME. */ private long timeout = 0L; /** DOCUMENT_ME. */ private boolean finished = false; /** * Instantiates a new process launcher. */ public ProcessLauncher() { this(null, null, null, 0L); } /** * The Constructor. * * @param out Outputstream vers lequel sera redirige la sortie standard de * l'application externe (null pour ne pas rediriger). * @param err Outputstream vers lequel sera redirige la sortie d'erreur de * l'application externe (null pour ne pas rediriger). */ public ProcessLauncher(OutputStream out, OutputStream err) { this(out, err, null, 0L); } /** * The Constructor. * * @param out Outputstream vers lequel sera redirige la sortie standard de * l'application externe (null pour ne pas rediriger). * @param err Outputstream vers lequel sera redirige la sortie d'erreur de * l'application externe (null pour ne pas rediriger). * @param in InputStream vers lequel sera redirige l'entree standard de * l'application externe (null pour ne pas rediriger). */ public ProcessLauncher(OutputStream out, OutputStream err, InputStream in) { this(out, err, in, 0L); } /** * The Constructor. * * @param out Outputstream vers lequel sera redirige la sortie standard de * l'application externe (null pour ne pas rediriger). * @param err Outputstream vers lequel sera redirige la sortie d'erreur de * l'application externe (null pour ne pas rediriger). * @param timeout temps en millisecondes avant de forcer l'arret de l'application * externe (0 pour ne jamais forcer l'arret). */ public ProcessLauncher(OutputStream out, OutputStream err, long timeout) { this(out, err, null, timeout); } /** * The Constructor. * * @param out Outputstream vers lequel sera redirige la sortie standard de * l'application externe (null pour ne pas rediriger). * @param err Outputstream vers lequel sera redirige la sortie d'erreur de * l'application externe (null pour ne pas rediriger). * @param in InputStream vers lequel sera redirige l'entree standard de * l'application externe (null pour ne pas rediriger). * @param timeout temps en millisecondes avant de forcer l'arret de l'application * externe (0 pour ne jamais forcer l'arret). */ public ProcessLauncher(OutputStream out, OutputStream err, InputStream in, long timeout) { this.out = out; this.err = err; this.in = in; this.timeout = timeout < 0 ? 0L : timeout; } /** * Execute une ligne de commande dans un processus separe. * * @param command ligne de commande a executer * * @return valeur de retour du processus * * @throws IOException Signals that an I/O exception has occurred. */ final public int exec(String command) throws IOException { process = Runtime.getRuntime().exec(command); return execute(); } /** * Execute une commande avec ses parametres dans un processus separe. * * @param cmdarray tableau de String contenant la commande et ses parametres * * @return valeur de retour du processus * * @throws IOException Signals that an I/O exception has occurred. */ final public int exec(String[] cmdarray) throws IOException { process = Runtime.getRuntime().exec(cmdarray); return execute(); } /** * Execute une commande avec ses parametres dans un processus separe en * specifiant des variables d'environnement. * * @param cmdarray tableau de String contenant la commande et ses parametres * @param envp variables d'environnement * * @return valeur de retour du processus * * @throws IOException Signals that an I/O exception has occurred. */ final public int exec(String[] cmdarray, String[] envp) throws IOException { process = Runtime.getRuntime().exec(cmdarray, envp); return execute(); } /** * Execute une commande avec ses parametres dans un processus separe en * specifiant des variables d'environnement et le repertoire de travail. * * @param cmdarray tableau de String contenant la commande et ses parametres * @param envp variables d'environnement * @param dir repertoire de travail * * @return valeur de retour du processus * * @throws IOException Signals that an I/O exception has occurred. */ final public int exec(String[] cmdarray, String[] envp, File dir) throws IOException { process = Runtime.getRuntime().exec(cmdarray, envp, dir); return execute(); } /** * Execute une ligne de commande dans un processus separe en specifiant des * variables d'environnement. * * @param command ligne de commande * @param envp variables d'environnement * * @return valeur de retour du processus * * @throws IOException Signals that an I/O exception has occurred. */ final public int exec(String command, String[] envp) throws IOException { process = Runtime.getRuntime().exec(command, envp); return execute(); } /** * Execute une ligne de commande dans un processus separe en specifiant des * variables d'environnement et le repertoire de travail. * * @param command ligne de commande * @param envp variables d'environnement * @param dir repertoire de travail * * @return valeur de retour du processus * * @throws IOException Signals that an I/O exception has occurred. */ final public int exec(String command, String[] envp, File dir) throws IOException { process = Runtime.getRuntime().exec(command, envp, dir); return execute(); } /** * Execute. * DOCUMENT_ME * * @return the int */ private int execute() { int status = -1; // Consommation des fluxs de sortie standard et d'erreur dans des // threads separes. if (err == null) { try { process.getErrorStream().close(); } catch (IOException e) { Log.error(e); } } else { createStreamThread(process.getErrorStream(), err); } if (out == null) { try { process.getInputStream().close(); } catch (IOException e) { Log.error(e); } } else { createStreamThread(process.getInputStream(), out); } // Mapping de l'entree standard de l'application si besoin est. if (in != null) { createStreamThread(in, process.getOutputStream()); } if (timeout > 0L) { Thread processThread = createProcessThread(process); processThread.start(); try { processThread.join(timeout); try { status = process.exitValue(); } catch (IllegalThreadStateException itse) { process.destroy(); status = process.exitValue(); } } catch (InterruptedException ie) { Log.error(ie); } } else if (timeout == 0L) { try { status = process.waitFor(); } catch (InterruptedException ie) { Log.error(ie); } } finished = true; return status; } /** * Creates the stream thread. * DOCUMENT_ME * * @param is DOCUMENT_ME * @param os DOCUMENT_ME */ private void createStreamThread(final InputStream is, final OutputStream os) { new Thread(new Runnable() { @Override public void run() { BufferedInputStream bis = new BufferedInputStream(is); BufferedOutputStream bos = null; if (os != null) { bos = new BufferedOutputStream(os); } byte[] data = new byte[2048]; int nbRead = 0; try { while ((nbRead = bis.read(data)) > 0) { if (bos != null) { if (finished) { break; } bos.write(data, 0, nbRead); bos.flush(); } } } catch (IOException ioe) { Log.error(ioe); } } }, "Create Stream Thread").start(); } /** * Creates the process thread. * DOCUMENT_ME * * @param process DOCUMENT_ME * * @return the thread */ private Thread createProcessThread(final Process process) { return new Thread("Process Watcher Thread") { @Override public void run() { try { process.waitFor(); } catch (InterruptedException ie) { Log.error(ie); } } }; } /** * Renvoie l'OutputStream vers lequel a ete redirige le flux d'erreur de * l'application externe. * * @return l'OutputStream vers lequel a ete redirige le flux d'erreur de * l'application externe */ public OutputStream getErrorStream() { return err; } /** * Renvoie l'InputStream duquel les donnees sont envoyees au flux d'entree * standard de l'application externe. * * @return l'InputStream duquel les donnees sont envoyees au flux d'entree * standard de l'application externe */ public InputStream getInputStream() { return in; } /** * Renvoie l'OutputStream vers lequel a ete redirige le flux de sortie * standard de l'application externe. * * @return l'OutputStream vers lequel a ete redirige le flux de sortie * standard de l'application externe */ public OutputStream getOutputStream() { return out; } /** * Renvoie le timeout. * * @return le timeout */ public long getTimeout() { return timeout; } /** * Specifie l'Outputstream vers lequel sera redirige la sortie d'erreur de * l'application externe. * * @param err Outputstream vers lequel sera redirige la sortie d'erreur de * l'application externe (null pour ne pas rediriger) */ public void setErrorStream(OutputStream err) { this.err = err; } /** * Specifie l'InputStream vers lequel sera redirige l'entree standard de * l'application externe. * * @param in InputStream vers lequel sera redirige l'entree standard de * l'application externe (null pour ne pas rediriger) */ public void setInputStream(InputStream in) { this.in = in; } /** * Specifie l'Outputstream vers lequel sera redirige la sortie standard de * l'application externe. * * @param out Outputstream vers lequel sera redirige la sortie standard de * l'application externe (null pour ne pas rediriger) */ public void setOutputStream(OutputStream out) { this.out = out; } /** * Specifie le timeout temps en millisecondes avant de forcer l'arret de * l'application externe. * * @param timeout temps en millisecondes avant de forcer l'arret de l'application * externe (0 pour ne jamais forcer l'arret) */ public void setTimeout(long timeout) { this.timeout = timeout; } } jajuk-1.9.6.orig/src/main/java/ext/AutoCompleteDocument.java0000644000175000017500000002360511720500104023661 0ustar drazzibdrazzib/* Jajuk Specific version of this swingx class to fix * this: https://swingx.dev.java.net/issues/show_bug.cgi?id=464 * * This file has been adapted to Jajuk by the Jajuk Team. * Jajuk Copyright (C) 2007 The Jajuk Team * * The original copyrights and license follow: * * Copyright 2004 Sun Microsystems, Inc., 4150 * Network Circle, Santa Clara, California 95054, U.S.A. All rights * reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package ext; import javax.swing.UIManager; import javax.swing.text.AttributeSet; import javax.swing.text.BadLocationException; import javax.swing.text.PlainDocument; import org.jdesktop.swingx.autocomplete.AbstractAutoCompleteAdaptor; import org.jdesktop.swingx.autocomplete.ObjectToStringConverter; /** * A document that can be plugged into any JTextComponent to enable automatic * completion. It finds and selects matching items using any implementation of * the AbstractAutoCompleteAdaptor. */ public class AutoCompleteDocument extends PlainDocument { /** Generated serialVersionUID. */ private static final long serialVersionUID = -4353609211147483101L; /** Flag to indicate if adaptor.setSelectedItem has been called. Subsequent calls to remove/insertString should be ignored as they are likely have been caused by the adapted Component that is trying to set the text for the selected component. */ boolean selecting = false; /** true, if only items from the adaptors's list can be entered false, otherwise (selected item might not be in the adaptors's list). */ boolean strictMatching; /** The adaptor that is used to find and select items. */ AbstractAutoCompleteAdaptor adaptor; /** DOCUMENT_ME. */ ObjectToStringConverter stringConverter; /** * Creates a new AutoCompleteDocument for the given * AbstractAutoCompleteAdaptor. * * @param adaptor The adaptor that will be used to find and select matching items. * @param strictMatching true, if only items from the adaptor's list should be allowed to * be entered * @param stringConverter the converter used to transform items to strings */ public AutoCompleteDocument(AbstractAutoCompleteAdaptor adaptor, boolean strictMatching, ObjectToStringConverter stringConverter) { this.adaptor = adaptor; this.strictMatching = strictMatching; this.stringConverter = stringConverter; // Handle initially selected object Object selected = adaptor.getSelectedItem(); if (selected != null) { setText(stringConverter.getPreferredStringForItem(selected)); } adaptor.markEntireText(); } /** * Creates a new AutoCompleteDocument for the given * AbstractAutoCompleteAdaptor. * * @param strictMatching true, if only items from the adaptor's list should be allowed to * be entered * @param adaptor The adaptor that will be used to find and select matching items. */ public AutoCompleteDocument(AbstractAutoCompleteAdaptor adaptor, boolean strictMatching) { this(adaptor, strictMatching, ObjectToStringConverter.DEFAULT_IMPLEMENTATION); } /** * Returns if only items from the adaptor's list should be allowed to be * entered. * * @return if only items from the adaptor's list should be allowed to be * entered */ public boolean isStrictMatching() { return strictMatching; } /* (non-Javadoc) * @see javax.swing.text.AbstractDocument#remove(int, int) */ @Override public void remove(int offs, int len) throws BadLocationException { // return immediately when selecting an item if (selecting) { return; } super.remove(offs, len); if (!strictMatching) { setSelectedItem(getText(0, getLength()), getText(0, getLength())); adaptor.getTextComponent().setCaretPosition(offs); } } /* (non-Javadoc) * @see javax.swing.text.PlainDocument#insertString(int, java.lang.String, javax.swing.text.AttributeSet) */ @Override public void insertString(int pOffs, String str, AttributeSet a) throws BadLocationException { int offs = pOffs; // return immediately when selecting an item if (selecting) { return; } // insert the string into the document super.insertString(offs, str, a); // lookup and select a matching item LookupResult lookupResult = lookupItem(getText(0, getLength())); if (lookupResult.matchingItem != null) { setSelectedItem(lookupResult.matchingItem, lookupResult.matchingString); } else if (strictMatching) { // keep old item selected if there is no match lookupResult.matchingItem = adaptor.getSelectedItem(); lookupResult.matchingString = adaptor.getSelectedItemAsString(); // imitate no insert (later on offs will be incremented by // str.length(): selection won't move forward) offs = offs - str.length(); // provide feedback to the user that his input has been received but can // not be accepted UIManager.getLookAndFeel().provideErrorFeedback(adaptor.getTextComponent()); } else { // no item matches => use the current input as selected item lookupResult.matchingItem = getText(0, getLength()); lookupResult.matchingString = getText(0, getLength()); setSelectedItem(lookupResult.matchingItem, lookupResult.matchingString); } setText(lookupResult.matchingString); // select the completed part adaptor.markText(offs + str.length()); } /** * Sets the text of this AutoCompleteDocument to the given text. * * @param text the text that will be set for this document */ private void setText(String text) { try { // remove all text and insert the completed string super.remove(0, getLength()); super.insertString(0, text, null); } catch (BadLocationException e) { throw new IllegalArgumentException(e); } } /** * Selects the given item using the AbstractAutoCompleteAdaptor. * * @param itemAsString string representation of the item to be selected * @param item the item that is to be selected */ private void setSelectedItem(Object item, String itemAsString) { selecting = true; adaptor.setSelectedItem(item); adaptor.setSelectedItemAsString(itemAsString); selecting = false; } /** * Searches for an item that matches the given pattern. The * AbstractAutoCompleteAdaptor is used to access the candidate items. The * match is case-sensitive and will only match at the beginning of each item's * string representation. * * @param pattern the pattern that should be matched * * @return the first item that matches the pattern or null if * no item matches */ private LookupResult lookupItem(String pattern) { // iterate over all items to find an exact match LookupResult ret = findMatch(pattern, true); if (ret != null) { return ret; } // check if the currently selected item matches Object selectedItem = adaptor.getSelectedItem(); String[] possibleStrings = stringConverter.getPossibleStringsForItem(selectedItem); if (possibleStrings != null) { for (String element : possibleStrings) { if (startsWith(element, pattern)) { return new LookupResult(selectedItem, element); } } } // search for any matching item, if the currently selected does not match ret = findMatch(pattern, false); if (ret != null) { return ret; } // no item starts with the pattern => return null return new LookupResult(null, ""); } /** * Find match. * * @param pattern DOCUMENT_ME * @param exactMatch DOCUMENT_ME * * @return the lookup result */ private LookupResult findMatch(final String pattern, final boolean exactMatch) { String[] possibleStrings; for (int i = 0, n = adaptor.getItemCount(); i < n; i++) { Object currentItem = adaptor.getItem(i); possibleStrings = stringConverter.getPossibleStringsForItem(currentItem); if (possibleStrings != null) { // check if current item exactly matches the pattern // or starts with the string depending on flag for (String element : possibleStrings) { if ((exactMatch && element.equals(pattern)) || (!exactMatch && startsWith(element, pattern))) { return new LookupResult(currentItem, element); } } } } return null; } /** * DOCUMENT_ME. */ private static class LookupResult { /** DOCUMENT_ME. */ Object matchingItem; /** DOCUMENT_ME. */ String matchingString; /** * Instantiates a new lookup result. * * @param matchingItem DOCUMENT_ME * @param matchingString DOCUMENT_ME */ public LookupResult(Object matchingItem, String matchingString) { this.matchingItem = matchingItem; this.matchingString = matchingString; } } /** * Returns true if base starts with prefix * (taking case into account). * * @param base the string to be checked * @param prefix the prefix to check for * * @return true if base starts with prefix; * false otherwise */ private boolean startsWith(String base, String prefix) { if (base.length() < prefix.length()) { return false; } return base.regionMatches(false, 0, prefix, 0, prefix.length()); } } jajuk-1.9.6.orig/src/main/java/ext/package.html0000644000175000017500000000014111720500104021165 0ustar drazzibdrazzib

Public code from external sources with or without copyright

jajuk-1.9.6.orig/src/main/java/ext/scrollablepopupmenu/0000755000175000017500000000000011720500104023003 5ustar drazzibdrazzibjajuk-1.9.6.orig/src/main/java/ext/scrollablepopupmenu/XCheckedButton.java0000644000175000017500000001573611720500104026534 0ustar drazzibdrazzib/* * Copyright balajihe from * http://www.beginner-java-tutorial.com/scrollable-jpopupmenu.html * */ package ext.scrollablepopupmenu; import java.awt.Color; import java.awt.event.ItemEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import javax.swing.Action; import javax.swing.BorderFactory; import javax.swing.ButtonGroup; import javax.swing.Icon; import javax.swing.ImageIcon; import javax.swing.JButton; import javax.swing.JToggleButton; import javax.swing.SwingConstants; import javax.swing.UIManager; import javax.swing.plaf.ComponentUI; import javax.swing.plaf.basic.BasicButtonUI; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; /** * The Class XCheckedButton. * * @author balajihe from * http://www.beginner-java-tutorial.com/scrollable-jpopupmenu.html */ public class XCheckedButton extends JButton { /** Generated serialVersionUID. */ private static final long serialVersionUID = 6665536733427576873L; // Icon to be used to for the Checked Icon of the Button /** DOCUMENT_ME. */ private ImageIcon checkedIcon; /** Requires the icon to be always displayed, even when the item is unselected. */ private boolean iconAlwaysVisible = false; /** These colors are required in order to simulate the JMenuItem's L&F. */ public static final Color MENU_HIGHLIGHT_BG_COLOR = UIManager .getColor("MenuItem.selectionBackground"); /** The Constant MENU_HIGHLIGHT_FG_COLOR. DOCUMENT_ME */ public static final Color MENU_HIGHLIGHT_FG_COLOR = UIManager .getColor("MenuItem.selectionForeground"); /** The Constant MENUITEM_BG_COLOR. DOCUMENT_ME */ public static final Color MENUITEM_BG_COLOR = UIManager.getColor("MenuItem.background"); /** The Constant MENUITEM_FG_COLOR. DOCUMENT_ME */ public static final Color MENUITEM_FG_COLOR = UIManager.getColor("MenuItem.foreground"); // This property if set to false, will result in the checked Icon not being // displayed // when the button is selected /** DOCUMENT_ME. */ private boolean displayCheck = true; /** * Instantiates a new x checked button. */ public XCheckedButton() { super(); init(); } /** * Instantiates a new x checked button. * * @param a DOCUMENT_ME */ public XCheckedButton(Action a) { super(a); init(); } /** * Instantiates a new x checked button. * * @param icon DOCUMENT_ME */ public XCheckedButton(Icon icon) { super(icon); init(); } /** * Instantiates a new x checked button. * * @param text DOCUMENT_ME * @param icon DOCUMENT_ME */ public XCheckedButton(String text, Icon icon) { super(text, icon); init(); } /** * Instantiates a new x checked button. * * @param text DOCUMENT_ME */ public XCheckedButton(String text) { super(text); init(); } /** * Initialize component LAF and add Listeners. */ private void init() { MouseAdapter mouseAdapter = getMouseAdapter(); // Basically JGoodies LAF UI for JButton does not allow Background color // to be set. // So we need to set the default UI, ComponentUI ui = BasicButtonUI.createUI(this); this.setUI(ui); setBorder(BorderFactory.createEmptyBorder(3, 0, 3, 2)); setMenuItemDefaultColors(); // setContentAreaFilled(false); setHorizontalTextPosition(SwingConstants.RIGHT); setHorizontalAlignment(SwingConstants.LEFT); // setModel(new JToggleButton.ToggleButtonModel()); setModel(new XCheckedButtonModel()); setSelected(false); this.addMouseListener(mouseAdapter); } /** * Sets the menu item default colors. * DOCUMENT_ME */ private void setMenuItemDefaultColors() { XCheckedButton.this.setBackground(MENUITEM_BG_COLOR); XCheckedButton.this.setForeground(MENUITEM_FG_COLOR); } /** * Gets the mouse adapter. * * @return the mouse adapter */ private MouseAdapter getMouseAdapter() { return new MouseAdapter() { // For static menuitems, the background color remains the // highlighted color, if this is not overridden @Override public void mousePressed(MouseEvent e) { setMenuItemDefaultColors(); } @Override public void mouseEntered(MouseEvent e) { XCheckedButton.this.setBackground(MENU_HIGHLIGHT_BG_COLOR); XCheckedButton.this.setForeground(MENU_HIGHLIGHT_FG_COLOR); } @Override public void mouseExited(MouseEvent e) { setMenuItemDefaultColors(); } }; } /** * Display icon. * * @param checkedFlag DOCUMENT_ME */ public void displayIcon(boolean checkedFlag) { if (checkedFlag && isDisplayCheck()) { if (checkedIcon == null) { checkedIcon = IconLoader.getIcon(JajukIcons.OK); } this.setIcon(checkedIcon); } else { this.setIcon(IconLoader.getIcon(JajukIcons.EMPTY)); } this.repaint(); } /** * DOCUMENT_ME. */ private class XCheckedButtonModel extends JToggleButton.ToggleButtonModel { /** Generated serialVersionUID. */ private static final long serialVersionUID = 4628990599914525833L; /* * Need to Override keeping the super code, else the check mark won't come */ /* (non-Javadoc) * @see javax.swing.JToggleButton.ToggleButtonModel#setSelected(boolean) */ @Override public void setSelected(final boolean b) { boolean set = b; ButtonGroup group = getGroup(); if (group != null) { // use the group model instead group.setSelected(this, set); set = group.isSelected(this); } if (isSelected() == set) { return; } if (set) { stateMask |= SELECTED; } else { stateMask &= ~SELECTED; } // Send ChangeEvent fireStateChanged(); // Send ItemEvent fireItemStateChanged(new ItemEvent(this, ItemEvent.ITEM_STATE_CHANGED, this, this .isSelected() ? ItemEvent.SELECTED : ItemEvent.DESELECTED)); XCheckedButton.this.displayIcon(set | iconAlwaysVisible); } } // Returns true if Button will display Checked Icon on Click. Default // Behaviour is to display a Checked Icon /** * Checks if is display check. * * @return true, if is display check */ public boolean isDisplayCheck() { return displayCheck; } /** * Sets the property which determines whether a checked Icon should be * displayed or not Setting to false, makes this button display like a normal * button. * * @param displayCheck DOCUMENT_ME */ public void setDisplayCheck(boolean displayCheck) { this.displayCheck = displayCheck; } /** * Sets the checked icon. * * @param checkedIcon the new checked icon */ public void setCheckedIcon(ImageIcon checkedIcon) { this.checkedIcon = checkedIcon; } /** * Sets the icon always visible. * * @param iconAlwaysVisible the new icon always visible */ public void setIconAlwaysVisible(boolean iconAlwaysVisible) { this.iconAlwaysVisible = iconAlwaysVisible; } } jajuk-1.9.6.orig/src/main/java/ext/scrollablepopupmenu/XJPopupMenu.java0000644000175000017500000001420311720500104026040 0ustar drazzibdrazzib/* * This class implements a scrollable Popup Menu * * Copyright balajihe from * http://www.beginner-java-tutorial.com/scrollable-jpopupmenu.html * */ package ext.scrollablepopupmenu; import java.awt.BorderLayout; import java.awt.Component; import java.awt.Dimension; import java.awt.Graphics; import java.awt.GridLayout; import java.awt.Point; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.AbstractButton; import javax.swing.Icon; import javax.swing.ImageIcon; import javax.swing.JComponent; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.JPopupMenu; import javax.swing.JScrollPane; import javax.swing.JSeparator; import javax.swing.SwingConstants; import javax.swing.UIManager; import javax.swing.plaf.ComponentUI; import javax.swing.plaf.basic.BasicSeparatorUI; /** * This class implements a scrollable Popup Menu. * * @author balajihe from * http://www.beginner-java-tutorial.com/scrollable-jpopupmenu.html */ public class XJPopupMenu extends JPopupMenu implements ActionListener { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1; /** DOCUMENT_ME. */ private final JPanel panelMenus = new JPanel(); /** DOCUMENT_ME. */ private JScrollPane scroll = null; /** DOCUMENT_ME. */ private JFrame jframe = null; /** The Constant EMPTY_IMAGE_ICON. DOCUMENT_ME */ public static final Icon EMPTY_IMAGE_ICON = new ImageIcon("menu_spacer.gif"); /** * Instantiates a new xJ popup menu. * * @param jframe DOCUMENT_ME */ public XJPopupMenu(JFrame jframe) { super(); this.jframe = jframe; this.setLayout(new BorderLayout()); panelMenus.setLayout(new GridLayout(0, 1)); panelMenus.setBackground(UIManager.getColor("MenuItem.background")); // panelMenus.setBorder(BorderFactory.createEmptyBorder(0, 5, 0, 5)); init(); } /** * Inits the. * DOCUMENT_ME */ private void init() { super.removeAll(); scroll = new JScrollPane(); scroll.setViewportView(panelMenus); scroll.setBorder(null); scroll.setMinimumSize(new Dimension(240, 40)); scroll.setMaximumSize(new Dimension(scroll.getMaximumSize().width, this.getToolkit().getScreenSize().height - this.getToolkit().getScreenInsets(jframe.getGraphicsConfiguration()).top - this.getToolkit().getScreenInsets(jframe.getGraphicsConfiguration()).bottom - 4)); super.add(scroll, BorderLayout.CENTER); // super.add(scroll); } /* (non-Javadoc) * @see javax.swing.JPopupMenu#show(java.awt.Component, int, int) */ @Override public void show(Component invoker, int x, int y) { init(); // this.pack(); panelMenus.validate(); int maxsize = scroll.getMaximumSize().height; int realsize = panelMenus.getPreferredSize().height; int sizescroll = 0; if (maxsize < realsize) { sizescroll = scroll.getVerticalScrollBar().getPreferredSize().width; } scroll.setPreferredSize(new Dimension(scroll.getPreferredSize().width + sizescroll + 20, scroll.getPreferredSize().height)); this.pack(); this.setInvoker(invoker); if (sizescroll != 0) { // Set popup size only if scrollbar is visible this.setPopupSize(new Dimension(scroll.getPreferredSize().width + 20, scroll.getMaximumSize().height - 20)); } // this.setMaximumSize(scroll.getMaximumSize()); Point invokerOrigin = invoker.getLocationOnScreen(); this.setLocation((int) invokerOrigin.getX() + x, (int) invokerOrigin.getY() + y); this.setVisible(true); } /** * Hidemenu. * DOCUMENT_ME */ public void hidemenu() { if (this.isVisible()) { this.setVisible(false); } } /** * Adds the. * DOCUMENT_ME * * @param menuItem DOCUMENT_ME */ public void add(AbstractButton menuItem) { // menuItem.setMargin(new Insets(0, 20, 0 , 0)); if (menuItem == null) { return; } panelMenus.add(menuItem); menuItem.removeActionListener(this); menuItem.addActionListener(this); if (menuItem.getIcon() == null) { menuItem.setIcon(EMPTY_IMAGE_ICON); } } /* (non-Javadoc) * @see javax.swing.JPopupMenu#addSeparator() */ @Override public void addSeparator() { panelMenus.add(new XSeperator()); } /* (non-Javadoc) * @see java.awt.Container#removeAll() */ @Override public void removeAll() { panelMenus.removeAll(); } /* (non-Javadoc) * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent) */ @Override public void actionPerformed(ActionEvent e) { this.hidemenu(); } /* (non-Javadoc) * @see java.awt.Container#getComponents() */ @Override public Component[] getComponents() { return panelMenus.getComponents(); } /** * DOCUMENT_ME. */ private static class XSeperator extends JSeparator { /** Generated serialVersionUID. */ private static final long serialVersionUID = -6249719411021239596L; /** * Instantiates a new x seperator. */ XSeperator() { ComponentUI ui = XBasicSeparatorUI.createUI(this); XSeperator.this.setUI(ui); } /** * DOCUMENT_ME. */ private static class XBasicSeparatorUI extends BasicSeparatorUI { /** * Creates the ui. * DOCUMENT_ME * * @param c DOCUMENT_ME * * @return the component ui */ public static ComponentUI createUI(JComponent c) { return new XBasicSeparatorUI(); } /* (non-Javadoc) * @see javax.swing.plaf.basic.BasicSeparatorUI#paint(java.awt.Graphics, javax.swing.JComponent) */ @Override public void paint(Graphics g, JComponent c) { Dimension s = c.getSize(); if (((JSeparator) c).getOrientation() == SwingConstants.VERTICAL) { g.setColor(c.getForeground()); g.drawLine(0, 0, 0, s.height); g.setColor(c.getBackground()); g.drawLine(1, 0, 1, s.height); } else // HORIZONTAL { g.setColor(c.getForeground()); g.drawLine(0, 7, s.width, 7); g.setColor(c.getBackground()); g.drawLine(0, 8, s.width, 8); } } } } } jajuk-1.9.6.orig/src/main/java/ext/scrollablepopupmenu/package.html0000644000175000017500000000017111720500104025263 0ustar drazzibdrazzib DOCUMENT_ME jajuk-1.9.6.orig/src/main/java/ext/JVM.java0000644000175000017500000001160111720500104020206 0ustar drazzibdrazzib/* * This file has been adapted to Jajuk by the Jajuk Team. * * The original copyrights and license follow: * * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, * Santa Clara, California 95054, U.S.A. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * $Revision$ */ package ext; /** * Deals with the different version of the Java Virtual Machine.
*/ public class JVM { /** The Constant JDK1_0. DOCUMENT_ME */ public static final int JDK1_0 = 10; /** The Constant JDK1_1. DOCUMENT_ME */ public static final int JDK1_1 = 11; /** The Constant JDK1_2. DOCUMENT_ME */ public static final int JDK1_2 = 12; /** The Constant JDK1_3. DOCUMENT_ME */ public static final int JDK1_3 = 13; /** The Constant JDK1_4. DOCUMENT_ME */ public static final int JDK1_4 = 14; /** The Constant JDK1_5. DOCUMENT_ME */ public static final int JDK1_5 = 15; /** The Constant JDK1_6. DOCUMENT_ME */ public static final int JDK1_6 = 16; /** The Constant JDK1_7. DOCUMENT_ME */ public static final int JDK1_7 = 17; /** The Constant JDK1_8. DOCUMENT_ME */ public static final int JDK1_8 = 18; /** The Constant JDK1_9. DOCUMENT_ME */ public static final int JDK1_9 = 19; /** DOCUMENT_ME. */ private static JVM current; static { current = new JVM(); } /** * Current. * * @return the current JVM object */ public static JVM current() { return current; } /** DOCUMENT_ME. */ private int jdkVersion; /** * Creates a new JVM data from the java.version System property */ public JVM() { this(System.getProperty("java.version")); } /** * Constructor for the OS object. * * @param pJavaVersion DOCUMENT_ME */ public JVM(String pJavaVersion) { if (pJavaVersion.startsWith("1.9.")) { jdkVersion = JDK1_9; } else if (pJavaVersion.startsWith("1.8.")) { jdkVersion = JDK1_8; } else if (pJavaVersion.startsWith("1.7.")) { jdkVersion = JDK1_7; } else if (pJavaVersion.startsWith("1.6.")) { jdkVersion = JDK1_6; } else if (pJavaVersion.startsWith("1.5.")) { jdkVersion = JDK1_5; } else if (pJavaVersion.startsWith("1.4.")) { jdkVersion = JDK1_4; } else if (pJavaVersion.startsWith("1.3.")) { jdkVersion = JDK1_3; } else if (pJavaVersion.startsWith("1.2.")) { jdkVersion = JDK1_2; } else if (pJavaVersion.startsWith("1.1.")) { jdkVersion = JDK1_1; } else if (pJavaVersion.startsWith("1.0.")) { jdkVersion = JDK1_0; } else { // unknown version, assume 1.5 jdkVersion = JDK1_5; } } /** * Checks if is or later. * * @param pVersion DOCUMENT_ME * * @return true, if is or later */ public boolean isOrLater(int pVersion) { return jdkVersion >= pVersion; } /** * Checks if is one dot one. * * @return true, if is one dot one */ public boolean isOneDotOne() { return jdkVersion == JDK1_1; } /** * Checks if is one dot two. * * @return true, if is one dot two */ public boolean isOneDotTwo() { return jdkVersion == JDK1_2; } /** * Checks if is one dot three. * * @return true, if is one dot three */ public boolean isOneDotThree() { return jdkVersion == JDK1_3; } /** * Checks if is one dot four. * * @return true, if is one dot four */ public boolean isOneDotFour() { return jdkVersion == JDK1_4; } /** * Checks if is one dot five. * * @return true, if is one dot five */ public boolean isOneDotFive() { return jdkVersion == JDK1_5; } /** * Checks if is one dot six. * * @return true, if is one dot six */ public boolean isOneDotSix() { return jdkVersion == JDK1_6; } /** * Checks if is one dot seven. * * @return true, if is one dot seven */ public boolean isOneDotSeven() { return jdkVersion == JDK1_7; } /** * Checks if is one dot eight. * * @return true, if is one dot eight */ public boolean isOneDotEight() { return jdkVersion == JDK1_8; } /** * Checks if is one dot nine. * * @return true, if is one dot nine */ public boolean isOneDotNine() { return jdkVersion == JDK1_9; } } jajuk-1.9.6.orig/src/main/java/ext/JScrollingText.java0000644000175000017500000000602011720500104022464 0ustar drazzibdrazzib/* * Scrolling text component Code found at * http://www.developpez.net/forums/archive/index.php/t-41622.html Thanks * "herve91" */ package ext; import java.awt.FontMetrics; import java.awt.Graphics; import java.awt.Insets; import java.util.Timer; import java.util.TimerTask; import javax.swing.JLabel; /** * DOCUMENT_ME. */ public class JScrollingText extends JLabel { /** Generated serialVersionUID. */ private static final long serialVersionUID = 3068213731703270035L; /** DOCUMENT_ME. */ private final int speed; /** DOCUMENT_ME. */ private final int period; /** DOCUMENT_ME. */ private final int offset; /** DOCUMENT_ME. */ private int x = 300; /** * Instantiates a new j scrolling text. * * @param text DOCUMENT_ME */ public JScrollingText(String text) { this(text, 1); } /** * Instantiates a new j scrolling text. * * @param text DOCUMENT_ME * @param speed DOCUMENT_ME */ public JScrollingText(String text, int speed) { this(text, speed, 100); } /** * Instantiates a new j scrolling text. * * @param text DOCUMENT_ME * @param speed DOCUMENT_ME * @param period DOCUMENT_ME */ public JScrollingText(String text, int speed, int period) { this(text, speed, period, 0); } /** * Instantiates a new j scrolling text. * * @param text DOCUMENT_ME * @param speed DOCUMENT_ME * @param period DOCUMENT_ME * @param offset DOCUMENT_ME */ public JScrollingText(String text, int speed, int period, int offset) { super(text); this.speed = speed; this.period = period; this.offset = offset; } /* (non-Javadoc) * @see javax.swing.JComponent#paintComponent(java.awt.Graphics) */ @Override public void paintComponent(Graphics g) { if (isOpaque()) { g.setColor(getBackground()); g.fillRect(0, 0, getWidth(), getHeight()); } g.setColor(getForeground()); FontMetrics fm = g.getFontMetrics(); Insets insets = getInsets(); int width = getWidth() - (insets.left + insets.right); int height = getHeight() - (insets.top + insets.bottom); int textWidth = fm.stringWidth(getText()); if (width < textWidth) { width = textWidth + offset; } x %= width; int textX = insets.left + x; int textY = insets.top + (height - fm.getHeight()) / 2 + fm.getAscent(); g.drawString(getText(), textX, textY); g.drawString(getText(), textX + (speed > 0 ? -width : width), textY); } /** DOCUMENT_ME. */ Timer timer; /** * Start. * DOCUMENT_ME */ public void start() { timer = new Timer("Scrolling Text Timer"); TimerTask task = new TimerTask() { @Override public void run() { x += speed; repaint(); } }; timer.scheduleAtFixedRate(task, 1000, period); } /* (non-Javadoc) * @see javax.swing.JComponent#removeNotify() */ @Override public void removeNotify() { // clean out the timer if (timer != null) { timer.cancel(); timer = null; } super.removeNotify(); } } jajuk-1.9.6.orig/src/main/java/ext/FlowScrollPanel.java0000644000175000017500000001250011720500104022617 0ustar drazzibdrazzib/* * Code found at: http://groups.google.fr/group/comp.lang.java.gui/browse_thread/thread/11403002a25da9a3/da4cea55cf283a52?q=%2BJscrollPane++%2Bflowlayout&rnum=2&hl=fr#da4cea55cf283a52 * Chris Long <*> all...@cs.berkeley.edu <*> http://www.cs.berkeley.edu/~allanl * * This file has been adapted to Jajuk by the Jajuk Team. * */ package ext; import java.awt.AWTError; import java.awt.Component; import java.awt.Dimension; import java.awt.FlowLayout; import java.awt.Insets; import java.awt.LayoutManager; import java.awt.Rectangle; import java.awt.event.ComponentAdapter; import java.awt.event.ComponentEvent; import javax.swing.JScrollBar; import javax.swing.JScrollPane; import org.jdesktop.swingx.JXPanel; /** * DOCUMENT_ME. */ public class FlowScrollPanel extends JXPanel { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** DOCUMENT_ME. */ private FlowLayout layout = new FlowLayout(); /** DOCUMENT_ME. */ private JScrollPane scroller; /** * Instantiates a new flow scroll panel. */ public FlowScrollPanel() { this(null); } /** * Instantiates a new flow scroll panel. * * @param scrollPane DOCUMENT_ME */ public FlowScrollPanel(JScrollPane scrollPane) { super(); super.setLayout(layout); setScroller(scrollPane); } /** * Sets the scroller. * * @param scrollPane the new scroller */ public final void setScroller(JScrollPane scrollPane) { // FIXME: do we really want to compare instances here instead of content?? if (scroller != scrollPane) { scroller = scrollPane; if (scroller != null) { scroller.getViewport().setView(this); scroller.addComponentListener(new ComponentAdapter() { @Override public void componentResized(ComponentEvent e) { scroller.getViewport().setViewSize(getSize()); scroller.invalidate(); scroller.validate(); doLayout(); } }); } } } /* (non-Javadoc) * @see javax.swing.JComponent#getPreferredSize() */ @Override public Dimension getPreferredSize() { if (scroller == null) { return super.getPreferredSize(); } Insets insets = getInsets(); int hgap = layout.getHgap(); int vgap = layout.getVgap(); JScrollBar vsb = scroller.getVerticalScrollBar(); if (vsb == null) { vsb = scroller.createVerticalScrollBar(); } int scrollerWidth = scroller.getSize().width - (insets.left + insets.right + hgap * 2) - vsb.getSize().width /*-2*/; // the -2 is a voodoo constant. I don't know why it's needed, but // it is. (I suspect that this routine and FlowLayout compute // required sizes in a subtly different way.) // No longer needed with Swing 1.1 (I think). int nmembers = getComponentCount(); int x = 0, y = insets.top + vgap; int rowh = 0; int maxRowWidth = scrollerWidth; for (int i = 0; i < nmembers; i++) { Component m = getComponent(i); if (m.isVisible()) { Dimension d = m.getPreferredSize(); if ((x == 0) || ((x + d.width) <= scrollerWidth)) { if (x > 0) { x += hgap; } x += d.width; rowh = Math.max(rowh, d.height); } else { if (x > maxRowWidth) { maxRowWidth = x + hgap; } x = d.width; y += vgap + rowh; rowh = d.height; } } } if (x > maxRowWidth) { maxRowWidth = x + 2 * hgap + insets.left + insets.right; } y += vgap + rowh + insets.bottom; return new Dimension(maxRowWidth, y); } /* (non-Javadoc) * @see java.awt.Container#setLayout(java.awt.LayoutManager) */ @Override public void setLayout(LayoutManager l) { if (l instanceof FlowLayout) { layout = (FlowLayout) l; super.setLayout(l); } else { throw new AWTError("FlowScrollPane can have only FlowLayout, not " + l); } } // // Scrollable methods // /* (non-Javadoc) * @see org.jdesktop.swingx.JXPanel#getPreferredScrollableViewportSize() */ @Override public Dimension getPreferredScrollableViewportSize() { return getPreferredSize(); } /** * Returns height of a row. * * @param visibleRect DOCUMENT_ME * @param orientation DOCUMENT_ME * @param direction DOCUMENT_ME * * @return the scrollable unit increment */ @Override public int getScrollableUnitIncrement(Rectangle visibleRect, int orientation, int direction) { Dimension prefSize = layout.preferredLayoutSize(this); return prefSize.height / 20; } /** * returns the height of the visible rect (so it scrolls by one screenfull). * * @param visibleRect DOCUMENT_ME * @param orientation DOCUMENT_ME * @param direction DOCUMENT_ME * * @return the scrollable block increment */ @Override public int getScrollableBlockIncrement(Rectangle visibleRect, int orientation, int direction) { return visibleRect.height; } /* (non-Javadoc) * @see org.jdesktop.swingx.JXPanel#getScrollableTracksViewportWidth() */ @Override public boolean getScrollableTracksViewportWidth() { return true; } /* (non-Javadoc) * @see org.jdesktop.swingx.JXPanel#getScrollableTracksViewportHeight() */ @Override public boolean getScrollableTracksViewportHeight() { return false; } } jajuk-1.9.6.orig/src/main/java/ext/AutoCompleteDecorator.java0000644000175000017500000003216111720500104024022 0ustar drazzibdrazzib/* Jajuk Specific version of this swingx class to fix * this: https://swingx.dev.java.net/issues/show_bug.cgi?id=464 * * This file has been adapted to Jajuk by the Jajuk Team. * Jajuk Copyright (C) 2007 The Jajuk Team * * The original copyrights and license follow: * * Copyright 2004 Sun Microsystems, Inc., 4150 * Network Circle, Santa Clara, California 95054, U.S.A. All rights * reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package ext; import java.awt.event.ActionEvent; import java.awt.event.FocusAdapter; import java.awt.event.FocusEvent; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.util.List; import javax.swing.Action; import javax.swing.ActionMap; import javax.swing.ComboBoxEditor; import javax.swing.InputMap; import javax.swing.JComboBox; import javax.swing.JList; import javax.swing.KeyStroke; import javax.swing.UIManager; import javax.swing.text.DefaultEditorKit; import javax.swing.text.JTextComponent; import javax.swing.text.TextAction; import org.jdesktop.swingx.autocomplete.AbstractAutoCompleteAdaptor; import org.jdesktop.swingx.autocomplete.AutoCompleteComboBoxEditor; import org.jdesktop.swingx.autocomplete.ComboBoxAdaptor; import org.jdesktop.swingx.autocomplete.ListAdaptor; import org.jdesktop.swingx.autocomplete.ObjectToStringConverter; import org.jdesktop.swingx.autocomplete.TextComponentAdaptor; /** * This class contains only static utility methods that can be used to set up * automatic completion for some Swing components. *

* Usage examples: *

*

* *


 * JComboBox comboBox = [...];
 * AutoCompleteDecorator.<b>decorate</b>(comboBox);
 * 
 * List items = [...];
 * JTextField textField = [...];
 * AutoCompleteDecorator.<b>decorate</b>(textField, items);
 * 
 * JList list = [...];
 * JTextField textField = [...];
 * AutoCompleteDecorator.<b>decorate</b>(list, textField);
 * 
* *

* * @author Thomas Bierhance */ public final class AutoCompleteDecorator { /** * private constructor to avoid instantiating utility class. */ private AutoCompleteDecorator() { } /** * Enables automatic completion for the given JTextComponent based on the * items contained in the given List. * * @param textComponent the text component that will be used for automatic completion. * @param items contains the items that are used for autocompletion * @param strictMatching true, if only given items should be allowed to be * entered */ public static void decorate(JTextComponent textComponent, List items, boolean strictMatching) { decorate(textComponent, items, strictMatching, ObjectToStringConverter.DEFAULT_IMPLEMENTATION); } /** * Enables automatic completion for the given JTextComponent based on the * items contained in the given List. * * @param textComponent the text component that will be used for automatic completion. * @param items contains the items that are used for autocompletion * @param strictMatching true, if only given items should be allowed to be * entered * @param stringConverter the converter used to transform items to strings */ public static void decorate(JTextComponent textComponent, List items, boolean strictMatching, ObjectToStringConverter stringConverter) { AbstractAutoCompleteAdaptor adaptor = new TextComponentAdaptor(textComponent, items); AutoCompleteDocument document = new AutoCompleteDocument(adaptor, strictMatching, stringConverter); decorate(textComponent, document, adaptor); } /** * Enables automatic completion for the given JTextComponent based on the * items contained in the given JList. The two components will be * synchronized. The automatic completion will always be strict. * * @param list a JList containing the items for automatic completion * @param textComponent the text component that will be enabled for automatic completion */ public static void decorate(JList list, JTextComponent textComponent) { decorate(list, textComponent, ObjectToStringConverter.DEFAULT_IMPLEMENTATION); } /** * Enables automatic completion for the given JTextComponent based on the * items contained in the given JList. The two components will be * synchronized. The automatic completion will always be strict. * * @param list a JList containing the items for automatic completion * @param textComponent the text component that will be used for automatic completion * @param stringConverter the converter used to transform items to strings */ public static void decorate(JList list, JTextComponent textComponent, ObjectToStringConverter stringConverter) { AbstractAutoCompleteAdaptor adaptor = new ListAdaptor(list, textComponent, stringConverter); AutoCompleteDocument document = new AutoCompleteDocument(adaptor, true, stringConverter); decorate(textComponent, document, adaptor); } /** * Enables automatic completion for the given JComboBox. The automatic * completion will be strict (only items from the combo box can be selected) * if the combo box is not editable. * * @param comboBox a combo box */ public static void decorate(final JComboBox comboBox) { decorate(comboBox, ObjectToStringConverter.DEFAULT_IMPLEMENTATION); } /** * Enables automatic completion for the given JComboBox. The automatic * completion will be strict (only items from the combo box can be selected) * if the combo box is not editable. * * @param comboBox a combo box * @param stringConverter the converter used to transform items to strings */ public static void decorate(final JComboBox comboBox, final ObjectToStringConverter stringConverter) { boolean strictMatching = !comboBox.isEditable(); // has to be editable comboBox.setEditable(true); // configure the text component=editor component JTextComponent editorComponent = (JTextComponent) comboBox.getEditor().getEditorComponent(); final AbstractAutoCompleteAdaptor adaptor = new ComboBoxAdaptor(comboBox); final AutoCompleteDocument document = new AutoCompleteDocument(adaptor, strictMatching, stringConverter); decorate(editorComponent, document, adaptor); // show the popup list when the user presses a key final KeyListener keyListener = new KeyAdapter() { @Override public void keyPressed(KeyEvent keyEvent) { // don't popup on action keys (cursor movements, etc...) if (keyEvent.isActionKey()) { return; } // don't popup if the combobox isn't visible anyway if (comboBox.isDisplayable() && !comboBox.isPopupVisible()) { int keyCode = keyEvent.getKeyCode(); // don't popup when the user hits shift,ctrl or alt if (keyCode == KeyEvent.VK_SHIFT || keyCode == KeyEvent.VK_CONTROL || keyCode == KeyEvent.VK_ALT) { return; } // don't popup when the user hits escape (see issue #311) if (keyCode == KeyEvent.VK_ESCAPE) { return; } comboBox.setPopupVisible(true); } } }; editorComponent.addKeyListener(keyListener); if (stringConverter != ObjectToStringConverter.DEFAULT_IMPLEMENTATION) { comboBox.setEditor(new AutoCompleteComboBoxEditor(comboBox.getEditor(), stringConverter)); } // Changing the l&f can change the combobox' editor which in turn // would not be autocompletion-enabled. The new editor needs to be // set-up. comboBox.addPropertyChangeListener("editor", new PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent e) { ComboBoxEditor editor = (ComboBoxEditor) e.getNewValue(); if (editor != null && editor.getEditorComponent() != null) { if (!(editor instanceof AutoCompleteComboBoxEditor) && stringConverter != ObjectToStringConverter.DEFAULT_IMPLEMENTATION) { comboBox.setEditor(new AutoCompleteComboBoxEditor(editor, stringConverter)); // Don't do the decorate step here because calling // setEditor will trigger // the propertychange listener a second time, which will // do the decorate // and addKeyListener step. } else { decorate((JTextComponent) editor.getEditorComponent(), document, adaptor); editor.getEditorComponent().addKeyListener(keyListener); } } } }); } /** * Decorates a given text component for automatic completion using the given * AutoCompleteDocument and AbstractAutoCompleteAdaptor. * * @param textComponent a text component that should be decorated * @param document the AutoCompleteDocument to be installed on the text component * @param adaptor the AbstractAutoCompleteAdaptor to be used */ public static void decorate(JTextComponent textComponent, AutoCompleteDocument document, final AbstractAutoCompleteAdaptor adaptor) { // install the document on the text component textComponent.setDocument(document); // mark entire text when the text component gains focus // otherwise the last mark would have been retained which is quiet // confusing textComponent.addFocusListener(new FocusAdapter() { @Override public void focusGained(FocusEvent e) { adaptor.markEntireText(); } }); // Tweak some key bindings InputMap editorInputMap = textComponent.getInputMap(); if (document.isStrictMatching()) { // move the selection to the left on VK_BACK_SPACE editorInputMap.put(KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_BACK_SPACE, 0), DefaultEditorKit.selectionBackwardAction); // ignore VK_DELETE and CTRL+VK_X and beep instead when strict // matching editorInputMap.put(KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_DELETE, 0), errorFeedbackAction); editorInputMap.put(KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_X, java.awt.event.InputEvent.CTRL_DOWN_MASK), errorFeedbackAction); } else { ActionMap editorActionMap = textComponent.getActionMap(); // leave VK_DELETE and CTRL+VK_X as is // VK_BACKSPACE will move the selection to the left if the selected // item is in the list // it will delete the previous character otherwise editorInputMap.put(KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_BACK_SPACE, 0), "nonstrict-backspace"); editorActionMap.put("nonstrict-backspace", new NonStrictBackspaceAction(editorActionMap .get(DefaultEditorKit.deletePrevCharAction), editorActionMap .get(DefaultEditorKit.selectionBackwardAction), adaptor)); } } /** * DOCUMENT_ME. */ static class NonStrictBackspaceAction extends TextAction { /** Generated serialVersionUID. */ private static final long serialVersionUID = -5508607690462561673L; /** DOCUMENT_ME. */ private Action backspace; /** DOCUMENT_ME. */ private Action selectionBackward; /** DOCUMENT_ME. */ private AbstractAutoCompleteAdaptor adaptor; /** * Instantiates a new non strict backspace action. * * @param backspace DOCUMENT_ME * @param selectionBackward DOCUMENT_ME * @param adaptor DOCUMENT_ME */ public NonStrictBackspaceAction(Action backspace, Action selectionBackward, AbstractAutoCompleteAdaptor adaptor) { super("nonstrict-backspace"); this.backspace = backspace; this.selectionBackward = selectionBackward; this.adaptor = adaptor; } /* (non-Javadoc) * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent) */ @Override public void actionPerformed(ActionEvent e) { if (adaptor.listContainsSelectedItem()) { selectionBackward.actionPerformed(e); } else { backspace.actionPerformed(e); } } } /** A TextAction that provides an error feedback for the text component that invoked the action. The error feedback is most likely a "beep". */ static Object errorFeedbackAction = new TextAction("provide-error-feedback") { private static final long serialVersionUID = -3868819565696640330L; @Override public void actionPerformed(ActionEvent e) { UIManager.getLookAndFeel().provideErrorFeedback(getTextComponent(e)); } }; } jajuk-1.9.6.orig/src/main/java/ext/JXTrayIcon.java0000644000175000017500000000615311720500104021552 0ustar drazzibdrazzib/* * Code modified from Alexander Potochkin's JXTray class at * https://swinghelper.dev.java.net/source/browse/swinghelper/src/java/org/jdesktop/swinghelper/tray/JXTrayIcon.java?view=markup * Copyright 2008 Sun Microsystems, Inc., 4150 Network Circle, * Santa Clara, California 95054, U.S.A. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package ext; import java.awt.Frame; import java.awt.Image; import java.awt.TrayIcon; import java.awt.event.MouseEvent; import javax.swing.JDialog; import javax.swing.JPopupMenu; import javax.swing.event.PopupMenuEvent; import javax.swing.event.PopupMenuListener; /** * This class allow to add a Swing JDialog into an AWT Systray * * See http://weblogs.java.net/blog/alexfromsun/archive/2008/02/jtrayicon_updat.html */ public class JXTrayIcon extends TrayIcon { /** DOCUMENT_ME. */ private JPopupMenu menu; /** DOCUMENT_ME. */ private static JDialog dialog; static { dialog = new JDialog((Frame) null, "TrayDialog"); dialog.setUndecorated(true); dialog.setAlwaysOnTop(true); } /** DOCUMENT_ME. */ private static PopupMenuListener popupListener = new PopupMenuListener() { @Override public void popupMenuWillBecomeVisible(PopupMenuEvent e) { // required by interface, but nothing to do here... } @Override public void popupMenuWillBecomeInvisible(PopupMenuEvent e) { dialog.setVisible(false); } @Override public void popupMenuCanceled(PopupMenuEvent e) { dialog.setVisible(false); } }; /** * Instantiates a new jX tray icon. * * @param image DOCUMENT_ME */ public JXTrayIcon(Image image) { super(image); } /** * Show j popup menu. * DOCUMENT_ME * * @param e DOCUMENT_ME */ public void showJPopupMenu(MouseEvent e) { if (menu != null) { dialog.setLocation(e.getXOnScreen(), e.getYOnScreen()); dialog.setVisible(true); menu.show(dialog.getContentPane(), 0, 0); // popup works only for focused windows dialog.toFront(); } } /** * Gets the JPopupMenu. * * @return the JPopupMenu */ public JPopupMenu getJPopuMenu() { return menu; } /** * Sets the JPopupMenu. * * @param menu the new JPopupMenu */ public void setJPopuMenu(JPopupMenu menu) { if (this.menu != null) { this.menu.removePopupMenuListener(popupListener); } this.menu = menu; menu.addPopupMenuListener(popupListener); } } jajuk-1.9.6.orig/src/main/java/ext/MersenneTwister.java0000644000175000017500000005341011720500104022714 0ustar drazzibdrazzib/* * This file has been adapted (and deeply reduced) to Jajuk by the Jajuk Team. * See original MersenneTwister copyright notice bellow * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package ext; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; /** *

MersenneTwister and MersenneTwisterFast

*

Version 13, based on version MT199937(99/10/29) * of the Mersenne Twister algorithm found at * * The Mersenne Twister Home Page, with the initialization * improved using the new 2002/1/26 initialization algorithm * By Sean Luke, October 2004. * *

MersenneTwister is a drop-in subclass replacement * for java.util.Random. It is properly synchronized and * can be used in a multithreaded environment. On modern VMs such * as HotSpot, it is approximately 1/3 slower than java.util.Random. * *

MersenneTwisterFast is not a subclass of java.util.Random. It has * the same public methods as Random does, however, and it is * algorithmically identical to MersenneTwister. MersenneTwisterFast * has hard-code inlined all of its methods directly, and made all of them * final (well, the ones of consequence anyway). Further, these * methods are not synchronized, so the same MersenneTwisterFast * instance cannot be shared by multiple threads. But all this helps * MersenneTwisterFast achieve well over twice the speed of MersenneTwister. * java.util.Random is about 1/3 slower than MersenneTwisterFast. * *

About the Mersenne Twister

*

This is a Java version of the C-program for MT19937: Integer version. * The MT19937 algorithm was created by Makoto Matsumoto and Takuji Nishimura, * who ask: "When you use this, send an email to: matumoto@math.keio.ac.jp * with an appropriate reference to your work". Indicate that this * is a translation of their algorithm into Java. * *

Reference. * Makato Matsumoto and Takuji Nishimura, * "Mersenne Twister: A 623-Dimensionally Equidistributed Uniform * Pseudo-Random Number Generator", * ACM Transactions on Modeling and Computer Simulation, * Vol. 8, No. 1, January 1998, pp 3--30. * *

About this Version

* *

Changes Since V12: clone() method added. * *

Changes Since V11: stateEquals(...) method added. MersenneTwisterFast * is equal to other MersenneTwisterFasts with identical state; likewise * MersenneTwister is equal to other MersenneTwister with identical state. * This isn't equals(...) because that requires a contract of immutability * to compare by value. * *

Changes Since V10: A documentation error suggested that * setSeed(int[]) required an int[] array 624 long. In fact, the array * can be any non-zero length. The new version also checks for this fact. * *

Changes Since V9: readState(stream) and writeState(stream) * provided. * *

Changes Since V8: setSeed(int) was only using the first 28 bits * of the seed; it should have been 32 bits. For small-number seeds the * behavior is identical. * *

Changes Since V7: A documentation error in MersenneTwisterFast * (but not MersenneTwister) stated that nextDouble selects uniformly from * the full-open interval [0,1]. It does not. nextDouble's contract is * identical across MersenneTwisterFast, MersenneTwister, and java.util.Random, * namely, selection in the half-open interval [0,1). That is, 1.0 should * not be returned. A similar contract exists in nextFloat. * *

Changes Since V6: License has changed from LGPL to BSD. * New timing information to compare against * java.util.Random. Recent versions of HotSpot have helped Random increase * in speed to the point where it is faster than MersenneTwister but slower * than MersenneTwisterFast (which should be the case, as it's a less complex * algorithm but is synchronized). * *

Changes Since V5: New empty constructor made to work the same * as java.util.Random -- namely, it seeds based on the current time in * milliseconds. * *

Changes Since V4: New initialization algorithms. See * (see * http://www.math.keio.ac.jp/matumoto/MT2002/emt19937ar.html) * *

The MersenneTwister code is based on standard MT19937 C/C++ * code by Takuji Nishimura, * with suggestions from Topher Cooper and Marc Rieffel, July 1997. * The code was originally translated into Java by Michael Lecuyer, * January 1999, and the original code is Copyright (c) 1999 by Michael Lecuyer. * *

Java notes

* *

This implementation implements the bug fixes made * in Java 1.2's version of Random, which means it can be used with * earlier versions of Java. See * * the JDK 1.2 java.util.Random documentation for further documentation * on the random-number generation contracts made. Additionally, there's * an undocumented bug in the JDK java.util.Random.nextBytes() method, * which this code fixes. * *

Just like java.util.Random, this * generator accepts a long seed but doesn't use all of it. java.util.Random * uses 48 bits. The Mersenne Twister instead uses 32 bits (int size). * So it's best if your seed does not exceed the int range. * *

MersenneTwister can be used reliably * on JDK version 1.1.5 or above. Earlier Java versions have serious bugs in * java.util.Random; only MersenneTwisterFast (and not MersenneTwister nor * java.util.Random) should be used with them. * *

License

* * Copyright (c) 2003 by Sean Luke.
* Portions copyright (c) 1993 by Michael Lecuyer.
* All rights reserved.
* *

Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: *

    *
  • Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. *
  • Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. *
  • Neither the name of the copyright owners, their employers, nor the * names of its contributors may be used to endorse or promote products * derived from this software without specific prior written permission. *
*

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNERS OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * * @version 13 */ public class MersenneTwister extends java.util.Random implements Serializable, Cloneable { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; // Period parameters /** The Constant N. DOCUMENT_ME */ private static final int N = 624; /** The Constant M. DOCUMENT_ME */ private static final int M = 397; /** The Constant MATRIX_A. DOCUMENT_ME */ private static final int MATRIX_A = 0x9908b0df; // private static final * constant vector a /** The Constant UPPER_MASK. DOCUMENT_ME */ private static final int UPPER_MASK = 0x80000000; // most significant w-r bits /** The Constant LOWER_MASK. DOCUMENT_ME */ private static final int LOWER_MASK = 0x7fffffff; // least significant r bits // Tempering parameters /** The Constant TEMPERING_MASK_B. DOCUMENT_ME */ private static final int TEMPERING_MASK_B = 0x9d2c5680; /** The Constant TEMPERING_MASK_C. DOCUMENT_ME */ private static final int TEMPERING_MASK_C = 0xefc60000; /** DOCUMENT_ME. */ private int mt[]; // the array for the state vector /** DOCUMENT_ME. */ private int mti; // mti==N+1 means mt[N] is not initialized /** DOCUMENT_ME. */ private int mag01[]; // a good initial seed (of int size, though stored in a long) // private static final long GOOD_SEED = 4357; /* * implemented here because there's a bug in Random's implementation of the Gaussian code (divide * by zero, and log(0), ugh!), yet its gaussian variables are private so we can't access them * here. :-( */ /** DOCUMENT_ME. */ private double __nextNextGaussian; /** DOCUMENT_ME. */ private boolean __haveNextNextGaussian; /* We're overriding all internal data, to my knowledge, so this should be okay */ /* (non-Javadoc) * @see java.lang.Object#clone() */ @Override public Object clone() throws CloneNotSupportedException { MersenneTwister f = (MersenneTwister) (super.clone()); f.mt = mt.clone(); f.mag01 = mag01.clone(); return f; } /** * State equals. * DOCUMENT_ME * * @param o DOCUMENT_ME * * @return true if... */ public boolean stateEquals(Object o) { if (o == this) return true; if (o == null || !(o instanceof MersenneTwister)) return false; MersenneTwister other = (MersenneTwister) o; if (mti != other.mti) return false; for (int x = 0; x < mag01.length; x++) if (mag01[x] != other.mag01[x]) return false; for (int x = 0; x < mt.length; x++) if (mt[x] != other.mt[x]) return false; return true; } /** * Reads the entire state of the MersenneTwister RNG from the stream. * * @param stream DOCUMENT_ME * * @throws IOException Signals that an I/O exception has occurred. */ public void readState(DataInputStream stream) throws IOException { int len = mt.length; for (int x = 0; x < len; x++) mt[x] = stream.readInt(); len = mag01.length; for (int x = 0; x < len; x++) mag01[x] = stream.readInt(); mti = stream.readInt(); __nextNextGaussian = stream.readDouble(); __haveNextNextGaussian = stream.readBoolean(); } /** * Writes the entire state of the MersenneTwister RNG to the stream. * * @param stream DOCUMENT_ME * * @throws IOException Signals that an I/O exception has occurred. */ public void writeState(DataOutputStream stream) throws IOException { int len = mt.length; for (int x = 0; x < len; x++) stream.writeInt(mt[x]); len = mag01.length; for (int x = 0; x < len; x++) stream.writeInt(mag01[x]); stream.writeInt(mti); stream.writeDouble(__nextNextGaussian); stream.writeBoolean(__haveNextNextGaussian); } /** * Constructor using the default seed. */ public MersenneTwister() { this(System.currentTimeMillis()); } /** * Constructor using a given seed. Though you pass this seed in * as a long, it's best to make sure it's actually an integer. * * @param seed DOCUMENT_ME */ public MersenneTwister(final long seed) { super(seed); /* just in case */ setSeed(seed); } /** * Constructor using an array of integers as seed. * Your array must have a non-zero length. Only the first 624 integers * in the array are used; if the array is shorter than this then * integers are repeatedly used in a wrap-around fashion. * * @param array DOCUMENT_ME */ public MersenneTwister(final int[] array) { super(System.currentTimeMillis()); /* pick something at random just in case */ setSeed(array); } /** * Initalize the pseudo random number generator. Don't * pass in a long that's bigger than an int (Mersenne Twister * only uses the first 32 bits for its seed). * * @param seed DOCUMENT_ME */ @Override synchronized public void setSeed(final long seed) { // it's always good style to call super super.setSeed(seed); // Due to a bug in java.util.Random clear up to 1.2, we're // doing our own Gaussian variable. __haveNextNextGaussian = false; mt = new int[N]; mag01 = new int[2]; mag01[0] = 0x0; mag01[1] = MATRIX_A; mt[0] = (int) (seed & 0xffffffff); for (mti = 1; mti < N; mti++) { mt[mti] = (1812433253 * (mt[mti - 1] ^ (mt[mti - 1] >>> 30)) + mti); /* See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier. */ /* In the previous versions, MSBs of the seed affect */ /* only MSBs of the array mt[]. */ /* 2002/01/09 modified by Makoto Matsumoto */ mt[mti] &= 0xffffffff; /* for >32 bit machines */ } } /** * Sets the seed of the MersenneTwister using an array of integers. * Your array must have a non-zero length. Only the first 624 integers * in the array are used; if the array is shorter than this then * integers are repeatedly used in a wrap-around fashion. * * @param array DOCUMENT_ME */ synchronized public void setSeed(final int[] array) { if (array.length == 0) throw new IllegalArgumentException("Array length must be greater than zero"); int i, j, k; setSeed(19650218); i = 1; j = 0; k = (N > array.length ? N : array.length); for (; k != 0; k--) { mt[i] = (mt[i] ^ ((mt[i - 1] ^ (mt[i - 1] >>> 30)) * 1664525)) + array[j] + j; /* non linear */ mt[i] &= 0xffffffff; /* for WORDSIZE > 32 machines */ i++; j++; if (i >= N) { mt[0] = mt[N - 1]; i = 1; } if (j >= array.length) j = 0; } for (k = N - 1; k != 0; k--) { mt[i] = (mt[i] ^ ((mt[i - 1] ^ (mt[i - 1] >>> 30)) * 1566083941)) - i; /* non linear */ mt[i] &= 0xffffffff; /* for WORDSIZE > 32 machines */ i++; if (i >= N) { mt[0] = mt[N - 1]; i = 1; } } mt[0] = 0x80000000; /* MSB is 1; assuring non-zero initial array */ } /** * Returns an integer with bits bits filled with a random number. * * @param bits DOCUMENT_ME * * @return the int */ @Override synchronized protected int next(final int bits) { int y; if (mti >= N) // generate N words at one time { int kk; final int[] mt = this.mt; // locals are slightly faster final int[] mag01 = this.mag01; // locals are slightly faster for (kk = 0; kk < N - M; kk++) { y = (mt[kk] & UPPER_MASK) | (mt[kk + 1] & LOWER_MASK); mt[kk] = mt[kk + M] ^ (y >>> 1) ^ mag01[y & 0x1]; } for (; kk < N - 1; kk++) { y = (mt[kk] & UPPER_MASK) | (mt[kk + 1] & LOWER_MASK); mt[kk] = mt[kk + (M - N)] ^ (y >>> 1) ^ mag01[y & 0x1]; } y = (mt[N - 1] & UPPER_MASK) | (mt[0] & LOWER_MASK); mt[N - 1] = mt[M - 1] ^ (y >>> 1) ^ mag01[y & 0x1]; mti = 0; } y = mt[mti++]; y ^= y >>> 11; // TEMPERING_SHIFT_U(y) y ^= (y << 7) & TEMPERING_MASK_B; // TEMPERING_SHIFT_S(y) y ^= (y << 15) & TEMPERING_MASK_C; // TEMPERING_SHIFT_T(y) y ^= (y >>> 18); // TEMPERING_SHIFT_L(y) return y >>> (32 - bits); // hope that's right! } /* * If you've got a truly old version of Java, you can omit these two next methods. */ /** * Write object. * DOCUMENT_ME * * @param out DOCUMENT_ME * * @throws IOException Signals that an I/O exception has occurred. */ private synchronized void writeObject(final ObjectOutputStream out) throws IOException { // just so we're synchronized. out.defaultWriteObject(); } /** * Read object. * DOCUMENT_ME * * @param in DOCUMENT_ME * * @throws IOException Signals that an I/O exception has occurred. * @throws ClassNotFoundException the class not found exception */ private synchronized void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException { // just so we're synchronized. in.defaultReadObject(); } /** * This method is missing from jdk 1.0.x and below. JDK 1.1 * includes this for us, but what the heck. * * @return true, if next boolean */ @Override public boolean nextBoolean() { return next(1) != 0; } /** * This generates a coin flip with a probability probability * of returning true, else returning false. probability must * be between 0.0 and 1.0, inclusive. Not as precise a random real * event as nextBoolean(double), but twice as fast. To explicitly * use this, remember you may need to cast to float first. * * @param probability DOCUMENT_ME * * @return true, if next boolean */ public boolean nextBoolean(final float probability) { if (probability < 0.0f || probability > 1.0f) throw new IllegalArgumentException("probability must be between 0.0 and 1.0 inclusive."); if (probability == 0.0f) return false; // fix half-open issues else if (probability == 1.0f) return true; // fix half-open issues return nextFloat() < probability; } /** * This generates a coin flip with a probability probability * of returning true, else returning false. probability must * be between 0.0 and 1.0, inclusive. * * @param probability DOCUMENT_ME * * @return true, if next boolean */ public boolean nextBoolean(final double probability) { if (probability < 0.0 || probability > 1.0) throw new IllegalArgumentException("probability must be between 0.0 and 1.0 inclusive."); if (probability == 0.0) return false; // fix half-open issues else if (probability == 1.0) return true; // fix half-open issues return nextDouble() < probability; } /** * This method is missing from JDK 1.1 and below. JDK 1.2 * includes this for us, but what the heck. * * @param n DOCUMENT_ME * * @return the int */ @Override public int nextInt(final int n) { if (n <= 0) throw new IllegalArgumentException("n must be > 0"); if ((n & -n) == n) return (int) ((n * (long) next(31)) >> 31); int bits, val; do { bits = next(31); val = bits % n; } while (bits - val + (n - 1) < 0); return val; } /** * This method is for completness' sake. * Returns a long drawn uniformly from 0 to n-1. Suffice it to say, * n must be > 0, or an IllegalArgumentException is raised. * * @param n DOCUMENT_ME * * @return the long */ public long nextLong(final long n) { if (n <= 0) throw new IllegalArgumentException("n must be > 0"); long bits, val; do { bits = (nextLong() >>> 1); val = bits % n; } while (bits - val + (n - 1) < 0); return val; } /** * A bug fix for versions of JDK 1.1 and below. JDK 1.2 fixes * this for us, but what the heck. * * @return the double */ @Override public double nextDouble() { return (((long) next(26) << 27) + next(27)) / (double) (1L << 53); } /** * A bug fix for versions of JDK 1.1 and below. JDK 1.2 fixes * this for us, but what the heck. * * @return the float */ @Override public float nextFloat() { return next(24) / ((float) (1 << 24)); } /** * A bug fix for all versions of the JDK. The JDK appears to * use all four bytes in an integer as independent byte values! * Totally wrong. I've submitted a bug report. * * @param bytes DOCUMENT_ME */ @Override public void nextBytes(final byte[] bytes) { for (int x = 0; x < bytes.length; x++) bytes[x] = (byte) next(8); } /** * For completeness' sake, though it's not in java.util.Random. * * @return the char */ public char nextChar() { // chars are 16-bit UniCode values return (char) (next(16)); } /** * For completeness' sake, though it's not in java.util.Random. * * @return the short */ public short nextShort() { return (short) (next(16)); } /** * For completeness' sake, though it's not in java.util.Random. * * @return the byte */ public byte nextByte() { return (byte) (next(8)); } /** * A bug fix for all JDK code including 1.2. nextGaussian can theoretically * ask for the log of 0 and divide it by 0! See Java bug * * http://developer.java.sun.com/developer/bugParade/bugs/4254501.html * * @return the double */ @Override synchronized public double nextGaussian() { if (__haveNextNextGaussian) { __haveNextNextGaussian = false; return __nextNextGaussian; } else { double v1, v2, s; do { v1 = 2 * nextDouble() - 1; // between -1.0 and 1.0 v2 = 2 * nextDouble() - 1; // between -1.0 and 1.0 s = v1 * v1 + v2 * v2; } while (s >= 1 || s == 0); double multiplier = /* Strict */Math.sqrt(-2 * /* Strict */Math.log(s) / s); __nextNextGaussian = v2 * multiplier; __haveNextNextGaussian = true; return v1 * multiplier; } } } jajuk-1.9.6.orig/src/main/java/ext/JSplash.java0000644000175000017500000001630511720500104021124 0ustar drazzibdrazzib/* * JSplash.java * * This file has been adapted to Jajuk by the Jajuk Team. * * The original copyrights and license follow: * * Copyright (c) 2004,2005 Gregory Kotsaftis * gregkotsaftis@yahoo.com * http://zeus-jscl.sourceforge.net/ * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package ext; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Dimension; import java.awt.Font; import java.awt.GridLayout; import java.net.URL; import javax.swing.BorderFactory; import javax.swing.ImageIcon; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.JProgressBar; import javax.swing.JRootPane; import javax.swing.border.EmptyBorder; import org.jajuk.ui.helpers.FontManager; import org.jajuk.ui.helpers.FontManager.JajukFont; import org.jajuk.util.Messages; import org.jajuk.util.UtilSystem; /** * A simple, yet nice splash screen implementation for java applications. * Follows Sun recommendations for splash screen and logos: see * "Designing Graphics for Corporate and Product Identity". Draws a * black border of one pixel wide around the splash image. Also uses a simple * progress bar that the user must "progress" manually in his code in order for * it to work. Also, it has options for percent display, custom loading messages * display and application version string display at the bottom-right corner of * the image. *

* * @author Gregory Kotsaftis * @since 1.0 *

* Adapted to Jajuk by The Jajuk Team */ public final class JSplash extends JFrame { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** The Constant JAJUK_ICON. DOCUMENT_ME */ private static final String JAJUK_ICON = "icons/64x64/jajuk-icon_64x64.png"; /** Progress bar to use in the splash screen. */ private JProgressBar mProgress = null; /** Check for whether to use the progress bar or not. */ private boolean mProgressBar = false; /** Check for whether to use progress bar messages or not. */ private boolean mProgressBarMessages = false; /** Check for whether to use percentage values or not. */ private boolean mProgressBarPercent = false; /** * Constructor for the splash window. *

* * @param url Image for ImageIcon. * @param progress Do we want a progress bar at all? * @param messages If we want a progress bar, do we want to display messages inside * the progress bar? * @param percent If we want a progress bar, do we want to display the percent? * @param copyrightString Copyright notice * @param versionString If null no string is displayed on the bottom-right of the splash * window. * @param versionStringFont Font for version string, if null default. *

* NOTE: Use only one flag for: messages / percent (one or * the other, NOT both). */ public JSplash(URL url, boolean progress, boolean messages, boolean percent, String copyrightString, String versionString, Font versionStringFont) { super(); setTitle(Messages.getString("JajukWindow.17")); // check if we can load the icon URL icon = UtilSystem.getResource(JAJUK_ICON); if (null == icon) { throw new IllegalArgumentException( "Resource not found in Classpath. Can not load icon from location: " + JAJUK_ICON); } // Do not use IconLoader class here to avoid loading all icons now setIconImage(new ImageIcon(icon).getImage()); setUndecorated(true); getRootPane().setWindowDecorationStyle(JRootPane.NONE); mProgressBar = progress; mProgressBarMessages = messages; mProgressBarPercent = percent; // build a panel with a black line for border, // and set it as the content pane JPanel panel = new JPanel(); panel.setLayout(new BorderLayout()); panel.setBorder(BorderFactory.createLineBorder(Color.BLACK)); setContentPane(panel); if (url == null) { throw new IllegalArgumentException("Invalid URL specified for Splashscreen"); } // build a label and set it's icon JSplashLabel label = new JSplashLabel(url, copyrightString, versionString, versionStringFont); // build a progress bar and a tips of the day scrolling text String totd = Messages.getShuffleTipOfTheDay(); // Remove pictures urls if (totd.matches(".* * * @param value The progress indicator value. */ public void setProgress(int value) { if (mProgressBar && value >= 0 && value <= 100) { mProgress.setValue(value); } } /** * Sets the progress indicator (values: 0 - 100) and a label to print inside * the progress bar. *

* * @param value The progress indicator value. * @param msg The message to print. */ public void setProgress(int value, String msg) { setProgress(value); repaint(); if (mProgressBarMessages && !mProgressBarPercent && msg != null) { mProgress.setString(msg); } } } jajuk-1.9.6.orig/src/main/java/ext/services/0000755000175000017500000000000011720500104020533 5ustar drazzibdrazzibjajuk-1.9.6.orig/src/main/java/ext/services/network/0000755000175000017500000000000011720500104022224 5ustar drazzibdrazzibjajuk-1.9.6.orig/src/main/java/ext/services/network/package.html0000644000175000017500000000017111720500104024504 0ustar drazzibdrazzib DOCUMENT_ME jajuk-1.9.6.orig/src/main/java/ext/services/network/NetworkUtils.java0000644000175000017500000001705511720500104025551 0ustar drazzibdrazzib/* * aTunes 1.14.0 code adapted by Jajuk team * * Original copyright notice bellow : * * Copyright (C) 2006-2009 Alex Aranda, Sylvain Gaudard, Thomas Beckers and contributors * * See http://www.atunes.org/wiki/index.php?title=Contributing for information about contributors * * http://www.atunes.org * http://sourceforge.net/projects/atunes * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ package ext.services.network; import java.awt.Image; import java.io.DataOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.UnsupportedEncodingException; import java.net.HttpURLConnection; import java.net.URL; import java.net.URLConnection; import java.net.URLEncoder; import javax.imageio.ImageIO; import org.jajuk.util.Conf; import org.jajuk.util.Const; import org.jajuk.util.log.Log; /** * DOCUMENT_ME. */ public final class NetworkUtils { /** * Instantiates a new network utils. */ private NetworkUtils() { // default hidden constructor for utility classes } /** * Gets the connection. * * @param urlString DOCUMENT_ME * @param proxy DOCUMENT_ME * * @return the connection * * @throws IOException Signals that an I/O exception has occurred. */ public static HttpURLConnection getConnection(String urlString, Proxy proxy) throws IOException { // Drop the query if user required "none Internet access from jajuk". // This method shouldn't be called anyway because we views have to deal with // this option at their level, this is a additional control. if (Conf.getBoolean(Const.CONF_NETWORK_NONE_INTERNET_ACCESS)) { return null; } URL url = new URL(urlString); HttpURLConnection connection = getConnection(url, proxy); setConfiguration(connection); return connection; } /** * Gets the connection. * * @param url DOCUMENT_ME * @param proxy DOCUMENT_ME * * @return the connection * * @throws IOException Signals that an I/O exception has occurred. */ public static HttpURLConnection getConnection(URL url, Proxy proxy) throws IOException { // Drop the query if user required "none Internet access from jajuk". // This method shouldn't be called anyway because we views have to deal with // this option at their level, this is a additional control. if (Conf.getBoolean(Const.CONF_NETWORK_NONE_INTERNET_ACCESS)) { return null; } Log.debug("Opening Connection With: {{" + url + "}}"); HttpURLConnection connection; if (proxy == null) { URLConnection urlconnection = url.openConnection(); if (urlconnection instanceof HttpURLConnection) { connection = (HttpURLConnection) urlconnection; } else { throw new IllegalArgumentException("URL to connect to is not a HttpURL: " + url.toString()); } } else { connection = (HttpURLConnection) proxy.getConnection(url); } setConfiguration(connection); return connection; } /** * Sets the configuration. * * @param connection the new configuration */ private static void setConfiguration(HttpURLConnection connection) { connection.setConnectTimeout(1000 * Conf.getInt(Const.CONF_NETWORK_CONNECTION_TO)); // Google needs this connection.addRequestProperty("Accept", "image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, */*"); connection.addRequestProperty("Accept-Language", "en-us"); connection.addRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0)"); connection.addRequestProperty("Connection", "Keep-Alive"); } /** * Read url. * DOCUMENT_ME * * @param connection DOCUMENT_ME * @param charset DOCUMENT_ME * * @return the string * * @throws IOException Signals that an I/O exception has occurred. */ public static String readURL(URLConnection connection, String charset) throws IOException { // Drop the query if user required "none Internet access from jajuk". // This method shouldn't be called anyway because we views have to deal with // this option at their level, this is a additional control. if (Conf.getBoolean(Const.CONF_NETWORK_NONE_INTERNET_ACCESS)) { return null; } StringBuilder builder = new StringBuilder(); InputStream input = connection.getInputStream(); try { byte[] array = new byte[1024]; int read; while ((read = input.read(array)) > 0) { builder.append(new String(array, 0, read, charset)); } } finally { input.close(); } return builder.toString(); } /** * Read url. * DOCUMENT_ME * * @param connection DOCUMENT_ME * * @return the string * * @throws IOException Signals that an I/O exception has occurred. */ public static String readURL(URLConnection connection) throws IOException { return readURL(connection, "UTF-8"); } /** * Read post url. * DOCUMENT_ME * * @param connection DOCUMENT_ME * @param post DOCUMENT_ME * * @return the string * * @throws IOException Signals that an I/O exception has occurred. */ public static String readPostURL(HttpURLConnection connection, String post) throws IOException { // Drop the query if user required "none Internet access from jajuk". // This method shouldn't be called anyway because we views have to deal with // this option at their level, this is a additional control. if (Conf.getBoolean(Const.CONF_NETWORK_NONE_INTERNET_ACCESS)) { return null; } OutputStream out = connection.getOutputStream(); DataOutputStream writer = new DataOutputStream(out); try { writer.writeBytes(post); writer.flush(); } finally { writer.close(); } if (connection.getResponseCode() != 200) { throw new IllegalArgumentException("Invalid HTTP return code"); } StringBuilder builder = new StringBuilder(); InputStream input = connection.getInputStream(); try { byte[] array = new byte[1024]; int read; while ((read = input.read(array)) > 0) { builder.append(new String(array, 0, read, "UTF-8")); } } finally { input.close(); } return builder.toString(); } /** * Gets the image. * * @param connection DOCUMENT_ME * * @return the image * * @throws IOException Signals that an I/O exception has occurred. */ public static Image getImage(URLConnection connection) throws IOException { // Drop the query if user required "none Internet access from jajuk". // This method shouldn't be called anyway because we views have to deal with // this option at their level, this is a additional control. if (Conf.getBoolean(Const.CONF_NETWORK_NONE_INTERNET_ACCESS)) { return null; } InputStream input = connection.getInputStream(); return ImageIO.read(input); } /** * Encodes a string in a format suitable to send a http request. * * @param s DOCUMENT_ME * * @return the string */ public static String encodeString(String s) { try { return URLEncoder.encode(s, "UTF-8"); } catch (UnsupportedEncodingException e) { return s; } } } jajuk-1.9.6.orig/src/main/java/ext/services/network/Proxy.java0000644000175000017500000000573011720500104024215 0ustar drazzibdrazzib/* * aTunes 1.14.0 code adapted by Jajuk team * * Original copyright notice bellow : * * Copyright (C) 2006-2009 Alex Aranda, Sylvain Gaudard, Thomas Beckers and contributors * * See http://www.atunes.org/wiki/index.php?title=Contributing for information about contributors * * http://www.atunes.org * http://sourceforge.net/projects/atunes * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ package ext.services.network; import java.io.IOException; import java.net.Socket; import java.net.URL; import java.net.URLConnection; import java.net.UnknownHostException; import org.apache.commons.codec.binary.Base64; /** * DOCUMENT_ME. */ public class Proxy extends java.net.Proxy { /** Generated serialVersionUID. */ private static final long serialVersionUID = 7495084217081194366L; /** DOCUMENT_ME. */ private final String url; /** DOCUMENT_ME. */ private final int port; /** DOCUMENT_ME. */ private final String user; /** DOCUMENT_ME. */ private final String password; /** * Instantiates a new proxy. * * @param type DOCUMENT_ME * @param url DOCUMENT_ME * @param port DOCUMENT_ME * @param user DOCUMENT_ME * @param password DOCUMENT_ME * * @throws UnknownHostException the unknown host exception * @throws IOException Signals that an I/O exception has occurred. */ public Proxy(Type type, String url, int port, String user, String password) throws UnknownHostException, IOException { super(type, new Socket(url, port).getRemoteSocketAddress()); this.url = url; this.port = port; this.user = user; this.password = password; } /** * Gets the connection. * * @param u DOCUMENT_ME * * @return the connection * * @throws IOException Signals that an I/O exception has occurred. */ public URLConnection getConnection(URL u) throws IOException { URLConnection con = u.openConnection(this); String encodedUserPwd = new String(Base64.encodeBase64((user + ':' + password).getBytes())); con.setRequestProperty("Proxy-Authorization", "Basic " + encodedUserPwd); return con; } /** * Gets the password. * * @return the password */ public String getPassword() { return password; } /** * Gets the url. * * @return the url */ public String getUrl() { return url; } /** * Gets the port. * * @return the port */ public int getPort() { return port; } /** * Gets the user. * * @return the user */ public String getUser() { return user; } } jajuk-1.9.6.orig/src/main/java/ext/services/lastfm/0000755000175000017500000000000011720500104022021 5ustar drazzibdrazzibjajuk-1.9.6.orig/src/main/java/ext/services/lastfm/LastFmAlbum.java0000644000175000017500000002033611720500104025037 0ustar drazzibdrazzib/* * aTunes 1.14.0 code adapted by Jajuk team * * Original copyright notice bellow : * * Copyright (C) 2006-2009 Alex Aranda, Sylvain Gaudard, Thomas Beckers and contributors * * See http://www.atunes.org/wiki/index.php?title=Contributing for information about contributors * * http://www.atunes.org * http://sourceforge.net/projects/atunes * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ package ext.services.lastfm; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Calendar; import java.util.Date; import java.util.List; import java.util.Locale; import javax.swing.ImageIcon; import net.roarsoftware.lastfm.Album; import net.roarsoftware.lastfm.ImageSize; import net.roarsoftware.lastfm.Playlist; import net.roarsoftware.lastfm.Track; import org.jajuk.util.UtilString; /** * The Class LastFmAlbum. */ public class LastFmAlbum implements AlbumInfo { /** The Constant DF. */ private static final ThreadLocal DF = new ThreadLocal() { @Override protected SimpleDateFormat initialValue() { return new SimpleDateFormat("d MMM yyyy, HH:mm", Locale.US); } }; /** The artist. */ private String artist; /** The title. */ private String title; /** The url. */ private String url; /** The release date string. */ private String releaseDateString; /** The big cover url. */ private String bigCoverURL; /** The cover url. */ private String coverURL; /** The small cover url. */ private String smallCoverURL; /** The tracks. */ private List tracks; // Used by renderers /** The cover. */ private ImageIcon cover; /** * Gets the album. * * @param a DOCUMENT_ME * @param pl DOCUMENT_ME * * @return the album */ public static AlbumInfo getAlbum(Album a, Playlist pl) { LastFmAlbum album = new LastFmAlbum(); album.artist = a.getArtist(); album.title = a.getName(); album.url = a.getUrl(); album.releaseDateString = a.getReleaseDate() != null ? a.getReleaseDate().toString() : ""; album.bigCoverURL = a.getImageURL(ImageSize.LARGE); album.coverURL = a.getImageURL(ImageSize.ORIGINAL); album.smallCoverURL = a.getImageURL(ImageSize.SMALL); if (pl != null) { List ts = new ArrayList(); for (Track t : pl.getTracks()) { ts.add(LastFmTrack.getTrack(t)); } // Process track list: if all tracks have a common string between (), [], // {} as "(Live)" then it's removed from all of them // In this way track names are more accurate if (!ts.isEmpty()) { handleTracks(ts); } album.tracks = ts; } return album; } /** * Handle tracks. * DOCUMENT_ME * * @param ts DOCUMENT_ME */ private static void handleTracks(List ts) { String firstTrackTitle = ts.get(0).getTitle(); // Get all text between () [] {} List tokensOfFirstTrackTitle = UtilString .getTextBetweenChars(firstTrackTitle, '(', ')'); tokensOfFirstTrackTitle.addAll(UtilString.getTextBetweenChars(firstTrackTitle, '[', ']')); tokensOfFirstTrackTitle.addAll(UtilString.getTextBetweenChars(firstTrackTitle, '{', '}')); // Check what tokens are present in all track titles List commonTokens = new ArrayList(); for (String token : tokensOfFirstTrackTitle) { boolean common = true; for (int i = 1; i < ts.size() && common; i++) { if (!ts.get(i).getTitle().contains(token)) { common = false; } } if (common) { commonTokens.add(token); } } // Then remove common tokens from all titles for (TrackInfo ti : ts) { for (String token : commonTokens) { ti.setTitle(ti.getTitle().replace(token, "")); } ti.setTitle(ti.getTitle().trim()); } } /** * Gets the artist. * * @return the artist */ @Override public String getArtist() { return artist; } /** * Gets the artist url. * * @return the artist url */ @Override public String getArtistUrl() { if (url == null) { return null; } if (!url.contains("/")) { return url; } return url.substring(0, url.lastIndexOf('/')); } /** * Gets the big cover url. * * @return the bigCoverURL */ @Override public String getBigCoverURL() { return bigCoverURL; } /** * Gets the cover. * * @return the cover */ @Override public ImageIcon getCover() { return cover; } /** * Gets the cover url. * * @return the cover url */ @Override public String getCoverURL() { return coverURL; } /** * Gets the release date. * * @return the release date */ @Override public Date getReleaseDate() { if (releaseDateString == null) { return null; } try { return DF.get().parse(releaseDateString); } catch (ParseException e) { return null; } } /** * Gets the release date string. * * @return the releaseDateString */ @Override public String getReleaseDateString() { return releaseDateString; } /** * Gets the small cover url. * * @return the small cover url */ @Override public String getSmallCoverURL() { return smallCoverURL; } /** * Gets the title. * * @return the title */ @Override public String getTitle() { return title; } /** * Gets the tracks. * * @return the tracks */ @Override public List getTracks() { return tracks; } /** * Gets the url. * * @return the url */ @Override public String getUrl() { return url; } /** * Gets the year. * * @return the year */ @Override public String getYear() { Date releaseDate = getReleaseDate(); if (releaseDate == null) { return ""; } Calendar c = Calendar.getInstance(); c.setTime(releaseDate); return Integer.toString(c.get(Calendar.YEAR)); } /** * Sets the artist. * * @param artist the artist to set */ @Override public void setArtist(String artist) { this.artist = artist; } /** * Sets the big cover url. * * @param bigCoverURL the bigCoverURL to set */ @Override public void setBigCoverURL(String bigCoverURL) { this.bigCoverURL = bigCoverURL; } /** * Sets the cover. * * @param cover the cover to set */ @Override public void setCover(ImageIcon cover) { this.cover = cover; } /** * Sets the cover url. * * @param coverURL the coverURL to set */ @Override public void setCoverURL(String coverURL) { this.coverURL = coverURL; } /** * Sets the release date string. * * @param releaseDateString the releaseDateString to set */ @Override public void setReleaseDateString(String releaseDateString) { this.releaseDateString = releaseDateString; } /** * Sets the small cover url. * * @param smallCoverURL the smallCoverURL to set */ @Override public void setSmallCoverURL(String smallCoverURL) { this.smallCoverURL = smallCoverURL; } /** * Sets the title. * * @param title the title to set */ @Override public void setTitle(String title) { this.title = title; } /** * Sets the tracks. * * @param tracks the tracks to set */ @Override public void setTracks(List tracks) { this.tracks = tracks != null ? new ArrayList(tracks) : null; } /** * Sets the url. * * @param url the url to set */ @Override public void setUrl(String url) { this.url = url; } /* * (non-Javadoc) * * @see java.lang.Object#toString() */ @Override public String toString() { return UtilString.concat(artist, " - ", title); } } jajuk-1.9.6.orig/src/main/java/ext/services/lastfm/LastFmAlbumsRunnable.java0000644000175000017500000001755311720500104026720 0ustar drazzibdrazzib/* * aTunes 1.14.0 code adapted by Jajuk team * * Original copyright notice bellow : * * Copyright (C) 2006-2009 Alex Aranda, Sylvain Gaudard, Thomas Beckers and contributors * * See http://www.atunes.org/wiki/index.php?title=Contributing for information about contributors * * http://www.atunes.org * http://sourceforge.net/projects/atunes * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ package ext.services.lastfm; import java.awt.Image; import java.io.File; import java.util.List; import java.util.Locale; import java.util.StringTokenizer; import javax.swing.ImageIcon; import javax.swing.SwingUtilities; import org.apache.commons.lang.StringUtils; import org.jajuk.base.Track; import org.jajuk.util.Messages; import org.jajuk.util.UtilGUI; import org.jajuk.util.log.Log; /** * The Class LastFmAlbumsRunnable. */ public class LastFmAlbumsRunnable implements Runnable { /** The listener. */ ContextListener listener; /** The service. */ private LastFmService service; /** The audio object. */ AudioObject audioObject; /** The interrupted. */ private volatile boolean interrupted; /** The retrieve artist info. */ private boolean retrieveArtistInfo = true; /** The id. */ long id; /** * Instantiates a new audio scrobbler albums runnable. * * @param listener the listener * @param service the service * @param audioObject the audio object * @param id the id */ public LastFmAlbumsRunnable(ContextListener listener, LastFmService service, AudioObject audioObject, long id) { this.listener = listener; this.service = service; this.audioObject = audioObject; this.id = id; } /** * Interrupt. */ public void interrupt() { interrupted = true; } /* * (non-Javadoc) * * @see java.lang.Runnable#run() */ @Override public void run() { if (!interrupted) { listener.setLastAlbumRetrieved(null, id); if (retrieveArtistInfo) { listener.setLastArtistRetrieved(null, id); } } // Get wiki start for artist final String wikiText = service.getWikiText(audioObject.getArtist()); final String wikiURL = service.getWikiURL(audioObject.getArtist()); SwingUtilities.invokeLater(new Runnable() { @Override public void run() { listener.notifyWikiInfoRetrieved(wikiText, wikiURL, id); } }); Image image = null; AlbumInfo album = null; List albums = null; if (!interrupted) { // If possible use album artist String artist = audioObject.getAlbumArtist().isEmpty() ? audioObject.getArtist() : audioObject.getAlbumArtist(); album = service.getAlbum(artist, audioObject.getAlbum()); final AlbumInfo albumHelp = album; listener.setAlbum(albumHelp, id); if (album != null) { image = service.getImage(album); } listener.setImage(image, audioObject, id); } if (image != null && !interrupted) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { listener.notifyAlbumRetrieved(audioObject, id); } }); } try { Thread.sleep(1000); // Wait a second to prevent IP banning } catch (InterruptedException e) { Log.debug("albums runnable interrupted"); } // If we have to retrieve artist info do it. If not, get previous retrieved // albums list if (retrieveArtistInfo) { if (!interrupted) { String sArtist = audioObject.getArtist(); if (StringUtils.isNotBlank(sArtist) && !sArtist.equalsIgnoreCase(Messages.getString("unknown_artist"))) { AlbumListInfo albumList = service.getAlbumList(sArtist, true, 0); if (albumList != null) { albums = albumList.getAlbums(); } } if (albums == null) { interrupted = true; } listener.setAlbums(albums, id); } } else { albums = listener.getAlbums(); } if (album == null && albums != null && !interrupted) { // Try to find an album which fits AlbumInfo auxAlbum = null; int i = 0; while (!interrupted && auxAlbum == null && i < albums.size()) { AlbumInfo a = albums.get(i); StringTokenizer st = new StringTokenizer(a.getTitle(), " "); boolean matches = true; int tokensAnalyzed = 0; while (st.hasMoreTokens() && matches) { String t = st.nextToken(); if (forbiddenToken(t)) { // Ignore album if contains forbidden chars matches = false; break; } if (!validToken(t)) { // Ignore tokens without alphanumerics if (tokensAnalyzed == 0 && !st.hasMoreTokens()) { matches = false; } else { continue; } } if (!audioObject.getAlbum().toLowerCase(Locale.getDefault()).contains( t.toLowerCase(Locale.getDefault()))) { matches = false; } tokensAnalyzed++; } if (matches) { auxAlbum = a; } i++; } if (!interrupted && auxAlbum != null) { auxAlbum = service.getAlbum(auxAlbum.getArtist(), auxAlbum.getTitle()); if (auxAlbum != null) { listener.setAlbum(auxAlbum, id); image = service.getImage(auxAlbum); listener.setImage(image, audioObject, id); } } if (!interrupted && auxAlbum != null) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { listener.notifyAlbumRetrieved(audioObject, id); } }); } } } /** * Sets the retrieve artist info. * * @param retrieveArtistInfo the new retrieve artist info */ public void setRetrieveArtistInfo(boolean retrieveArtistInfo) { this.retrieveArtistInfo = retrieveArtistInfo; } /** * Valid token. * * @param t the t * * @return true, if successful */ private boolean validToken(String t) { return t.matches("[A-Za-z]+"); // t.contains("(") || t.contains(")") } /** * Forbidden token. * * @param t the t * * @return true, if successful */ private boolean forbiddenToken(String t) { return t.contains("/"); } /** * Returns an image associated to an audio file, with following order: - If a * image saved by aTunes exists, then return it. - If not, find an internal * image - If not, find an external image - If not, return null * * @param track DOCUMENT_ME * @param width Width in pixels or -1 to keep original width * @param height Height in pixels or -1 to keep original height * @return the image for audio file */ public static ImageIcon getImageForAudioFile(Track track, int width, int height) { ImageIcon result = null; File fileCover = track.getAlbum().findCover(); if (fileCover != null) { if (fileCover.exists()) { ImageIcon image = new ImageIcon(fileCover.getAbsolutePath()); if (width == -1 || height == -1) { return image; } int maxSize = (image.getIconWidth() > image.getIconHeight()) ? image.getIconWidth() : image .getIconHeight(); int newWidth = (int) ((float) image.getIconWidth() / (float) maxSize * width); int newHeight = (int) ((float) image.getIconHeight() / (float) maxSize * height); return UtilGUI.getResizedImage(image, newWidth, newHeight); } } return result; } } jajuk-1.9.6.orig/src/main/java/ext/services/lastfm/LastFmCoversRunnable.java0000644000175000017500000000536411720500104026733 0ustar drazzibdrazzib/* * aTunes 1.14.0 code adapted by Jajuk team * * Original copyright notice bellow : * * Copyright (C) 2006-2009 Alex Aranda, Sylvain Gaudard, Thomas Beckers and contributors * * See http://www.atunes.org/wiki/index.php?title=Contributing for information about contributors * * http://www.atunes.org * http://sourceforge.net/projects/atunes * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ package ext.services.lastfm; import java.awt.Image; import java.util.List; import javax.swing.SwingUtilities; /** * The Class LastFmCoversRunnable. */ public class LastFmCoversRunnable implements Runnable { /** The listener. */ ContextListener listener; /** The service. */ private LastFmService service; /** The albums. */ private List albums; /** The interrupted. */ private volatile boolean interrupted; /** The id. */ long id; /** The audio file. */ AudioObject audioObject; /** * Instantiates a new audio scrobbler covers runnable. * * @param listener the listener * @param service the service * @param albums the albums * @param id the id * @param audioObject DOCUMENT_ME */ public LastFmCoversRunnable(ContextListener listener, LastFmService service, List albums, long id, AudioObject audioObject) { this.listener = listener; this.service = service; this.albums = albums; this.id = id; this.audioObject = audioObject; } /** * Interrupt. */ public void interrupt() { interrupted = true; } /* * (non-Javadoc) * * @see java.lang.Runnable#run() */ @Override public void run() { if (albums != null) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { listener.notifyStartRetrievingCovers(id); } }); for (int i = 0; i < albums.size(); i++) { final Image img; final AlbumInfo album = albums.get(i); if (!interrupted) { img = service.getImage(album); } else { img = null; } if (!interrupted) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { listener.notifyCoverRetrieved(album, img, id); } }); } } } } } jajuk-1.9.6.orig/src/main/java/ext/services/lastfm/LastFmCache.java0000644000175000017500000006350211720500104025004 0ustar drazzibdrazzib/* * aTunes 1.14.0 code adapted by Jajuk team * * Original copyright notice bellow : * * Copyright (C) 2006-2009 Alex Aranda, Sylvain Gaudard, Thomas Beckers and contributors * * See http://www.atunes.org/wiki/index.php?title=Contributing for information about contributors * * http://www.atunes.org * http://sourceforge.net/projects/atunes * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ package ext.services.lastfm; import ext.services.xml.XMLUtils; import java.awt.Image; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; import javax.swing.ImageIcon; import net.roarsoftware.lastfm.scrobble.SubmissionData; import org.apache.commons.io.FileUtils; import org.jajuk.services.core.SessionService; import org.jajuk.util.Const; import org.jajuk.util.MD5Processor; import org.jajuk.util.UtilGUI; import org.jajuk.util.UtilString; import org.jajuk.util.log.Log; /** * The Class LastFmCache. */ public class LastFmCache { /** Album Cover Cache dir. */ private static File albumCoverCacheDir = SessionService.getConfFileByPath(Const.FILE_CACHE + '/' + Const.LASTFM_CACHE + '/' + Const.LAST_FM_ALBUM_COVER_CACHE_DIR); /** Album Cover Cache dir. */ private static File albumInfoCacheDir = SessionService.getConfFileByPath(Const.FILE_CACHE + '/' + Const.LASTFM_CACHE + '/' + Const.LAST_FM_ALBUM_INFO_CACHE_DIR); /** DOCUMENT_ME. */ private static File artistInfoCacheDir = SessionService.getConfFileByPath(Const.FILE_CACHE + '/' + Const.LASTFM_CACHE + '/' + Const.LAST_FM_ARTIST_INFO_CACHE_DIR); /** Artist thumbs cache dir. */ private static File artistThumbCacheDir = SessionService.getConfFileByPath(Const.FILE_CACHE + '/' + Const.LASTFM_CACHE + '/' + Const.LAST_FM_ARTIST_THUMB_CACHE_DIR); /** Artist image cache dir. */ private static File artistImageCacheDir = SessionService.getConfFileByPath(Const.FILE_CACHE + '/' + Const.LASTFM_CACHE + '/' + Const.LAST_FM_ARTIST_IMAGE_CACHE_DIR); /** Artist image cache dir. */ private static File artistSimilarCacheDir = SessionService.getConfFileByPath(Const.FILE_CACHE + '/' + Const.LASTFM_CACHE + '/' + Const.LAST_FM_ARTIST_SIMILAR_CACHE_DIR); /** Album list cache dir. */ private static File albumListCacheDir = SessionService.getConfFileByPath(Const.FILE_CACHE + '/' + Const.LASTFM_CACHE + '/' + Const.LAST_FM_ALBUM_LIST_CACHE_DIR); /** Artist info cache dir. */ private static File artistWikiCacheDir = SessionService.getConfFileByPath(Const.FILE_CACHE + '/' + Const.LASTFM_CACHE + '/' + Const.LAST_FM_ARTIST_WIKI_CACHE_DIR); /** DOCUMENT_ME. */ private static File submissionCacheDir = SessionService.getConfFileByPath(Const.FILE_CACHE + '/' + Const.LASTFM_CACHE + '/' + Const.LAST_FM_SUBMISSION_CACHE_DIR); /** * Clears the cache. * * @return If an IOException occured during clearing */ public synchronized boolean clearCache() { boolean exception = false; try { FileUtils.cleanDirectory(getAlbumCoverCacheDir()); } catch (IOException e) { Log.info("Could not delete all files from album cover cache"); exception = true; } try { FileUtils.cleanDirectory(getAlbumInfoCacheDir()); } catch (IOException e) { Log.info("Could not delete all files from album info cache"); exception = true; } try { FileUtils.cleanDirectory(getArtistImageCacheDir()); } catch (IOException e) { Log.info("Could not delete all files from artist image cache"); exception = true; } try { FileUtils.cleanDirectory(getAlbumListCacheDir()); } catch (IOException e) { Log.info("Could not delete all files from album list cache"); exception = true; } try { FileUtils.cleanDirectory(getArtistSimilarCacheDir()); } catch (IOException e) { Log.info("Could not delete all files from similar artist cache"); exception = true; } try { FileUtils.cleanDirectory(getArtistThumbsCacheDir()); } catch (IOException e) { Log.info("Could not delete all files from artist thumbs cache"); exception = true; } try { FileUtils.cleanDirectory(getArtistWikiCacheDir()); } catch (IOException e) { Log.info("Could not delete all files from artist wiki cache"); exception = true; } try { FileUtils.cleanDirectory(getArtistInfoCacheDir()); } catch (IOException e) { Log.info("Could not delete all files from artist info cache"); exception = true; } try { FileUtils.cleanDirectory(getSubmissionDataDir()); } catch (IOException e) { Log.info("Could not delete all files from submission data cache"); exception = true; } return exception; } /** * Private getter for albumCoverCacheDir. If dir does not exist, it's created * * @return the album cover cache dir * * @throws IOException Signals that an I/O exception has occurred. */ private synchronized File getAlbumCoverCacheDir() throws IOException { if (!albumCoverCacheDir.exists()) { FileUtils.forceMkdir(albumCoverCacheDir); } return albumCoverCacheDir; } /** * Private getter for albumInfoCacheDir. If dir does not exist, it's created * * @return the album info cache dir * * @throws IOException Signals that an I/O exception has occurred. */ private synchronized File getAlbumInfoCacheDir() throws IOException { if (!albumInfoCacheDir.exists()) { FileUtils.forceMkdir(albumInfoCacheDir); } return albumInfoCacheDir; } /** * Private getter for artistInfoCacheDir. If dir does not exist, it's created * * @return the artist info cache dir * * @throws IOException Signals that an I/O exception has occurred. */ private synchronized File getArtistInfoCacheDir() throws IOException { if (!artistInfoCacheDir.exists()) { FileUtils.forceMkdir(artistInfoCacheDir); } return artistInfoCacheDir; } /** * Private getter for artistImageCacheDir. If dir does not exist, it's created * * @return the artist image cache dir * * @throws IOException Signals that an I/O exception has occurred. */ private synchronized File getArtistImageCacheDir() throws IOException { if (!artistImageCacheDir.exists()) { FileUtils.forceMkdir(artistImageCacheDir); } return artistImageCacheDir; } /** * Private getter for artistInfoCacheDir. If dir does not exist, it's created * * @return the artist info cache dir * * @throws IOException Signals that an I/O exception has occurred. */ private synchronized File getAlbumListCacheDir() throws IOException { if (!albumListCacheDir.exists()) { FileUtils.forceMkdir(albumListCacheDir); } return albumListCacheDir; } /** * Private getter for artistSimilarCacheDir. If dir does not exist, it's * created * * @return the artist similar cache dir * * @throws IOException Signals that an I/O exception has occurred. */ private synchronized File getArtistSimilarCacheDir() throws IOException { if (!artistSimilarCacheDir.exists()) { FileUtils.forceMkdir(artistSimilarCacheDir); } return artistSimilarCacheDir; } /** * Private getter for artistThumbCacheDir. If dir does not exist, it's created * * @return the artist thumbs cache dir * * @throws IOException Signals that an I/O exception has occurred. */ private synchronized File getArtistThumbsCacheDir() throws IOException { if (!artistThumbCacheDir.exists()) { FileUtils.forceMkdir(artistThumbCacheDir); } return artistThumbCacheDir; } /** * Private getter for artistWikiCacheDir. If dir does not exist, it's created * * @return the artist wiki cache dir * * @throws IOException Signals that an I/O exception has occurred. */ private synchronized File getArtistWikiCacheDir() throws IOException { if (!artistWikiCacheDir.exists()) { FileUtils.forceMkdir(artistWikiCacheDir); } return artistWikiCacheDir; } /** * Gets the submission data dir. * * @return the submission data dir * * @throws IOException Signals that an I/O exception has occurred. */ private synchronized File getSubmissionDataDir() throws IOException { if (!submissionCacheDir.exists()) { FileUtils.forceMkdir(submissionCacheDir); } return submissionCacheDir; } /** * Album Cover Filename. * * @param album the album * * @return the file name for album cover */ private String getFileNameForAlbumCover(AlbumInfo album) { return UtilString.concat(MD5Processor.hash(album.getBigCoverURL()), ".png"); } /** * Absolute Path to Album Cover Filename. * * @param album the album * * @return the file name for album cover at cache * * @throws IOException Signals that an I/O exception has occurred. */ private String getFileNameForAlbumCoverAtCache(AlbumInfo album) throws IOException { File albumCoverCacheDirFile = getAlbumCoverCacheDir(); if (albumCoverCacheDirFile == null) { return null; } return UtilString.concat(albumCoverCacheDirFile.getAbsolutePath(), File.separator, getFileNameForAlbumCover(album)); } /** * Album Cover Filename. * * @param artist the artist * @param album the album * @return the file name for album info */ private String getFileNameForAlbumInfo(String artist, String album) { return UtilString.concat(MD5Processor.hash(artist), MD5Processor.hash(album), ".xml"); } /** * Absolute Path to Album Info Filename. * * @param artist the artist * @param album the album * @return the file name for album info at cache * @throws IOException Signals that an I/O exception has occurred. */ private String getFileNameForAlbumInfoAtCache(String artist, String album) throws IOException { File albumInfoCacheDirFile = getAlbumInfoCacheDir(); if (albumInfoCacheDirFile == null) { return null; } return UtilString.concat(albumInfoCacheDirFile.getAbsolutePath(), File.separator, getFileNameForAlbumInfo(artist, album)); } /** * Absolute Path to Artist Info Filename. * * @param artist the artist * * @return the file name for artist info at cache * * @throws IOException Signals that an I/O exception has occurred. */ private String getFileNameForArtistInfoAtCache(String artist) throws IOException { File artistInfoCacheDirFile = getArtistInfoCacheDir(); if (artistInfoCacheDirFile == null) { return null; } return UtilString.concat(artistInfoCacheDirFile.getAbsolutePath(), File.separator, getFileNameForArtistInfo(artist)); } /** * Artist Image Filename. * * @param artist the artist * * @return the file name for artist image */ private String getFileNameForArtistImage(SimilarArtistsInfo artist) { return UtilString.concat(MD5Processor.hash(artist.getArtistName()), ".png"); } /** * Absolute Path to Artist Image Filename. * * @param artist the artist * * @return the file name for artist image at cache * * @throws IOException Signals that an I/O exception has occurred. */ private String getFileNameForArtistImageAtCache(SimilarArtistsInfo artist) throws IOException { File artistImageCacheDirFile = getArtistImageCacheDir(); if (artistImageCacheDirFile == null) { return null; } return UtilString.concat(artistImageCacheDirFile.getAbsolutePath(), File.separator, getFileNameForArtistImage(artist)); } /** * Artist Info Filename. * * @param artist the artist * * @return the file name for artist info */ private String getFileNameForArtistInfo(String artist) { return UtilString.concat(MD5Processor.hash(artist), ".xml"); } /** * Absolute Path to Artist info Filename. * * @param artist the artist * * @return the file name for artist info at cache * * @throws IOException Signals that an I/O exception has occurred. */ private String getFileNameForAlbumListAtCache(String artist) throws IOException { File albumListCacheDirFile = getAlbumListCacheDir(); if (albumListCacheDirFile == null) { return null; } return UtilString.concat(albumListCacheDirFile.getAbsolutePath(), File.separator, getFileNameForArtistInfo(artist)); } /** * Artist Similar Filename. * * @param artist the artist * * @return the file name for artist similar */ private String getFileNameForArtistSimilar(String artist) { return UtilString.concat(MD5Processor.hash(artist), ".xml"); } /** * Absolute Path to Artist similar Filename. * * @param artist the artist * * @return the file name for artist similar at cache * * @throws IOException Signals that an I/O exception has occurred. */ private String getFileNameForArtistSimilarAtCache(String artist) throws IOException { File artistSimilarCacheDirFile = getArtistSimilarCacheDir(); if (artistSimilarCacheDirFile == null) { return null; } return UtilString.concat(artistSimilarCacheDirFile.getAbsolutePath(), File.separator, getFileNameForArtistSimilar(artist)); } /** * Artist Thumb Filename. * * @param artist the artist * * @return the file name for artist thumb */ private String getFileNameForArtistThumb(ArtistInfo artist) { return UtilString.concat(MD5Processor.hash(artist.getName()), ".png"); } /** * Absolute Path to Artist Thumb Filename. * * @param artist the artist * * @return the file name for artist thumb at cache * * @throws IOException Signals that an I/O exception has occurred. */ private String getFileNameForArtistThumbAtCache(ArtistInfo artist) throws IOException { File artistThumbCacheDirFile = getArtistThumbsCacheDir(); if (artistThumbCacheDirFile == null) { return null; } return UtilString.concat(artistThumbCacheDirFile.getAbsolutePath(), File.separator, getFileNameForArtistThumb(artist)); } /** * Artist Info Filename. * * @param artist the artist * * @return the file name for artist wiki */ private String getFileNameForArtistWiki(String artist) { return UtilString.concat(MD5Processor.hash(artist), ".xml"); } /** * Absolute Path to Artist similar Filename. * * @param artist the artist * * @return the file name for artist wiki at cache * * @throws IOException Signals that an I/O exception has occurred. */ private String getFileNameForArtistWikiAtCache(String artist) throws IOException { File artistWikiCacheDirFile = getArtistWikiCacheDir(); if (artistWikiCacheDirFile == null) { return null; } return UtilString.concat(artistWikiCacheDirFile.getAbsolutePath(), File.separator, getFileNameForArtistWiki(artist)); } /** * Gets the file name for submission cache. * * @return the file name for submission cache * * @throws IOException Signals that an I/O exception has occurred. */ private String getFileNameForSubmissionCache() throws IOException { File submissionDataDirFile = getSubmissionDataDir(); if (submissionDataDirFile == null) { return null; } return UtilString.concat(submissionDataDirFile.getAbsolutePath(), File.separator, "submissionDataCache.xml"); } /** * Retrieves an Album Cover from cache. * * @param album the album * * @return the image */ public synchronized Image retrieveAlbumCover(AlbumInfo album) { try { String path = getFileNameForAlbumCoverAtCache(album); if (path != null && new File(path).exists()) { return new ImageIcon(path).getImage(); } } catch (IOException e) { Log.error(e); } return null; } /** * Retrieves an Album Cover from cache. * * @param artist the artist * @param album the album * @return the audio scrobbler album */ public synchronized AlbumInfo retrieveAlbumInfo(String artist, String album) { try { String path = getFileNameForAlbumInfoAtCache(artist, album); if (path != null && new File(path).exists()) { return (AlbumInfo) XMLUtils.readBeanFromFile(path); } } catch (IOException e) { Log.error(e); } return null; } /** * Retrieves an artist infos from cache. * * @param artist the artist * * @return the audio scrobbler artist */ public synchronized ArtistInfo retrieveArtistInfo(String artist) { try { String path = getFileNameForArtistInfoAtCache(artist); if (path != null && new File(path).exists()) { return (ArtistInfo) XMLUtils.readBeanFromFile(path); } } catch (IOException e) { Log.error(e); } return null; } /** * Retrieves an Artist Image from cache. * * @param artist the artist * * @return the image */ public synchronized Image retrieveArtistImage(SimilarArtistsInfo artist) { try { String path = getFileNameForArtistImageAtCache(artist); if (path != null && new File(path).exists()) { return new ImageIcon(path).getImage(); } } catch (IOException e) { Log.error(e); } return null; } /** * Retrieves an albumList from cache. * * @param artist the artist * * @return the audio scrobbler album list */ public synchronized AlbumListInfo retrieveAlbumList(String artist) { try { String path = getFileNameForAlbumListAtCache(artist); if (path != null && new File(path).exists()) { return (AlbumListInfo) XMLUtils.readBeanFromFile(path); } } catch (IOException e) { Log.error(e); } return null; } /** * Retrieves an Artist similar from cache. * * @param artist the artist * * @return the audio scrobbler similar artists */ public synchronized SimilarArtistsInfo retrieveArtistSimilar(String artist) { try { String path = getFileNameForArtistSimilarAtCache(artist); if (path != null && new File(path).exists()) { return (SimilarArtistsInfo) XMLUtils.readBeanFromFile(path); } } catch (IOException e) { Log.error(e); } return null; } /** * Retrieves an Artist Thumb from cache. * * @param artist the artist * * @return the image */ public synchronized Image retrieveArtistThumbImage(ArtistInfo artist) { try { String path = getFileNameForArtistThumbAtCache(artist); if (path != null && new File(path).exists()) { return new ImageIcon(path).getImage(); } } catch (IOException e) { Log.error(e); } return null; } /** * Retrieves an Artist wiki from cache. * * @param artist the artist * * @return the string */ public synchronized String retrieveArtistWiki(String artist) { try { String path = getFileNameForArtistWikiAtCache(artist); if (path != null && new File(path).exists()) { return (String) XMLUtils.readBeanFromFile(path); } } catch (IOException e) { Log.error(e); } return null; } /** * Stores an Album Cover at cache. * * @param album the album * @param cover the cover */ public synchronized void storeAlbumCover(AlbumInfo album, Image cover) { if (cover == null || album == null) { return; } try { String fileAbsPath = getFileNameForAlbumCoverAtCache(album); if (fileAbsPath != null) { UtilGUI.extractImage(cover, new File(fileAbsPath)); Log.debug(UtilString.concat("Stored album Cover for album {{", album.getTitle(), "}}")); } } catch (IOException e) { Log.error(e); } } /** * Stores an Album Cover at cache. * * @param artist the artist * @param album the album * @param albumObject the album object */ public synchronized void storeAlbumInfo(String artist, String album, AlbumInfo albumObject) { if (artist == null || album == null || albumObject == null) { return; } try { String fileAbsPath = getFileNameForAlbumInfoAtCache(artist, album); if (fileAbsPath != null) { XMLUtils.writeBeanToFile(albumObject, fileAbsPath); Log.debug(UtilString.concat("Stored album info for album {{", artist, " ", album, "}}")); } } catch (IOException e) { Log.error(e); } } /** * Stores an artist info at cache. * * @param artist the artist * @param artistObject DOCUMENT_ME */ public synchronized void storeArtistInfo(String artist, ArtistInfo artistObject) { if (artist == null) { return; } try { String fileAbsPath = getFileNameForArtistInfoAtCache(artist); if (fileAbsPath != null) { XMLUtils.writeBeanToFile(artistObject, fileAbsPath); Log.debug(UtilString.concat("Stored artist info for artist {{", artist, "}}")); } } catch (IOException e) { Log.error(e); } } /** * Store an Artist Image at cache. * * @param artist the artist * @param image the image */ public synchronized void storeArtistImage(SimilarArtistsInfo artist, Image image) { if (image == null || artist == null) { return; } try { String fileAbsPath = getFileNameForArtistImageAtCache(artist); if (fileAbsPath != null) { UtilGUI.extractImage(image, new File(fileAbsPath)); Log.debug(UtilString.concat("Stored artist image for {{", artist.getArtistName(), "}}")); } } catch (IOException e) { Log.error(e); } } /** * Store an album list at cache. * * @param artist the artist * @param list the list */ public synchronized void storeAlbumList(String artist, AlbumListInfo list) { if (artist == null || list == null) { return; } try { String fileAbsPath = getFileNameForAlbumListAtCache(artist); if (fileAbsPath != null) { XMLUtils.writeBeanToFile(list, fileAbsPath); Log.debug(UtilString.concat("Stored album list for {{", artist, "}}")); } } catch (IOException e) { Log.error(e); } } /** * Store an Artist similar at cache. * * @param artist the artist * @param similar the similar */ public synchronized void storeArtistSimilar(String artist, SimilarArtistsInfo similar) { if (artist == null || similar == null) { return; } try { String fileAbsPath = getFileNameForArtistSimilarAtCache(artist); if (fileAbsPath != null) { XMLUtils.writeBeanToFile(similar, fileAbsPath); Log.debug(UtilString.concat("Stored artist similar for {{", artist, "}}")); } } catch (IOException e) { Log.error(e); } } /** * Stores an Artist Thumb at cache. * * @param artist the artist * @param image the image */ public synchronized void storeArtistThumbImage(ArtistInfo artist, Image image) { if (image == null || artist == null) { return; } try { String fileAbsPath = getFileNameForArtistThumbAtCache(artist); if (fileAbsPath != null) { UtilGUI.extractImage(image, new File(fileAbsPath)); Log.debug(UtilString.concat("Stored artist thumb for {{", artist.getName() + "}}")); } } catch (IOException e) { Log.error(e); } } /** * Store an Artist wiki at cache. * * @param artist the artist * @param wikiText the wiki text */ public synchronized void storeArtistWiki(String artist, String wikiText) { if (artist == null || wikiText == null) { return; } try { String fileAbsPath = getFileNameForArtistWikiAtCache(artist); if (fileAbsPath != null) { XMLUtils.writeBeanToFile(wikiText, fileAbsPath); Log.debug(UtilString.concat("Stored artist wiki for {{", artist, "}}")); } } catch (IOException e) { Log.error(e); } } /** * Adds the submission data. * DOCUMENT_ME * * @param submissionData DOCUMENT_ME */ public synchronized void addSubmissionData(FullSubmissionData submissionData) { List submissionDataList = getSubmissionData(); submissionDataList.add(submissionData); Collections.sort(submissionDataList, new Comparator() { @Override public int compare(FullSubmissionData o1, FullSubmissionData o2) { return Integer.valueOf(o1.getStartTime()).compareTo(o2.getStartTime()); } }); try { String path = getFileNameForSubmissionCache(); if (path != null) { XMLUtils.writeObjectToFile(submissionDataList, path); Log.debug(UtilString.concat("Stored submission data: {{" + submissionData, "}}")); } } catch (IOException e) { Log.error(e); } } /** * Gets the submission data. * * @return the submission data */ @SuppressWarnings("unchecked") public synchronized List getSubmissionData() { try { String path = getFileNameForSubmissionCache(); if (path != null && new File(path).exists()) { return (List) XMLUtils.readObjectFromFile(path); } } catch (IOException e) { Log.error(e); } return new ArrayList(); } /** * Removes the submission data. * DOCUMENT_ME */ public synchronized void removeSubmissionData() { try { String path = getFileNameForSubmissionCache(); if (path != null && new File(path).exists()) { XMLUtils.writeObjectToFile(new ArrayList(), path); } } catch (IOException e) { Log.error(e); } } } jajuk-1.9.6.orig/src/main/java/ext/services/lastfm/AlbumInfo.java0000644000175000017500000000706611720500104024551 0ustar drazzibdrazzib/* * aTunes 1.14.0 code adapted by Jajuk team * * Original copyright notice bellow : * * Copyright (C) 2006-2009 Alex Aranda, Sylvain Gaudard, Thomas Beckers and contributors * * See http://www.atunes.org/wiki/index.php?title=Contributing for information about contributors * * http://www.atunes.org * http://sourceforge.net/projects/atunes * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ package ext.services.lastfm; import java.util.Date; import java.util.List; import javax.swing.ImageIcon; /** * DOCUMENT_ME. */ public interface AlbumInfo { /** * Gets the artist. * * @return the artist */ public String getArtist(); /** * Gets the artist url. * * @return the artist url */ public String getArtistUrl(); /** * Gets the big cover url. * * @return the bigCoverURL */ public String getBigCoverURL(); /** * Gets the cover. * * @return the cover */ public ImageIcon getCover(); /** * Gets the cover url. * * @return the cover url */ public String getCoverURL(); /** * Gets the release date. * * @return the release date */ public Date getReleaseDate(); /** * Gets the release date string. * * @return the releaseDateString */ public String getReleaseDateString(); /** * Gets the small cover url. * * @return the small cover url */ public String getSmallCoverURL(); /** * Gets the title. * * @return the title */ public String getTitle(); /** * Gets the tracks. * * @return the tracks */ public List getTracks(); /** * Gets the url. * * @return the url */ public String getUrl(); /** * Gets the year. * * @return the year */ public String getYear(); /** * Sets the artist. * * @param artist the artist to set */ public void setArtist(String artist); /** * Sets the big cover url. * * @param bigCoverURL the bigCoverURL to set */ public void setBigCoverURL(String bigCoverURL); /** * Sets the cover. * * @param cover the cover to set */ public void setCover(ImageIcon cover); /** * Sets the cover url. * * @param coverURL the coverURL to set */ public void setCoverURL(String coverURL); /** * Sets the release date string. * * @param releaseDateString the releaseDateString to set */ public void setReleaseDateString(String releaseDateString); /** * Sets the small cover url. * * @param smallCoverURL the smallCoverURL to set */ public void setSmallCoverURL(String smallCoverURL); /** * Sets the title. * * @param title the title to set */ public void setTitle(String title); /** * Sets the tracks. * * @param tracks the tracks to set */ public void setTracks(List tracks); /** * Sets the url. * * @param url the url to set */ public void setUrl(String url); /* * (non-Javadoc) * * @see java.lang.Object#toString() */ /** * To string. * DOCUMENT_ME * * @return the string */ @Override public String toString(); } jajuk-1.9.6.orig/src/main/java/ext/services/lastfm/package.html0000644000175000017500000000017111720500104024301 0ustar drazzibdrazzib DOCUMENT_ME jajuk-1.9.6.orig/src/main/java/ext/services/lastfm/LastFmSimilarArtistsRunnable.java0000644000175000017500000000640111720500104030435 0ustar drazzibdrazzib/* * aTunes 1.14.0 code adapted by Jajuk team * * Original copyright notice bellow : * * Copyright (C) 2006-2009 Alex Aranda, Sylvain Gaudard, Thomas Beckers and contributors * * See http://www.atunes.org/wiki/index.php?title=Contributing for information about contributors * * http://www.atunes.org * http://sourceforge.net/projects/atunes * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ package ext.services.lastfm; import java.awt.Image; import javax.swing.SwingUtilities; import org.apache.commons.lang.StringUtils; import org.jajuk.util.Messages; /** * The Class LastFmSimilarArtistsRunnable. */ public class LastFmSimilarArtistsRunnable implements Runnable { /** The listener. */ ContextListener listener; /** The service. */ private LastFmService service; /** The artist. */ private String artist; /** The interrupted. */ private volatile boolean interrupted; /** The id. */ long id; /** * Instantiates a new audio scrobbler similar artists runnable. * * @param listener the listener * @param service the service * @param artist the artist * @param id the id */ public LastFmSimilarArtistsRunnable(ContextListener listener, LastFmService service, String artist, long id) { this.listener = listener; this.service = service; this.artist = artist; this.id = id; } /** * Interrupt. */ public void interrupt() { interrupted = true; } /* * (non-Javadoc) * * @see java.lang.Runnable#run() */ @Override public void run() { if (!interrupted && StringUtils.isNotBlank(artist) && !artist.equalsIgnoreCase(Messages.getString("unknown_artist"))) { SimilarArtistsInfo artists = service.getSimilarArtists(artist); if (!interrupted && artists != null) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { listener.notifyStartRetrievingArtistImages(id); } }); final Image artistImage = service.getImage(artists); if (!interrupted && artistImage != null) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { listener.notifyArtistImage(artistImage, id); } }); } for (int i = 0; i < artists.getArtists().size(); i++) { final Image img; final ArtistInfo a = artists.getArtists().get(i); if (!interrupted) { img = service.getImage(a); } else { img = null; } if (!interrupted) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { listener.notifyFinishGetSimilarArtist(a, img, id); } }); } } } } } } jajuk-1.9.6.orig/src/main/java/ext/services/lastfm/ArtistInfo.java0000644000175000017500000000433611720500104024754 0ustar drazzibdrazzib/* * aTunes 1.14.0 code adapted by Jajuk team * * Original copyright notice bellow : * * Copyright (C) 2006-2009 Alex Aranda, Sylvain Gaudard, Thomas Beckers and contributors * * See http://www.atunes.org/wiki/index.php?title=Contributing for information about contributors * * http://www.atunes.org * http://sourceforge.net/projects/atunes * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ package ext.services.lastfm; import javax.swing.ImageIcon; /** * DOCUMENT_ME. */ public interface ArtistInfo { /** * Gets the image. * * @return the image */ public ImageIcon getImage(); /** * Gets the image url. * * @return the image url */ public String getImageUrl(); /** * Gets the match. * * @return the match */ public String getMatch(); /** * Gets the name. * * @return the name */ public String getName(); /** * Gets the url. * * @return the url */ public String getUrl(); /** * Sets the image. * * @param image the new image */ public void setImage(ImageIcon image); /** * Sets the image url. * * @param imageUrl the imageUrl to set */ public void setImageUrl(String imageUrl); /** * Sets the match. * * @param match the match to set */ public void setMatch(String match); /** * Sets the name. * * @param name the name to set */ public void setName(String name); /** * Sets the url. * * @param url the url to set */ public void setUrl(String url); /** * Sets the available property. * * @param available DOCUMENT_ME */ public void setAvailable(boolean available); /** * Returns if available. * * @return true if the available property is set */ public boolean isAvailable(); } jajuk-1.9.6.orig/src/main/java/ext/services/lastfm/LastFmAlbumList.java0000644000175000017500000000450611720500104025674 0ustar drazzibdrazzib/* * aTunes 1.14.0 code adapted by Jajuk team * * Original copyright notice bellow : * * Copyright (C) 2006-2009 Alex Aranda, Sylvain Gaudard, Thomas Beckers and contributors * * See http://www.atunes.org/wiki/index.php?title=Contributing for information about contributors * * http://www.atunes.org * http://sourceforge.net/projects/atunes * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ package ext.services.lastfm; import java.util.ArrayList; import java.util.Collection; import java.util.List; import net.roarsoftware.lastfm.Album; /** * The Class LastFmAlbumList. */ public class LastFmAlbumList implements AlbumListInfo { /** The artist. */ private String artist; /** The albums. */ private List albums; /** * Gets the album list. * * @param as DOCUMENT_ME * @param artist DOCUMENT_ME * * @return the album list */ public static AlbumListInfo getAlbumList(Collection as, String artist) { List albums = new ArrayList(); AlbumListInfo albumList = new LastFmAlbumList(); for (Album a : as) { AlbumInfo album = LastFmAlbum.getAlbum(a, null); albums.add(album); } albumList.setAlbums(albums); return albumList; } /** * Gets the albums. * * @return the albums */ @Override public List getAlbums() { return albums; } /** * Gets the artist. * * @return the artist */ @Override public String getArtist() { return artist; } /** * Sets the albums. * * @param albums the albums to set */ @Override public void setAlbums(List albums) { this.albums = albums != null ? new ArrayList(albums) : null; } /** * Sets the artist. * * @param artist the artist to set */ @Override public void setArtist(String artist) { this.artist = artist; } } jajuk-1.9.6.orig/src/main/java/ext/services/lastfm/AudioObject.java0000644000175000017500000000536411720500104025064 0ustar drazzibdrazzib/* * aTunes 1.14.0 code adapted by Jajuk team * * Original copyright notice bellow : * * Copyright (C) 2006-2009 Alex Aranda, Sylvain Gaudard, Thomas Beckers and contributors * * See http://www.atunes.org/wiki/index.php?title=Contributing for information about contributors * * http://www.atunes.org * http://sourceforge.net/projects/atunes * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ package ext.services.lastfm; /** * Interface for all audio objects (e.g. AudioFile, Radio, PodcastFeedEntry) */ public interface AudioObject { /** * Gets the album. * * @return the album */ public String getAlbum(); /** * Gets the album artist. * * @return the album artist */ public String getAlbumArtist(); /** * Gets the artist. * * @return the artist */ public String getArtist(); /** * Gets the bitrate. * * @return the bitrate */ public long getBitrate(); /** * Gets the composer. * * @return the composer */ public String getComposer(); /** * Gets the duration. * * @return the duration */ public long getDuration(); /** * Gets the frequency. * * @return the frequency */ public int getFrequency(); /** * Gets the genre. * * @return the genre */ public String getGenre(); /** * Gets the lyrics. * * @return the lyrics */ public String getLyrics(); /** * Gets the stars. * * @return the stars */ public int getStars(); /** * Gets the title. * * @return the title */ public String getTitle(); /** * Gets the title or file name. * * @return the title or file name */ public String getTitleOrFileName(); /** * Gets the track number. * * @return the track number */ public Integer getTrackNumber(); /** * Gets the url. * * @return the url */ public String getUrl(); /** * Gets the year. * * @return the year */ public String getYear(); /** * Sets the stars. * * @param stars the new stars */ public void setStars(int stars); /** * Checks if is seekable. * * @return true, if is seekable */ public boolean isSeekable(); /** * Gets the disc number. * * @return the disc number */ public Integer getDiscNumber(); } jajuk-1.9.6.orig/src/main/java/ext/services/lastfm/LastFmService.java0000644000175000017500000005226311720500104025403 0ustar drazzibdrazzib/* * aTunes 1.14.0 code adapted by Jajuk team * * Original copyright notice bellow : * * Copyright (C) 2006-2009 Alex Aranda, Sylvain Gaudard, Thomas Beckers and contributors * * See http://www.atunes.org/wiki/index.php?title=Contributing for information about contributors * * http://www.atunes.org * http://sourceforge.net/projects/atunes * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ package ext.services.lastfm; import ext.services.network.Proxy; import java.awt.Image; import java.io.IOException; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Locale; import java.util.Set; import net.roarsoftware.lastfm.Album; import net.roarsoftware.lastfm.Artist; import net.roarsoftware.lastfm.Caller; import net.roarsoftware.lastfm.ImageSize; import net.roarsoftware.lastfm.PaginatedResult; import net.roarsoftware.lastfm.Playlist; import net.roarsoftware.lastfm.scrobble.ResponseStatus; import net.roarsoftware.lastfm.scrobble.Scrobbler; import net.roarsoftware.lastfm.scrobble.Source; import net.roarsoftware.lastfm.scrobble.SubmissionData; import org.apache.commons.lang.StringEscapeUtils; import org.apache.commons.lang.StringUtils; import org.jajuk.base.Track; import org.jajuk.util.Conf; import org.jajuk.util.Const; import org.jajuk.util.DownloadManager; import org.jajuk.util.LocaleManager; import org.jajuk.util.Messages; import org.jajuk.util.UtilString; import org.jajuk.util.log.Log; /** * The Class LastFmService. * * This class is responsible of retrieve information from Last.fm web services. * */ public class LastFmService { /* * DO NOT USE THESE KEYS FOR OTHER APPLICATIONS THAN Jajuk! */ /** The Constant API_KEY. DOCUMENT_ME */ private static final String API_KEY = "711591ss6q695ps349o6681pr1oq1467"; /** The Constant CLIENT_ID. DOCUMENT_ME */ private static final String CLIENT_ID = "jaj"; /** The Constant CLIENT_VERSION. DOCUMENT_ME */ private static final String CLIENT_VERSION = "0.2"; // Assigned by Last.FM // team /** The Constant ARTIST_WILDCARD. DOCUMENT_ME */ private static final String ARTIST_WILDCARD = "(%ARTIST%)"; /** The Constant LANGUAGE_PARAM. DOCUMENT_ME */ private static final String LANGUAGE_PARAM = "?setlang="; /** The Constant LANGUAGE_WILDCARD. DOCUMENT_ME */ private static final String LANGUAGE_WILDCARD = "(%LANGUAGE%)"; /** The Constant ARTIST_WIKI_URL. DOCUMENT_ME */ private static final String ARTIST_WIKI_URL = UtilString.concat("http://www.lastfm.com/music/", ARTIST_WILDCARD, "/+wiki", LANGUAGE_PARAM, LANGUAGE_WILDCARD); /** The Constant VARIOUS_ARTISTS. DOCUMENT_ME */ private static final String VARIOUS_ARTISTS = "Various Artists"; /** The Constant MIN_DURATION_TO_SUBMIT. DOCUMENT_ME */ private static final int MIN_DURATION_TO_SUBMIT = 30; /** The Constant MAX_SUBMISSIONS. DOCUMENT_ME */ private static final int MAX_SUBMISSIONS = 50; /** DOCUMENT_ME. */ private Scrobbler scrobbler; /** DOCUMENT_ME. */ private boolean handshakePerformed; /** DOCUMENT_ME. */ private Locale locale; /** DOCUMENT_ME. */ private LastFmCache lastFmCache; /** The singleton. */ private static LastFmService self; /** * Instantiates a new Last.fm service * * @param proxy the proxy * @param user the Last.fm username * @param password the Last.fm password * @param locale DOCUMENT_ME * @param lastFmCache DOCUMENT_ME */ private LastFmService(Locale locale, LastFmCache lastFmCache) { Proxy proxy = DownloadManager.getProxy(); Caller.getInstance().setCache(null); Caller.getInstance().setProxy(proxy); Caller.getInstance().setUserAgent(CLIENT_ID); String user = Conf.getString(Const.CONF_LASTFM_USER); // Use encoded version name to avoid errors from server scrobbler = Scrobbler.newScrobbler(CLIENT_ID, ext.services.network.NetworkUtils.encodeString(CLIENT_VERSION), user); this.handshakePerformed = false; this.locale = locale; this.lastFmCache = lastFmCache; } /** * Return the LastFMService singleton. * * @return the LastFMService singleton */ static public LastFmService getInstance() { if (self == null) { LastFmCache cache = new LastFmCache(); Locale locale = LocaleManager.getLocale(); self = new LastFmService(locale, cache); } return self; } /** * Gets the artist. * * @param artist DOCUMENT_ME * * @return the artist */ public ArtistInfo getArtist(String artist) { try { // Try to get from cache ArtistInfo artistInfo = lastFmCache.retrieveArtistInfo(artist); if (artistInfo == null) { Artist a = Artist.getInfo(artist, UtilString.rot13(API_KEY)); if (a != null) { artistInfo = LastFmArtist.getArtist(a); lastFmCache.storeArtistInfo(artist, artistInfo); } } return artistInfo; } catch (Exception e) { Log.error(e); } return null; } /** * Gets the album. * * @param artist the artist * @param album the album * * @return the album */ public AlbumInfo getAlbum(String artist, String album) { try { // Try to get from cache AlbumInfo albumObject = lastFmCache.retrieveAlbumInfo(artist, album); if (albumObject == null) { Album a = Album.getInfo(artist, album, UtilString.rot13(API_KEY)); if (a != null) { Playlist pl = Playlist.fetchAlbumPlaylist(a.getId(), UtilString.rot13(API_KEY)); albumObject = LastFmAlbum.getAlbum(a, pl); lastFmCache.storeAlbumInfo(artist, album, albumObject); } } return albumObject; } catch (Exception e) { Log.error(e); } return null; } /** * Gets the album list. * * @param artist the artist * @param hideVariousArtists if true albums with artist name "Various Artists" * are nor returned * @param minimumSongNumber albums with less songs than this argument won't be returned * * @return the album list */ public AlbumListInfo getAlbumList(String artist, boolean hideVariousArtists, int minimumSongNumber) { try { // Try to get from cache AlbumListInfo albumList = lastFmCache.retrieveAlbumList(artist); if (albumList == null) { Collection as = Artist.getTopAlbums(artist, UtilString.rot13(API_KEY)); if (as != null) { AlbumListInfo albums = LastFmAlbumList.getAlbumList(as, artist); List result = new ArrayList(); for (AlbumInfo a : albums.getAlbums()) { if (a.getBigCoverURL() != null && !a.getBigCoverURL().isEmpty()) { result.add(a); } } albumList = new LastFmAlbumList(); albumList.setArtist(artist); albumList.setAlbums(result); lastFmCache.storeAlbumList(artist, albumList); } } if (albumList != null) { List albumsFiltered = null; // Apply filter to hide "Various Artists" albums if (hideVariousArtists) { albumsFiltered = new ArrayList(); for (AlbumInfo albumInfo : albumList.getAlbums()) { if (!albumInfo.getArtist().equals(VARIOUS_ARTISTS)) { albumsFiltered.add(albumInfo); } } albumList.setAlbums(albumsFiltered); } // Apply filter to hide albums with less than X songs if (minimumSongNumber > 0) { albumsFiltered = new ArrayList(); for (AlbumInfo albumInfo : albumList.getAlbums()) { AlbumInfo extendedAlbumInfo = getAlbum(artist, albumInfo.getTitle()); if (extendedAlbumInfo != null && extendedAlbumInfo.getTracks() != null && extendedAlbumInfo.getTracks().size() >= minimumSongNumber) { albumsFiltered.add(albumInfo); } } } if (albumsFiltered != null) { albumList.setAlbums(albumsFiltered); } } return albumList; } catch (Exception e) { Log.error(e); } return null; } /** * Gets the artist top tag. * * @param artist the artist * * @return the artist top tag */ public String getArtistTopTag(String artist) { try { Collection topTags = Artist.getTopTags(artist, UtilString.rot13(API_KEY)); List tags = new ArrayList(topTags); return tags.isEmpty() ? "" : tags.get(0); } catch (Exception e) { Log.error(e); } return null; } /** * Gets the image. * * @param album the album * * @return the image */ public Image getImage(AlbumInfo album) { try { Image img = null; Proxy proxy = DownloadManager.getProxy(); // Try to retrieve from cache img = lastFmCache.retrieveAlbumCover(album); if (img == null && album.getBigCoverURL() != null && !album.getBigCoverURL().isEmpty()) { img = ext.services.network.NetworkUtils.getImage(ext.services.network.NetworkUtils .getConnection(album.getBigCoverURL(), proxy)); lastFmCache.storeAlbumCover(album, img); } return img; } catch (IOException e) { Log.error(e); } return null; } /** * Gets the image of an artist. * * @param artist the artist * * @return the image */ public Image getImage(ArtistInfo artist) { try { // Try to retrieve from cache Image img = lastFmCache.retrieveArtistThumbImage(artist); Proxy proxy = DownloadManager.getProxy(); if (img == null && artist.getImageUrl() != null && !artist.getImageUrl().isEmpty()) { // Try to get from Artist.getImages() method img = getArtistImageFromLastFM(artist.getName()); // if not then get from artist info if (img == null) { img = ext.services.network.NetworkUtils.getImage(ext.services.network.NetworkUtils .getConnection(artist.getImageUrl(), proxy)); } lastFmCache.storeArtistThumbImage(artist, img); } return img; } catch (Exception e) { Log.error(e); } return null; } /** * Gets the image of the artist. * * @param similar the similar * * @return the image */ public Image getImage(SimilarArtistsInfo similar) { try { // Try to retrieve from cache Image img = lastFmCache.retrieveArtistImage(similar); Proxy proxy = DownloadManager.getProxy(); if (img != null) { return img; } // Try to get from LastFM img = getArtistImageFromLastFM(similar.getArtistName()); // Get from similar artist info if (img == null) { String similarUrl = similar.getPicture(); if (!similarUrl.trim().isEmpty()) { img = ext.services.network.NetworkUtils.getImage(ext.services.network.NetworkUtils .getConnection(similarUrl, proxy)); } } if (img != null) { lastFmCache.storeArtistImage(similar, img); } return img; } catch (Exception e) { Log.error(e); } return null; } /** * Returns current artist image at LastFM. * * @param artistName DOCUMENT_ME * * @return the artist image from last fm */ private Image getArtistImageFromLastFM(String artistName) { try { Proxy proxy = DownloadManager.getProxy(); // Try to get from Artist.getImages() method PaginatedResult images = Artist.getImages(artistName, 1, 1, UtilString.rot13(API_KEY)); List imageList = new ArrayList( images.getPageResults()); if (!imageList.isEmpty()) { Set sizes = imageList.get(0).availableSizes(); // Try to get original if (sizes.contains(ImageSize.ORIGINAL)) { return ext.services.network.NetworkUtils.getImage(ext.services.network.NetworkUtils .getConnection(imageList.get(0).getImageURL(ImageSize.ORIGINAL), proxy)); } } } catch (IOException e) { Log.error(e); } return null; } /** * Gets the similar artists. * * @param artist the artist * * @return the similar artists */ public SimilarArtistsInfo getSimilarArtists(String artist) { try { // Try to get from cache SimilarArtistsInfo similar = lastFmCache.retrieveArtistSimilar(artist); if (similar == null) { Collection as = Artist.getSimilar(artist, UtilString.rot13(API_KEY)); Artist a = Artist.getInfo(artist, UtilString.rot13(API_KEY)); if (a != null) { similar = LastFmSimilarArtists.getSimilarArtists(as, a); lastFmCache.storeArtistSimilar(artist, similar); } } return similar; } catch (Exception e) { Log.error(e); } return null; } /** * Gets the wiki text. * * @param artist the artist * * @return the wiki text */ public String getWikiText(String artist) { try { // Try to get from cache String wikiText = lastFmCache.retrieveArtistWiki(artist); if (wikiText == null) { Artist a = Artist.getInfo(artist, locale, UtilString.rot13(API_KEY)); wikiText = a != null ? a.getWikiSummary() : ""; if (wikiText != null) { wikiText = wikiText.replaceAll("<.*?>", ""); wikiText = StringEscapeUtils.unescapeHtml(wikiText); } lastFmCache.storeArtistWiki(artist, wikiText); } return wikiText; } catch (Exception e) { Log.error(e); } return null; } /** * Gets the wiki url. * * @param artist the artist * * @return the wiki url */ public String getWikiURL(String artist) { return ARTIST_WIKI_URL.replace(ARTIST_WILDCARD, ext.services.network.NetworkUtils.encodeString(artist)).replace(LANGUAGE_WILDCARD, locale.getLanguage()); } /** * Submits song to Last.fm * * @param track DOCUMENT_ME * @param millisPlayed ms the audio file has already played * @throws ScrobblerException the scrobbler exception */ public void submit(Track track, long millisPlayed) throws ScrobblerException { // Do all necessary checks if (!checkUser() || !checkPassword() || !checkArtist(track) || !checkTitle(track) || !checkDuration(track)) { return; } // Get started to play in secs UTC and not in MS (lastfm-bindings API was unclear about it) long startedToPlay = (System.currentTimeMillis() - millisPlayed) / 1000; Log.info("Trying to submit song to Last.fm, play time=" + millisPlayed / 1000 + " secs"); try { performHandshakeIfNeeded(); SubmissionData submissionData = new SubmissionData(track.getArtist().getName2(), track.getName(), track.getAlbum().getName2(), (int) track.getDuration(), (int) track.getOrder(), Source.USER, null, startedToPlay); ResponseStatus status = scrobbler.submit(submissionData); if (status.ok()) { Log.info("Song submitted to Last.fm"); } else { handshakePerformed = false; lastFmCache.addSubmissionData(new FullSubmissionData(track.getArtist().getName2(), track .getName(), track.getAlbum().getName2(), (int) track.getDuration(), (int) track .getOrder(), Source.USER.toString(), (int) startedToPlay)); throw new ScrobblerException(status.getStatus()); } } catch (IOException e) { Log.error(e); handshakePerformed = false; lastFmCache.addSubmissionData(new FullSubmissionData(track.getArtist().getName2(), track .getName(), track.getAlbum().getName2(), (int) track.getDuration(), (int) track .getOrder(), Source.USER.toString(), (int) startedToPlay)); throw new ScrobblerException(e.getMessage()); } } /** * Submits cache data to Last.fm * * @throws ScrobblerException the scrobbler exception */ public void submitCache() throws ScrobblerException { // Do all necessary checks if (!checkUser() || !checkPassword()) { return; } List collectionWithSubmissionData = lastFmCache.getSubmissionData(); if (!collectionWithSubmissionData.isEmpty()) { // More than MAX_SUBMISSIONS submissions at once are not allowed int size = collectionWithSubmissionData.size(); if (size > MAX_SUBMISSIONS) { collectionWithSubmissionData = collectionWithSubmissionData.subList(size - MAX_SUBMISSIONS, size); } Log.info("Trying to submit cache to Last.fm"); try { performHandshakeIfNeeded(); List submissionDataList = new ArrayList(); for (ext.services.lastfm.FullSubmissionData submissionData : collectionWithSubmissionData) { SubmissionData sd = new SubmissionData(submissionData.getArtist(), submissionData.getTitle(), submissionData.getAlbum(), submissionData.getDuration(), submissionData.getTrackNumber(), Source.valueOf(submissionData.getSource()), null, submissionData.getStartTime()); submissionDataList.add(sd); } ResponseStatus status = scrobbler.submit(submissionDataList); if (status.ok()) { lastFmCache.removeSubmissionData(); Log.info("Cache submitted to Last.fm"); } else { handshakePerformed = false; throw new ScrobblerException(status.getStatus()); } } catch (IOException e) { Log.error(e); handshakePerformed = false; throw new ScrobblerException(e.getMessage()); } } } /** * Submits now playing info to Last.fm * * @param track DOCUMENT_ME * * @throws ScrobblerException the scrobbler exception */ public void submitNowPlayingInfo(Track track) throws ScrobblerException { // Do all necessary checks if (!checkUser() || !checkPassword() || !checkArtist(track) || !checkTitle(track)) { return; } Log.info("Trying to submit now playing info to Last.fm"); try { performHandshakeIfNeeded(); ResponseStatus status = scrobbler.nowPlaying(track.getArtist().getName2(), track.getName(), track.getAlbum().getName2(), (int) track.getDuration(), (int) track.getOrder()); if (status.ok()) { Log.info("Now playing info submitted to Last.fm"); } else { handshakePerformed = false; throw new ScrobblerException(status.getStatus()); } } catch (IOException e) { Log.error(e); handshakePerformed = false; throw new ScrobblerException(e.getMessage()); } } /** * Performs handshake for submissions if needed. * * @throws IOException Signals that an I/O exception has occurred. * @throws ScrobblerException the scrobbler exception */ private void performHandshakeIfNeeded() throws IOException, ScrobblerException { if (!handshakePerformed) { String password = UtilString.rot13(Conf.getString(Const.CONF_LASTFM_PASSWORD)); ResponseStatus status = scrobbler.handshake(password); if (!status.ok()) { throw new ScrobblerException(status.getStatus()); } handshakePerformed = true; } } /** * Checks user. * * @return true, if check user */ private boolean checkUser() { String user = Conf.getString(Const.CONF_LASTFM_USER); if (user == null || user.equals("")) { Log.debug("Don't submit to Last.fm: Empty user"); return false; } return true; } /** * Check password. * * @return true, if check password */ private boolean checkPassword() { String password = UtilString.rot13(Conf.getString(Const.CONF_LASTFM_PASSWORD)); if (StringUtils.isBlank(password)) { Log.debug("Don't submit to Last.fm: Empty password"); return false; } return true; } /** * Check artist. * * @param track DOCUMENT_ME * * @return true, if check artist */ private boolean checkArtist(Track track) { String sArtist = track.getArtist().getName2(); if (StringUtils.isBlank(sArtist) || sArtist.equalsIgnoreCase(Messages.getString("unknown_artist"))) { Log.debug("Don't submit to Last.fm: Unknown artist"); return false; } return true; } /** * Check title. * * @param track DOCUMENT_ME * * @return true, if check title */ private boolean checkTitle(Track track) { if (StringUtils.isBlank(track.getName())) { Log.debug("Don't submit to Last.fm: Unknown Title"); return false; } return true; } /** * Check duration. * * @param track DOCUMENT_ME * * @return true, if check duration */ private boolean checkDuration(Track track) { if (track.getDuration() < MIN_DURATION_TO_SUBMIT) { Log.debug(UtilString.concat("Don't submit to Last.fm: Lenght < ", MIN_DURATION_TO_SUBMIT)); return false; } return true; } } jajuk-1.9.6.orig/src/main/java/ext/services/lastfm/ScrobblerException.java0000644000175000017500000000341611720500104026464 0ustar drazzibdrazzib/* * aTunes 1.14.0 code adapted by Jajuk team * * Original copyright notice bellow : * * Copyright (C) 2006-2009 Alex Aranda, Sylvain Gaudard, Thomas Beckers and contributors * * See http://www.atunes.org/wiki/index.php?title=Contributing for information about contributors * * http://www.atunes.org * http://sourceforge.net/projects/atunes * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ package ext.services.lastfm; import org.jajuk.util.UtilString; /** * The Class ScrobblerException. */ public class ScrobblerException extends Exception { /** Generated serialVersionUID. */ private static final long serialVersionUID = -7383228060002549115L; /** DOCUMENT_ME. */ private int status = -1; /** * Instantiates a new scrobbler exception. * * @param cause the cause */ public ScrobblerException(String cause) { super(UtilString.concat("Error submitting to Last.fm. Cause: ", cause)); } /** * Instantiates a new scrobbler exception. * * @param status DOCUMENT_ME */ public ScrobblerException(int status) { super(UtilString.concat("Error submitting to Last.fm. Status: ", Integer.valueOf(status))); this.status = status; } /** * Returns the status (-1 if no status was set). * * @return the status */ public int getStatus() { return status; } } jajuk-1.9.6.orig/src/main/java/ext/services/lastfm/LastFmSimilarArtists.java0000644000175000017500000000700011720500104026742 0ustar drazzibdrazzib/* * aTunes 1.14.0 code adapted by Jajuk team * * Original copyright notice bellow : * * Copyright (C) 2006-2009 Alex Aranda, Sylvain Gaudard, Thomas Beckers and contributors * * See http://www.atunes.org/wiki/index.php?title=Contributing for information about contributors * * http://www.atunes.org * http://sourceforge.net/projects/atunes * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ package ext.services.lastfm; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.List; import net.roarsoftware.lastfm.Artist; import net.roarsoftware.lastfm.ImageSize; /** * The Class LastFmSimilarArtists. */ public class LastFmSimilarArtists implements SimilarArtistsInfo { /** The Constant MAX_SIMILAR_ARTISTS. */ private static final int MAX_SIMILAR_ARTISTS = 15; /** The artist name. */ private String artistName; /** The picture. */ private String picture; /** The artists. */ private List artists; /** * Gets the similar artists. * * @param as DOCUMENT_ME * @param a DOCUMENT_ME * * @return the similar artists */ public static SimilarArtistsInfo getSimilarArtists(Collection as, Artist a) { List list = new ArrayList(as); LastFmSimilarArtists similar = new LastFmSimilarArtists(); similar.setArtistName(a.getName()); similar.setPicture(a.getImageURL(ImageSize.LARGE)); List artists = new ArrayList(); for (int i = 0; i < list.size(); i++) { if (i == MAX_SIMILAR_ARTISTS) { break; } artists.add(LastFmArtist.getArtist(list.get(i))); } similar.setArtists(artists); return similar; } /** * Gets the artist name. * * @return the artist name */ @Override public String getArtistName() { return artistName; } /** * Gets the artists. * * @return the artists */ @Override public List getArtists() { // artists is null for void (unknown) similar artists if (artists != null) { // Sort similar artists ignoring case Collections.sort(artists, new Comparator() { @Override public int compare(ArtistInfo o1, ArtistInfo o2) { return o1.getName().compareToIgnoreCase(o2.getName()); } }); } return artists; } /** * Gets the picture. * * @return the picture */ @Override public String getPicture() { return picture; } /** * Sets the artist name. * * @param artistName the artistName to set */ @Override public void setArtistName(String artistName) { this.artistName = artistName; } /** * Sets the artists. * * @param artists the artists to set */ @Override public void setArtists(List artists) { this.artists = artists != null ? artists : new ArrayList(); } /** * Sets the picture. * * @param picture the picture to set */ @Override public void setPicture(String picture) { this.picture = picture; } } jajuk-1.9.6.orig/src/main/java/ext/services/lastfm/FullSubmissionData.java0000644000175000017500000000743011720500104026440 0ustar drazzibdrazzib/* * aTunes 1.14.0 code adapted by Jajuk team * * Original copyright notice bellow : * * Copyright (C) 2006-2009 Alex Aranda, Sylvain Gaudard, Thomas Beckers and contributors * * See http://www.atunes.org/wiki/index.php?title=Contributing for information about contributors * * http://www.atunes.org * http://sourceforge.net/projects/atunes * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ package ext.services.lastfm; /** * DOCUMENT_ME. */ public class FullSubmissionData { /** DOCUMENT_ME. */ private String artist; /** DOCUMENT_ME. */ private String title; /** DOCUMENT_ME. */ private String album; /** DOCUMENT_ME. */ private int duration; /** DOCUMENT_ME. */ private int trackNumber; /** DOCUMENT_ME. */ private String source; /** DOCUMENT_ME. */ private int startTime; /** * Instantiates a new full submission data. * * @param artist DOCUMENT_ME * @param title DOCUMENT_ME * @param album DOCUMENT_ME * @param duration DOCUMENT_ME * @param trackNumber DOCUMENT_ME * @param source DOCUMENT_ME * @param startTime DOCUMENT_ME */ public FullSubmissionData(String artist, String title, String album, int duration, int trackNumber, String source, int startTime) { this.album = album; this.artist = artist; this.duration = duration; this.source = source; this.startTime = startTime; this.title = title; this.trackNumber = trackNumber; } /** * Gets the artist. * * @return the artist */ public String getArtist() { return artist; } /** * Sets the artist. * * @param artist the artist to set */ public void setArtist(String artist) { this.artist = artist; } /** * Gets the title. * * @return the title */ public String getTitle() { return title; } /** * Sets the title. * * @param title the title to set */ public void setTitle(String title) { this.title = title; } /** * Gets the album. * * @return the album */ public String getAlbum() { return album; } /** * Sets the album. * * @param album the album to set */ public void setAlbum(String album) { this.album = album; } /** * Gets the duration. * * @return the duration */ public int getDuration() { return duration; } /** * Sets the duration. * * @param duration the duration to set */ public void setDuration(int duration) { this.duration = duration; } /** * Gets the track number. * * @return the trackNumber */ public int getTrackNumber() { return trackNumber; } /** * Sets the track number. * * @param trackNumber the trackNumber to set */ public void setTrackNumber(int trackNumber) { this.trackNumber = trackNumber; } /** * Gets the source. * * @return the source */ public String getSource() { return source; } /** * Sets the source. * * @param source the source to set */ public void setSource(String source) { this.source = source; } /** * Gets the start time. * * @return the startTime */ public int getStartTime() { return startTime; } /** * Sets the start time. * * @param startTime the startTime to set */ public void setStartTime(int startTime) { this.startTime = startTime; } } jajuk-1.9.6.orig/src/main/java/ext/services/lastfm/LastFmArtist.java0000644000175000017500000000722011720500104025242 0ustar drazzibdrazzib/* * aTunes 1.14.0 code adapted by Jajuk team * * Original copyright notice bellow : * * Copyright (C) 2006-2009 Alex Aranda, Sylvain Gaudard, Thomas Beckers and contributors * * See http://www.atunes.org/wiki/index.php?title=Contributing for information about contributors * * http://www.atunes.org * http://sourceforge.net/projects/atunes * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ package ext.services.lastfm; import javax.swing.ImageIcon; import net.roarsoftware.lastfm.Artist; import net.roarsoftware.lastfm.ImageSize; /** * The Class LastFmArtist. */ public class LastFmArtist implements ArtistInfo { /** The name. */ private String name; /** The match. */ private String match; /** The url. */ private String url; /** The image url. */ private String imageUrl; // Used by renderers /** The image. */ private ImageIcon image; /** true if this artist is available at repository. */ private transient boolean available; /** * Gets the artist. * * @param a DOCUMENT_ME * * @return the artist */ public static LastFmArtist getArtist(Artist a) { LastFmArtist artist = new LastFmArtist(); artist.name = a.getName(); artist.match = String.valueOf(a.getSimilarityMatch()); String url2 = a.getUrl(); artist.url = url2.startsWith("http") ? url2 : "http://" + url2; // SMALL images have low quality when scaling. Better to get largest image artist.imageUrl = a.getImageURL(ImageSize.LARGE); return artist; } /** * Gets the image. * * @return the image */ @Override public ImageIcon getImage() { return image; } /** * Gets the image url. * * @return the image url */ @Override public String getImageUrl() { return imageUrl; } /** * Gets the match. * * @return the match */ @Override public String getMatch() { return match; } /** * Gets the name. * * @return the name */ @Override public String getName() { return name; } /** * Gets the url. * * @return the url */ @Override public String getUrl() { return url; } /** * Sets the image. * * @param image the new image */ @Override public void setImage(ImageIcon image) { this.image = image; } /** * Sets the image url. * * @param imageUrl the imageUrl to set */ @Override public void setImageUrl(String imageUrl) { this.imageUrl = imageUrl; } /** * Sets the match. * * @param match the match to set */ @Override public void setMatch(String match) { this.match = match; } /** * Sets the name. * * @param name the name to set */ @Override public void setName(String name) { this.name = name; } /** * Sets the url. * * @param url the url to set */ @Override public void setUrl(String url) { this.url = url; } /** * Checks if is available. * * @return the available */ @Override public boolean isAvailable() { return available; } /** * Sets the available. * * @param available the available to set */ @Override public void setAvailable(boolean available) { this.available = available; } } jajuk-1.9.6.orig/src/main/java/ext/services/lastfm/LastFmRunnable.java0000644000175000017500000001000511720500104025535 0ustar drazzibdrazzib/* * aTunes 1.14.0 code adapted by Jajuk team * * Original copyright notice bellow : * * Copyright (C) 2006-2009 Alex Aranda, Sylvain Gaudard, Thomas Beckers and contributors * * See http://www.atunes.org/wiki/index.php?title=Contributing for information about contributors * * http://www.atunes.org * http://sourceforge.net/projects/atunes * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ package ext.services.lastfm; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Future; import org.jajuk.util.log.Log; /** * The Class LastFmRunnable. */ public class LastFmRunnable implements Runnable { /** The interrupted. */ private volatile boolean interrupted; /** The albums runnable. */ private LastFmAlbumsRunnable albumsRunnable; /** The covers runnable. */ private LastFmCoversRunnable coversRunnable; /** The artists runnable. */ private LastFmSimilarArtistsRunnable artistsRunnable; /** The listener. */ private ContextListener listener; /** The service. */ private LastFmService service; /** The audio object. */ private AudioObject audioObject; /** The retrieve artist info. */ private boolean retrieveArtistInfo = true; /** The id. */ private long id; /** The executor service. */ private ExecutorService executorService; /** * Instantiates a new audio scrobbler runnable. * * @param listener the listener * @param service the service * @param audioObject the audio object * @param id the id * @param executorService DOCUMENT_ME */ public LastFmRunnable(ContextListener listener, LastFmService service, AudioObject audioObject, long id, ExecutorService executorService) { this.listener = listener; this.service = service; this.audioObject = audioObject; this.id = id; this.executorService = executorService; } /** * Interrupt. */ public void interrupt() { interrupted = true; if (albumsRunnable != null) { albumsRunnable.interrupt(); } if (coversRunnable != null) { coversRunnable.interrupt(); } if (artistsRunnable != null) { artistsRunnable.interrupt(); } } /* * (non-Javadoc) * * @see java.lang.Runnable#run() */ @Override public void run() { albumsRunnable = new LastFmAlbumsRunnable(listener, service, audioObject, id); albumsRunnable.setRetrieveArtistInfo(retrieveArtistInfo); Future albumsRunnableFuture = executorService.submit(albumsRunnable); Log.debug("LastFmAlbumsRunnable started with id " + id + " for " + audioObject.getArtist()); try { albumsRunnableFuture.get(); } catch (ExecutionException e) { Log.error(e); } catch (InterruptedException e) { Log.debug("albums runnable interrupted"); } if (retrieveArtistInfo && !interrupted) { coversRunnable = new LastFmCoversRunnable(listener, service, listener.getAlbums(), id, audioObject); executorService.submit(coversRunnable); Log.debug("LastFmCoversRunnable started with id " + id); artistsRunnable = new LastFmSimilarArtistsRunnable(listener, service, audioObject.getArtist(), id); executorService.submit(artistsRunnable); Log.debug("LastFmSimilarArtistsRunnable started with id " + id + " for " + audioObject.getArtist()); } } /** * Sets the retrieve artist info. * * @param retrieveArtistInfo the new retrieve artist info */ public void setRetrieveArtistInfo(boolean retrieveArtistInfo) { this.retrieveArtistInfo = retrieveArtistInfo; } } jajuk-1.9.6.orig/src/main/java/ext/services/lastfm/LastFmTrack.java0000644000175000017500000000357111720500104025045 0ustar drazzibdrazzib/* * aTunes 1.14.0 code adapted by Jajuk team * * Original copyright notice bellow : * * Copyright (C) 2006-2009 Alex Aranda, Sylvain Gaudard, Thomas Beckers and contributors * * See http://www.atunes.org/wiki/index.php?title=Contributing for information about contributors * * http://www.atunes.org * http://sourceforge.net/projects/atunes * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ package ext.services.lastfm; import net.roarsoftware.lastfm.Track; /** * The Class LastFmTrack. */ public class LastFmTrack implements TrackInfo { /** The title. */ private String title; /** The url. */ private String url; /** * Gets the track. * * @param t DOCUMENT_ME * * @return the track */ protected static LastFmTrack getTrack(Track t) { LastFmTrack track = new LastFmTrack(); track.title = t.getName(); track.url = t.getUrl(); return track; } /** * Gets the title. * * @return the title */ @Override public String getTitle() { return title; } /** * Gets the url. * * @return the url */ @Override public String getUrl() { return url; } /** * Sets the title. * * @param title the title to set */ @Override public void setTitle(String title) { this.title = title; } /** * Sets the url. * * @param url the url to set */ @Override public void setUrl(String url) { this.url = url; } } jajuk-1.9.6.orig/src/main/java/ext/services/lastfm/AlbumListInfo.java0000644000175000017500000000262511720500104025401 0ustar drazzibdrazzib/* * aTunes 1.14.0 code adapted by Jajuk team * * Original copyright notice bellow : * * Copyright (C) 2006-2009 Alex Aranda, Sylvain Gaudard, Thomas Beckers and contributors * * See http://www.atunes.org/wiki/index.php?title=Contributing for information about contributors * * http://www.atunes.org * http://sourceforge.net/projects/atunes * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ package ext.services.lastfm; import java.util.List; /** * DOCUMENT_ME. */ public interface AlbumListInfo { /** * Gets the albums. * * @return the albums */ public List getAlbums(); /** * Gets the artist. * * @return the artist */ public String getArtist(); /** * Sets the albums. * * @param albums the albums to set */ public void setAlbums(List albums); /** * Sets the artist. * * @param artist the artist to set */ public void setArtist(String artist); } jajuk-1.9.6.orig/src/main/java/ext/services/lastfm/TrackInfo.java0000644000175000017500000000247511720500104024554 0ustar drazzibdrazzib/* * aTunes 1.14.0 code adapted by Jajuk team * * Original copyright notice bellow : * * Copyright (C) 2006-2009 Alex Aranda, Sylvain Gaudard, Thomas Beckers and contributors * * See http://www.atunes.org/wiki/index.php?title=Contributing for information about contributors * * http://www.atunes.org * http://sourceforge.net/projects/atunes * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ package ext.services.lastfm; /** * DOCUMENT_ME. */ public interface TrackInfo { /** * Gets the title. * * @return the title */ public String getTitle(); /** * Gets the url. * * @return the url */ public String getUrl(); /** * Sets the title. * * @param title the title to set */ public void setTitle(String title); /** * Sets the url. * * @param url the url to set */ public void setUrl(String url); } jajuk-1.9.6.orig/src/main/java/ext/services/lastfm/ContextListener.java0000644000175000017500000000612111720500104026016 0ustar drazzibdrazzib/* * aTunes 1.14.0 code adapted by Jajuk team * * Original copyright notice bellow : * * Copyright (C) 2006-2009 Alex Aranda, Sylvain Gaudard, Thomas Beckers and contributors * * See http://www.atunes.org/wiki/index.php?title=Contributing for information about contributors * * http://www.atunes.org * http://sourceforge.net/projects/atunes * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ package ext.services.lastfm; import java.awt.Image; import java.util.List; /** * The listener interface for receiving context events. */ public interface ContextListener { /** * Gets the albums. * * @return the albums */ public List getAlbums(); /** * Notify album retrieved. * * @param file the file * @param id the id */ public void notifyAlbumRetrieved(AudioObject file, long id); /** * Notify artist image. * * @param img the img * @param id the id */ public void notifyArtistImage(Image img, long id); /** * Notify cover retrieved. * * @param album the album * @param cover the cover * @param id the id */ public void notifyCoverRetrieved(AlbumInfo album, Image cover, long id); /** * Notify finish get similar artist. * * @param a the a * @param img the img * @param id the id */ public void notifyFinishGetSimilarArtist(ArtistInfo a, Image img, long id); /** * Notify start retrieving artist images. * * @param id the id */ public void notifyStartRetrievingArtistImages(long id); /** * Notify start retrieving covers. * * @param id the id */ public void notifyStartRetrievingCovers(long id); /** * Notify wiki info retrieved. * * @param wikiText the wiki text * @param wikiURL the wiki url * @param id the id */ public void notifyWikiInfoRetrieved(String wikiText, String wikiURL, long id); /** * Sets the album. * * @param album the album * @param id the id */ public void setAlbum(AlbumInfo album, long id); /** * Sets the albums. * * @param album the album * @param id the id */ public void setAlbums(List album, long id); /** * Sets the image. * * @param img the img * @param ao audio object * @param id the id */ public void setImage(Image img, AudioObject ao, long id); /** * Sets the last album retrieved. * * @param album the album * @param id the id */ public void setLastAlbumRetrieved(String album, long id); /** * Sets the last artist retrieved. * * @param artist the artist * @param id the id */ public void setLastArtistRetrieved(String artist, long id); } jajuk-1.9.6.orig/src/main/java/ext/services/lastfm/SimilarArtistsInfo.java0000644000175000017500000000323111720500104026451 0ustar drazzibdrazzib/* * aTunes 1.14.0 code adapted by Jajuk team * * Original copyright notice bellow : * * Copyright (C) 2006-2009 Alex Aranda, Sylvain Gaudard, Thomas Beckers and contributors * * See http://www.atunes.org/wiki/index.php?title=Contributing for information about contributors * * http://www.atunes.org * http://sourceforge.net/projects/atunes * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ package ext.services.lastfm; import java.util.List; /** * DOCUMENT_ME. */ public interface SimilarArtistsInfo { /** * Gets the artist name. * * @return the artist name */ public String getArtistName(); /** * Gets the artists. * * @return the artists */ public List getArtists(); /** * Gets the picture. * * @return the picture */ public String getPicture(); /** * Sets the artist name. * * @param artistName the artistName to set */ public void setArtistName(String artistName); /** * Sets the artists. * * @param artists the artists to set */ public void setArtists(List artists); /** * Sets the picture. * * @param picture the picture to set */ public void setPicture(String picture); } jajuk-1.9.6.orig/src/main/java/ext/services/xml/0000755000175000017500000000000011720500104021333 5ustar drazzibdrazzibjajuk-1.9.6.orig/src/main/java/ext/services/xml/package.html0000644000175000017500000000017111720500104023613 0ustar drazzibdrazzib DOCUMENT_ME jajuk-1.9.6.orig/src/main/java/ext/services/xml/XMLBuilder.java0000644000175000017500000000363711720500104024156 0ustar drazzibdrazzib/* * aTunes 1.14.0 code adapted by Jajuk team * * Original copyright notice bellow : * * Copyright (C) 2006-2009 Alex Aranda, Sylvain Gaudard, Thomas Beckers and contributors * * See http://www.atunes.org/wiki/index.php?title=Contributing for information about contributors * * http://www.atunes.org * http://sourceforge.net/projects/atunes * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ package ext.services.xml; import java.io.IOException; import java.io.StringReader; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import org.w3c.dom.Document; import org.xml.sax.InputSource; import org.xml.sax.SAXException; /** * DOCUMENT_ME. */ public final class XMLBuilder { /** * private constructor to avoid instantiating utility class. */ private XMLBuilder() { } /** * Gets the xML document. * * @param xml DOCUMENT_ME * * @return the xML document */ public static Document getXMLDocument(String xml) { if ((null != xml) && (xml.length() != 0)) { try { DocumentBuilder parser = DocumentBuilderFactory.newInstance().newDocumentBuilder(); return parser.parse(new InputSource(new StringReader(xml))); } catch (SAXException e) { return null; } catch (IOException e) { return null; } catch (ParserConfigurationException e) { return null; } } return null; } } jajuk-1.9.6.orig/src/main/java/ext/services/xml/XMLUtils.java0000644000175000017500000001362211720500104023663 0ustar drazzibdrazzib/* * aTunes 1.14.0 code adapted by Jajuk team * * Original copyright notice bellow : * * Copyright (C) 2006-2009 Alex Aranda, Sylvain Gaudard, Thomas Beckers and contributors * * See http://www.atunes.org/wiki/index.php?title=Contributing for information about contributors * * http://www.atunes.org * http://sourceforge.net/projects/atunes * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ package ext.services.xml; import com.thoughtworks.xstream.XStream; import com.thoughtworks.xstream.io.xml.DomDriver; import java.beans.XMLDecoder; import java.beans.XMLEncoder; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.CharArrayReader; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.io.Reader; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import org.apache.commons.lang.StringUtils; import org.jajuk.util.log.Log; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NodeList; import org.xml.sax.InputSource; /** * DOCUMENT_ME. */ public final class XMLUtils { /** The x stream. */ private static XStream xStream = new XStream(new DomDriver()); /** * private constructor to avoid instantiating utility class. */ private XMLUtils() { } /** * Gets the child element. * * @param el DOCUMENT_ME * @param tagName DOCUMENT_ME * * @return the child element */ public static Element getChildElement(Element el, String tagName) { if (el == null) { return null; } NodeList list = el.getElementsByTagName(tagName); if (list != null && list.getLength() > 0) { return (Element) list.item(0); } return null; } /** * Gets the attribute value. * * @param el DOCUMENT_ME * @param attributeName DOCUMENT_ME * * @return the attribute value */ public static String getAttributeValue(Element el, String attributeName) { return (null == el ? null : el.getAttribute(attributeName)); } /** * Gets the child element content. * * @param el DOCUMENT_ME * @param tagName DOCUMENT_ME * * @return the child element content */ public static String getChildElementContent(Element el, String tagName) { Element el2 = getChildElement(el, tagName); return el2 == null ? "" : el2.getTextContent(); } /** * Writes an object to an XML file. * * @param bean the bean * @param filename the filename * * @throws IOException Signals that an I/O exception has occurred. */ public static void writeBeanToFile(Object bean, String filename) throws IOException { XMLEncoder encoder = null; try { encoder = new XMLEncoder(new BufferedOutputStream(new FileOutputStream(filename))); encoder.writeObject(bean); } finally { if (encoder != null) { encoder.close(); } } } /** * Reads an object from an XML file. * * @param filename the filename * * @return the object * * @throws IOException Signals that an I/O exception has occurred. */ public static Object readBeanFromFile(String filename) throws IOException { XMLDecoder decoder = null; try { decoder = new XMLDecoder(new BufferedInputStream(new FileInputStream(filename))); return decoder.readObject(); } finally { if (decoder != null) { decoder.close(); } } } /** * Reads an object from a file as xml. * * @param filename filename * * @return The object read from the xml file * * @throws IOException Signals that an I/O exception has occurred. */ public static Object readObjectFromFile(String filename) throws IOException { InputStreamReader inputStreamReader = null; try { inputStreamReader = new InputStreamReader(new FileInputStream(filename), "UTF-8"); return xStream.fromXML(inputStreamReader); } finally { if (inputStreamReader != null) { inputStreamReader.close(); } } } /** * Writes an object to a file as xml. * * @param object Object that should be writen to a xml file * @param filename filename * * @throws IOException Signals that an I/O exception has occurred. */ public static void writeObjectToFile(Object object, String filename) throws IOException { OutputStreamWriter outputStreamWriter = null; try { outputStreamWriter = new OutputStreamWriter(new FileOutputStream(filename), "UTF-8"); xStream.toXML(object, outputStreamWriter); } finally { if (outputStreamWriter != null) { outputStreamWriter.flush(); outputStreamWriter.close(); } } } /** * Return a DOM document for a given string
* In case of parsing error, this method handles the exception and null is * returned. * * @param xml the string to parse * * @return a DOM document for a given string */ public static Document getDocument(String xml) { Document out = null; try { DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder(); Reader reader = new CharArrayReader(xml.toCharArray()); out = builder.parse(new InputSource(reader)); } catch (Exception e) { // print first 500 characters of string that cannot be parsed... Log.debug("First 500 characters of XML: " + StringUtils.substring(xml, 0, 500)); Log.error(e); } return out; } } jajuk-1.9.6.orig/src/main/java/org/0000755000175000017500000000000011720500104016677 5ustar drazzibdrazzibjajuk-1.9.6.orig/src/main/java/org/jajuk/0000755000175000017500000000000011720500104020003 5ustar drazzibdrazzibjajuk-1.9.6.orig/src/main/java/org/jajuk/package.html0000644000175000017500000000005311720500104022262 0ustar drazzibdrazzib Root package jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/0000755000175000017500000000000011720500104020420 5ustar drazzibdrazzibjajuk-1.9.6.orig/src/main/java/org/jajuk/ui/perspectives/0000755000175000017500000000000011720500104023134 5ustar drazzibdrazzibjajuk-1.9.6.orig/src/main/java/org/jajuk/ui/perspectives/ConfigurationPerspective.java0000644000175000017500000000304611720500104031023 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.perspectives; import javax.swing.ImageIcon; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; /** * Configuration perspective. */ public class ConfigurationPerspective extends PerspectiveAdapter { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /* * (non-Javadoc) * * @see org.jajuk.ui.IPerspective#getDesc() */ @Override public String getDesc() { return Messages.getString("Perspective_Description_Configuration"); } /* (non-Javadoc) * @see org.jajuk.ui.perspectives.IPerspective#getIcon() */ @Override public ImageIcon getIcon() { return IconLoader.getIcon(JajukIcons.PERSPECTIVE_CONFIGURATION); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/perspectives/package.html0000644000175000017500000000014311720500104025413 0ustar drazzibdrazzib

Interfaces and implementations of standard Jajuk perspectives

jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/perspectives/IPerspective.java0000644000175000017500000000365111720500104026406 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.perspectives; import java.awt.Container; import java.util.Set; import javax.swing.ImageIcon; import org.jajuk.ui.views.IView; /** * Representation of a perspective. */ public interface IPerspective { /** * Gets the id. * * @return the perspective's id */ String getID(); /** * Gets the desc. * * @return the desc */ String getDesc(); /** * Return the icon. * * @return perspective icon */ ImageIcon getIcon(); /** * Gets the views. * * @return Arraylist views registered in the perspective. */ Set getViews(); /** * Gets the content pane. * * @return Returns the desktop. */ Container getContentPane(); /** * Serialize the perspective. * * @throws Exception the exception */ void commit() throws Exception; /** * Deserialize the perspective. * * @throws Exception the exception */ void load() throws Exception; /** * Restore defaults views. */ void restoreDefaults(); /** * As been selected flag. * * @param b DOCUMENT_ME */ void setAsBeenSelected(boolean b); } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/perspectives/SimplePerspective.java0000644000175000017500000000307611720500104027450 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.perspectives; import javax.swing.ImageIcon; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; /** * Simple perspective, contains only the logical table view. */ public class SimplePerspective extends PerspectiveAdapter { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /* * (non-Javadoc) * * @see org.jajuk.ui.perspectives.IPerspective#getDesc() */ @Override public String getDesc() { return Messages.getString("Perspective_Description_Simple"); } /* (non-Javadoc) * @see org.jajuk.ui.perspectives.IPerspective#getIcon() */ @Override public ImageIcon getIcon() { return IconLoader.getIcon(JajukIcons.PERSPECTIVE_SIMPLE); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/perspectives/StatPerspective.java0000644000175000017500000000302411720500104027123 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.perspectives; import javax.swing.ImageIcon; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; /** * Statistics perspective. */ public class StatPerspective extends PerspectiveAdapter { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /* * (non-Javadoc) * * @see org.jajuk.ui.IPerspective#getDesc() */ @Override public String getDesc() { return Messages.getString("Perspective_Description_Statistics"); } /* (non-Javadoc) * @see org.jajuk.ui.perspectives.IPerspective#getIcon() */ @Override public ImageIcon getIcon() { return IconLoader.getIcon(JajukIcons.PERSPECTIVE_STATISTICS); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/perspectives/AlbumsPerspective.java0000644000175000017500000000307411720500104027440 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.perspectives; import javax.swing.ImageIcon; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; /** * Catalog perspective, shows all default covers by album. */ public class AlbumsPerspective extends PerspectiveAdapter { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /* * (non-Javadoc) * * @see org.jajuk.ui.perspectives.IPerspective#getDesc() */ @Override public String getDesc() { return Messages.getString("Perspective_Description_Albums"); } /* (non-Javadoc) * @see org.jajuk.ui.perspectives.IPerspective#getIcon() */ @Override public ImageIcon getIcon() { return IconLoader.getIcon(JajukIcons.PERSPECTIVE_CATALOG); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/perspectives/DisplayPerspective.java0000644000175000017500000000311611720500104027617 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.perspectives; import javax.swing.ImageIcon; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; /** * Player perspective, contains view useful to be displayed during playing. */ public class DisplayPerspective extends PerspectiveAdapter { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /* * (non-Javadoc) * * @see org.jajuk.ui.perspectives.IPerspective#getDesc() */ @Override public String getDesc() { return Messages.getString("Perspective_Description_Display"); } /* (non-Javadoc) * @see org.jajuk.ui.perspectives.IPerspective#getIcon() */ @Override public ImageIcon getIcon() { return IconLoader.getIcon(JajukIcons.PERSPECTIVE_PLAYER); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/perspectives/PlaylistsPerspective.java0000644000175000017500000000310611720500104030175 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.perspectives; import javax.swing.ImageIcon; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; /** * Contains all views that deals with playlist manipulation. */ public class PlaylistsPerspective extends PerspectiveAdapter { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /* * (non-Javadoc) * * @see org.jajuk.ui.perspectives.IPerspective#getDesc() */ @Override public String getDesc() { return Messages.getString("Perspective_Description_Playlists"); } /* (non-Javadoc) * @see org.jajuk.ui.perspectives.IPerspective#getIcon() */ @Override public ImageIcon getIcon() { return IconLoader.getIcon(JajukIcons.PERSPECTIVE_PLAYLISTS); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/perspectives/PerspectiveAdapter.java0000644000175000017500000002572711720500104027606 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.perspectives; import com.vlsolutions.swing.docking.AutoHideButton; import com.vlsolutions.swing.docking.AutoHideExpandPanel; import com.vlsolutions.swing.docking.DockKey; import com.vlsolutions.swing.docking.Dockable; import com.vlsolutions.swing.docking.DockableResolver; import com.vlsolutions.swing.docking.DockableState; import com.vlsolutions.swing.docking.DockingContext; import com.vlsolutions.swing.docking.DockingDesktop; import com.vlsolutions.swing.docking.event.DockingActionCloseEvent; import com.vlsolutions.swing.docking.event.DockingActionDockableEvent; import com.vlsolutions.swing.docking.event.DockingActionEvent; import com.vlsolutions.swing.docking.event.DockingActionListener; import java.awt.Component; import java.awt.Container; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.net.URL; import java.util.HashSet; import java.util.Set; import java.util.StringTokenizer; import javax.xml.parsers.ParserConfigurationException; import org.jajuk.events.ObservationManager; import org.jajuk.events.Observer; import org.jajuk.services.core.SessionService; import org.jajuk.ui.views.IView; import org.jajuk.ui.views.ViewAdapter; import org.jajuk.ui.views.ViewFactory; import org.jajuk.util.Const; import org.jajuk.util.Messages; import org.jajuk.util.UtilSystem; import org.jajuk.util.log.Log; import org.xml.sax.SAXException; /** * Perspective adapter, provide default implementation for perspectives. */ public abstract class PerspectiveAdapter extends DockingDesktop implements IPerspective, Const { /** The Constant XML_EXT. DOCUMENT_ME */ private static final String XML_EXT = ".xml"; /** Generated serialVersionUID. */ private static final long serialVersionUID = 698162872976536725L; /** Perspective id (class). */ private final String sID; /** As been selected flag (workaround for VLDocking issue when saving position). */ protected boolean bAsBeenSelected = false; /** * Constructor. */ public PerspectiveAdapter() { super(); this.sID = getClass().getName(); } /* * (non-Javadoc) * * @see org.jajuk.ui.perspectives.IPerspective#getID() */ @Override public String getID() { return sID; } /** * toString method. * * @return the string */ @Override public String toString() { return "Perspective[name=" + getID() + " description='" + getDesc() + "]"; } /* * (non-Javadoc) * * @see org.jajuk.ui.perspectives.IPerspective#commit() */ @Override public void commit() throws IOException { // workaround for a VLDocking issue + performances if (!bAsBeenSelected) { return; } // The writeXML method must be called in the EDT to avoid freezing, it // requires a lock some UI components File saveFile = SessionService.getConfFileByPath(getClass().getSimpleName() + XML_EXT); BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(saveFile)); try { writeXML(out); out.flush(); } finally { out.close(); } } /* * (non-Javadoc) * * @see org.jajuk.ui.perspectives.IPerspective#load() */ @Override public void load() throws IOException, ParserConfigurationException, SAXException { // Try to read XML conf file from home directory File loadFile = SessionService.getConfFileByPath(getClass().getSimpleName() + XML_EXT); // If file doesn't exist (normally only at first install), read // perspective conf from the jar URL url = loadFile.toURI().toURL(); if (!loadFile.exists()) { url = UtilSystem.getResource(FILE_DEFAULT_PERSPECTIVES_PATH + '/' + getClass().getSimpleName() + XML_EXT); } BufferedInputStream in = new BufferedInputStream(url.openStream()); // then, load the workspace try { DockingContext ctx = new DockingContext(); DockableResolver resolver = new DockableResolver() { @Override public Dockable resolveDockable(String keyName) { Dockable view = null; try { StringTokenizer st = new StringTokenizer(keyName, "/"); String className = st.nextToken(); int id = Integer.parseInt(st.nextToken()); view = ViewFactory.createView(Class.forName(className), PerspectiveAdapter.this, id); } catch (Exception e) { Log.error(e); } return view; } }; // register a listener to unregister the view upon closing ctx.addDockingActionListener(new DockingActionListener() { @Override public void dockingActionPerformed(DockingActionEvent dockingactionevent) { // on closing/removing of a view try to unregister it at the // ObservationManager if (dockingactionevent instanceof DockingActionCloseEvent) { Dockable obj = ((DockingActionDockableEvent) dockingactionevent).getDockable(); if (obj instanceof Observer) { ObservationManager.unregister((Observer) obj); } // it seems the Docking-library does not unregister these things by itself // so we need to do it on our own here as well. We create the Dockable (i.e. // the View) from scratch every time (see constructor of JajukJMenuBar where we create // the menu entries to add new views and ViewFactory) unregisterDockable(obj); // workaround for DockingDesktop-leaks, we need to remove the Dockable from the // "TitleBar" // if it is one of those that are hidden on the left side. removeFromDockingDesktop(PerspectiveAdapter.this, obj); // do some additional cleanup on the View itself if necessary if (obj instanceof ViewAdapter) { ((ViewAdapter) obj).cleanup(); } } } @Override public boolean acceptDockingAction(DockingActionEvent dockingactionevent) { // always accept here return true; } }); ctx.setDockableResolver(resolver); setContext(ctx); ctx.addDesktop(this); try { ctx.readXML(in); } catch (Exception e) { // error parsing the file, user can't be blocked, use // default conf Log.error(e); Log.debug("Error parsing conf file, use defaults - " + getID()); url = UtilSystem.getResource(FILE_DEFAULT_PERSPECTIVES_PATH + '/' + getClass().getSimpleName() + XML_EXT); in = new BufferedInputStream(url.openStream()); ctx.readXML(in); } } finally { in.close(); // stream isn't closed } } /** * Helper method that performs some additional cleanup for the Dockable. * * @param c The Container to look at, usually the DockingDesktop, i.e. * the PerspectiveAdapter in this case. * @param dockable The Dockable to remove/replace. */ private static void removeFromDockingDesktop(Container c, Dockable dockable) { /** * walk through the list of components and replace the Dockable with * an empty new one whereever necessary to free all references */ for (int i = 0; i < c.getComponentCount(); i++) { Component comp = c.getComponent(i); // on the AutoHideExpandPanel, we need to set a new Dockable on the TitleBar // as it otherwise keeps the Dockable as "target" if (comp instanceof AutoHideExpandPanel) { AutoHideExpandPanel panel = (AutoHideExpandPanel) comp; panel.getTitleBar().setDockable(new Dockable() { @Override public DockKey getDockKey() { return new DockKey(); } @Override public Component getComponent() { return null; } }); } // the AutoHideButton points at the dockable, replace it with a new one here as well if (comp instanceof AutoHideButton) { AutoHideButton button = (AutoHideButton) comp; if (button.getDockable() == dockable) { // set an empty dockable to free up this one... button.init(new Dockable() { @Override public DockKey getDockKey() { return new DockKey(); } @Override public Component getComponent() { return null; } }, button.getZone()); } } // recursively call the Container to also look at it's components if (comp instanceof Container) { removeFromDockingDesktop((Container) comp, dockable); } } } /* * (non-Javadoc) * * @see org.jajuk.ui.perspectives.IPerspective#getContentPane() */ @Override public Container getContentPane() { return this; } /* * (non-Javadoc) * * @see org.jajuk.ui.IPerspective#restaureDefaults() */ @Override public void restoreDefaults() { // SHOULD BE CALLED ONLY FOR THE CURRENT PERSPECTIVE // to ensure views are not invisible try { // Remove current conf file to force using default file from the // jar File loadFile = SessionService.getConfFileByPath(getClass().getSimpleName() + XML_EXT); // lazy deletion, the file can be already removed by a previous reset loadFile.delete(); // Remove all registered dockables DockableState[] ds = getDockables(); for (DockableState element : ds) { close(element.getDockable()); } // force reload load(); // set perspective again to force UI refresh PerspectiveManager.setCurrentPerspective(this); } catch (Exception e) { // display an error message Log.error(e); Messages.showErrorMessage(163); } } /* * (non-Javadoc) * * @see org.jajuk.ui.IPerspective#setAsBeenSelected() */ @Override public void setAsBeenSelected(boolean b) { bAsBeenSelected = b; } /* * (non-Javadoc) * * @see org.jajuk.ui.perspectives.IPerspective#getViews() */ @Override public Set getViews() { Set views = new HashSet(); DockableState[] dockables = getDockables(); for (DockableState element : dockables) { views.add((IView) element.getDockable()); } return views; } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/perspectives/InfoPerspective.java0000644000175000017500000000311611720500104027105 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.perspectives; import javax.swing.ImageIcon; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; /** * Information perspective, display various information about played tracks. */ public class InfoPerspective extends PerspectiveAdapter { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /* * (non-Javadoc) * * @see org.jajuk.ui.perspectives.IPerspective#getDesc() */ @Override public String getDesc() { return Messages.getString("Perspective_Description_Info"); } /* (non-Javadoc) * @see org.jajuk.ui.perspectives.IPerspective#getIcon() */ @Override public ImageIcon getIcon() { return IconLoader.getIcon(JajukIcons.PERSPECTIVE_INFORMATION); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/perspectives/TracksPerspective.java0000644000175000017500000000301411720500104027436 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.perspectives; import javax.swing.ImageIcon; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; /** * Logical perspective. */ public class TracksPerspective extends PerspectiveAdapter { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /* * (non-Javadoc) * * @see org.jajuk.ui.IPerspective#getDesc() */ @Override public String getDesc() { return Messages.getString("Perspective_Description_Tracks"); } /* (non-Javadoc) * @see org.jajuk.ui.perspectives.IPerspective#getIcon() */ @Override public ImageIcon getIcon() { return IconLoader.getIcon(JajukIcons.PERSPECTIVE_LOGICAL); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/perspectives/FilesPerspective.java0000644000175000017500000000301411720500104027251 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.perspectives; import javax.swing.ImageIcon; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; /** * Physical perspective. */ public class FilesPerspective extends PerspectiveAdapter { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /* * (non-Javadoc) * * @see org.jajuk.ui.IPerspective#getDesc() */ @Override public String getDesc() { return Messages.getString("Perspective_Description_Files"); } /* (non-Javadoc) * @see org.jajuk.ui.perspectives.IPerspective#getIcon() */ @Override public ImageIcon getIcon() { return IconLoader.getIcon(JajukIcons.PERSPECTIVE_PHYSICAL); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/perspectives/PerspectiveManager.java0000644000175000017500000002234411720500104027570 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.perspectives; import java.awt.BorderLayout; import java.awt.Component; import java.io.File; import java.util.Arrays; import java.util.HashMap; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; import javax.swing.JPanel; import javax.swing.SwingUtilities; import org.jajuk.events.JajukEvent; import org.jajuk.events.JajukEvents; import org.jajuk.events.ObservationManager; import org.jajuk.services.core.SessionService; import org.jajuk.services.startup.StartupGUIService; import org.jajuk.ui.views.IView; import org.jajuk.ui.widgets.PerspectiveBarJPanel; import org.jajuk.ui.windows.JajukMainWindow; import org.jajuk.util.Conf; import org.jajuk.util.Const; import org.jajuk.util.Messages; import org.jajuk.util.UpgradeManager; import org.jajuk.util.UtilGUI; import org.jajuk.util.error.JajukException; import org.jajuk.util.log.Log; /** * Perspectives Manager. */ public final class PerspectiveManager { /** Current perspective. */ private static IPerspective currentPerspective = null; /** Perspective name -> perspective. */ private static Map hmNameInstance = new HashMap(10); /** perspective, required despite the Map above in order to keep the order of the perspectives as the order in the Map is undefined. */ private static Set perspectives = new LinkedHashSet(10); /** List of perspectives that need reset from version n-1. */ // None perspective to reset from 1.6 to 1.7 private static String[] perspectivesToReset = new String[] {}; /** * private constructor to avoid instantiating utility class. */ private PerspectiveManager() { } /** * Reset registered perspectives. */ private static void reset() { perspectives.clear(); hmNameInstance.clear(); } /** * Load configuration file. * * @throws JajukException the jajuk exception */ public static void load() throws JajukException { registerDefaultPerspectives(); if (UpgradeManager.isUpgradeDetected()) { /* * Force loading of defaults perspectives * * - If this is a migration from a version n-i with i >1, we force a full reset * * - If it is a migration from version n-1, only reset perspectives with changes (see * perspectiveList) */ if (UpgradeManager.doNeedPerspectiveResetAtUpgrade()) { // upgrade message Messages.showInfoMessage(Messages.getString("Note.0")); resetPerspectives(); } } // Load each perspective try { for (IPerspective perspective : getPerspectives()) { perspective.load(); } } catch (Exception e) { throw new JajukException(108, e); } } /** * Reset perspectives. * DOCUMENT_ME */ private static void resetPerspectives() { List perspectivesToReset = Arrays.asList(PerspectiveManager.perspectivesToReset); for (IPerspective perspective : getPerspectives()) { String className = perspective.getClass().getSimpleName(); // Remove current conf file to force using default file from the // jar File loadFile = SessionService.getConfFileByPath(className + ".xml"); if (loadFile.exists() && (perspectivesToReset.contains(className) || UpgradeManager.isMajorMigration())) { loadFile.delete(); } } } /** * Begins management. */ public static void init() { // Use Simple perspective as a default IPerspective perspective = hmNameInstance.get(SimplePerspective.class.getName()); String sPerspective = StartupGUIService.getDefaultPerspective(); // Check if a default perspective is forced if (sPerspective == null) { sPerspective = Conf.getString(Const.CONF_PERSPECTIVE_DEFAULT); // no? take the configuration ( user last perspective) } perspective = hmNameInstance.get(sPerspective); // If perspective is no more known, take first perspective found if (perspective == null) { perspective = perspectives.iterator().next(); } setCurrentPerspective(perspective); } /* * @see org.jajuk.ui.perspectives.IPerspectiveManager#getCurrentPerspective() */ /** * Gets the current perspective. * * @return the current perspective */ public static IPerspective getCurrentPerspective() { return PerspectiveManager.currentPerspective; } /* * @see org.jajuk.ui.perspectives.IPerspectiveManager#setCurrentPerspective(Perspective) */ /** * Sets the current perspective. * * @param perspective the new current perspective */ protected static void setCurrentPerspective(final IPerspective perspective) { UtilGUI.waiting(); // views display SwingUtilities.invokeLater(new Runnable() { @Override public void run() { perspective.setAsBeenSelected(true); PerspectiveManager.currentPerspective = perspective; for (IView view : perspective.getViews()) { if (!view.isPopulated()) { try { view.initUI(); } catch (Exception e) { Log.error(e); } view.setIsPopulated(true); } // Perform specific view operation at perspective display view.onPerspectiveSelection(); } // Clear the perspective panel JPanel perspectivePanel = JajukMainWindow.getInstance().getPerspectivePanel(); if (perspectivePanel.getComponentCount() > 0) { Component[] components = perspectivePanel.getComponents(); for (Component element : components) { perspectivePanel.remove(element); } } perspectivePanel.add(perspective.getContentPane(), BorderLayout.CENTER); // refresh UI perspectivePanel.revalidate(); perspectivePanel.repaint(); // Select right item in perspective selector PerspectiveBarJPanel.getInstance().setActivated(perspective); // store perspective selection Conf.setProperty(Const.CONF_PERSPECTIVE_DEFAULT, perspective.getID()); UtilGUI.stopWaiting(); // Emit a event ObservationManager.notify(new JajukEvent(JajukEvents.PERSPECTIVE_CHANGED, ObservationManager.getDetailsLastOccurence(JajukEvents.FILE_LAUNCHED))); } }); } /** * Set current perspective. * * @param sPerspectiveID DOCUMENT_ME */ public static void setCurrentPerspective(String sPerspectiveID) { IPerspective perspective = hmNameInstance.get(sPerspectiveID); if (perspective == null) { perspective = perspectives.iterator().next(); } setCurrentPerspective(perspective); } /** * Get all perspectives. * * @return all perspectives as a collection */ public static Set getPerspectives() { return perspectives; } /** * Saves perspectives and views position in the perspective.xml file Must be * executed in EDT to avoid dead locks on getComponent() * * @throws Exception the exception */ public static void commit() throws Exception { for (IPerspective perspective : getPerspectives()) { perspective.commit(); } } /** * Register default perspective configuration. Will be overwritten by * perspective.xml parsing if it exists *

* We set an icon for each perspective, resizing it if user selected another * size than 40x40 *

*/ private static void registerDefaultPerspectives() { reset(); // Simple perspective registerPerspective(new SimplePerspective()); // Files perspective registerPerspective(new FilesPerspective()); // Tracks perspective registerPerspective(new TracksPerspective()); // Catalog perspective registerPerspective(new AlbumsPerspective()); // Playlists perspective registerPerspective(new PlaylistsPerspective()); // Display perspective registerPerspective(new DisplayPerspective()); // Information perspective registerPerspective(new InfoPerspective()); // Configuration perspective registerPerspective(new ConfigurationPerspective()); // Stats perspective registerPerspective(new StatPerspective()); } /** * Register a new perspective. * * @param perspective DOCUMENT_ME * * @return registered perspective */ private static IPerspective registerPerspective(IPerspective perspective) { hmNameInstance.put(perspective.getID(), perspective); perspectives.add(perspective); return perspective; } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/widgets/0000755000175000017500000000000011720500104022066 5ustar drazzibdrazzibjajuk-1.9.6.orig/src/main/java/org/jajuk/ui/widgets/SmartPlaylistView.java0000644000175000017500000000705111720500104026377 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.widgets; import javax.swing.BorderFactory; import javax.swing.JLabel; import javax.swing.JPanel; import org.jajuk.base.Playlist; import org.jajuk.base.Playlist.Type; import org.jajuk.base.SmartPlaylist; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; /** * A physical playlist icon + text. */ public class SmartPlaylistView extends JPanel { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** Icon. */ private JLabel jlIcon; /** DOCUMENT_ME. */ private final Type type; /** Associated playlist. */ private Playlist plf; /** * Constructor. * * @param type DOCUMENT_ME */ public SmartPlaylistView(Playlist.Type type) { this.type = type; if (type == Type.NEW) { jlIcon = new JLabel(IconLoader.getIcon(JajukIcons.PLAYLIST_NEW)); plf = new SmartPlaylist(Type.NEW, Integer.toString(Playlist.Type.NEW.ordinal()), getName(), null); } else if (type == Type.BESTOF) { jlIcon = new JLabel(IconLoader.getIcon(JajukIcons.PLAYLIST_BESTOF)); plf = new SmartPlaylist(Type.BESTOF, Integer.toString(Playlist.Type.BESTOF.ordinal()), getName(), null); } else if (type == Type.BOOKMARK) { jlIcon = new JLabel(IconLoader.getIcon(JajukIcons.PLAYLIST_BOOKMARK)); plf = new SmartPlaylist(Type.BOOKMARK, Integer.toString(Playlist.Type.BOOKMARK.ordinal()), getName(), null); } else if (type == Type.NOVELTIES) { jlIcon = new JLabel(IconLoader.getIcon(JajukIcons.PLAYLIST_NOVELTIES)); plf = new SmartPlaylist(Type.NOVELTIES, Integer.toString(Playlist.Type.NOVELTIES.ordinal()), getName(), null); } setToolTipText(getName()); add(jlIcon); getIcon().setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); } /** * Gets the type. * * @return Returns the Type. */ public Type getType() { return type; } /** * Gets the playlist. * * @return Associated playlist */ public Playlist getPlaylist() { return plf; } /** * Get a name for this playlist item. * * @return playlist item name ( playlist name or label for special ones ) */ @Override public final String getName() { String sOut = ""; if (type == Type.NEW) { sOut = Messages.getString("PlaylistFileItem.2"); } else if (type == Type.BESTOF) { sOut = Messages.getString("PlaylistFileItem.4"); } else if (type == Type.BOOKMARK) { sOut = Messages.getString("PlaylistFileItem.3"); } else if (type == Type.NOVELTIES) { sOut = Messages.getString("PlaylistFileItem.1"); } return sOut; } /** * Gets the icon. * * @return icon */ public JLabel getIcon() { return this.jlIcon; } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/widgets/TrackPositionSliderToolbar.java0000644000175000017500000002614711720500104030222 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.widgets; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.MouseWheelEvent; import java.awt.event.MouseWheelListener; import java.text.DecimalFormat; import java.util.HashSet; import java.util.Set; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JSlider; import javax.swing.SwingUtilities; import javax.swing.Timer; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import net.miginfocom.swing.MigLayout; import org.jajuk.events.JajukEvent; import org.jajuk.events.JajukEvents; import org.jajuk.events.ObservationManager; import org.jajuk.events.Observer; import org.jajuk.services.players.Player; import org.jajuk.services.players.QueueModel; import org.jajuk.ui.helpers.JajukTimer; import org.jajuk.util.Conf; import org.jajuk.util.Const; import org.jajuk.util.Messages; import org.jajuk.util.UtilFeatures; import org.jajuk.util.UtilString; import org.jajuk.util.log.Log; /** * DOCUMENT_ME. */ public class TrackPositionSliderToolbar extends JPanel implements ChangeListener, MouseWheelListener, Observer { /** Generic playing position toolbar, used in information panel a full screen. */ private static final long serialVersionUID = 1L; /** Last slider manual move date. */ private long lDateLastAdjust; /** DOCUMENT_ME. */ private JSlider jsPosition; /** DOCUMENT_ME. */ private JLabel jlCurrent; /** DOCUMENT_ME. */ String sCurrentStatus; /** Swing Timer to refresh the component. */ private final Timer timer = new Timer(JajukTimer.D_MS_HEARTBEAT, new ActionListener() { @Override public void actionPerformed(ActionEvent e) { try { update(new JajukEvent(JajukEvents.HEART_BEAT)); } catch (Exception ex) { Log.error(ex); } } }); /** * Instantiates a new track position slider toolbar. */ public TrackPositionSliderToolbar() { super(); initGui(); // check if some errors occurred before the view has been displayed if (ObservationManager.containsEvent(JajukEvents.PLAY_ERROR)) { update(new JajukEvent(JajukEvents.PLAY_ERROR, ObservationManager.getDetailsLastOccurence(JajukEvents.PLAY_ERROR))); } // check if some track has been launched before the view has been // displayed UtilFeatures.updateStatus(this); // register for given events ObservationManager.register(this); timer.start(); } /** * Inits the gui. DOCUMENT_ME */ private void initGui() { setLayout(new MigLayout("ins 0 5 0 5", "[70%,fill][30%,grow]")); setToolTipText(Messages.getString("InformationJPanel.7")); jsPosition = new JSlider(0, 100, 0); jsPosition.addChangeListener(this); jsPosition.setOpaque(false); jsPosition.addMouseWheelListener(this); jsPosition.setEnabled(false); jlCurrent = new JLabel(); jlCurrent.setToolTipText(Messages.getString("CommandJPanel.15")); jlCurrent.addMouseListener(new TimeDisplaySwitchMouseAdapter()); add(jsPosition,"grow"); add(jlCurrent,"grow,left"); } /* * (non-Javadoc) * * @see * javax.swing.event.ChangeListener#stateChanged(javax.swing.event.ChangeEvent * ) */ @Override public void stateChanged(ChangeEvent e) { if (e.getSource() == jsPosition && !jsPosition.getValueIsAdjusting()) { lDateLastAdjust = System.currentTimeMillis(); setPosition((float) jsPosition.getValue() / 100); } } /** * Call a seek. * * @param fPosition DOCUMENT_ME */ private void setPosition(final float fPosition) { new Thread("TrackSlider Position Thread") { @Override public void run() { Player.seek(fPosition); } }.start(); } /* * (non-Javadoc) * * @seejava.awt.event.MouseWheelListener#mouseWheelMoved(java.awt.event. * MouseWheelEvent) */ @Override public void mouseWheelMoved(MouseWheelEvent e) { if (e.getSource() == jsPosition) { int iOld = jsPosition.getValue(); int iNew = iOld - (e.getUnitsToScroll() * 3); jsPosition.setValue(iNew); } } /** * Gets the current position. * * @return Position value */ public int getCurrentPosition() { return this.jsPosition.getValue(); } /** * Set the current status for current track ex : 01:01:01/02:02:02. * * @param lTime DOCUMENT_ME * @param length DOCUMENT_ME */ public final void setCurrentTimeMessage(long lTime, long length) { String string; int timeFormat = 0; // Set the required decimal precision for percentage here DecimalFormat df = new DecimalFormat("0"); // (0.##) for 2 decimal places try { timeFormat = Conf.getInt(Const.CONF_FORMAT_TIME_ELAPSED); } catch (Exception e) { Log.debug(e); } float lTimePercent = 0f; if (lTime > 0) { lTimePercent = (float) ((float) lTime / (float) length * 100.0); } switch (timeFormat) { /* * same as default... case 0: { string = UtilString.formatTimeBySec(lTime) + * " / " + UtilString.formatTimeBySec(length); break; } */ case 1: { string = "-" + UtilString.formatTimeBySec(length - lTime) + " / " + UtilString.formatTimeBySec(length); break; } case 2: { string = df.format(lTimePercent) + " % / " + UtilString.formatTimeBySec(length); break; } case 3: { string = df.format(lTimePercent - 100f) + " % / " + UtilString.formatTimeBySec(length); break; } default: { string = UtilString.formatTimeBySec(lTime) + " / " + UtilString.formatTimeBySec(length); } } sCurrentStatus = string; jlCurrent.setText(string); } /* * (non-Javadoc) * * @see org.jajuk.events.Observer#getRegistrationKeys() */ @Override public Set getRegistrationKeys() { Set eventSubjectSet = new HashSet(); eventSubjectSet.add(JajukEvents.ZERO); eventSubjectSet.add(JajukEvents.PLAY_ERROR); eventSubjectSet.add(JajukEvents.PLAYER_PAUSE); eventSubjectSet.add(JajukEvents.PLAYER_RESUME); eventSubjectSet.add(JajukEvents.PLAYER_STOP); return eventSubjectSet; } /* * (non-Javadoc) * * @see org.jajuk.events.Observer#update(org.jajuk.events.JajukEvent) */ @Override public final void update(final JajukEvent event) { final JajukEvents subject = event.getSubject(); // do not insert this subject inside the invokeLater because we have to // leave the awt dispatcher called inside the setMessage and THEN, sleep // for 2 secs. if (JajukEvents.PLAY_ERROR.equals(subject)) { try { // we synchronize this code to make sure error message is // visible all 2 secs synchronized (this) { // reset data setCurrentTimeMessage(0, 0); } } catch (Exception e) { Log.error(e); } } else { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { if (JajukEvents.HEART_BEAT.equals(subject) && !QueueModel.isStopped() && !Player.isPaused()) { long length = JajukTimer.getInstance().getCurrentTrackTotalTime(); long lTime = JajukTimer.getInstance().getCurrentTrackEllapsedTime(); int iPos = (int) (100 * Player.getCurrentPosition()); setCurrentTimeMessage(lTime, length); // Make sure to enable the slider if (!jsPosition.isEnabled()) { jsPosition.setEnabled(true); } // if position is adjusting, don't disturb user if (jsPosition.getValueIsAdjusting() || Player.isSeeking()) { return; } // make sure not to set to old position if ((System.currentTimeMillis() - lDateLastAdjust) < 2000) { return; } // remove and re-add listener to make sure not to add it // twice jsPosition.removeChangeListener(TrackPositionSliderToolbar.this); jsPosition.setValue(iPos); jsPosition.addChangeListener(TrackPositionSliderToolbar.this); } else if (JajukEvents.ZERO.equals(subject) || JajukEvents.PLAYER_STOP.equals(subject)) { setCurrentTimeMessage(0, 0); jsPosition.setEnabled(false); jsPosition.removeMouseWheelListener(TrackPositionSliderToolbar.this); jsPosition.removeChangeListener(TrackPositionSliderToolbar.this); // use set value, not setPosition that would cause // a seek that could fail with some formats jsPosition.setValue(0); // reset startup position Conf.setProperty(Const.CONF_STARTUP_LAST_POSITION, "0"); jsPosition.addMouseWheelListener(TrackPositionSliderToolbar.this); jsPosition.addChangeListener(TrackPositionSliderToolbar.this); } else if (JajukEvents.PLAYER_PAUSE.equals(subject)) { jsPosition.setEnabled(false); jsPosition.removeMouseWheelListener(TrackPositionSliderToolbar.this); jsPosition.removeChangeListener(TrackPositionSliderToolbar.this); } else if (JajukEvents.PLAYER_RESUME.equals(subject)) { // Avoid adding listeners twice if (jsPosition.getMouseWheelListeners().length == 0) { jsPosition.addMouseWheelListener(TrackPositionSliderToolbar.this); } if (jsPosition.getChangeListeners().length == 0) { jsPosition.addChangeListener(TrackPositionSliderToolbar.this); } jsPosition.setEnabled(true); } } }); } } /** * Gets the current status message. * * @return the current status message */ public String getCurrentStatusMessage() { return sCurrentStatus; } /** * Small MouseAdapter to loop through the different ways of displaying the * elapsed time. */ private final class TimeDisplaySwitchMouseAdapter extends MouseAdapter { /* (non-Javadoc) * @see java.awt.event.MouseAdapter#mouseClicked(java.awt.event.MouseEvent) */ @Override public void mouseClicked(MouseEvent e) { int currentFormat = Conf.getInt(Const.CONF_FORMAT_TIME_ELAPSED); Conf.setProperty(Const.CONF_FORMAT_TIME_ELAPSED, Integer.toString(((currentFormat + 1) % Const.FORMAT_TIME_ELAPSED_MAX))); } } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/widgets/JajukToast.java0000644000175000017500000000617711720500104025023 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.widgets; import java.awt.Window; import org.jajuk.ui.helpers.animations.AnimationCompletedEvent; import org.jajuk.ui.helpers.animations.AnimationCompletedListener; import org.jajuk.ui.helpers.animations.FadeAnimation; import org.jajuk.ui.helpers.animations.SlideAnimation; import org.jajuk.ui.helpers.animations.SlideAnimation.InDirections; import org.jajuk.ui.helpers.animations.SlideAnimation.ScreenPositions; import org.jajuk.ui.helpers.animations.SlideAnimation.StartingPositions; import org.jajuk.util.log.Log; /** * Animated information dialog that appears and disappears by itself. */ public class JajukToast extends JajukInformationDialog { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** * Instantiates a new jajuk toast. * * @param text DOCUMENT_ME * @param owner parent owner, see #1582 ([Linux] Void entry in task bar for information dialog) */ public JajukToast(String text, Window owner) { super(text, owner); } /* * (non-Javadoc) * * @see org.jajuk.ui.widgets.JajukInformationDialog#display() */ @Override public void display() { SlideAnimation slide = new SlideAnimation(this, ScreenPositions.BOTTOM_RIGHT, StartingPositions.RIGHT, InDirections.LEFT); slide.addAnimationCompletedListener(new AnimationCompletedListener() { @Override public void animationCompleted(final AnimationCompletedEvent e) { final FadeAnimation fade = new FadeAnimation(e.getWindow(), FadeAnimation.Directions.OUT); fade.addAnimationCompletedListener(new AnimationCompletedListener() { @Override public void animationCompleted(AnimationCompletedEvent e) { JajukToast.this.dispose(); } }); new Thread(new Runnable() { @Override public void run() { try { // Keep toast visible some times before beginning the fading (windows only) Thread.sleep(3000); // No fading if user already closed the toast by clicking on it if (!JajukToast.this.isVisible()) { return; } } catch (InterruptedException ex) { Log.error(ex); } fade.animate(1000); } }).start(); } }); slide.animate(2000); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/widgets/JPressButton.java0000644000175000017500000002050211720500104025332 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.widgets; import java.awt.AWTEvent; import java.awt.EventQueue; import java.awt.event.ActionEvent; import java.awt.event.InputEvent; import javax.swing.Action; import javax.swing.DefaultButtonModel; import javax.swing.Icon; import javax.swing.UIManager; import javax.swing.plaf.ButtonUI; /** * A specialized button, firing successive ActionEvent's as long * as the button remains pressed. */ public class JPressButton extends JajukButton { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** The Constant DEFAULT_INTERVAL. DOCUMENT_ME */ private static final long DEFAULT_INTERVAL = 250; /** The interval between successive fireActionPerformed() calls. */ private long actionInterval; /** Re-use the L&F component of a normal JButton. */ private static final String UI_CLASS_ID = "ButtonUI"; /** * Creates a button with no set text or icon and a default action interval. */ public JPressButton() { this(null, null, DEFAULT_INTERVAL); } /** * Creates a button with no set text or icon. * * @param actionInterval the interval between 2 successive actionperformed calls. */ public JPressButton(long actionInterval) { this(null, null, actionInterval); } /** * Creates a button with an icon and a default action interval. * * @param icon the Icon image to display on the button */ public JPressButton(Icon icon) { this(null, icon, DEFAULT_INTERVAL); } /** * Creates a button with an icon. * * @param icon the Icon image to display on the button * @param actionInterval DOCUMENT_ME */ public JPressButton(Icon icon, long actionInterval) { this(null, icon, actionInterval); } /** * Creates a button with text and a default action interval. * * @param text the text of the button */ public JPressButton(String text) { this(text, null, DEFAULT_INTERVAL); } /** * Creates a button with text. * * @param text the text of the button * @param actionInterval DOCUMENT_ME */ public JPressButton(String text, long actionInterval) { this(text, null, actionInterval); } /** * Creates a button where properties are taken from the Action * supplied. The default action interval is used. * * @param a the Action used to specify the new button */ public JPressButton(Action a) { this(a, DEFAULT_INTERVAL); setAction(a); } /** * Creates a button where properties are taken from the Action * supplied. * * @param a the Action used to specify the new button * @param actionInterval DOCUMENT_ME */ public JPressButton(Action a, long actionInterval) { this(); this.actionInterval = actionInterval; setAction(a); } /** * Creates a button with initial text and an icon and a default action * interval. * * @param text the text of the button * @param icon the Icon image to display on the button */ public JPressButton(String text, Icon icon) { this(text, icon, DEFAULT_INTERVAL); } /** * Creates a button with initial text and an icon. * * @param text the text of the button * @param icon the Icon image to display on the button * @param actionInterval DOCUMENT_ME */ public JPressButton(String text, Icon icon, long actionInterval) { this.actionInterval = actionInterval; // Create the model setModel(new PressButtonModel(this)); // initialize init(text, icon); // Set border setRolloverEnabled(true); } /** * Gets the action interval. * * @return the used interval between two successive calls to actionPerformed. */ public long getActionInterval() { return actionInterval; } /** * Sets the action interval. * * @param actionInterval sets the interval between two successive calls to actionPerformed. */ public void setActionInterval(long actionInterval) { this.actionInterval = actionInterval; } /** * Resets the UI property to a value from the current look and feel. * * @see javax.swing.JComponent#updateUI */ @Override public void updateUI() { setUI((ButtonUI) UIManager.getUI(this)); } /** * Returns a string that specifies the name of the L&F class that renders this * component. * * @return the string "ButtonUI" * * @see javax.swing.JComponent#getUIClassID * @see javax.swing.UIDefaults#getUI */ @Override public String getUIClassID() { return UI_CLASS_ID; } /** * Button model for the PressButton. The model launches a * thread when the button remains pressed. The ends whenever the button * releases. * * @see ActionThread */ public static class PressButtonModel extends DefaultButtonModel { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** DOCUMENT_ME. */ private ActionThread thread; /** DOCUMENT_ME. */ private final JPressButton button; /** * Instantiates a new press button model. * * @param button DOCUMENT_ME */ public PressButtonModel(JPressButton button) { this.button = button; } /* (non-Javadoc) * @see javax.swing.DefaultButtonModel#setPressed(boolean) */ @Override public void setPressed(boolean b) { if ((isPressed() == b) || !isEnabled()) { return; } if (b) { stateMask |= PRESSED; } else { stateMask &= ~PRESSED; } if (isArmed()) { int modifiers = 0; AWTEvent currentEvent = EventQueue.getCurrentEvent(); if (currentEvent instanceof InputEvent) { modifiers = ((InputEvent) currentEvent).getModifiers(); } else if (currentEvent instanceof ActionEvent) { modifiers = ((ActionEvent) currentEvent).getModifiers(); } if (isPressed() && thread == null) { thread = button.new ActionThread(new ActionEvent(button, ActionEvent.ACTION_PERFORMED, getActionCommand(), EventQueue.getMostRecentEventTime(), modifiers)); thread.start(); } else if (!isPressed() && thread != null) { thread.setActive(false); thread.interrupt(); thread = null; } } fireStateChanged(); } } /** * Thread extension. While alive, fires an actionPerformed * event at a certain interval. */ private class ActionThread extends Thread { /** DOCUMENT_ME. */ private final ActionEvent evt; /** DOCUMENT_ME. */ private boolean active = true; /** DOCUMENT_ME. */ private final long interval; /** * Instantiates a new action thread. * * @param evt DOCUMENT_ME */ public ActionThread(ActionEvent evt) { this(evt, DEFAULT_INTERVAL); } /** * Instantiates a new action thread. * * @param evt DOCUMENT_ME * @param interval DOCUMENT_ME */ public ActionThread(ActionEvent evt, long interval) { super("JPressButton Action Thread"); this.interval = interval; this.evt = evt; } /** * Sets the active. * * @param active the new active */ public void setActive(boolean active) { this.active = active; } /* (non-Javadoc) * @see java.lang.Thread#run() */ @Override public void run() { while (active) { try { fireActionPerformed(evt); Thread.sleep(interval); } catch (InterruptedException e) { // Ignore } } } } }jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/widgets/IconLabel.java0000644000175000017500000001226711720500104024571 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.widgets; import java.awt.Color; import java.awt.Font; import java.util.HashMap; import java.util.Map; import javax.swing.ImageIcon; import org.jajuk.ui.helpers.FontManager; import org.jajuk.ui.helpers.FontManager.JajukFont; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; import org.jajuk.util.log.Log; /** * Encapsulates a label with a text and an icon, used for tables. */ public class IconLabel extends ImageIcon implements Comparable { /** Generated serialVersionUID. */ private static final long serialVersionUID = 3794262035337113611L; /** Text. */ private final String sText; /** Background color. */ private Color cBackground; /** Foreground color. */ private Color cForeground; /** Font. */ private Font font; /** Tooltip. */ private String sTooltip; /** DOCUMENT_ME. */ private static Map cachedIcons = new HashMap(); /** * Constructor. * * @param icon DOCUMENT_ME * @param sText DOCUMENT_ME * @param cBackground DOCUMENT_ME * @param cForeground DOCUMENT_ME * @param font DOCUMENT_ME * @param sTooltip DOCUMENT_ME */ public IconLabel(ImageIcon icon, String sText, Color cBackground, Color cForeground, Font font, String sTooltip) { super(icon.getImage()); this.sText = sText; this.cBackground = cBackground; this.cForeground = cForeground; this.font = font; this.sTooltip = sTooltip; } /** * Instantiates a new icon label. * * @param icon DOCUMENT_ME * @param sText DOCUMENT_ME */ private IconLabel(ImageIcon icon, String sText) { super(icon.getImage()); this.sText = sText; } /** * Gets the text. * * @return Returns the sText. */ public String getText() { return sText; } /** * Gets the background. * * @return Returns the cBackground. */ public Color getBackground() { return cBackground; } /** * Gets the foreground. * * @return Returns the cForeground. */ public Color getForeground() { return cForeground; } /** * Gets the font. * * @return Returns the font. */ public Font getFont() { return font; } /** * toString method. * * @return the string */ @Override public String toString() { return sText; } /** * Gets the tooltip. * * @return Returns the sTooltip. */ public String getTooltip() { return sTooltip; } /* * (non-Javadoc) * * @see java.lang.Comparable#compareTo(T) */ @Override public int compareTo(IconLabel ilOther) { // if no integer value then simply compare tooltip strings if (ilOther.getTooltip() != null && this.getTooltip() != null) { return ilOther.getTooltip().compareTo(getTooltip()); } else { return 0; } } /** * Gets an IconLabel from a cache for memory saving reasons. * Note that this doesn't handle StarIconLabel that owns its own cache. * * @param icon DOCUMENT_ME * * @return the icon */ public static IconLabel getIconLabel(JajukIcons icon) { if (icon == JajukIcons.TRACK_FIFO_PLANNED) { if (!cachedIcons.containsKey(icon)) { cachedIcons.put(icon, new IconLabel(IconLoader.getIcon(JajukIcons.TRACK_FIFO_PLANNED), "", null, null, FontManager.getInstance().getFont(JajukFont.PLANNED), Messages .getString("AbstractPlaylistEditorView.20"))); } } else if (icon == JajukIcons.TRACK_FIFO_REPEAT) { if (!cachedIcons.containsKey(icon)) { cachedIcons.put(icon, new IconLabel(IconLoader.getIcon(icon), "", null, null, null, Messages.getString("AbstractPlaylistEditorView.19"))); } } else if (icon == JajukIcons.TRACK_FIFO_PLAYING) { if (!cachedIcons.containsKey(icon)) { cachedIcons.put(icon, new IconLabel(IconLoader.getIcon(icon), "", null, null, null, Messages.getString("AbstractPlaylistEditorView.29"))); } } else if (icon == JajukIcons.TRACK_FIFO_NORM) { if (!cachedIcons.containsKey(icon)) { cachedIcons.put(icon, new IconLabel(IconLoader.getIcon(icon), "", null, null, null, Messages.getString("AbstractPlaylistEditorView.18"))); } } else { Log.warn("Unsupported icon requested in IconLabel.getIcon(): " + icon.toString()); return null; } return cachedIcons.get(icon); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/widgets/PreferenceToolbar.java0000644000175000017500000002143311720500104026335 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.widgets; import java.awt.Component; import java.awt.Dimension; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.HashSet; import java.util.Set; import javax.swing.JComboBox; import javax.swing.JList; import javax.swing.SwingUtilities; import javax.swing.border.EmptyBorder; import javax.swing.plaf.basic.BasicComboBoxRenderer; import org.jajuk.base.File; import org.jajuk.base.Track; import org.jajuk.events.JajukEvent; import org.jajuk.events.JajukEvents; import org.jajuk.events.ObservationManager; import org.jajuk.events.Observer; import org.jajuk.services.players.QueueModel; import org.jajuk.ui.actions.ActionManager; import org.jajuk.ui.actions.JajukActions; import org.jajuk.util.Const; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; /** * The evaluation toolbar is displayed in command panel and slimbar *

* It contains the ban button to ban the current track
* and an evaluation combo box to evaluate current track *

. */ public class PreferenceToolbar extends JajukJToolbar implements Observer { /** Generated serialVersionUID. */ private static final long serialVersionUID = 3869208492725759632L; /** DOCUMENT_ME. */ JajukButton jbBan; /** DOCUMENT_ME. */ JComboBox jcbPreference; /** DOCUMENT_ME. */ ActionListener listener; /** * Instantiates a new preference toolbar. */ public PreferenceToolbar() { super(); jbBan = new JajukButton(ActionManager.getAction(JajukActions.BAN)); // Preference combo: /* * track preference (from -3 to 3: -3: hate, -2=dislike, -1=ok, +1=like, * +2=love +3=crazy). The preference is a factor given by the user to * increase or decrease a track rate. */ jcbPreference = new JComboBox(); // Add tooltips on combo items jcbPreference.setRenderer(new ComboBoxRenderer()); jcbPreference.setMinimumSize(new Dimension(45, 0)); jcbPreference.setPreferredSize(new Dimension(45, 0)); jcbPreference.setToolTipText(Messages.getString("Preference.0")); jcbPreference.addItem(IconLoader.getIcon(JajukIcons.PREFERENCE_ADORE)); jcbPreference.addItem(IconLoader.getIcon(JajukIcons.PREFERENCE_LOVE)); jcbPreference.addItem(IconLoader.getIcon(JajukIcons.PREFERENCE_LIKE)); jcbPreference.addItem(IconLoader.getIcon(JajukIcons.PREFERENCE_UNSET)); jcbPreference.addItem(IconLoader.getIcon(JajukIcons.PREFERENCE_AVERAGE)); jcbPreference.addItem(IconLoader.getIcon(JajukIcons.PREFERENCE_POOR)); jcbPreference.addItem(IconLoader.getIcon(JajukIcons.PREFERENCE_HATE)); // Set default to unset preference if not playing and to current track value // if playing if (!QueueModel.isStopped() && QueueModel.getPlayingFile() != null) { setPreference(QueueModel.getPlayingFile().getTrack().getLongValue(Const.XML_TRACK_PREFERENCE)); } else { jcbPreference.setSelectedIndex(3); } listener = new ActionListener() { @Override public void actionPerformed(ActionEvent e) { File file = QueueModel.getPlayingFile(); if (file != null) { Track track = file.getTrack(); track.setPreference(3 - jcbPreference.getSelectedIndex()); } // Force immediate rating refresh (without using the rating manager) ObservationManager.notify(new JajukEvent(JajukEvents.RATE_CHANGED)); } }; jcbPreference.addActionListener(listener); add(jbBan); add(jcbPreference); ObservationManager.register(this); // Force initial update if (QueueModel.isPlayingTrack()) { update(new JajukEvent(JajukEvents.FILE_LAUNCHED)); } } /* (non-Javadoc) * @see org.jajuk.events.Observer#getRegistrationKeys() */ @Override public Set getRegistrationKeys() { Set eventSubjectSet = new HashSet(); eventSubjectSet.add(JajukEvents.RATE_CHANGED); eventSubjectSet.add(JajukEvents.FILE_LAUNCHED); eventSubjectSet.add(JajukEvents.ZERO); eventSubjectSet.add(JajukEvents.PLAYER_STOP); eventSubjectSet.add(JajukEvents.BANNED); eventSubjectSet.add(JajukEvents.WEBRADIO_LAUNCHED); return eventSubjectSet; } /** * Set right combo selection for given selection. * * @param preference DOCUMENT_ME */ public final void setPreference(long preference) { jcbPreference.removeActionListener(listener); jcbPreference.setSelectedIndex(-1 * (int) preference + 3); jcbPreference.addActionListener(listener); } /* * (non-Javadoc) * * @see org.jajuk.ui.Observer#update(java.lang.String) */ @Override public final void update(final JajukEvent event) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { // current is null when stopped or when playing web radios, disable the // preference controls if (!QueueModel.isPlayingTrack()) { jbBan.setEnabled(false); jcbPreference.setEnabled(false); return; } File current = QueueModel.getPlayingFile(); if (JajukEvents.RATE_CHANGED.equals(event.getSubject())) { setPreference(current.getTrack().getLongValue(Const.XML_TRACK_PREFERENCE)); } else if (JajukEvents.FILE_LAUNCHED.equals(event.getSubject())) { // Update evaluation toolbar jcbPreference.setEnabled(true); jbBan.setEnabled(true); updateBanIcon(); File file = QueueModel.getPlayingFile(); if (file != null) { setPreference(file.getTrack().getLongValue(Const.XML_TRACK_PREFERENCE)); } } else if (JajukEvents.ZERO.equals(event.getSubject()) || JajukEvents.PLAYER_STOP.equals(event.getSubject())) { jcbPreference.setEnabled(false); jbBan.setEnabled(false); setPreference(0); } else if (JajukEvents.BANNED.equals(event.getSubject())) { updateBanIcon(); } } }); } /** * Update ban icon state according to current track. */ private void updateBanIcon() { if (QueueModel.getPlayingFile() == null || QueueModel.isStopped()) { jbBan.setIcon(IconLoader.getIcon(JajukIcons.BAN)); jbBan.setToolTipText(Messages.getString("BanSelectionAction.1")); } else { Track current = QueueModel.getPlayingFile().getTrack(); if (current.getBooleanValue(Const.XML_TRACK_BANNED)) { jbBan.setIcon(IconLoader.getIcon(JajukIcons.UNBAN)); jbBan.setToolTipText(Messages.getString("UnBanSelectionAction.1")); } else { jbBan.setIcon(IconLoader.getIcon(JajukIcons.BAN)); jbBan.setToolTipText(Messages.getString("BanSelectionAction.1")); } } } /** * DOCUMENT_ME. */ private class ComboBoxRenderer extends BasicComboBoxRenderer { /** Generated serialVersionUID. */ private static final long serialVersionUID = -6943363556191659895L; /* (non-Javadoc) * @see javax.swing.plaf.basic.BasicComboBoxRenderer#getListCellRendererComponent(javax.swing.JList, java.lang.Object, int, boolean, boolean) */ @Override public Component getListCellRendererComponent(final JList list, final Object value, final int index, final boolean isSelected, final boolean cellHasFocus) { super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); switch (index) { case 0: setToolTipText(Messages.getString("Preference.6")); break; case 1: setToolTipText(Messages.getString("Preference.5")); break; case 2: setToolTipText(Messages.getString("Preference.4")); break; case 3: setToolTipText(Messages.getString("Preference.8")); break; case 4: setToolTipText(Messages.getString("Preference.3")); break; case 5: setToolTipText(Messages.getString("Preference.2")); break; case 6: setToolTipText(Messages.getString("Preference.1")); break; } setBorder(new EmptyBorder(0, 3, 0, 3)); return this; } } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/widgets/CopyableLabel.java0000644000175000017500000000267111720500104025435 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision: 3132 $ */ package org.jajuk.ui.widgets; import javax.swing.JTextField; import org.jajuk.util.log.Log; /** * A label that user whom users can copy content */ public class CopyableLabel extends JTextField { /** * Default serial UID */ private static final long serialVersionUID = 1L; /** * Build a Copyable label * @param text : text to display */ public CopyableLabel(String text) { super(text); setBorder(null); setOpaque(false); setEditable(false); } /** * Override setText() method to make sure users can't change it */ public void setText() { Log.debug("Label edition is not allowed"); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/widgets/SteppedComboBox.java0000644000175000017500000000615211720500104025772 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.widgets; import java.awt.Dimension; import java.util.List; import java.util.Vector; import javax.swing.ComboBoxModel; import javax.swing.JComboBox; import javax.swing.plaf.ComboBoxUI; import javax.swing.plaf.basic.BasicComboPopup; import javax.swing.plaf.basic.ComboPopup; import org.jajuk.util.log.Log; /** * Stepped combo box allowing to display a long text in the history bar. */ public class SteppedComboBox extends JComboBox { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** DOCUMENT_ME. */ protected int popupWidth; /** * Instantiates a new stepped combo box. */ public SteppedComboBox() { super(); init(); } /** * Instantiates a new stepped combo box. * * @param aModel DOCUMENT_ME */ public SteppedComboBox(ComboBoxModel aModel) { super(aModel); init(); } /** * Instantiates a new stepped combo box. * * @param items DOCUMENT_ME */ public SteppedComboBox(final Object[] items) { super(items); init(); } /** * Instantiates a new stepped combo box. * * @param items DOCUMENT_ME */ @SuppressWarnings("unchecked") public SteppedComboBox(List items) { super(new Vector(items)); init(); } /** * Sets the popup width. * * @param width the new popup width */ public void setPopupWidth(int width) { popupWidth = width; } /** * Gets the popup size. * * @return the popup size */ public Dimension getPopupSize() { Dimension size = getSize(); if (popupWidth < 1) { popupWidth = size.width; } return new Dimension(popupWidth, size.height); } /** * Inits the. * DOCUMENT_ME */ protected final void init() { try { ComboBoxUI cbui = new org.jvnet.substance.SubstanceComboBoxUI() { @Override protected ComboPopup createPopup() { BasicComboPopup popup1 = new org.jajuk.ui.widgets.JajukBasicComboPopup(comboBox); popup1.getAccessibleContext().setAccessibleParent(comboBox); // Non opaque to avoid being transparent so we can't read // popup content over others text popup1.setOpaque(true); return popup1; } }; setUI(cbui); popupWidth = 0; } catch (Exception e) { Log.error(e); } } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/widgets/package.html0000644000175000017500000000020011720500104024337 0ustar drazzibdrazzib

Various Jajuk specific graphical interface components derivated from Swing and Swingx

jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/widgets/InformationJPanel.java0000644000175000017500000003271511720500104026320 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.widgets; import java.awt.Color; import java.awt.Dimension; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.HashSet; import java.util.Properties; import java.util.Set; import javax.swing.Box; import javax.swing.JLabel; import javax.swing.JToolBar; import javax.swing.SwingUtilities; import javax.swing.Timer; import javax.swing.border.EmptyBorder; import net.miginfocom.swing.MigLayout; import org.jajuk.base.Album; import org.jajuk.base.File; import org.jajuk.events.JajukEvent; import org.jajuk.events.JajukEvents; import org.jajuk.events.ObservationManager; import org.jajuk.events.Observer; import org.jajuk.services.players.Player; import org.jajuk.services.players.QueueModel; import org.jajuk.services.webradio.WebRadio; import org.jajuk.ui.helpers.JajukTimer; import org.jajuk.util.Conf; import org.jajuk.util.Const; import org.jajuk.util.Messages; import org.jajuk.util.UtilFeatures; import org.jajuk.util.UtilGUI; import org.jajuk.util.UtilString; import org.jajuk.util.error.JajukException; import org.jajuk.util.log.Log; import org.jdesktop.swingx.JXPanel; /** * Status / information panel ( static view ). */ public final class InformationJPanel extends JXPanel implements Observer { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** * DOCUMENT_ME. */ public static enum MessageType { /** DOCUMENT_ME. */ INFORMATIVE, /** DOCUMENT_ME. */ ERROR, /** DOCUMENT_ME. */ WARNING } /** Self instance. */ private static InformationJPanel ijp = new InformationJPanel(); /** Swing Timer to refresh the component. */ private final Timer timer = new Timer(JajukTimer.DEFAULT_HEARTBEAT, new ActionListener() { @Override public void actionPerformed(ActionEvent e) { try { update(new JajukEvent(JajukEvents.HEART_BEAT)); } catch (Exception ex) { Log.error(ex); } } }); /** * Singleton access. * * @return the instance */ public static InformationJPanel getInstance() { return ijp; } // widgets declaration /** DOCUMENT_ME. */ public JLabel jlMessage; /** DOCUMENT_ME. */ JLabel jlSelection; /** DOCUMENT_ME. */ JLabel jlTotal; // attributes /** DOCUMENT_ME. */ String sMessage; /** Current message type. */ MessageType type = MessageType.INFORMATIVE; /** DOCUMENT_ME. */ String sSelection; /** DOCUMENT_ME. */ String sTotalStatus; /** DOCUMENT_ME. */ private final TrackPositionSliderToolbar trackPositionSliderToolbar; /** * Instantiates a new information j panel. */ private InformationJPanel() { super(); // message bar JToolBar jtbMessage = new JajukJToolbar(); // Set a zero minimum size to allow user to reduce window width jtbMessage.setMinimumSize(new Dimension(0, 0)); // We use toolbar to display vertical separator lines jlMessage = new JLabel(); setMessage(Messages.getString("JajukWindow.18"), MessageType.INFORMATIVE); jtbMessage.add(jlMessage); jtbMessage.add(Box.createHorizontalGlue()); jtbMessage.addSeparator(); trackPositionSliderToolbar = new TrackPositionSliderToolbar(); jlTotal = new JLabel(); // Make sure to get always 5 px at the left and right of the label jlTotal.setBorder(new EmptyBorder(0,5,0,5)); jlTotal.setToolTipText(Messages.getString("InformationJPanel.5")); // selection bar jlSelection = new JLabel(Messages.getString("InformationJPanel.9")); // Make sure to get always 5 px at the left and right of the label jlSelection.setBorder(new EmptyBorder(0,5,0,3)); // add widgets setLayout(new MigLayout("insets 2", "[40%,grow][40%,grow][10%,grow][10%,grow]")); add(jtbMessage, "grow,left"); add(trackPositionSliderToolbar, "grow"); add(jlTotal, "grow"); add(jlSelection, "grow,right"); // check if some errors occurred before the view has been displayed if (ObservationManager.containsEvent(JajukEvents.PLAY_ERROR)) { update(new JajukEvent(JajukEvents.PLAY_ERROR, ObservationManager .getDetailsLastOccurence(JajukEvents.PLAY_ERROR))); } // check if some track has been launched before the view has been // displayed UtilFeatures.updateStatus(this); // register for given events ObservationManager.register(this); // start timer timer.start(); } /* * (non-Javadoc) * * @see org.jajuk.events.Observer#getRegistrationKeys() */ @Override public Set getRegistrationKeys() { Set eventSubjectSet = new HashSet(); eventSubjectSet.add(JajukEvents.ZERO); eventSubjectSet.add(JajukEvents.FILE_LAUNCHED); eventSubjectSet.add(JajukEvents.PLAY_ERROR); eventSubjectSet.add(JajukEvents.WEBRADIO_LAUNCHED); eventSubjectSet.add(JajukEvents.PLAYER_STOP); eventSubjectSet.add(JajukEvents.THUMB_CREATED); eventSubjectSet.add(JajukEvents.FILE_COPIED); eventSubjectSet.add(JajukEvents.FILE_CONVERSION); return eventSubjectSet; } /** * Gets the message. * * @return the message */ public String getMessage() { return sMessage; } /** * Gets the selection. * * @return the selection */ public String getSelection() { return this.sSelection; } /** * Sets the message. * * @param sMessage DOCUMENT_ME * @param messageType DOCUMENT_ME */ public void setMessage(final String sMessage, final MessageType messageType) { this.sMessage = sMessage; this.type = messageType; SwingUtilities.invokeLater(new Runnable() { @Override public void run() { InformationJPanel.this.sMessage = sMessage; jlMessage.setText(sMessage); jlMessage.setToolTipText(sMessage); //Use default look and feel color for informative if (messageType == MessageType.ERROR) { jlMessage.setForeground(Color.RED); } else if (messageType == MessageType.WARNING) { jlMessage.setForeground(Color.ORANGE); } else if (messageType == MessageType.INFORMATIVE) { jlMessage.setForeground(UtilGUI.getForegroundColor()); } } }); } /** * Sets the selection. * * @param sSelection DOCUMENT_ME */ public void setSelection(String sSelection) { this.sSelection = sSelection; jlSelection.setText(sSelection); jlSelection.setToolTipText(sSelection); } /** * Gets the total time message. * * @return the total time message */ public String getTotalTimeMessage() { return sTotalStatus; } /** * Sets the total time message. * * @param string DOCUMENT_ME */ public void setTotalTimeMessage(String string) { sTotalStatus = string; jlTotal.setText(string); } /* * (non-Javadoc) * * @see org.jajuk.ui.Observer#update(java.lang.String) */ @Override public void update(final JajukEvent event) { final JajukEvents subject = event.getSubject(); // do not insert this subject inside the invokeLater because we have to // leave the awt dispatcher called inside the setMessage and THEN, sleep // for 2 secs. if (JajukEvents.PLAY_ERROR.equals(subject)) { try { // we synchronize this code to make sure error message is // visible all 2 secs synchronized (this) { // set error message Object o = ObservationManager.getDetail(event, Const.DETAIL_CONTENT); // current item is a file // display associated error code is given Object detail = ObservationManager.getDetail(event, Const.DETAIL_REASON); int errorCode = 0; if (detail != null) { errorCode = Integer.parseInt((String) detail); } // Already playing a track if (o instanceof File) { File fCurrent = (File) o; if (detail != null) { setMessage(Messages.getErrorMessage(errorCode) + ": " + fCurrent.getAbsolutePath(), InformationJPanel.MessageType.ERROR); } else {// default message setMessage(Messages.getString("Error.007") + fCurrent.getName(), InformationJPanel.MessageType.ERROR); } } else if (o instanceof WebRadio) { WebRadio radio = (WebRadio) o; // display associated error code is given if (detail != null) { setMessage(Messages.getErrorMessage(errorCode) + ": " + radio.toString(), InformationJPanel.MessageType.ERROR); } else {// default message setMessage(Messages.getString("Error.007") + radio.toString(), InformationJPanel.MessageType.ERROR); } } } } catch (Exception e) { Log.error(e); } } else if (JajukEvents.THUMB_CREATED.equals(subject)) { Album album = (Album) event.getDetails().get(Const.DETAIL_CONTENT); setMessage(Messages.getString("CatalogView.5") + " " + album.getName2(), InformationJPanel.MessageType.INFORMATIVE); } else { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { if (JajukEvents.HEART_BEAT.equals(subject) && !QueueModel.isStopped() && !Player.isPaused() && !QueueModel.isPlayingRadio()) { final long timeToPlay; if (QueueModel.containsRepeat()) { // if repeat mode, total // time has no sense timeToPlay = -1; } else { timeToPlay = JajukTimer.getInstance().getTotalTimeToPlay(); } String sCurrentTotalMessage = UtilString.formatTimeBySec(timeToPlay); setTotalTimeMessage(sCurrentTotalMessage + " [" + QueueModel.getCountTracksLeft() + "]"); } else if (JajukEvents.ZERO.equals(subject) || JajukEvents.PLAYER_STOP.equals(subject)) { // reset startup position Conf.setProperty(Const.CONF_STARTUP_LAST_POSITION, "0"); setTotalTimeMessage("00:00:00"); setMessage(Messages.getString("JajukWindow.18"), InformationJPanel.MessageType.INFORMATIVE); } else if (JajukEvents.FILE_LAUNCHED.equals(subject)) { File file = QueueModel.getPlayingFile(); if (file != null) { String message = ""; String pattern = Conf.getString(Const.CONF_PATTERN_INFORMATION); try { message = UtilString.applyPattern(file, pattern, false, false); } catch (JajukException e) { Log.error(e); } setMessage(message, InformationJPanel.MessageType.INFORMATIVE); } } else if (JajukEvents.WEBRADIO_LAUNCHED.equals(subject)) { setTotalTimeMessage("00:00:00"); if (event.getDetails() == null) { return; } WebRadio radio = (WebRadio) event.getDetails().get(Const.DETAIL_CONTENT); if (radio != null) { String message = Messages.getString("FIFO.14") + " " + radio.getName(); setMessage(message, InformationJPanel.MessageType.INFORMATIVE); } } else if (JajukEvents.FILE_COPIED.equals(subject)) { Properties properties = event.getDetails(); if (properties == null) { // if no property, the party is done setMessage("", InformationJPanel.MessageType.INFORMATIVE); } else { String filename = properties.getProperty(Const.DETAIL_CONTENT); if (filename != null) { setMessage(Messages.getString("Device.45") + filename + "]", InformationJPanel.MessageType.INFORMATIVE); } } } else if (JajukEvents.FILE_CONVERSION.equals(subject)) { Properties properties = event.getDetails(); if (properties == null) { // if no property, the party is done setMessage("", InformationJPanel.MessageType.INFORMATIVE); } else { String filename = properties.getProperty(Const.DETAIL_CONTENT); String target = properties.getProperty(Const.DETAIL_NEW); if (filename != null) { setMessage(Messages.getString("Device.46") + filename + Messages.getString("Device.47") + target + "]", InformationJPanel.MessageType.INFORMATIVE); } } } } }); } } /** * toString() method. * * @return the string */ @Override public String toString() { return getClass().getName(); } /** * Gets the message type. * * @return the message type */ public MessageType getMessageType() { return type; } }jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/widgets/JajukButton.java0000644000175000017500000000462111720500104025174 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.widgets; import javax.swing.Action; import javax.swing.Icon; import javax.swing.JButton; /** * jajuk default button, comes with few GUI default properties. */ public class JajukButton extends JButton { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** * Instantiates a new jajuk button. */ public JajukButton() { this(null, null); } /** * Instantiates a new jajuk button. * * @param icon DOCUMENT_ME */ public JajukButton(Icon icon) { this(null, icon); } /** * Instantiates a new jajuk button. * * @param a DOCUMENT_ME */ public JajukButton(Action a) { super(a); setOpaque(false); setRolloverEnabled(true); } /** * Instantiates a new jajuk button. * * @param text DOCUMENT_ME * @param icon DOCUMENT_ME */ public JajukButton(String text, Icon icon) { super(text, icon); setOpaque(false); } /* (non-Javadoc) * @see javax.swing.AbstractButton#init(java.lang.String, javax.swing.Icon) */ @Override protected void init(String text, Icon icon) { // Hide action text on button if (icon != null) { putClientProperty("hideActionText", Boolean.TRUE); } super.init(text, icon); } /* (non-Javadoc) * @see javax.swing.AbstractButton#configurePropertiesFromAction(javax.swing.Action) */ @Override protected void configurePropertiesFromAction(Action action) { if (action.getValue(Action.SMALL_ICON) != null) { putClientProperty("hideActionText", Boolean.TRUE); } super.configurePropertiesFromAction(action); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/widgets/JajukJToolbar.java0000644000175000017500000000270411720500104025435 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.widgets; import javax.swing.JToolBar; import javax.swing.SwingConstants; /** * Jajuk specific toolbar : non opaque and non floatable. */ public class JajukJToolbar extends JToolBar { /** Generated serialVersionUID. */ private static final long serialVersionUID = 3947108459544670564L; /** * Instantiates a new jajuk j toolbar. */ public JajukJToolbar() { this(SwingConstants.HORIZONTAL); } /** * Instantiates a new jajuk j toolbar. * * @param i DOCUMENT_ME */ public JajukJToolbar(int i) { super(i); setFloatable(false); setOpaque(false); setRollover(true); setBorder(null); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/widgets/SizedButton.java0000644000175000017500000000547611720500104025217 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.widgets; import javax.swing.Action; import javax.swing.Icon; import javax.swing.ImageIcon; import org.jajuk.util.UtilGUI; /** * Button whose icon has a fixed size All icons are resized to 16x16 pixels by * default Override getWidth() and getHeight() methods to set your own * dimensions (we can't set width and height directly because the setIcon method * is called in constructor before we can do anything). */ public class SizedButton extends JajukButton { /** Generated serialVersionUID. */ private static final long serialVersionUID = -3859493434696496345L; /** DOCUMENT_ME. */ private boolean showText = false; /** * Menu item with a fixed 16x216 icon dimension. * * @param action action */ public SizedButton(Action action) { super(action); } /** * Instantiates a new sized button. * * @param text DOCUMENT_ME * @param icon DOCUMENT_ME */ public SizedButton(String text, Icon icon) { super(text, icon); } /** * The Constructor. * * @param action Action * @param bText DOCUMENT_ME */ public SizedButton(Action action, boolean bText) { super(action); this.showText = bText; } /* (non-Javadoc) * @see javax.swing.AbstractButton#setIcon(javax.swing.Icon) */ @Override public void setIcon(Icon icon) { int width = getW(); int height = getH(); super.setIcon(UtilGUI.getResizedImage((ImageIcon) icon, width, height)); } /* (non-Javadoc) * @see javax.swing.AbstractButton#setText(java.lang.String) */ @Override public void setText(String text) { if (showText) { super.setText(text); } else { super.setText(null); } } /** * Return the width in pixels Must be overwritten to get a button with a * resizeable size != 16. * * @return the W */ public int getW() { return 16; } /** * Return the width in pixels Must be overwritten to get a button with a * resizeable size != 16. * * @return the H */ public int getH() { return 16; } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/widgets/JajukInformationDialog.java0000644000175000017500000001046611720500104027332 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.widgets; import java.awt.Color; import java.awt.Window; import java.awt.event.ComponentAdapter; import java.awt.event.ComponentEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import javax.swing.JDialog; import javax.swing.JLabel; import javax.swing.JRootPane; import javax.swing.SwingUtilities; import javax.swing.border.EmptyBorder; import javax.swing.border.LineBorder; import org.jajuk.ui.helpers.FontManager; import org.jajuk.ui.helpers.FontManager.JajukFont; import org.jajuk.util.log.Log; /** * Dialog displayed by slimbar and tray or notificators. */ public class JajukInformationDialog extends JDialog { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** Has this dialog already been hidden ? */ private boolean hasAlreadyBeenHidden = false; /** * The Constructor. * * @param text : text to display * @param owner parent owner, see #1582 ([Linux] Void entry in task bar for information dialog) */ public JajukInformationDialog(String text, Window owner) { // An annoying entry appears under linux in the taskbar. We have no way so far to fix it. // We tried this trick : set the owner window to fix a JRE issue under Linux only // See http://www.velocityreviews.com/forums/t125048-re-jdialog-in-taskbar-under-linux.html // It fixes the problem but a new problem arises : the main window appears / disappears // with the toast, it is even worse than the previous issue. super(owner); setFocusableWindowState(false); setFocusable(false); setUndecorated(true); // Don't use setAlwaysOnTop or the toast steals the focus, see #1636 //setAlwaysOnTop(true); getRootPane().setWindowDecorationStyle(JRootPane.NONE); getRootPane().setBorder(new LineBorder(Color.BLACK)); JLabel jl = new JLabel(text); jl.setFont(FontManager.getInstance().getFont(JajukFont.DEFAULT)); jl.setBorder(new EmptyBorder(5, 5, 5, 5)); // Allow user to close the dialog by clicking on it addMouseListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { dispose(); } }); // Fix for #1778 : the Window.dispose() method doesn't seem to work (under Linux at least) if the component is not visible. // We add a component listener to detect hide/show. If the dialog has already been hidden once, it is disposed. addComponentListener(new ComponentAdapter() { @Override public void componentShown(ComponentEvent e) { if (hasAlreadyBeenHidden) { dispose(); } } @Override public void componentHidden(ComponentEvent e) { hasAlreadyBeenHidden = true; } }); add(jl); pack(); } /** * Show the balloon and hide it after few secs. */ public void display() { setVisible(true); // The toFront() is required under windows when main window is not // visible toFront(); // Dispose the dialog after 5 seconds new Thread("Balloon Display Thread") { @Override public void run() { try { Thread.sleep(3000); close(); } catch (InterruptedException e) { Log.error(e); } } }.start(); } /** * Close the dialog */ public void close() { // Call dispose from the EDT, otherwise, it seems to block in some rare cases under // Windows, see #1514 SwingUtilities.invokeLater(new Runnable() { @Override public void run() { dispose(); } }); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/widgets/PerspectiveBarJPanel.java0000644000175000017500000001160011720500104026737 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.widgets; import java.awt.Font; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.List; import javax.swing.BoxLayout; import javax.swing.ImageIcon; import javax.swing.JButton; import javax.swing.JScrollPane; import javax.swing.JToolBar; import javax.swing.ScrollPaneConstants; import javax.swing.SwingConstants; import javax.swing.border.EmptyBorder; import org.jajuk.ui.helpers.FontManager; import org.jajuk.ui.helpers.FontManager.JajukFont; import org.jajuk.ui.perspectives.IPerspective; import org.jajuk.ui.perspectives.PerspectiveManager; import org.jajuk.util.Conf; import org.jajuk.util.Const; import org.jajuk.util.UtilGUI; import org.jajuk.util.UtilString; import org.jdesktop.swingx.JXPanel; /** * Menu bar used to choose the current perspective. */ public final class PerspectiveBarJPanel extends JXPanel { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** Perspectives tool bar*. */ private JToolBar jtbPerspective; /** Self instance. */ private static PerspectiveBarJPanel pb = new PerspectiveBarJPanel(); /** Perspective button. */ private final List alButtons = new ArrayList(10); /** * Singleton access. * * @return the instance */ public static PerspectiveBarJPanel getInstance() { return pb; } /** * Constructor for PerspectiveBarJPanel. */ private PerspectiveBarJPanel() { update(); } /** * update contents. */ public void update() { // Perspectives tool bar jtbPerspective = new JajukJToolbar(SwingConstants.VERTICAL); Iterator it = PerspectiveManager.getPerspectives().iterator(); while (it.hasNext()) { final IPerspective perspective = it.next(); Font font = FontManager.getInstance().getFont(JajukFont.PERSPECTIVES); int iconSize = Conf.getInt(Const.CONF_PERSPECTIVE_ICONS_SIZE); // resize if necessary ImageIcon icon = perspective.getIcon(); if (Conf.getInt(Const.CONF_PERSPECTIVE_ICONS_SIZE) != 40) { icon = UtilGUI.getResizedImage(icon, iconSize, iconSize); } JButton jb = new JButton(icon); jb.setToolTipText(perspective.getDesc()); jb.setBorder(new EmptyBorder(5, 5, 0, 5)); if (iconSize >= 32) { int glyphSize = font.getSize(); // Limit perspective label to icon width String desc = UtilString .getLimitedString(perspective.getDesc(), 3 + (iconSize / glyphSize)); // No text for icon < 32 pixels in width: too narrow jb.setText(desc); } jb.setVerticalTextPosition(SwingConstants.BOTTOM); jb.setHorizontalTextPosition(SwingConstants.CENTER); jb.setFont(font); jb.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { // no thread, it causes ugly screen repaint PerspectiveManager.setCurrentPerspective(perspective.getID()); } }); jtbPerspective.add(jb); alButtons.add(jb); } setLayout(new BoxLayout(this, BoxLayout.X_AXIS)); JScrollPane jsp = new JScrollPane(jtbPerspective); jsp.setBorder(null); jsp.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); add(jsp); } /** * Show selected perspective. * * @param perspective DOCUMENT_ME */ public void setActivated(IPerspective perspective) { Collection perspectives = PerspectiveManager.getPerspectives(); Iterator it = alButtons.iterator(); Iterator it2 = perspectives.iterator(); while (it.hasNext()) { final JButton jb = it.next(); IPerspective perspective2 = it2.next(); if (perspective2.equals(perspective)) { // this perspective is // selected jb.setSelected(true); } else { jb.setSelected(false); } } } /** * ToString() method. * * @return the string */ @Override public String toString() { return getClass().getName(); } }jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/widgets/CommandJPanel.java0000644000175000017500000006133211720500104025406 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.widgets; import static org.jajuk.ui.actions.JajukActions.CONFIGURE_DJS; import static org.jajuk.ui.actions.JajukActions.FINISH_ALBUM; import static org.jajuk.ui.actions.JajukActions.MUTE_STATE; import static org.jajuk.ui.actions.JajukActions.NEXT_ALBUM; import static org.jajuk.ui.actions.JajukActions.NEXT_TRACK; import static org.jajuk.ui.actions.JajukActions.PAUSE_RESUME_TRACK; import static org.jajuk.ui.actions.JajukActions.PREVIOUS_ALBUM; import static org.jajuk.ui.actions.JajukActions.PREVIOUS_TRACK; import static org.jajuk.ui.actions.JajukActions.STOP_TRACK; import ext.DropDownButton; import ext.scrollablepopupmenu.XCheckedButton; import ext.scrollablepopupmenu.XJPopupMenu; import java.awt.FlowLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseEvent; import java.awt.event.MouseWheelEvent; import java.awt.event.MouseWheelListener; import java.util.HashSet; import java.util.Iterator; import java.util.Set; import javax.swing.Action; import javax.swing.ButtonGroup; import javax.swing.ImageIcon; import javax.swing.JButton; import javax.swing.JCheckBoxMenuItem; import javax.swing.JLabel; import javax.swing.JMenuItem; import javax.swing.JPanel; import javax.swing.JPopupMenu; import javax.swing.JRadioButtonMenuItem; import javax.swing.JSlider; import javax.swing.JToolBar; import javax.swing.SwingUtilities; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import net.miginfocom.swing.MigLayout; import org.jajuk.events.JajukEvent; import org.jajuk.events.JajukEvents; import org.jajuk.events.ObservationManager; import org.jajuk.events.Observer; import org.jajuk.services.dj.DigitalDJ; import org.jajuk.services.dj.DigitalDJManager; import org.jajuk.services.players.Player; import org.jajuk.services.players.QueueModel; import org.jajuk.services.webradio.WebRadio; import org.jajuk.services.webradio.WebRadioManager; import org.jajuk.ui.actions.ActionManager; import org.jajuk.ui.actions.ActionUtil; import org.jajuk.ui.actions.JajukAction; import org.jajuk.ui.actions.JajukActions; import org.jajuk.ui.actions.MuteAction; import org.jajuk.ui.helpers.JajukMouseAdapter; import org.jajuk.ui.helpers.PlayerStateMediator; import org.jajuk.ui.substance.CircleButtonShaper; import org.jajuk.ui.substance.LeftConcaveButtonShaper; import org.jajuk.ui.substance.RightConcaveButtonShaper; import org.jajuk.ui.substance.RoundRectButtonShaper; import org.jajuk.ui.windows.JajukMainWindow; import org.jajuk.util.Conf; import org.jajuk.util.Const; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; import org.jajuk.util.UtilFeatures; import org.jajuk.util.log.Log; import org.jdesktop.swingx.JXPanel; import org.jvnet.substance.SubstanceLookAndFeel; /** * Command panel ( static view ) *

* Singleton *

. */ public class CommandJPanel extends JXPanel implements ActionListener, ChangeListener, Observer, MouseWheelListener { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; // singleton /** DOCUMENT_ME. */ private static CommandJPanel command = new CommandJPanel(); // widgets declaration /** Continue mode button. */ private JajukToggleButton jbContinue; /** DOCUMENT_ME. */ private JajukToggleButton jbRepeat; /** DOCUMENT_ME. */ private JajukToggleButton jbRandom; /** DOCUMENT_ME. */ private JToolBar jtbSpecial; /** DOCUMENT_ME. */ private DropDownButton ddbGlobalRandom; /** DOCUMENT_ME. */ private JRadioButtonMenuItem jmiShuffleModeSong; /** DOCUMENT_ME. */ private JRadioButtonMenuItem jmiShuffleModeAlbum; /** DOCUMENT_ME. */ private JRadioButtonMenuItem jmiShuffleModeAlbum2; /** DOCUMENT_ME. */ private JPopupMenu popupGlobalRandom; /** DOCUMENT_ME. */ private JajukButton jbBestof; /** DOCUMENT_ME. */ private DropDownButton ddbNovelties; /** DOCUMENT_ME. */ private JPopupMenu popupNovelties; /** DOCUMENT_ME. */ private DropDownButton ddbWebRadio; /** DOCUMENT_ME. */ private XJPopupMenu popupWebRadio; /** DOCUMENT_ME. */ private JRadioButtonMenuItem jmiNoveltiesModeSong; /** DOCUMENT_ME. */ private JRadioButtonMenuItem jmiNoveltiesModeAlbum; /** DOCUMENT_ME. */ private JajukButton jbNorm; /** DOCUMENT_ME. */ private DropDownButton ddbDDJ; /** DOCUMENT_ME. */ private JPopupMenu popupDDJ; /** DOCUMENT_ME. */ private JButton jbPrevious; /** DOCUMENT_ME. */ private JButton jbNext; /** DOCUMENT_ME. */ private JButton jbPlayPause; /** DOCUMENT_ME. */ private JButton jbStop; /** DOCUMENT_ME. */ private JSlider jsVolume; /** DOCUMENT_ME. */ private JLabel jlVolume; /** DOCUMENT_ME. */ private PreferenceToolbar evaltoobar; /** DOCUMENT_ME. */ private JajukButton jbMute; // variables declaration /** DOCUMENT_ME. */ private JajukToggleButton jbRepeatAll; /** * Gets the instance. * * @return singleton */ public static CommandJPanel getInstance() { return command; } /** * Constructor, this objects needs to be implemented for the tray (child * object). */ public CommandJPanel() { super(); } /** * Inits the ui. * DOCUMENT_ME */ public void initUI() { // Instanciate the PlayerStateMediator to listen for player basic controls PlayerStateMediator.getInstance(); // Install keystrokes on invisible components ActionUtil.installKeystrokes(CommandJPanel.this, ActionManager.getAction(NEXT_ALBUM), ActionManager.getAction(PREVIOUS_ALBUM)); // Mode toolbar // we need an inner toolbar to apply size properly JPanel jpModes = new JPanel(); jpModes.setLayout(new FlowLayout(FlowLayout.LEFT, 5, 3)); // make it not floatable as this behavior is managed by vldocking jbContinue = new JajukToggleButton(ActionManager.getAction(JajukActions.CONTINUE_MODE)); jbContinue.setSelected(Conf.getBoolean(Const.CONF_STATE_CONTINUE)); jbRepeat = new JajukToggleButton(ActionManager.getAction(JajukActions.REPEAT_MODE)); jbRepeat.setSelected(Conf.getBoolean(Const.CONF_STATE_REPEAT)); jbRepeatAll = new JajukToggleButton(ActionManager.getAction(JajukActions.REPEAT_ALL_MODE)); jbRepeatAll.setSelected(Conf.getBoolean(Const.CONF_STATE_REPEAT_ALL)); jbRandom = new JajukToggleButton(ActionManager.getAction(JajukActions.SHUFFLE_MODE)); jbRandom.setSelected(Conf.getBoolean(Const.CONF_STATE_SHUFFLE)); jpModes.add(jbContinue); jpModes.add(jbRepeat); jpModes.add(jbRepeatAll); jpModes.add(jbRandom); // Eval toolbar evaltoobar = new PreferenceToolbar(); // Volume int iVolume = (int) (100 * Conf.getFloat(Const.CONF_VOLUME)); // Perform bounds test, -1 or >100 can occur in some undefined cases (see // #1169) if (iVolume > 100) { iVolume = 100; } else if (iVolume < 0) { iVolume = 0; } jsVolume = new JSlider(0, 100, iVolume); jlVolume = new JLabel(iVolume + " %"); jsVolume.addChangeListener(CommandJPanel.this); jbMute = new JajukButton(ActionManager.getAction(MUTE_STATE)); jbMute.setText(null); jbMute.putClientProperty(SubstanceLookAndFeel.BUTTON_SHAPER_PROPERTY, new RoundRectButtonShaper()); MuteAction.setVolumeIcon(iVolume); jbMute.addMouseWheelListener(CommandJPanel.this); jsVolume.addMouseWheelListener(CommandJPanel.this); ActionUtil.installKeystrokes(jbMute, ActionManager.getAction(JajukActions.DECREASE_VOLUME), ActionManager.getAction(JajukActions.INCREASE_VOLUME)); ActionUtil.installKeystrokes(jsVolume, ActionManager.getAction(JajukActions.DECREASE_VOLUME), ActionManager.getAction(JajukActions.INCREASE_VOLUME)); // Special functions toolbar jtbSpecial = new JajukJToolbar(); ddbGlobalRandom = new DropDownButton(IconLoader.getIcon(JajukIcons.SHUFFLE_GLOBAL)) { private static final long serialVersionUID = 1L; @Override protected JPopupMenu getPopupMenu() { return popupGlobalRandom; } }; ddbGlobalRandom.setAction(ActionManager.getAction(JajukActions.SHUFFLE_GLOBAL)); popupGlobalRandom = new JPopupMenu(); // Global shuffle jmiShuffleModeSong = new JRadioButtonMenuItem(Messages.getString("CommandJPanel.20")); jmiShuffleModeSong.addActionListener(this); // album / album jmiShuffleModeAlbum = new JRadioButtonMenuItem(Messages.getString("CommandJPanel.21")); jmiShuffleModeAlbum.addActionListener(this); // Shuffle album / album jmiShuffleModeAlbum2 = new JRadioButtonMenuItem(Messages.getString("CommandJPanel.22")); jmiShuffleModeAlbum2.addActionListener(this); if (Conf.getString(Const.CONF_GLOBAL_RANDOM_MODE).equals(Const.MODE_TRACK)) { jmiShuffleModeSong.setSelected(true); } else if (Conf.getString(Const.CONF_GLOBAL_RANDOM_MODE).equals(Const.MODE_ALBUM2)) { jmiShuffleModeAlbum2.setSelected(true); } else { jmiShuffleModeAlbum.setSelected(true); } ButtonGroup bgGlobalRandom = new ButtonGroup(); bgGlobalRandom.add(jmiShuffleModeSong); bgGlobalRandom.add(jmiShuffleModeAlbum); bgGlobalRandom.add(jmiShuffleModeAlbum2); popupGlobalRandom.add(jmiShuffleModeSong); popupGlobalRandom.add(jmiShuffleModeAlbum); popupGlobalRandom.add(jmiShuffleModeAlbum2); ddbGlobalRandom.setText("");// no text visible jbBestof = new JajukButton(ActionManager.getAction(JajukActions.BEST_OF)); ddbNovelties = new DropDownButton(IconLoader.getIcon(JajukIcons.NOVELTIES)) { private static final long serialVersionUID = 1L; @Override protected JPopupMenu getPopupMenu() { return popupNovelties; } }; ddbNovelties.setAction(ActionManager.getAction(JajukActions.NOVELTIES)); popupNovelties = new JPopupMenu(); jmiNoveltiesModeSong = new JRadioButtonMenuItem(Messages.getString("CommandJPanel.20")); jmiNoveltiesModeSong.addActionListener(this); jmiNoveltiesModeAlbum = new JRadioButtonMenuItem(Messages.getString("CommandJPanel.22")); jmiNoveltiesModeAlbum.addActionListener(this); if (Conf.getString(Const.CONF_NOVELTIES_MODE).equals(Const.MODE_TRACK)) { jmiNoveltiesModeSong.setSelected(true); } else { jmiNoveltiesModeAlbum.setSelected(true); } ButtonGroup bgNovelties = new ButtonGroup(); bgNovelties.add(jmiNoveltiesModeSong); bgNovelties.add(jmiNoveltiesModeAlbum); popupNovelties.add(jmiNoveltiesModeSong); popupNovelties.add(jmiNoveltiesModeAlbum); ddbNovelties.setText("");// no text visible jbNorm = new JajukButton(ActionManager.getAction(FINISH_ALBUM)); // Radio tool bar popupDDJ = new JPopupMenu(); ddbDDJ = new DropDownButton(IconLoader.getIcon(JajukIcons.DIGITAL_DJ)) { private static final long serialVersionUID = 1L; @Override protected JPopupMenu getPopupMenu() { return popupDDJ; } }; ddbDDJ.setAction(ActionManager.getAction(JajukActions.DJ)); populateDJs(); // no text visible ddbDDJ.setText(""); popupWebRadio = new XJPopupMenu(JajukMainWindow.getInstance()); ddbWebRadio = new DropDownButton(IconLoader.getIcon(JajukIcons.WEBRADIO)) { private static final long serialVersionUID = 1L; @Override protected JPopupMenu getPopupMenu() { return popupWebRadio; } }; ddbWebRadio.setAction(ActionManager.getAction(JajukActions.WEB_RADIO)); populateWebRadios(); // no text ddbWebRadio.setText(""); JToolBar jtbWebRadio = new JajukJToolbar(); ddbWebRadio.addToToolBar(jtbWebRadio); ddbDDJ.addToToolBar(jtbSpecial); ddbNovelties.addToToolBar(jtbSpecial); ddbGlobalRandom.addToToolBar(jtbSpecial); jtbSpecial.add(jbBestof); jtbSpecial.add(jbNorm); // Play buttons jbPrevious = new JajukButton(ActionManager.getAction(PREVIOUS_TRACK)); // Manage right click : replay the track (this not triggers an action so we use a MouseAdapter here) jbPrevious.addMouseListener(new JajukMouseAdapter() { @Override public void handlePopup(final MouseEvent me) { // Create an ActionEvent from this MouseEvent with a custom modifier : the right click ActionEvent ae = new ActionEvent(jbPrevious, 0, PREVIOUS_TRACK.name(), 4332424); try { ActionManager.getAction(PREVIOUS_TRACK).perform(ae); } catch (Exception e) { Log.error(e); } } }); // Compute concavity of player icon int concavity = IconLoader.getIcon(JajukIcons.PLAYER_PLAY).getIconHeight(); jbPrevious.putClientProperty(SubstanceLookAndFeel.BUTTON_SHAPER_PROPERTY, new RightConcaveButtonShaper(concavity)); jbNext = new JajukButton(ActionManager.getAction(NEXT_TRACK)); jbNext.putClientProperty(SubstanceLookAndFeel.BUTTON_SHAPER_PROPERTY, new LeftConcaveButtonShaper(concavity)); jbPlayPause = new JajukButton(ActionManager.getAction(PAUSE_RESUME_TRACK)); jbPlayPause.putClientProperty(SubstanceLookAndFeel.BUTTON_SHAPER_PROPERTY, new CircleButtonShaper()); jbStop = new JajukButton(ActionManager.getAction(STOP_TRACK)); jbStop.putClientProperty(SubstanceLookAndFeel.BUTTON_SHAPER_PROPERTY, new RoundRectButtonShaper()); // Add items setLayout(new MigLayout("insets 5 0 0 5", "[grow][grow][grow]")); add(jtbWebRadio, "left,split 2,gapright 10"); add(jtbSpecial, "left,gapright 10"); add(jbStop, "center,split 7,width 40!,height 30,gapright 5!"); add(jbPrevious, "center,width 58!,height 30!,gapright 0"); add(jbPlayPause, "center,width 45!,height 45!,gapright 0"); add(jbNext, "center,width 58!,height 30!,gapright 3"); add(jbMute, "center,width 42!,height 30!,gapright 5"); add(jsVolume, "center,growx,width 25::100,gapright 3"); add(jlVolume, "width 40!,gapright 10"); add(jpModes, "right,split 2,gapright 5"); add(evaltoobar, "right"); // register to player events ObservationManager.register(CommandJPanel.this); // Update initial status UtilFeatures.updateStatus(this); } /* * (non-Javadoc) * * @see org.jajuk.events.Observer#getRegistrationKeys() */ @Override public Set getRegistrationKeys() { Set eventSubjectSet = new HashSet(); eventSubjectSet.add(JajukEvents.PLAYER_STOP); eventSubjectSet.add(JajukEvents.PLAYER_PLAY); eventSubjectSet.add(JajukEvents.PLAYER_PAUSE); eventSubjectSet.add(JajukEvents.PLAYER_RESUME); eventSubjectSet.add(JajukEvents.SPECIAL_MODE); eventSubjectSet.add(JajukEvents.ZERO); eventSubjectSet.add(JajukEvents.REPEAT_MODE_STATUS_CHANGED); eventSubjectSet.add(JajukEvents.CLEAR_HISTORY); eventSubjectSet.add(JajukEvents.VOLUME_CHANGED); eventSubjectSet.add(JajukEvents.DJS_CHANGE); eventSubjectSet.add(JajukEvents.WEBRADIOS_CHANGE); eventSubjectSet.add(JajukEvents.WEBRADIO_LAUNCHED); return eventSubjectSet; } /* * (non-Javadoc) * * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent) */ @Override public void actionPerformed(final ActionEvent ae) { // do not run this in a separate thread because Player actions would die // with the thread try { if (ae.getSource().equals(jmiNoveltiesModeSong)) { Conf.setProperty(Const.CONF_NOVELTIES_MODE, Const.MODE_TRACK); } else if (ae.getSource().equals(jmiNoveltiesModeAlbum)) { Conf.setProperty(Const.CONF_NOVELTIES_MODE, Const.MODE_ALBUM); } else if (ae.getSource().equals(jmiShuffleModeSong)) { Conf.setProperty(Const.CONF_GLOBAL_RANDOM_MODE, Const.MODE_TRACK); } else if (ae.getSource().equals(jmiShuffleModeAlbum)) { Conf.setProperty(Const.CONF_GLOBAL_RANDOM_MODE, Const.MODE_ALBUM); } else if (ae.getSource().equals(jmiShuffleModeAlbum2)) { Conf.setProperty(Const.CONF_GLOBAL_RANDOM_MODE, Const.MODE_ALBUM2); } else if (ae.getSource().equals(jmiShuffleModeAlbum2)) { Conf.setProperty(Const.CONF_GLOBAL_RANDOM_MODE, Const.MODE_ALBUM2); } } catch (Exception e) { Log.error(e); } } /* * @see javax.swing.event.ChangeListener#stateChanged(javax.swing.event.ChangeEvent ) */ /* * (non-Javadoc) * * @see javax.swing.event.ChangeListener#stateChanged(javax.swing.event.ChangeEvent) */ @Override public void stateChanged(ChangeEvent e) { if (e.getSource() == jsVolume) { float newVolume = (float) jsVolume.getValue() / 100; Player.setVolume(newVolume); } } /* * (non-Javadoc) * * @seejava.awt.event.MouseWheelListener#mouseWheelMoved(java.awt.event. MouseWheelEvent) */ @Override public void mouseWheelMoved(MouseWheelEvent e) { if (e.getSource() == jsVolume || e.getSource() == jbMute) { int iOld = jsVolume.getValue(); float newVolume = ((float) (iOld - (e.getUnitsToScroll() * 3))) / 100; Player.setVolume(newVolume); } } /** * Gets the current volume. * * @return Volume value */ public int getCurrentVolume() { return this.jsVolume.getValue(); } /* * (non-Javadoc) * * @see org.jajuk.ui.Observer#update(java.lang.String) */ @Override public void update(final JajukEvent event) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { JajukEvents subject = event.getSubject(); if (JajukEvents.PLAYER_PAUSE.equals(subject)) { // Disable volume control when pausing to fix an mplayer // issue: // setting the volume resume the file jsVolume.setEnabled(false); jbMute.removeMouseWheelListener(CommandJPanel.this); jsVolume.removeMouseWheelListener(CommandJPanel.this); } else if (JajukEvents.PLAYER_RESUME.equals(subject)) { // Enable the volume when resuming (fix a mplayer issue, see // above) jsVolume.setEnabled(true); jbMute.addMouseWheelListener(CommandJPanel.this); jsVolume.addMouseWheelListener(CommandJPanel.this); } else if (JajukEvents.PLAYER_PLAY.equals(subject)) { jsVolume.setEnabled(true); } else if (JajukEvents.SPECIAL_MODE.equals(subject)) { if (ObservationManager.getDetail(event, Const.DETAIL_ORIGIN).equals( Const.DETAIL_SPECIAL_MODE_NORMAL)) { // deselect shuffle mode Conf.setProperty(Const.CONF_STATE_SHUFFLE, Const.FALSE); JajukJMenuBar.getInstance().setShuffleSelected(false); CommandJPanel.getInstance().jbRandom.setSelected(false); // computes planned tracks QueueModel.computesPlanned(true); } } else if (JajukEvents.REPEAT_MODE_STATUS_CHANGED.equals(subject)) { if (ObservationManager.getDetail(event, Const.DETAIL_SELECTION).equals(Const.FALSE)) { // deselect repeat mode Conf.setProperty(Const.CONF_STATE_REPEAT, Const.FALSE); JajukJMenuBar.getInstance().setRepeatSelected(false); CommandJPanel.getInstance().jbRepeat.setSelected(false); } } else if (JajukEvents.VOLUME_CHANGED.equals(event.getSubject())) { // Update volume GUI jsVolume.removeChangeListener(CommandJPanel.this); jbMute.removeMouseWheelListener(CommandJPanel.this); jsVolume.removeMouseWheelListener(CommandJPanel.this); jsVolume.setValue((int) (100 * Player.getCurrentVolume())); String sVolume = (int) (100 * Player.getCurrentVolume()) + " %"; jsVolume.setToolTipText(sVolume); jlVolume.setText(sVolume); jbMute.setSelected(Player.isMuted()); jsVolume.addChangeListener(CommandJPanel.this); jbMute.addMouseWheelListener(CommandJPanel.this); jsVolume.addMouseWheelListener(CommandJPanel.this); } else if (JajukEvents.DJS_CHANGE.equals(event.getSubject())) { populateDJs(); // If no more DJ, change the tooltip if (DigitalDJManager.getInstance().getDJs().size() == 0) { JajukAction action = ActionManager.getAction(JajukActions.DJ); action.setShortDescription(Messages.getString("CommandJPanel.18")); } } else if (JajukEvents.WEBRADIOS_CHANGE.equals(event.getSubject())) { populateWebRadios(); } else if (JajukEvents.WEBRADIO_LAUNCHED.equals(event.getSubject())) { populateWebRadios(); } } }); } /** * Populate DJs. */ private void populateDJs() { try { ddbDDJ.setToolTipText(Const.HTML + Messages.getString("CommandJPanel.18") + Const.P_B + DigitalDJManager.getCurrentDJ() + ""); popupDDJ.removeAll(); JMenuItem jmiNew = new JMenuItem(ActionManager.getAction(CONFIGURE_DJS)); popupDDJ.add(jmiNew); Iterator it = DigitalDJManager.getInstance().getDJs().iterator(); while (it.hasNext()) { final DigitalDJ dj = it.next(); JCheckBoxMenuItem jmi = new JCheckBoxMenuItem(dj.getName(), IconLoader .getIcon(JajukIcons.DIGITAL_DJ_16X16)); jmi.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent arg0) { Conf.setProperty(Const.CONF_DEFAULT_DJ, dj.getID()); DigitalDJManager.setCurrentDJ(dj); // force to reselect the item populateDJs(); // update action tooltip on main button with right item JajukAction action = ActionManager.getAction(JajukActions.DJ); action.setShortDescription(Const.HTML + Messages.getString("CommandJPanel.18") + Const.P_B + dj.getName() + Const.B_P_HTML); } }); popupDDJ.add(jmi); jmi.setSelected(Conf.getString(Const.CONF_DEFAULT_DJ).equals(dj.getID())); } } catch (Exception e) { Log.error(e); } } /** * Populate webradios. */ private void populateWebRadios() { try { // Update button tooltip ddbWebRadio.setToolTipText(WebRadioManager.getCurrentWebRadioTooltip()); // Clear previous elements popupWebRadio.removeAll(); // Add configure radios item JajukAction actionConf = ActionManager.getAction(JajukActions.CONFIGURE_WEBRADIOS); XCheckedButton jmiConf = new XCheckedButton(actionConf); // Set icon so it is correctly displayed after a selection jmiConf.setCheckedIcon((ImageIcon) actionConf.getValue(Action.SMALL_ICON)); // The icon should be always displayed jmiConf.setIconAlwaysVisible(true); popupWebRadio.add(jmiConf); for (final WebRadio radio : WebRadioManager.getInstance().getWebRadios()) { XCheckedButton jmi = new XCheckedButton(radio.getName()); jmi.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { Conf.setProperty(Const.CONF_DEFAULT_WEB_RADIO, radio.getName()); // force to reselect the item populateWebRadios(); // update action tooltip on main button with right item JajukAction action = ActionManager.getAction(JajukActions.WEB_RADIO); action.setShortDescription(Const.HTML + Messages.getString("CommandJPanel.25") + Const.P_B + radio.getName() + Const.B_P_HTML); } }); jmi.setSelected(Conf.getString(Const.CONF_DEFAULT_WEB_RADIO).equals(radio.getName())); // Show the check icon jmi.setDisplayCheck(true); popupWebRadio.add(jmi); } } catch (Exception e) { Log.error(e); } } /** * ToString() method. * * @return the string */ @Override public String toString() { return getClass().getName(); } /** * Sets the repeat selected. * * @param b the new repeat selected */ public void setRepeatSelected(final boolean b) { this.jbRepeat.setSelected(b); } /** * Sets the repeat all selected. * * @param b the new repeat all selected */ public void setRepeatAllSelected(final boolean b) { this.jbRepeatAll.setSelected(b); } /** * Sets the random selected. * * @param b the new random selected */ public void setRandomSelected(final boolean b) { this.jbRandom.setSelected(b); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/widgets/SearchBox.java0000644000175000017500000003166711720500104024624 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.widgets; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Component; import java.awt.Dimension; import java.awt.Graphics; import java.awt.Insets; import java.awt.Point; import java.awt.Toolkit; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.util.Collections; import java.util.List; import javax.swing.ActionMap; import javax.swing.BorderFactory; import javax.swing.DefaultListModel; import javax.swing.InputMap; import javax.swing.JComponent; import javax.swing.JLabel; import javax.swing.JList; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTextField; import javax.swing.KeyStroke; import javax.swing.ListCellRenderer; import javax.swing.Popup; import javax.swing.PopupFactory; import javax.swing.SwingConstants; import javax.swing.SwingUtilities; import javax.swing.SwingWorker; import javax.swing.Timer; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import org.jajuk.base.SearchResult; import org.jajuk.base.SearchResult.SearchResultType; import org.jajuk.base.TrackManager; import org.jajuk.services.players.QueueModel; import org.jajuk.services.players.StackItem; import org.jajuk.services.webradio.WebRadioManager; import org.jajuk.ui.actions.JajukAction; import org.jajuk.ui.helpers.FontManager; import org.jajuk.ui.helpers.FontManager.JajukFont; import org.jajuk.util.Conf; import org.jajuk.util.Const; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; import org.jajuk.util.UtilGUI; import org.jajuk.util.error.JajukException; import org.jajuk.util.log.Log; /** * Search combo box. Editable combo with search features. Comes with a default * selection implementation (see valueChanged() method) that could be changed */ public class SearchBox extends JTextField implements KeyListener, ListSelectionListener { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** Do search panel need a search. */ private boolean bNeedSearch = false; /** Default time in ms before launching a search automatically. */ private static final int WAIT_TIME = 1000; /** Minimum number of characters to start a search. */ private static final int MIN_CRITERIA_LENGTH = 2; /** Search result. */ private List alResults; /** Typed string. */ private String sTyped; /** DOCUMENT_ME. */ private Popup popup; /** DOCUMENT_ME. */ private JList jlist; /** DOCUMENT_ME. */ private long lDateTyped; /** Search when typing timer. */ Timer timer = new Timer(100, new ActionListener() { @Override public void actionPerformed(ActionEvent arg0) { if (bNeedSearch && (System.currentTimeMillis() - lDateTyped >= WAIT_TIME)) { search(); } } }); /** * Display results as a jlabel with an icon. */ private static class SearchListRenderer extends JPanel implements ListCellRenderer { /** Generated serialVersionUID. */ private static final long serialVersionUID = 8975989658927794678L; /* * (non-Javadoc) * * @see javax.swing.ListCellRenderer#getListCellRendererComponent(javax.swing .JList, * java.lang.Object, int, boolean, boolean) */ @Override public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { SearchResult sr = (SearchResult) value; JPanel jp = new JPanel(new BorderLayout()); JLabel jl = null; if (sr.getType() == SearchResultType.FILE) { jl = new JLabel(sr.getResu(), sr.getFile().getIconRepresentation(), SwingConstants.HORIZONTAL); } else if (sr.getType() == SearchResultType.WEBRADIO) { jl = new JLabel(sr.getResu(), IconLoader.getIcon(JajukIcons.WEBRADIO_16X16), SwingConstants.HORIZONTAL); } jp.add(jl, BorderLayout.WEST); return jp; } } /** * Constructor. */ public SearchBox() { setMargin(new Insets(0, 20, 0, 0)); timer.start(); addKeyListener(this); setToolTipText(Messages.getString("SearchBox.0")); // We use a font whose size cannot change with font size selected by user // because the search box cannot be enlarged vertically setFont(FontManager.getInstance().getFont(JajukFont.SEARCHBOX)); Color mediumGray = new Color(172, 172, 172); setForeground(mediumGray); installKeysrokes(); // Double click empties the field addMouseListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { super.mouseClicked(e); if (e.getClickCount() == 2) { setText(""); } } }); } /* * (non-Javadoc) * * @see java.awt.event.KeyListener#keyPressed(java.awt.event.KeyEvent) */ @Override public void keyPressed(KeyEvent e) { // required by interface, but nothing to do here... } /* * (non-Javadoc) * * @see java.awt.event.KeyListener#keyReleased(java.awt.event.KeyEvent) */ @Override public void keyReleased(KeyEvent e) { if (e.getKeyChar() == KeyEvent.VK_ESCAPE && popup != null) { popup.hide(); return; } bNeedSearch = false; // stop clock for auto-search sTyped = getText(); if (sTyped.length() >= MIN_CRITERIA_LENGTH) { // perform automatic search only when user provide more than 5 // letters if (e.getKeyChar() == KeyEvent.VK_ENTER) { search(); } else { bNeedSearch = true; lDateTyped = System.currentTimeMillis(); } } else if (popup != null) { popup.hide(); } } /* * (non-Javadoc) * * @see java.awt.event.KeyListener#keyTyped(java.awt.event.KeyEvent) */ @Override public void keyTyped(KeyEvent e) { // required by interface, but nothing to do here... } /** * Perform a search when user stop to type in the search combo for 2 sec or * pressed enter. */ private void search() { bNeedSearch = false; setEnabled(false); // no typing during search // second test to get sure user didn't // typed before entering this method if (sTyped.length() >= MIN_CRITERIA_LENGTH) { SwingWorker sw = new SwingWorker() { List resu = null; @Override public Void doInBackground() { try { UtilGUI.waiting(); resu = TrackManager.getInstance().search(sTyped); // Add web radio names resu.addAll(WebRadioManager.getInstance().search(sTyped)); // Sort the whole list Collections.sort(resu); } catch (Exception e) { Log.error(e); } return null; } @Override public void done() { if (resu != null && resu.size() > 0) { DefaultListModel model = new DefaultListModel(); SearchBox.this.alResults = resu; for (SearchResult sr : resu) { model.addElement(sr); } jlist = new JList(model); jlist.setLayoutOrientation(JList.VERTICAL); jlist.addListSelectionListener(SearchBox.this); jlist.setCellRenderer(new SearchListRenderer()); PopupFactory factory = PopupFactory.getSharedInstance(); JScrollPane jsp = new JScrollPane(jlist); int width = (int) ((float) Toolkit.getDefaultToolkit().getScreenSize().getWidth() * 0.7f); jsp.setMinimumSize(new Dimension(width, 250)); jsp.setPreferredSize(new Dimension(width, 250)); jsp.setMaximumSize(new Dimension(width, 250)); jlist.setSelectionMode(0); // For some reasons, we get the waiting cursor on the popup // sometimes, force it to default jlist.setCursor(UtilGUI.DEFAULT_CURSOR); jsp.setBorder(BorderFactory.createLineBorder(Color.BLACK)); if (popup != null) { popup.hide(); } // take upper-left point relative to the // textfield Point point = new Point(0, 0); // take absolute coordinates in the screen (popups works // only on absolute coordinates in opposition to swing // widgets) SwingUtilities.convertPointToScreen(point, SearchBox.this); if (((int) point.getY() > 300) && (((int) point.getX() + 500 - (width)) > 0)) { popup = factory.getPopup(null, jsp, (int) point.getX() + 500 - (width), (int) point .getY() - 250); } else if (((int) point.getX() + 500 - (width)) > 0) { popup = factory.getPopup(null, jsp, (int) point.getX() + 500 - (width), (int) point .getY() + 30); } else { popup = factory.getPopup(null, jsp, 10, (int) point.getY() + 30); } popup.show(); jlist.addMouseListener(new MouseAdapter() { @Override public void mouseExited(MouseEvent e) { popup.hide(); } }); } else { if (popup != null) { popup.hide(); } } requestFocusInWindow(); setEnabled(true); UtilGUI.stopWaiting(); } }; sw.execute(); } } /** * Gets the selected index. * * @return the selected index */ public int getSelectedIndex() { return jlist.getSelectedIndex(); } /** * Gets the result or. * * @return the result */ public SearchResult getResult() { if (jlist == null) { return null; } return alResults.get(getSelectedIndex()); } /** * Hide popup. */ public void hidePopup() { popup.hide(); } /** * Display the search icon inside the texfield. * * @param g the graphics */ @Override public void paint(Graphics g) { super.paint(g); g.drawImage(IconLoader.getIcon(JajukIcons.SEARCH).getImage(), 4, 3, 16, 16, null); } /** * Default list selection implementation (may be overwritten for different * behavior). * * @param e DOCUMENT_ME */ @Override public void valueChanged(final ListSelectionEvent e) { SwingWorker sw = new SwingWorker() { @Override public Void doInBackground() { if (!e.getValueIsAdjusting()) { SearchResult sr = getResult(); try { // If user selected a file if (sr.getType() == SearchResultType.FILE) { QueueModel.push(new StackItem(sr.getFile(), Conf .getBoolean(Const.CONF_STATE_REPEAT_ALL), true), Conf .getBoolean(Const.CONF_OPTIONS_PUSH_ON_CLICK)); } // User selected a web radio else if (sr.getType() == SearchResultType.WEBRADIO) { QueueModel.launchRadio(sr.getWebradio()); } } catch (JajukException je) { Log.error(je); } } return null; } @Override public void done() { if (!e.getValueIsAdjusting()) { hidePopup(); requestFocusInWindow(); } } }; sw.execute(); } /** * Free up resources, timers, ... * * TODO: I could not find out any way to do this automatically! How can I * listen on some event that is sent when the enclosing dialog is closed? */ public void close() { // stop the timer so it does not keep the element from garbage collection timer.stop(); } /** * Search box specific keystrokes. */ private void installKeysrokes() { InputMap inputMap = getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW); ActionMap actionMap = getActionMap(); inputMap.put(KeyStroke.getKeyStroke("ctrl F"), "search"); // We don't create a JajukAction dedicated class for this very simple case actionMap.put("search", new JajukAction("search", true) { private static final long serialVersionUID = 1L; @Override public void perform(ActionEvent evt) throws Exception { requestFocusInWindow(); } }); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/widgets/ToggleLink.java0000644000175000017500000000360611720500104024775 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.widgets; import java.awt.Font; import javax.swing.Action; import javax.swing.UIManager; import org.jdesktop.swingx.JXCollapsiblePane; import org.jdesktop.swingx.JXHyperlink; /** * Generic toggle hyperlink to open/collapse a collapsable panel. */ public class ToggleLink extends JXHyperlink { /** Generated serialVersionUID. */ private static final long serialVersionUID = 8652043694603450888L; /** * The Constructor. * * @param text hyperlink text * @param panel the associated collapsible panel */ public ToggleLink(String text, JXCollapsiblePane panel) { // get the built-in toggle action Action toggleAction = panel.getActionMap().get(JXCollapsiblePane.TOGGLE_ACTION); setAction(toggleAction); setText(text); setFont(getFont().deriveFont(Font.BOLD)); // use the collapse/expand icons from the JTree UI toggleAction.putValue(JXCollapsiblePane.COLLAPSE_ICON, UIManager.getIcon("Tree.expandedIcon")); toggleAction.putValue(JXCollapsiblePane.EXPAND_ICON, UIManager.getIcon("Tree.collapsedIcon")); setFocusPainted(false); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/widgets/PathSelector.java0000644000175000017500000001340111720500104025325 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.widgets; import java.awt.Color; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.File; import javax.swing.BorderFactory; import javax.swing.JButton; import javax.swing.JFileChooser; import javax.swing.JPanel; import javax.swing.JTextField; import net.miginfocom.swing.MigLayout; import org.jajuk.ui.windows.JajukMainWindow; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukFileFilter; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; import org.jajuk.util.filters.DirectoryFilter; /** * This is a widgets that contains an editable text field given a PATH and a * PATH selection button opening up a file selector. */ public class PathSelector extends JPanel { /** Generated serialVersionUID. */ private static final long serialVersionUID = -8370527665529267952L; /** DOCUMENT_ME. */ JTextField jtfUrl; /** DOCUMENT_ME. */ JButton button; /** * Construct a Path Selector. * * @param filter the filter used to select the item * @param sDefault Initialized path, null of none */ public PathSelector(final JajukFileFilter filter, final String sDefault) { super(); initUI(sDefault); button.addActionListener(new ActionListener() { @Override public void actionPerformed(final ActionEvent e) { final JajukFileChooser jfc = new JajukFileChooser(filter); jfc.setAcceptDirectories(true); jfc.setDialogTitle(Messages.getString("DeviceWizard.43")); jfc.setMultiSelectionEnabled(false); final String sUrl = jtfUrl.getText(); if (!sUrl.isEmpty()) { // if URL is already set, use it as current directory jfc.setCurrentDirectory(new File(sUrl)); } final int returnVal = jfc.showOpenDialog(JajukMainWindow.getInstance()); if (returnVal == JFileChooser.APPROVE_OPTION) { final String previousURL = jtfUrl.getText(); final java.io.File file = jfc.getSelectedFile(); final String newPath = file.getAbsolutePath(); jtfUrl.setText(newPath); // Call specific operation if URL changed if (!previousURL.equals(newPath)) { performOnURLChange(); } } } }); } /** * Construct a Path Selector for directory selection. * * @param sDefault Initialized path, null of none */ public PathSelector(final String sDefault) { super(); initUI(sDefault); button.addActionListener(new ActionListener() { @Override public void actionPerformed(final ActionEvent e) { final JajukFileChooser jfc = new JajukFileChooser(new JajukFileFilter(DirectoryFilter .getInstance())); jfc.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); jfc.setDialogTitle(Messages.getString("DeviceWizard.43")); jfc.setMultiSelectionEnabled(false); final String sUrl = jtfUrl.getText(); if (!sUrl.isEmpty()) { // if URL is already set, use it as current directory jfc.setCurrentDirectory(new File(sUrl)); } final int returnVal = jfc.showOpenDialog(JajukMainWindow.getInstance()); if (returnVal == JFileChooser.APPROVE_OPTION) { final String previousURL = jtfUrl.getText(); final java.io.File file = jfc.getSelectedFile(); final String newPath = file.getAbsolutePath(); jtfUrl.setText(newPath); // Call specific operation if URL changed if (!previousURL.equals(newPath)) { performOnURLChange(); } } } }); } /** * Gets the url. * * @return URL */ public String getUrl() { return jtfUrl.getText(); } /** * Inits the ui. * DOCUMENT_ME * * @param sDefault DOCUMENT_ME */ private void initUI(final String sDefault) { // Set layout setLayout(new MigLayout("ins 0", "[grow][]")); // Build items jtfUrl = new JTextField(); if (sDefault != null) { jtfUrl.setText(sDefault); } jtfUrl.setToolTipText(Messages.getString("Path")); jtfUrl.setBorder(BorderFactory.createLineBorder(Color.BLUE)); button = new JButton(IconLoader.getIcon(JajukIcons.OPEN_FILE)); button.setToolTipText(Messages.getString("Path")); // Add items add(jtfUrl, "grow,gapx 5"); add(button); } /** * This method can be extended to perform specific actions when selected * changes URL. */ public void performOnURLChange() { // empty on purpose... } /* (non-Javadoc) * @see javax.swing.JComponent#setEnabled(boolean) */ @Override public void setEnabled(final boolean b) { jtfUrl.setEnabled(b); button.setEnabled(b); } /** * Set tooltip. * * @param s DOCUMENT_ME */ @Override public void setToolTipText(final String s) { jtfUrl.setToolTipText(s); button.setToolTipText(s); } /** * Sets the uRL. * * @param sURL the new uRL */ public void setURL(final String sURL) { jtfUrl.setText(sURL); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/widgets/AmbienceComboBox.java0000644000175000017500000001353711720500104026076 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.widgets; import java.awt.Component; import java.awt.Toolkit; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.ItemListener; import javax.swing.JLabel; import javax.swing.JList; import javax.swing.SwingConstants; import javax.swing.plaf.basic.BasicComboBoxRenderer; import org.jajuk.events.JajukEvent; import org.jajuk.events.JajukEvents; import org.jajuk.events.ObservationManager; import org.jajuk.services.dj.Ambience; import org.jajuk.services.dj.AmbienceManager; import org.jajuk.ui.actions.ActionManager; import org.jajuk.ui.actions.JajukActions; import org.jajuk.util.Conf; import org.jajuk.util.Const; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; import org.jajuk.util.log.Log; /** * Ambience selection combo box. */ public class AmbienceComboBox extends SteppedComboBox { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** An instance of the ambience combo listener. */ private AmbienceListener ambienceListener; /** * Ambience combo listener. */ private class AmbienceListener implements ActionListener { /* (non-Javadoc) * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent) */ @Override public void actionPerformed(ActionEvent ae) { // Ambience Configuration if (getSelectedIndex() == 0) { // display the wizard try { ActionManager.getAction(JajukActions.CONFIGURE_AMBIENCES).perform(null); } catch (Exception e) { Log.error(e); } // Reset combo to last selected item. We do this to avoid to select the // "0" item that is not an ambience removeActionListener(ambienceListener); Ambience defaultAmbience = AmbienceManager.getInstance().getAmbience( Conf.getString(Const.CONF_DEFAULT_AMBIENCE)); if (defaultAmbience != null) { for (int i = 0; i < getItemCount(); i++) { if (((JLabel) getItemAt(i)).getText().equals(defaultAmbience.getName())) { setSelectedIndex(i); break; } } } else { setSelectedIndex(1); } addActionListener(ambienceListener); } // Selected 'Any" ambience else if (getSelectedIndex() == 1) { // reset default ambience Conf.setProperty(Const.CONF_DEFAULT_AMBIENCE, ""); ObservationManager.notify(new JajukEvent(JajukEvents.AMBIENCES_SELECTION_CHANGE)); } else {// Selected an ambience Ambience ambience = AmbienceManager.getInstance().getAmbienceByName( ((JLabel) getSelectedItem()).getText()); Conf.setProperty(Const.CONF_DEFAULT_AMBIENCE, ambience.getID()); ObservationManager.notify(new JajukEvent(JajukEvents.AMBIENCES_SELECTION_CHANGE)); } } } /** * Populate ambiences combo. */ void populateAmbiences() { removeActionListener(ambienceListener); ItemListener[] il = getItemListeners(); for (ItemListener element : il) { removeItemListener(element); } removeAllItems(); addItem(new JLabel(Messages.getString("CommandJPanel.19"), IconLoader .getIcon(JajukIcons.CONFIGURATION), SwingConstants.LEFT)); addItem(new JLabel("" + Messages.getString("DigitalDJWizard.64") + "", IconLoader.getIcon(JajukIcons.GENRE), SwingConstants.LEFT)); // Add available ambiences for (final Ambience ambience : AmbienceManager.getInstance().getAmbiences()) { addItem(new JLabel(ambience.getName(), IconLoader.getIcon(JajukIcons.GENRE), SwingConstants.LEFT)); } // Select right item Ambience defaultAmbience = AmbienceManager.getInstance().getAmbience( Conf.getString(Const.CONF_DEFAULT_AMBIENCE)); if (defaultAmbience != null) { for (int i = 0; i < getItemCount(); i++) { if (((JLabel) getItemAt(i)).getText().equals(defaultAmbience.getName())) { setSelectedIndex(i); break; } } } else { // or "any" ambience setSelectedIndex(1); } addActionListener(ambienceListener); } /** * Instantiates a new ambience combo box. */ public AmbienceComboBox() { super(); // Set size of the popup int popupWidth = (int) (Toolkit.getDefaultToolkit().getScreenSize().getWidth() / 4); setPopupWidth(popupWidth); setRenderer(new BasicComboBoxRenderer() { private static final long serialVersionUID = -6943363556191659895L; @Override public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); JLabel jl = (JLabel) value; setIcon(jl.getIcon()); setText(jl.getText()); return this; } }); setToolTipText(Messages.getString("DigitalDJWizard.66")); populateAmbiences(); ambienceListener = new AmbienceListener(); addActionListener(ambienceListener); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/widgets/JajukJSplitPane.java0000644000175000017500000000424011720500104025727 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.widgets; import java.awt.Graphics; import javax.swing.JSplitPane; /** * Splitpane fixing the setDeviderLocation bug Thanks * http://www.jguru.com/faq/view.jsp?EID=27191 */ public class JajukJSplitPane extends JSplitPane { /** Generated serialVersionUID. */ private static final long serialVersionUID = -7358047597849102849L; /** DOCUMENT_ME. */ protected boolean isPainted = false; /** DOCUMENT_ME. */ protected boolean hasProportionalLocation = false; /** DOCUMENT_ME. */ protected double proportionalLocation = -1; /* (non-Javadoc) * @see javax.swing.JSplitPane#setDividerLocation(double) */ @Override public void setDividerLocation(double proportionalLocation) { if (!isPainted) { hasProportionalLocation = true; this.proportionalLocation = proportionalLocation; } else { super.setDividerLocation(proportionalLocation); } } /* (non-Javadoc) * @see javax.swing.JComponent#paint(java.awt.Graphics) */ @Override public void paint(Graphics g) { if (!isPainted) { if (hasProportionalLocation) { super.setDividerLocation(proportionalLocation); } isPainted = true; } super.paint(g); } /** * Instantiates a new jajuk j split pane. * * @param orientation DOCUMENT_ME */ public JajukJSplitPane(int orientation) { super(orientation); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/widgets/JajukJDialog.java0000644000175000017500000000362011720500104025230 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.widgets; import java.awt.Frame; import javax.swing.JDialog; import javax.swing.JRootPane; import org.jajuk.ui.windows.JajukMainWindow; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; import org.jajuk.util.UtilGUI; /** * Custom JDialog. */ public class JajukJDialog extends JDialog { /** Generated serialVersionUID. */ private static final long serialVersionUID = 3280008357821054703L; /** * Instantiates a new jajuk j dialog. */ public JajukJDialog() { super(JajukMainWindow.getInstance()); setIconImage(IconLoader.getIcon(JajukIcons.LOGO).getImage()); } /** * The Constructor. * * @param owner DOCUMENT_ME * @param modal DOCUMENT_ME */ public JajukJDialog(Frame owner, boolean modal) { super(owner, modal); setIconImage(IconLoader.getIcon(JajukIcons.LOGO).getImage()); } /* (non-Javadoc) * @see javax.swing.JDialog#createRootPane() */ @Override protected JRootPane createRootPane() { JRootPane rootPane = new JRootPane(); UtilGUI.setEscapeKeyboardAction(this, rootPane); return rootPane; } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/widgets/JajukBasicComboPopup.java0000644000175000017500000000514511720500104026750 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.widgets; import java.awt.Dimension; import java.awt.Rectangle; import javax.swing.JComboBox; import javax.swing.JScrollPane; import javax.swing.ScrollPaneConstants; import javax.swing.plaf.basic.BasicComboPopup; /** * Basic combo popup. * * @created 28 nov. 2003 */ public class JajukBasicComboPopup extends BasicComboPopup { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** * Instantiates a new jajuk basic combo popup. * * @param jcb DOCUMENT_ME */ public JajukBasicComboPopup(JComboBox jcb) { super(jcb); } /* (non-Javadoc) * @see javax.swing.plaf.basic.BasicComboPopup#show() */ @Override public void show() { Dimension popupSize = ((SteppedComboBox) comboBox).getPopupSize(); popupSize.setSize(popupSize.width, getPopupHeightForRowCount(comboBox.getMaximumRowCount())); Rectangle popupBounds = computePopupBounds(0, comboBox.getBounds().height, popupSize.width, popupSize.height); scroller.setMaximumSize(popupBounds.getSize()); scroller.setPreferredSize(popupBounds.getSize()); scroller.setMinimumSize(popupBounds.getSize()); list.invalidate(); int selectedIndex = comboBox.getSelectedIndex(); if (selectedIndex == -1) { list.clearSelection(); } else { list.setSelectedIndex(selectedIndex); } list.ensureIndexIsVisible(list.getSelectedIndex()); setLightWeightPopupEnabled(comboBox.isLightWeightPopupEnabled()); show(comboBox, popupBounds.x, popupBounds.y); } /* (non-Javadoc) * @see javax.swing.plaf.basic.BasicComboPopup#createScroller() */ @Override protected JScrollPane createScroller() { return new JScrollPane(list, ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/widgets/JajukFileChooser.java0000644000175000017500000000614311720500104026124 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.widgets; import java.awt.Component; import java.awt.HeadlessException; import java.io.File; import javax.swing.JDialog; import javax.swing.JFileChooser; import javax.swing.filechooser.FileSystemView; import org.jajuk.util.JajukFileFilter; import org.jajuk.util.Messages; /** * Music-oriented file chooser. */ public class JajukFileChooser extends JFileChooser { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** DOCUMENT_ME. */ private final JajukFileFilter filter; /** * Constructor with specified file filter. * * @param jfilter filter to use */ public JajukFileChooser(JajukFileFilter jfilter) { super(); this.filter = jfilter; for (int i = 0; i < jfilter.getFilters().length; i++) { addChoosableFileFilter(jfilter.getFilters()[i]); } init(); } /** * Constructor with specified file filter and starting directory/file. * * @param jfilter filter to use * @param file DOCUMENT_ME */ public JajukFileChooser(JajukFileFilter jfilter, File file) { super(file); this.filter = jfilter; for (int i = 0; i < jfilter.getFilters().length; i++) { addChoosableFileFilter(jfilter.getFilters()[i]); } init(); } /** * Inits the. */ private final void init() { setDialogTitle(Messages.getString("JajukFileChooser.0")); setMultiSelectionEnabled(true); // don't hide hidden files setFileHidingEnabled(false); setAcceptAllFileFilterUsed(false); // Use default directory to store documents (My Documents under Windows // for ie) setCurrentDirectory(FileSystemView.getFileSystemView().getDefaultDirectory()); } /** * Force the filter to accept directories. * * @param b DOCUMENT_ME */ public void setAcceptDirectories(boolean b) { for (int i = 0; i < filter.getFilters().length; i++) { filter.getFilters()[i].setAcceptDirectories(b); } } /** * Make sure to keep the dialog always on top. * * @param parent DOCUMENT_ME * * @return the j dialog * * @throws HeadlessException the headless exception */ @Override protected JDialog createDialog(Component parent) throws HeadlessException { JDialog dialog = super.createDialog(parent); dialog.setAlwaysOnTop(true); return dialog; } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/widgets/JajukHtmlPanel.java0000644000175000017500000002134511720500104025607 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.widgets; import java.io.BufferedWriter; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.io.Reader; import java.io.Writer; import java.net.URL; import java.util.logging.Level; import java.util.logging.Logger; import javax.swing.SwingWorker; import org.jajuk.services.core.SessionService; import org.jajuk.util.Const; import org.jajuk.util.DownloadManager; import org.jajuk.util.Messages; import org.jajuk.util.UtilGUI; import org.jajuk.util.UtilSystem; import org.jajuk.util.log.Log; import org.lobobrowser.html.UserAgentContext; import org.lobobrowser.html.gui.HtmlPanel; import org.lobobrowser.html.parser.DocumentBuilderImpl; import org.lobobrowser.html.parser.InputSourceImpl; import org.lobobrowser.html.test.SimpleHtmlRendererContext; import org.lobobrowser.html.test.SimpleUserAgentContext; import org.w3c.dom.Document; import org.xml.sax.InputSource; import org.xml.sax.SAXException; /** * Cobra browser HTML panel. */ public class JajukHtmlPanel extends HtmlPanel { /** The Constant COLON. DOCUMENT_ME */ private static final String COLON = " : "; /** The Constant URL_COLON. DOCUMENT_ME */ private static final String URL_COLON = "URL: "; /** Generated serialVersionUID. */ private static final long serialVersionUID = -4033441908072591661L; /** DOCUMENT_ME. */ private final SimpleHtmlRendererContext rcontext; /** DOCUMENT_ME. */ private final DocumentBuilderImpl dbi; /** * A HTML renderer based on Cobra. */ public JajukHtmlPanel() { super(); // Disable Cobra traces Logger.getLogger("").setLevel(Level.OFF); UserAgentContext ucontext = new SimpleUserAgentContext(); rcontext = new SimpleHtmlRendererContext(this, ucontext); dbi = new DocumentBuilderImpl(ucontext, rcontext); } /** * Display a wikipedia url. * * @param url DOCUMENT_ME * @param lang DOCUMENT_ME */ public void setURL(final URL url, final String lang) { SwingWorker sw = new SwingWorker() { @Override public Void doInBackground() { File page = new File(SessionService.getConfFileByPath(Const.FILE_CACHE).getAbsolutePath() + '/' + UtilSystem.getOnlyFile(url.toString() + ".html")); try { setCursor(UtilGUI.WAIT_CURSOR); // first indicate that we are loading a new page setLoading(url); String sPage = DownloadManager.downloadText(url); // Leave if no result if (sPage == null) { return null; } // Remove scripting int index = -1; int lastindex = -1; StringBuilder sb = new StringBuilder(sPage); // only the part between and is // important to us index = sb.indexOf(""); lastindex = sb.indexOf(""); if (index > 0) { sb.delete(0, index); sb.delete(sb.indexOf("") + 20, lastindex); } sPage = sb.toString(); // fix internal links sPage = sPage.replaceAll("href=\"/", "href=\"http://" + lang + ".wikipedia.org/"); // Display the page showPage(sPage, page); // Set current url as a tooltip setToolTipText(url.toString()); } catch (FileNotFoundException e) { // This happens whenever the Artist is not listed on Wikipedia, so we should report this more user-friendly Log.debug("Could not read page: {{" + url.toString() + " Cache: " + page + "}}"); try { setFailedToLoad(Messages.getString("WikipediaView.9") + ": " + url.toString()); } catch (IOException e1) { Log.error(e1); } catch (SAXException e1) { Log.error(e1); } } catch (IOException e) { // report IOException only as warning here as we can expect this to // happen frequently with images on the net Log.warn("Could not read page: {{" + url.toString() + " Cache: " + page + "}}", e .getMessage()); try { setFailedToLoad(URL_COLON + url + COLON + e.getClass().getSimpleName() + COLON + e.getMessage()); } catch (IOException e1) { Log.error(e1); } catch (SAXException e1) { Log.error(e1); } } catch (Exception e) { Log.error(e); try { setFailedToLoad(URL_COLON + url + COLON + e.getClass().getSimpleName() + COLON + e.getMessage()); } catch (IOException e1) { Log.error(e1); } catch (SAXException e1) { Log.error(e1); } } finally { // Disable waiting cursor setCursor(UtilGUI.DEFAULT_CURSOR); } return null; } }; sw.execute(); } /** * Display a "nothing found" page. * * @throws IOException Signals that an I/O exception has occurred. * @throws SAXException the SAX exception */ public void setUnknown() throws IOException, SAXException { File page = new File(SessionService.getConfFileByPath(Const.FILE_CACHE).getAbsolutePath() + '/' + "noresult.html"); String sPage = "

" + Messages.getString("WikipediaView.10") + "

"; showPage(sPage, page); } /** * Sets the loading. * * @param url the new loading * * @throws IOException Signals that an I/O exception has occurred. * @throws SAXException the SAX exception */ private void setLoading(final URL url) throws IOException, SAXException { File page = new File(SessionService.getConfFileByPath(Const.FILE_CACHE).getAbsolutePath() + '/' + "loading.html"); String sPage = "

" + Messages.getString("WikipediaView.8") + " " + url.toString() + "

"; showPage(sPage, page); } /** * Sets the failed to load. * * @param msg the new failed to load * * @throws IOException Signals that an I/O exception has occurred. * @throws SAXException the SAX exception */ private void setFailedToLoad(String msg) throws IOException, SAXException { File page = new File(SessionService.getConfFileByPath(Const.FILE_CACHE).getAbsolutePath() + '/' + "failed.html"); String sPage = "

" + Messages.getString("WikipediaView.9") + "


" + msg + ""; showPage(sPage, page); } /** * Make the internal operations. * * @param sPage DOCUMENT_ME * @param page DOCUMENT_ME * * @throws IOException Signals that an I/O exception has occurred. * @throws SAXException the SAX exception */ private void showPage(String sPage, File page) throws IOException, SAXException { // Write the page itself Writer bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(page), "UTF-8")); try { bw.write(sPage); bw.flush(); } finally { bw.close(); } // A Reader should be created with the correct charset, // which may be obtained from the Content-Type header // of an HTTP response. Reader reader = new InputStreamReader(new FileInputStream(page), "UTF-8"); try { // InputSourceImpl constructor with URI recommended // so the renderer can resolve page component URLs. InputSource is = new InputSourceImpl(reader, "file://" + page.getAbsolutePath()); // A documentURI should be provided to resolve relative // URIs. Document document = dbi.parse(is); // Now set document in panel. This is what causes the // document to render. setDocument(document, rcontext); } finally { reader.close(); } } /** * Back. * DOCUMENT_ME */ public void back() { rcontext.back(); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/widgets/StarIconLabel.java0000644000175000017500000000545511720500104025424 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.widgets; import java.awt.Color; import java.awt.Font; import javax.swing.ImageIcon; /** * Icon Label supporting rating stars. */ public class StarIconLabel extends IconLabel { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** Number of stars. */ private int starsNumber = -1; /** Rate *. */ private int rate = 0; /** * Gets the rate. * * @return the rate */ public long getRate() { return this.rate; } /** * Gets the stars number. * * @return the starsNumber */ public int getStarsNumber() { return this.starsNumber; } /** * The Constructor. * * @param icon DOCUMENT_ME * @param sText DOCUMENT_ME * @param cBackground DOCUMENT_ME * @param cForeground DOCUMENT_ME * @param font DOCUMENT_ME * @param rate DOCUMENT_ME * @param starNumber DOCUMENT_ME */ public StarIconLabel(ImageIcon icon, String sText, Color cBackground, Color cForeground, Font font, int rate, int starNumber) { super(icon, sText, cBackground, cForeground, font, Long.toString(rate)); this.rate = rate; this.starsNumber = starNumber; } /* * (non-Javadoc) * * @see java.lang.Comparable#compareTo(T) */ @Override public int compareTo(IconLabel ilOther) { StarIconLabel silOther = (StarIconLabel) ilOther; // star Number == -1 means banned track, we want banned track to be the lowest // level in sorting but still sorted according rating between banned tracks if (starsNumber != -1 && silOther.getStarsNumber() != -1) { return (int) (rate - silOther.getRate()); } else { // current track banned, the other not if (starsNumber == -1 && silOther.getStarsNumber() != -1) { return -1; // Other track banned, current not } else if (starsNumber != -1 && silOther.getStarsNumber() == -1) { return 1; } // Both are banned tracks else { return (int) (rate - silOther.getRate()); } } } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/widgets/JajukToggleButton.java0000644000175000017500000000743611720500104026345 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.widgets; import java.awt.event.ActionEvent; import javax.swing.Action; import javax.swing.BorderFactory; import javax.swing.Icon; import javax.swing.border.Border; /** * A Jajuk button with two states. */ public class JajukToggleButton extends JajukButton { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** The Constant PRESSED_BORDER. DOCUMENT_ME */ private static final Border PRESSED_BORDER = BorderFactory.createLoweredBevelBorder(); /** The Constant UNPRESSED_BORDER. DOCUMENT_ME */ private static final Border UNPRESSED_BORDER = BorderFactory.createRaisedBevelBorder(); /** * Instantiates a new jajuk toggle button. */ public JajukToggleButton() { this(false); } /** * Instantiates a new jajuk toggle button. * * @param selected DOCUMENT_ME */ public JajukToggleButton(boolean selected) { this(null, null, selected); } /** * Instantiates a new jajuk toggle button. * * @param icon DOCUMENT_ME */ public JajukToggleButton(Icon icon) { this(icon, false); } /** * Instantiates a new jajuk toggle button. * * @param icon DOCUMENT_ME * @param selected DOCUMENT_ME */ public JajukToggleButton(Icon icon, boolean selected) { this(null, icon, selected); } /** * Instantiates a new jajuk toggle button. * * @param text DOCUMENT_ME */ public JajukToggleButton(String text) { this(text, false); } /** * Instantiates a new jajuk toggle button. * * @param text DOCUMENT_ME * @param selected DOCUMENT_ME */ public JajukToggleButton(String text, boolean selected) { this(text, null, selected); } /** * Instantiates a new jajuk toggle button. * * @param a DOCUMENT_ME */ public JajukToggleButton(Action a) { this(a, false); } /** * Instantiates a new jajuk toggle button. * * @param a DOCUMENT_ME * @param selected DOCUMENT_ME */ public JajukToggleButton(Action a, boolean selected) { super(a); setSelected(selected); } /** * Instantiates a new jajuk toggle button. * * @param text DOCUMENT_ME * @param icon DOCUMENT_ME */ public JajukToggleButton(String text, Icon icon) { this(text, icon, false); } /** * Instantiates a new jajuk toggle button. * * @param text DOCUMENT_ME * @param icon DOCUMENT_ME * @param selected DOCUMENT_ME */ public JajukToggleButton(String text, Icon icon, boolean selected) { super(text, icon); setSelected(selected); } /* (non-Javadoc) * @see javax.swing.AbstractButton#setSelected(boolean) */ @Override public final void setSelected(boolean b) { super.setSelected(b); setBorder(b ? PRESSED_BORDER : UNPRESSED_BORDER); } /* (non-Javadoc) * @see javax.swing.AbstractButton#fireActionPerformed(java.awt.event.ActionEvent) */ @Override protected void fireActionPerformed(ActionEvent event) { setSelected(!isSelected()); super.fireActionPerformed(event); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/widgets/SearchJPanel.java0000644000175000017500000002337211720500104025237 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.widgets; import java.awt.Component; import java.awt.Toolkit; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.HashSet; import java.util.Set; import javax.swing.DefaultComboBoxModel; import javax.swing.JLabel; import javax.swing.JList; import javax.swing.SwingUtilities; import javax.swing.plaf.basic.BasicComboBoxRenderer; import net.miginfocom.swing.MigLayout; import org.jajuk.base.FileManager; import org.jajuk.events.JajukEvent; import org.jajuk.events.JajukEvents; import org.jajuk.events.ObservationManager; import org.jajuk.events.Observer; import org.jajuk.services.bookmark.History; import org.jajuk.services.bookmark.HistoryItem; import org.jajuk.services.dj.Ambience; import org.jajuk.services.dj.AmbienceManager; import org.jajuk.services.players.QueueModel; import org.jajuk.services.players.StackItem; import org.jajuk.ui.actions.ActionManager; import org.jajuk.ui.actions.JajukAction; import org.jajuk.ui.actions.JajukActions; import org.jajuk.ui.helpers.PlayerStateMediator; import org.jajuk.util.Conf; import org.jajuk.util.Const; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; import org.jajuk.util.UtilFeatures; import org.jajuk.util.error.JajukException; import org.jajuk.util.log.Log; import org.jdesktop.swingx.JXPanel; /** * Ambience + History + search panel used in main jajuk window. */ public final class SearchJPanel extends JXPanel implements Observer, ActionListener { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** Self instance. */ private static SearchJPanel ijp = new SearchJPanel(); /** The search box (text field). */ private SearchBox sbSearch; /** the combo-genre history. */ private SteppedComboBox jcbHistory; /** the Ambience selection combo. */ private AmbienceComboBox ambiencesCombo; /** * Singleton access. * * @return the instance */ public static SearchJPanel getInstance() { return ijp; } // widgets declaration /** * Instantiates a new search j panel. */ private SearchJPanel() { super(); } /** * Inits the gui. */ public void initUI() { // Instanciate the PlayerStateMediator to listen for player basic controls PlayerStateMediator.getInstance(); // Search sbSearch = new SearchBox(); // History jcbHistory = new SteppedComboBox(); final JLabel jlHistory = new JLabel(IconLoader.getIcon(JajukIcons.HISTORY)); jlHistory.setToolTipText(Messages.getString("CommandJPanel.0")); // We use a combo box model to make sure we get good performances after // rebuilding the entire model like after a refresh jcbHistory.setModel(new DefaultComboBoxModel(History.getInstance().getHistory())); // None selection because if we start in stop mode, a selection of the // first item will not launch the track because the selected item is // still the same and no action event is thrown (Java >= 1.6) jcbHistory.setSelectedItem(null); int iWidth = (int) (Toolkit.getDefaultToolkit().getScreenSize().getWidth() / 2); // size of popup jcbHistory.setPopupWidth(iWidth); jcbHistory.setToolTipText(Messages.getString("CommandJPanel.0")); jcbHistory.addActionListener(SearchJPanel.this); // Set a custom render to hostory combo in order to show the search icon // inside the combobox jcbHistory.setRenderer(new BasicComboBoxRenderer() { private static final long serialVersionUID = -6943363556191659895L; @Override public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); setIcon(jlHistory.getIcon()); return this; } }); // Ambience combo ambiencesCombo = new AmbienceComboBox(); // Add items setLayout(new MigLayout("insets 5 0 4 3,gapx 30", "[grow 20][grow 70][grow 10]")); add(ambiencesCombo, "left,gap left 16,growx,width 100::"); add(jcbHistory, "grow,center"); add(sbSearch, "right,grow,width 100::"); // register to player events ObservationManager.register(this); // Update initial status UtilFeatures.updateStatus(this); } /* * (non-Javadoc) * * @see org.jajuk.events.Observer#getRegistrationKeys() */ @Override public Set getRegistrationKeys() { Set eventSubjectSet = new HashSet(); eventSubjectSet.add(JajukEvents.PLAYER_STOP); eventSubjectSet.add(JajukEvents.ZERO); eventSubjectSet.add(JajukEvents.FILE_LAUNCHED); eventSubjectSet.add(JajukEvents.AMBIENCES_CHANGE); eventSubjectSet.add(JajukEvents.AMBIENCES_SELECTION_CHANGE); eventSubjectSet.add(JajukEvents.CLEAR_HISTORY); return eventSubjectSet; } /* * (non-Javadoc) * * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent) */ @Override public void actionPerformed(final ActionEvent ae) { // do not run this in a separate thread because Player actions would die // with the thread try { if (ae.getSource() == jcbHistory) { HistoryItem hi; hi = History.getInstance().getHistoryItem(jcbHistory.getSelectedIndex()); if (hi != null) { org.jajuk.base.File file = FileManager.getInstance().getFileByID(hi.getFileId()); if (file != null) { try { QueueModel.push(new StackItem(file, Conf.getBoolean(Const.CONF_STATE_REPEAT_ALL), true), Conf.getBoolean(Const.CONF_OPTIONS_PUSH_ON_CLICK)); } catch (JajukException je) { // can be thrown if file is null } } else { Messages.showErrorMessage(120); jcbHistory.setSelectedItem(null); } } } } catch (Exception e) { Log.error(e); } } /* * (non-Javadoc) * * @see org.jajuk.ui.Observer#update(java.lang.String) */ @Override public void update(final JajukEvent event) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { JajukEvents subject = event.getSubject(); if (JajukEvents.PLAYER_STOP.equals(subject)) { // Reset history so user can launch again stopped // track (selection must change to throw an ActionEvent) jcbHistory.setSelectedIndex(-1); } else if (JajukEvents.ZERO.equals(subject)) { // Reset history so user can launch again stopped // track (selection must change to throw an ActionEvent) jcbHistory.setSelectedIndex(-1); } else if (JajukEvents.FILE_LAUNCHED.equals(subject)) { // Remove history listener, otherwise you'll get a looping // event generation jcbHistory.removeActionListener(SearchJPanel.this); if (jcbHistory.getItemCount() > 0) { jcbHistory.setSelectedIndex(0); jcbHistory.repaint(); } jcbHistory.addActionListener(SearchJPanel.this); } else if (JajukEvents.CLEAR_HISTORY.equals(event.getSubject())) { // clear selection bar (data itself is clear // from the model by History class) jcbHistory.setSelectedItem(null); } else if (JajukEvents.AMBIENCES_CHANGE.equals(event.getSubject()) || JajukEvents.AMBIENCES_SELECTION_CHANGE.equals(event.getSubject())) { ambiencesCombo.populateAmbiences(); updateTooltips(); } } }); } /** * Update global functions tooltip after a change in ambiences or an ambience * selection using the ambience selector. */ private void updateTooltips() { // Selected 'Any" ambience if (ambiencesCombo.getSelectedIndex() == 1) { JajukAction action = ActionManager.getAction(JajukActions.NOVELTIES); action.setShortDescription(Messages.getString("JajukWindow.31")); action = ActionManager.getAction(JajukActions.BEST_OF); action.setShortDescription(Messages.getString("JajukWindow.24")); action = ActionManager.getAction(JajukActions.SHUFFLE_GLOBAL); action.setShortDescription(Messages.getString("JajukWindow.23")); } else {// Selected an ambience Ambience ambience = AmbienceManager.getInstance().getAmbienceByName( ((JLabel) ambiencesCombo.getSelectedItem()).getText()); JajukAction action = ActionManager.getAction(JajukActions.NOVELTIES); action.setShortDescription(Const.HTML + Messages.getString("JajukWindow.31") + Const.P_B + ambience.getName() + Const.B_P_HTML); action = ActionManager.getAction(JajukActions.SHUFFLE_GLOBAL); action.setShortDescription(Const.HTML + Messages.getString("JajukWindow.23") + Const.P_B + ambience.getName() + Const.B_P_HTML); action = ActionManager.getAction(JajukActions.BEST_OF); action.setShortDescription(Const.HTML + Messages.getString("JajukWindow.24") + Const.P_B + ambience.getName() + Const.B_P_HTML); } } }jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/widgets/OKCancelPanel.java0000644000175000017500000000473411720500104025340 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.widgets; import java.awt.event.ActionListener; import javax.swing.JPanel; import net.miginfocom.swing.MigLayout; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; /** * Ok Cancel generic panel. */ public class OKCancelPanel extends JPanel { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** DOCUMENT_ME. */ private final JajukButton jbOk; /** DOCUMENT_ME. */ private final JajukButton jbCancel; /** Associated action listener. */ ActionListener al; /** * Instantiates a new oK cancel panel. * * @param al DOCUMENT_ME */ public OKCancelPanel(ActionListener al) { this.al = al; // buttons setLayout(new MigLayout("ins 5")); jbOk = new JajukButton(Messages.getString("Ok"), IconLoader.getIcon(JajukIcons.OK)); jbOk.addActionListener(al); jbCancel = new JajukButton(Messages.getString("Cancel"), IconLoader.getIcon(JajukIcons.KO)); jbCancel.addActionListener(al); add(jbOk, "tag ok,gapx 5"); add(jbCancel, "tag cancel"); } /** * OK Cancel panel with given button names. * * @param al DOCUMENT_ME * @param sOKTitle DOCUMENT_ME * @param sCancelTitle DOCUMENT_ME */ public OKCancelPanel(ActionListener al, String sOKTitle, String sCancelTitle) { this(al); jbOk.setText(sOKTitle); jbCancel.setText(sCancelTitle); } /** * Gets the oK button. * * @return the oK button */ public JajukButton getOKButton() { return jbOk; } /** * Gets the cancel button. * * @return the cancel button */ public JajukButton getCancelButton() { return jbCancel; } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/widgets/PasswordDialog.java0000644000175000017500000000671611720500104025665 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.widgets; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.ComponentAdapter; import java.awt.event.ComponentEvent; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import javax.swing.JOptionPane; import javax.swing.JPasswordField; import org.jajuk.ui.windows.JajukMainWindow; import org.jajuk.util.Messages; /** * A password dialog. */ public class PasswordDialog extends JajukJDialog implements ActionListener { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** DOCUMENT_ME. */ JPasswordField pf; /** DOCUMENT_ME. */ JOptionPane optionPane; /** * Instantiates a new password dialog. * * @param sMessage DOCUMENT_ME */ public PasswordDialog(String sMessage) { setTitle(sMessage); pf = new JPasswordField(20); // Create the JOptionPane. optionPane = new JOptionPane(new Object[] { Messages.getString("DownloadManager.0"), pf }, JOptionPane.QUESTION_MESSAGE, JOptionPane.OK_CANCEL_OPTION); optionPane.addPropertyChangeListener(new PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent e) { String prop = e.getPropertyName(); if (prop.equals(JOptionPane.VALUE_PROPERTY)) { String sPwd = new String(pf.getPassword()); if (sPwd.trim().equals("")) { // set a string to password to avoid asking again sPwd = "NOP"; } optionPane.setValue(sPwd); dispose(); } } }); // Make this dialog display it. setContentPane(optionPane); // Handle window closing correctly. setDefaultCloseOperation(DO_NOTHING_ON_CLOSE); // Register an event handler that puts the text into the option pane. pf.addActionListener(this); // Ensure the text field always gets the first focus. addComponentListener(new ComponentAdapter() { @Override public void componentShown(ComponentEvent ce) { pf.requestFocusInWindow(); } }); setLocation( JajukMainWindow.getInstance().getX() + JajukMainWindow.getInstance().getWidth() / 3, JajukMainWindow.getInstance().getY() + JajukMainWindow.getInstance().getHeight() / 3); pack(); setVisible(true); } /** * This method handles events for the text field. * * @param e DOCUMENT_ME */ @Override public void actionPerformed(ActionEvent e) { optionPane.setValue(new String(pf.getPassword())); dispose(); } /** * Gets the option pane. * * @return the option pane */ public JOptionPane getOptionPane() { return optionPane; } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/widgets/JajukTable.java0000644000175000017500000005245511720500104024760 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.widgets; import java.awt.event.MouseEvent; import java.text.DateFormat; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.Set; import java.util.StringTokenizer; import javax.swing.JPopupMenu; import javax.swing.JTable; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import javax.swing.event.TableColumnModelEvent; import javax.swing.event.TableColumnModelListener; import javax.swing.table.TableColumn; import javax.swing.table.TableModel; import org.jajuk.base.Item; import org.jajuk.events.JajukEvent; import org.jajuk.events.JajukEvents; import org.jajuk.events.ObservationManager; import org.jajuk.events.Observer; import org.jajuk.ui.helpers.ILaunchCommand; import org.jajuk.ui.helpers.JajukCellRenderer; import org.jajuk.ui.helpers.JajukMouseAdapter; import org.jajuk.ui.helpers.JajukTableModel; import org.jajuk.ui.perspectives.PerspectiveManager; import org.jajuk.ui.views.IView; import org.jajuk.util.Conf; import org.jajuk.util.Const; import org.jajuk.util.UtilGUI; import org.jajuk.util.UtilString; import org.jdesktop.swingx.JXTable; import org.jdesktop.swingx.decorator.CompoundHighlighter; import org.jdesktop.swingx.decorator.Highlighter; import org.jdesktop.swingx.table.DefaultTableColumnModelExt; import org.jdesktop.swingx.table.TableColumnExt; /** * JXTable with following features: *

* Remembers columns visibility *

* Tooltips on each cell *

* Maintain a table of selected rows *

* Bring a menu displayed on right click. */ public class JajukTable extends JXTable implements Observer, TableColumnModelListener, ListSelectionListener { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** DOCUMENT_ME. */ private final String sConf; /** User Selection*. */ private final List selection = new ArrayList(); /** DOCUMENT_ME. */ private final JPopupMenu jmenu; /** Specific action on double click. */ private ILaunchCommand command; /** Model refreshing flag. */ private volatile boolean acceptColumnsEvents = false; /** The Constant FORMATTER. DOCUMENT_ME */ private static final DateFormat FORMATTER = UtilString.getLocaleDateFormatter(); /** Stores the last index of column move to*. */ private int lastToIndex = 0; /** Mouse draging flag. */ private boolean isMouseDragging; /** List of list selection listeners whose valueChanged() method is called by this class valueChanged() method to avoid concurrency between them. Otherwise, the preference menu item could be set with the previous selection value. */ List listeners = new ArrayList(1); /** The Jajuk table mouse adapter used to handle click events. */ JajukMouseAdapter ma = new JajukMouseAdapter() { @Override public void handlePopup(MouseEvent e) { int iSelectedRow = rowAtPoint(e.getPoint()); // right click on a selected node set if none or 1 node is // selected, a right click on another node // select it if more than 1, we keep selection and display a // popup for them if (getSelectedRowCount() < 2) { getSelectionModel().setSelectionInterval(iSelectedRow, iSelectedRow); } // Use getMenu() here, do not use jmenu directly as we want to enable all // items before though getMenu() method getMenu().show(JajukTable.this, e.getX(), e.getY()); } @Override public void handleAction(final MouseEvent e) { command.launch(e.getClickCount()); } }; /** * Return drop row. * * @return drop row */ @SuppressWarnings("cast") public int getDropRow() { JTable.DropLocation dl = (JTable.DropLocation) getDropLocation(); return dl.getRow(); } /** * Constructor. * * @param model : model to use * @param bSortable : is this table sortable * @param sConf DOCUMENT_ME * * @sConf: configuration variable used to store columns conf */ public JajukTable(TableModel model, boolean bSortable, String sConf) { // Note that JTable automatically create a default ListSelectionModel // executing this.valueChanged() at selection changes // so don't add a new listener to avoid double events consumption super(model); acceptColumnsEvents = true; this.sConf = sConf; jmenu = new JPopupMenu(); setShowGrid(false); init(bSortable); // Listen for clicks addMouseListener(ma); //Let Laf handle drag gesture recognition (don't remove it or // a mouse clik disable multiple selection) setDragEnabled(true); // Add the Alternate Highlighter addHighlighter(UtilGUI.getAlternateHighlighter()); // Register itself to incoming events ObservationManager.register(this); } /** * Register a new list selection listener. * * @param listener the listener to register */ public void addListSelectionListener(ListSelectionListener listener) { listeners.add(listener); } /** * Constructor. * * @param model : model to use * @param sConf DOCUMENT_ME * * @sConf: configuration variable used to store columns conf */ public JajukTable(TableModel model, String sConf) { this(model, true, sConf); } /** * Inits the. DOCUMENT_ME * * @param bSortable DOCUMENT_ME */ private void init(boolean bSortable) { super.setSortable(bSortable); super.setColumnControlVisible(true); } /** * Select columns to show colsToShow list of columns id to keep. * * @param colsToShow DOCUMENT_ME */ @SuppressWarnings("unchecked") public void showColumns(List colsToShow) { boolean acceptColumnsEventsSave = acceptColumnsEvents; // Ignore columns event during these actions acceptColumnsEvents = false; Iterator it = ((DefaultTableColumnModelExt) getColumnModel()).getColumns(false).iterator(); while (it.hasNext()) { TableColumnExt col = (TableColumnExt) it.next(); if (!colsToShow.contains(((JajukTableModel) getModel()).getIdentifier(col.getModelIndex()))) { col.setVisible(false); } } reorderColumns(); // Force to use Jajuk cell render for all columns for (TableColumn col : getColumns()) { col.setCellRenderer(new JajukCellRenderer()); } acceptColumnsEvents = acceptColumnsEventsSave; } /* * Reorder columns order according to given conf */ /** * Reorder columns. * DOCUMENT_ME */ private void reorderColumns() { // Build the index array List index = new ArrayList(10); StringTokenizer st = new StringTokenizer(Conf.getString(this.sConf), ","); while (st.hasMoreTokens()) { index.add(st.nextToken()); } // Now reorder the columns: remove all columns and re-add them according the // new order JajukTableModel model = (JajukTableModel) getModel(); Map map = new HashMap(); List initialColumns = getColumns(true); for (TableColumn column : initialColumns) { map.put(model.getIdentifier(column.getModelIndex()), column); getColumnModel().removeColumn(column); } for (String sID : index) { TableColumn col = map.get(sID); if (col != null) { // Col can be null after user created a new custom property getColumnModel().addColumn(col); } } // Now add unvisible columns so they are available in table column selector // at after the visible ones for (TableColumn column : initialColumns) { if (!index.contains(model.getIdentifier(column.getModelIndex()))) { getColumnModel().addColumn(column); } } // set stored column width // disable auto-resize temporary to set stored sizes setAutoResizeMode(JTable.AUTO_RESIZE_OFF); String tableID = getTableId(); for (int currentColumnIndex = 0; currentColumnIndex < getColumnModel().getColumnCount(); currentColumnIndex++) { String identifier = ((JajukTableModel) getModel()) .getIdentifier(convertColumnIndexToModel(currentColumnIndex)); String confId = tableID + "." + identifier + ".width"; if (Conf.containsProperty(confId)) { getColumnModel().getColumn(currentColumnIndex).setPreferredWidth(Conf.getInt(confId)); } } setAutoResizeMode(JTable.AUTO_RESIZE_SUBSEQUENT_COLUMNS); // must be done here and not before we add columns if (Conf.containsProperty(getConfKeyForIsHorizontalScrollable())) { setHorizontalScrollEnabled(Conf.getBoolean(getConfKeyForIsHorizontalScrollable())); } } /** * Gets the columns conf. * * @return list of visible columns names as string */ public List getColumnsConf() { List alOut = new ArrayList(10); String value = Conf.getString(sConf); StringTokenizer st = new StringTokenizer(value, ","); while (st.hasMoreTokens()) { alOut.add(st.nextToken()); } return alOut; } /** * Add a new property into columns conf. * * @param property DOCUMENT_ME */ public void addColumnIntoConf(String property) { if (sConf == null) { return; } List alOut = getColumnsConf(); if (!alOut.contains(property)) { String value = Conf.getString(sConf); Conf.setProperty(sConf, value + "," + property); } } /** * Remove a property from columns conf. * * @param property DOCUMENT_ME */ public void removeColumnFromConf(String property) { if (sConf == null) { return; } List alOut = getColumnsConf(); alOut.remove(property); Conf.setProperty(sConf, getColumnsConf(alOut)); } /** * Column change. DOCUMENT_ME */ private void columnChange() { // ignore this column change when reloading // model if (acceptColumnsEvents) { // If a property is given to store the column, create the new columns // configuration if (this.sConf != null) { createColumnsConf(); } // Force table rebuilding Properties details = new Properties(); details.put(Const.DETAIL_CONTENT, this); ObservationManager.notify(new JajukEvent(JajukEvents.VIEW_REFRESH_REQUEST, details)); } } /* * (non-Javadoc) * * @see javax.swing.JTable#columnAdded(javax.swing.event.TableColumnModelEvent) */ @Override public void columnAdded(TableColumnModelEvent evt) { super.columnAdded(evt); columnChange(); } /* * (non-Javadoc) * * @seeorg.jdesktop.swingx.JXTable#columnRemoved(javax.swing.event. TableColumnModelEvent) */ @Override public void columnRemoved(TableColumnModelEvent evt) { super.columnRemoved(evt); columnChange(); } /* * (non-Javadoc) * * @see javax.swing.JTable#columnMoved(javax.swing.event.TableColumnModelEvent) */ @Override public void columnMoved(TableColumnModelEvent evt) { super.columnMoved(evt); /* * We ignore events if last to index is still the same for performances reasons (this event * doesn't come with a isAdjusting() method) */ if (acceptColumnsEvents && evt.getToIndex() != lastToIndex) { lastToIndex = evt.getToIndex(); if (this.sConf != null) { createColumnsConf(); } } } /** * Create the jtable visible columns conf. */ public void createColumnsConf() { StringBuilder sb = new StringBuilder(); int cols = getColumnCount(false); for (int i = 0; i < cols; i++) { String sIdentifier = ((JajukTableModel) getModel()) .getIdentifier(convertColumnIndexToModel(i)); sb.append(sIdentifier + ","); } String value; // remove last comma if (sb.length() > 0) { value = sb.substring(0, sb.length() - 1); } else { value = sb.toString(); } Conf.setProperty(sConf, value); } /** * Gets the columns conf. * * @param alCol DOCUMENT_ME * * @return columns configuration from given list of columns identifiers */ private String getColumnsConf(List alCol) { StringBuilder sb = new StringBuilder(); Iterator it = alCol.iterator(); while (it.hasNext()) { sb.append(it.next() + ","); } // remove last comma if (sb.length() > 0) { return sb.substring(0, sb.length() - 1); } else { return sb.toString(); } } /** * add tooltips to each cell. * * @param e DOCUMENT_ME * * @return the tool tip text */ @Override public String getToolTipText(MouseEvent e) { java.awt.Point p = e.getPoint(); int rowIndex = rowAtPoint(p); int colIndex = columnAtPoint(p); if (rowIndex < 0 || colIndex < 0) { return null; } Object o = getModel().getValueAt(convertRowIndexToModel(rowIndex), convertColumnIndexToModel(colIndex)); if (o == null) { return null; } else if (o instanceof IconLabel) { return ((IconLabel) o).getTooltip(); } else if (o instanceof Date) { return FORMATTER.format((Date) o); } else { return o.toString(); } } /** * Select a list of rows. * * @param indexes list of row indexes to be selected */ public void setSelectedRows(int[] indexes) { for (int element : indexes) { addRowSelectionInterval(element, element); } } /* * (non-Javadoc) * * @see javax.swing.JTable#valueChanged(javax.swing.event.ListSelectionEvent) */ @Override public void valueChanged(ListSelectionEvent e) { if (e.getValueIsAdjusting()) { return; } // Ignore event if the model is refreshing if (getModel() instanceof JajukTableModel) { if (((JajukTableModel) getModel()).isRefreshing()) { return; } } updateSelection(); // throw a table selection changed event providing the current perspective, view and // selection (used for tree/table sync) Properties properties = new Properties(); properties.put(Const.DETAIL_SELECTION, getSelection()); properties.put(Const.DETAIL_PERSPECTIVE, PerspectiveManager.getCurrentPerspective().getID()); // Test parent view nullity to avoid NPE IView parentView = UtilGUI.getParentView(this); if (parentView != null) { properties.put(Const.DETAIL_VIEW, parentView); } ObservationManager.notify(new JajukEvent(JajukEvents.TABLE_SELECTION_CHANGED, properties)); // Call specific behaviors for (ListSelectionListener listener : listeners) { listener.valueChanged(e); } } /** * Update the selection. */ public void updateSelection() { JajukTableModel model = (JajukTableModel) getModel(); selection.clear(); int[] rows = getSelectedRows(); for (int element : rows) { Item o = model.getItemAt(convertRowIndexToModel(element)); selection.add(o); } } /** * Gets the selection. * * @return the selection */ public List getSelection() { return this.selection; } /** * Return generic popup menu for items in a table.
* * @return generic popup menu for items in a table */ public JPopupMenu getMenu() { return this.jmenu; } /* * (non-Javadoc) * * @see java.awt.event.MouseListener#mouseClicked(java.awt.event.MouseEvent) */ /** * Mouse clicked. * DOCUMENT_ME * * @param e DOCUMENT_ME */ public void mouseClicked(MouseEvent e) { // nothing to do here for now } /* * (non-Javadoc) * * @see java.awt.event.MouseListener#mouseEntered(java.awt.event.MouseEvent) */ /** * Mouse entered. * DOCUMENT_ME * * @param e DOCUMENT_ME */ public void mouseEntered(MouseEvent e) { // nothing to do here for now } /* * (non-Javadoc) * * @see java.awt.event.MouseListener#mouseExited(java.awt.event.MouseEvent) */ /** * Mouse exited. * DOCUMENT_ME * * @param e DOCUMENT_ME */ public void mouseExited(MouseEvent e) { // nothing to do here for now } /** * Gets the command. * * @return the command */ public ILaunchCommand getCommand() { return this.command; } /** * Sets the command. * * @param command the new command */ public void setCommand(ILaunchCommand command) { this.command = command; } /** * Sets the accept columns events. * * @param acceptColumnsEvents the new accept columns events */ public void setAcceptColumnsEvents(boolean acceptColumnsEvents) { this.acceptColumnsEvents = acceptColumnsEvents; } /* * (non-Javadoc) * * @see org.jajuk.events.Observer#getRegistrationKeys() */ @Override public Set getRegistrationKeys() { Set eventSubjectSet = new HashSet(); eventSubjectSet.add(JajukEvents.EXITING); return eventSubjectSet; } /* * (non-Javadoc) * * @see org.jajuk.events.Observer#update(org.jajuk.events.JajukEvent) */ @Override public void update(JajukEvent event) { JajukEvents subject = event.getSubject(); if (JajukEvents.EXITING.equals(subject)) { Conf.setProperty(getConfKeyForIsHorizontalScrollable(), Boolean .toString(isHorizontalScrollEnabled())); // store column margin String tableID = getTableId(); for (int currentColumnIndex = 0; currentColumnIndex < getColumnModel().getColumnCount(); currentColumnIndex++) { String width = Integer.toString(getColumnModel().getColumn(currentColumnIndex).getWidth()); String identifier = ((JajukTableModel) getModel()) .getIdentifier(convertColumnIndexToModel(currentColumnIndex)); Conf.setProperty(tableID + "." + identifier + ".width", width); } } } /** * Gets the conf key for is horizontal scrollable. * * @return the conf key for is horizontal scrollable */ private String getConfKeyForIsHorizontalScrollable() { return getTableId() + ".is_horizontal_scrollable"; } /** * Gets the table id. * * @return the table id */ private String getTableId() { String tableID = sConf; if (tableID == null) { tableID = "jajuk.table"; } return tableID; } /** * Remove previous alternate highlighter and add a new one * It is required because after theme change, the alternate * highlighter colors are no more valid. * * @see org.jdesktop.swingx.JXTable#updateUI() */ @Override public void updateUI() { for (Highlighter highlighter : getHighlighters()) { if (highlighter instanceof CompoundHighlighter) { if (UtilGUI.isAlternateColorHighlighter(highlighter)) { removeHighlighter(highlighter); UtilGUI.resetAlternateColorHighlighter(); addHighlighter(UtilGUI.getAlternateHighlighter()); } } } super.updateUI(); } // Fix for a JRE issue,see : // During a single adjusting ListSelectionEvent, several rows can be selected // before the drag actually begins (except when using SINGLE_SELECTION selection mode). // For instance, select row 1 and release mouse // then select row 2 without releasing the mouse and begin to drag from the top to the bottom : // in some cases, when dragging quickly, rows 2 AND 3 (and even row 4 sometimes) are selected. // Fix thanks jeffsabin in http://forums.sun.com/thread.jspa?threadID=5436355 /* (non-Javadoc) * @see javax.swing.JComponent#processMouseEvent(java.awt.event.MouseEvent) */ @Override protected void processMouseEvent(MouseEvent e) { isMouseDragging = (e.getID() == MouseEvent.MOUSE_DRAGGED); super.processMouseEvent(e); } /* (non-Javadoc) * @see javax.swing.JComponent#processMouseMotionEvent(java.awt.event.MouseEvent) */ @Override protected void processMouseMotionEvent(MouseEvent e) { isMouseDragging = (e.getID() == MouseEvent.MOUSE_DRAGGED); super.processMouseMotionEvent(e); } /* (non-Javadoc) * @see javax.swing.JTable#setRowSelectionInterval(int, int) */ @Override public void setRowSelectionInterval(int index0, int index1) { if (!isMouseDragging) { super.setRowSelectionInterval(index0, index1); } } /* (non-Javadoc) * @see javax.swing.JTable#setColumnSelectionInterval(int, int) */ @Override public void setColumnSelectionInterval(int index0, int index1) { if (!isMouseDragging) { super.setColumnSelectionInterval(index0, index1); } } /* (non-Javadoc) * @see javax.swing.JTable#changeSelection(int, int, boolean, boolean) */ @Override public void changeSelection(int rowIndex, int columnIndex, boolean toggle, boolean extend) { if (!isMouseDragging) { super.changeSelection(rowIndex, columnIndex, toggle, extend); } } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/widgets/SizedJMenuItem.java0000644000175000017500000000301011720500104025557 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.widgets; import javax.swing.Action; import javax.swing.Icon; import javax.swing.ImageIcon; import javax.swing.JMenuItem; import org.jajuk.util.UtilGUI; /** * Menu item whose icon has a fixed size. */ public class SizedJMenuItem extends JMenuItem { /** Generated serialVersionUID. */ private static final long serialVersionUID = -3859493402696496345L; /** * Menu item with a fixed 16x216 icon dimension. * * @param action action */ public SizedJMenuItem(Action action) { super(action); } /** * Sets the icon. * * @param icon DOCUMENT_ME */ @Override public void setIcon(Icon icon) { super.setIcon(UtilGUI.getResizedImage((ImageIcon) icon, 16, 16)); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/widgets/JajukJMenuBar.java0000644000175000017500000004525511720500104025374 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.widgets; import static org.jajuk.ui.actions.JajukActions.CONFIGURE_AMBIENCES; import static org.jajuk.ui.actions.JajukActions.CONFIGURE_DJS; import static org.jajuk.ui.actions.JajukActions.CONTINUE_MODE; import static org.jajuk.ui.actions.JajukActions.CUSTOM_PROPERTIES_ADD; import static org.jajuk.ui.actions.JajukActions.CUSTOM_PROPERTIES_REMOVE; import static org.jajuk.ui.actions.JajukActions.EXTRA_TAGS_WIZARD; import static org.jajuk.ui.actions.JajukActions.HELP_REQUIRED; import static org.jajuk.ui.actions.JajukActions.INTRO_MODE; import static org.jajuk.ui.actions.JajukActions.OPTIONS; import static org.jajuk.ui.actions.JajukActions.QUALITY; import static org.jajuk.ui.actions.JajukActions.REPEAT_ALL_MODE; import static org.jajuk.ui.actions.JajukActions.REPEAT_MODE; import static org.jajuk.ui.actions.JajukActions.SHOW_ABOUT; import static org.jajuk.ui.actions.JajukActions.SHOW_DONATE; import static org.jajuk.ui.actions.JajukActions.SHOW_TRACES; import static org.jajuk.ui.actions.JajukActions.SHUFFLE_MODE; import static org.jajuk.ui.actions.JajukActions.SIMPLE_DEVICE_WIZARD; import static org.jajuk.ui.actions.JajukActions.TIP_OF_THE_DAY; import static org.jajuk.ui.actions.JajukActions.VIEW_RESTORE_DEFAULTS; import java.awt.BorderLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.HashSet; import java.util.Set; import javax.swing.Box; import javax.swing.JButton; import javax.swing.JCheckBoxMenuItem; import javax.swing.JLabel; import javax.swing.JMenu; import javax.swing.JMenuBar; import javax.swing.JMenuItem; import javax.swing.SwingConstants; import javax.swing.SwingUtilities; import javax.swing.SwingWorker; import org.apache.commons.lang.StringUtils; import org.jajuk.events.JajukEvent; import org.jajuk.events.JajukEvents; import org.jajuk.events.ObservationManager; import org.jajuk.events.Observer; import org.jajuk.services.core.SessionService; import org.jajuk.ui.actions.ActionManager; import org.jajuk.ui.actions.ActionUtil; import org.jajuk.ui.actions.JajukActions; import org.jajuk.ui.perspectives.PerspectiveAdapter; import org.jajuk.ui.perspectives.PerspectiveManager; import org.jajuk.ui.views.IView; import org.jajuk.ui.views.ViewFactory; import org.jajuk.util.Conf; import org.jajuk.util.Const; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; import org.jajuk.util.UpgradeManager; import org.jajuk.util.UtilSystem; import org.jajuk.util.log.Log; /** * Jajuk menu bar *

* Singleton. */ public final class JajukJMenuBar extends JMenuBar implements Observer { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** The singleton. */ static JajukJMenuBar jjmb = new JajukJMenuBar(); /** DOCUMENT_ME. */ JMenu file; /** DOCUMENT_ME. */ JMenuItem jmiFileExit; /** DOCUMENT_ME. */ JMenu views; /** DOCUMENT_ME. */ JMenuItem jmiRestoreDefaultViews; /** DOCUMENT_ME. */ JMenuItem jmiRestoreDefaultViewsAllPerpsectives; /** DOCUMENT_ME. */ JMenu properties; /** DOCUMENT_ME. */ JMenuItem jmiNewProperty; /** DOCUMENT_ME. */ JMenuItem jmiRemoveProperty; /** DOCUMENT_ME. */ JMenu mode; /** DOCUMENT_ME. */ JCheckBoxMenuItem jcbShowPopups; /** DOCUMENT_ME. */ JCheckBoxMenuItem jcbNoneInternetAccess; /** DOCUMENT_ME. */ private final JCheckBoxMenuItem jcbmiRepeat; /** DOCUMENT_ME. */ private final JCheckBoxMenuItem jcbmiShuffle; /** DOCUMENT_ME. */ private final JCheckBoxMenuItem jcbmiContinue; /** DOCUMENT_ME. */ private final JCheckBoxMenuItem jcbmiIntro; /** DOCUMENT_ME. */ private final JCheckBoxMenuItem jcbmiKaraoke; /** DOCUMENT_ME. */ JMenuBar mainmenu; /** DOCUMENT_ME. */ JMenu smart; /** DOCUMENT_ME. */ JMenuItem jmiShuffle; /** DOCUMENT_ME. */ JMenuItem jmiBestof; /** DOCUMENT_ME. */ JMenuItem jmiNovelties; /** DOCUMENT_ME. */ JMenuItem jmiFinishAlbum; /** DOCUMENT_ME. */ JMenu tools; /** DOCUMENT_ME. */ JMenuItem jmiduplicateFinder; /** DOCUMENT_ME. */ JMenuItem jmialarmClock; /** DOCUMENT_ME. */ JMenuItem jmiprepareParty; /** DOCUMENT_ME. */ JMenu configuration; /** DOCUMENT_ME. */ JMenuItem jmiDJ; /** DOCUMENT_ME. */ JMenuItem jmiAmbience; /** DOCUMENT_ME. */ JMenuItem jmiWebradios; /** DOCUMENT_ME. */ JMenuItem jmiWizard; /** DOCUMENT_ME. */ JMenuItem jmiOptions; /** DOCUMENT_ME. */ JCheckBoxMenuItem jmiUnmounted; /** DOCUMENT_ME. */ JMenu help; /** DOCUMENT_ME. */ JMenuItem jmiHelp; /** DOCUMENT_ME. */ JMenuItem jmiTipOfTheDay; /** DOCUMENT_ME. */ JMenuItem jmiQualityAgent; /** DOCUMENT_ME. */ JMenuItem jmiTraces; /** DOCUMENT_ME. */ JMenuItem jmiCheckforUpdates; /** DOCUMENT_ME. */ JMenuItem jmiAbout; /** DOCUMENT_ME. */ JLabel jlUpdate; /** DOCUMENT_ME. */ JButton jbGC; /** DOCUMENT_ME. */ JButton jbCommit; /** DOCUMENT_ME. */ JButton jbSlim; /** DOCUMENT_ME. */ private JajukButton jbFull = null; /** DOCUMENT_ME. */ private final JCheckBoxMenuItem jcbmiRepeatAll; /** The jmi activate tags. */ private JMenuItem jmiActivateTags; /** DOCUMENT_ME. */ private JMenuItem jmiDonate; /** * Instantiates a new jajuk j menu bar. */ private JajukJMenuBar() { setAlignmentX(0.0f); // File menu file = new JMenu(Messages.getString("JajukJMenuBar.0")); jmiFileExit = new JMenuItem(ActionManager.getAction(JajukActions.EXIT)); file.add(jmiFileExit); // Properties menu properties = new JMenu(Messages.getString("JajukJMenuBar.5")); jmiNewProperty = new JMenuItem(ActionManager.getAction(CUSTOM_PROPERTIES_ADD)); jmiRemoveProperty = new JMenuItem(ActionManager.getAction(CUSTOM_PROPERTIES_REMOVE)); jmiActivateTags = new JMenuItem(ActionManager.getAction(EXTRA_TAGS_WIZARD)); properties.add(jmiNewProperty); properties.add(jmiRemoveProperty); properties.add(jmiActivateTags); // View menu views = new JMenu(Messages.getString("JajukJMenuBar.8")); jmiRestoreDefaultViews = new JMenuItem(ActionManager.getAction(VIEW_RESTORE_DEFAULTS)); jmiRestoreDefaultViewsAllPerpsectives = new JMenuItem(ActionManager .getAction(JajukActions.ALL_VIEW_RESTORE_DEFAULTS)); views.add(jmiRestoreDefaultViews); views.add(jmiRestoreDefaultViewsAllPerpsectives); views.addSeparator(); // Add the list of available views parsed in XML files at startup JMenu jmViews = new JMenu(Messages.getString("JajukJMenuBar.25")); for (final Class view : ViewFactory.getKnownViews()) { JMenuItem jmi = null; try { jmi = new JMenuItem(view.newInstance().getDesc(), IconLoader.getIcon(JajukIcons.LOGO_FRAME)); } catch (Exception e1) { Log.error(e1); continue; } jmi.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { // Simply add the new view in the current perspective PerspectiveAdapter current = (PerspectiveAdapter) PerspectiveManager .getCurrentPerspective(); IView newView = ViewFactory.createView(view, current, (int) (Integer.MAX_VALUE * UtilSystem.getRandom().nextDouble())); newView.initUI(); newView.setIsPopulated(true); current.addDockable(newView); } }); jmViews.add(jmi); } views.add(jmViews); // Mode menu String modeText = Messages.getString("JajukJMenuBar.9"); mode = new JMenu(ActionUtil.strip(modeText)); jcbmiRepeat = new JCheckBoxMenuItem(ActionManager.getAction(REPEAT_MODE)); jcbmiRepeat.setSelected(Conf.getBoolean(Const.CONF_STATE_REPEAT)); jcbmiRepeatAll = new JCheckBoxMenuItem(ActionManager.getAction(REPEAT_ALL_MODE)); jcbmiRepeatAll.setSelected(Conf.getBoolean(Const.CONF_STATE_REPEAT_ALL)); jcbmiShuffle = new JCheckBoxMenuItem(ActionManager.getAction(SHUFFLE_MODE)); jcbmiShuffle.setSelected(Conf.getBoolean(Const.CONF_STATE_SHUFFLE)); jcbmiContinue = new JCheckBoxMenuItem(ActionManager.getAction(CONTINUE_MODE)); jcbmiContinue.setSelected(Conf.getBoolean(Const.CONF_STATE_CONTINUE)); jcbmiIntro = new JCheckBoxMenuItem(ActionManager.getAction(INTRO_MODE)); jcbmiIntro.setSelected(Conf.getBoolean(Const.CONF_STATE_INTRO)); jcbmiKaraoke = new JCheckBoxMenuItem(ActionManager.getAction(JajukActions.KARAOKE_MODE)); jcbmiKaraoke.setSelected(Conf.getBoolean(Const.CONF_STATE_KARAOKE)); mode.add(jcbmiRepeat); mode.add(jcbmiRepeatAll); mode.add(jcbmiShuffle); mode.add(jcbmiContinue); mode.add(jcbmiIntro); mode.add(jcbmiKaraoke); // Smart Menu smart = new JMenu(Messages.getString("JajukJMenuBar.29")); jmiShuffle = new SizedJMenuItem(ActionManager.getAction(JajukActions.SHUFFLE_GLOBAL)); jmiBestof = new SizedJMenuItem(ActionManager.getAction(JajukActions.BEST_OF)); jmiNovelties = new SizedJMenuItem(ActionManager.getAction(JajukActions.NOVELTIES)); jmiFinishAlbum = new SizedJMenuItem(ActionManager.getAction(JajukActions.FINISH_ALBUM)); smart.add(jmiShuffle); smart.add(jmiBestof); smart.add(jmiNovelties); smart.add(jmiFinishAlbum); // Tools Menu tools = new JMenu(Messages.getString("JajukJMenuBar.28")); jmiduplicateFinder = new JMenuItem(ActionManager.getAction(JajukActions.FIND_DUPLICATE_FILES)); jmialarmClock = new JMenuItem(ActionManager.getAction(JajukActions.ALARM_CLOCK)); jmiprepareParty = new JMenuItem(ActionManager.getAction(JajukActions.PREPARE_PARTY)); tools.add(jmiduplicateFinder); tools.add(jmialarmClock); tools.add(jmiprepareParty); // tools.addSeparator(); // Configuration menu configuration = new JMenu(Messages.getString("JajukJMenuBar.21")); jmiDJ = new JMenuItem(ActionManager.getAction(CONFIGURE_DJS)); // Overwrite default icon jmiDJ.setIcon(IconLoader.getIcon(JajukIcons.DIGITAL_DJ_16X16)); jmiAmbience = new JMenuItem(ActionManager.getAction(CONFIGURE_AMBIENCES)); jmiWebradios = new JMenuItem(ActionManager.getAction(JajukActions.CONFIGURE_WEBRADIOS)); jmiWebradios.setIcon(IconLoader.getIcon(JajukIcons.WEBRADIO_16X16)); jmiWizard = new JMenuItem(ActionManager.getAction(SIMPLE_DEVICE_WIZARD)); jmiOptions = new JMenuItem(ActionManager.getAction(OPTIONS)); jmiUnmounted = new JCheckBoxMenuItem(ActionManager.getAction(JajukActions.UNMOUNTED)); jmiUnmounted.setSelected(Conf.getBoolean(Const.CONF_OPTIONS_HIDE_UNMOUNTED)); jmiUnmounted.putClientProperty(Const.DETAIL_ORIGIN, jmiUnmounted); jcbShowPopups = new JCheckBoxMenuItem(Messages.getString("ParameterView.228")); jcbShowPopups.setSelected(Conf.getBoolean(Const.CONF_SHOW_POPUPS)); jcbShowPopups.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { Conf.setProperty(Const.CONF_SHOW_POPUPS, Boolean.toString(jcbShowPopups.isSelected())); // force parameter view to take this into account ObservationManager.notify(new JajukEvent(JajukEvents.PARAMETERS_CHANGE)); } }); jcbNoneInternetAccess = new JCheckBoxMenuItem(Messages.getString("ParameterView.264")); jcbNoneInternetAccess.setToolTipText(Messages.getString("ParameterView.265")); jcbNoneInternetAccess.setSelected(Conf.getBoolean(Const.CONF_NETWORK_NONE_INTERNET_ACCESS)); jcbNoneInternetAccess.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { Conf.setProperty(Const.CONF_NETWORK_NONE_INTERNET_ACCESS, Boolean .toString(jcbNoneInternetAccess.isSelected())); // force parameter view to take this into account ObservationManager.notify(new JajukEvent(JajukEvents.PARAMETERS_CHANGE)); } }); configuration.add(jmiUnmounted); configuration.add(jcbShowPopups); configuration.add(jcbNoneInternetAccess); configuration.addSeparator(); configuration.add(jmiDJ); configuration.add(jmiAmbience); configuration.add(jmiWebradios); configuration.add(jmiWizard); configuration.add(jmiOptions); // Help menu String helpText = Messages.getString("JajukJMenuBar.14"); help = new JMenu(ActionUtil.strip(helpText)); jmiHelp = new JMenuItem(ActionManager.getAction(HELP_REQUIRED)); jmiDonate = new JMenuItem(ActionManager.getAction(SHOW_DONATE)); jmiAbout = new JMenuItem(ActionManager.getAction(SHOW_ABOUT)); jmiTraces = new JMenuItem(ActionManager.getAction(SHOW_TRACES)); jmiTraces = new JMenuItem(ActionManager.getAction(SHOW_TRACES)); jmiCheckforUpdates = new JMenuItem(ActionManager.getAction(JajukActions.CHECK_FOR_UPDATES)); jmiTipOfTheDay = new JMenuItem(ActionManager.getAction(TIP_OF_THE_DAY)); help.add(jmiHelp); help.add(jmiTipOfTheDay); // Install this action only if Desktop class is supported, it is used to // open default mail client if (UtilSystem.isBrowserSupported()) { jmiQualityAgent = new JMenuItem(ActionManager.getAction(QUALITY)); help.add(jmiQualityAgent); } help.add(jmiTraces); help.add(jmiCheckforUpdates); help.add(jmiDonate); help.add(jmiAbout); mainmenu = new JMenuBar(); mainmenu.add(file); mainmenu.add(views); mainmenu.add(properties); mainmenu.add(mode); mainmenu.add(smart); mainmenu.add(tools); mainmenu.add(configuration); mainmenu.add(help); // Apply mnemonics (Alt + first char of the menu keystroke) applyMnemonics(); if (SessionService.isTestMode()) { jbCommit = new JajukButton(ActionManager.getAction(JajukActions.COMMIT)); jbGC = new JajukButton(ActionManager.getAction(JajukActions.GC)); } jbSlim = new JajukButton(ActionManager.getAction(JajukActions.SLIM_JAJUK)); jbFull = new JajukButton(ActionManager.getAction(JajukActions.FULLSCREEN_JAJUK)); JMenuBar eastmenu = new JMenuBar(); // only show GC-button in test-mode if (SessionService.isTestMode()) { eastmenu.add(jbCommit); eastmenu.add(jbGC); } eastmenu.add(jbSlim); eastmenu.add(jbFull); setLayout(new BorderLayout()); add(mainmenu, BorderLayout.WEST); add(eastmenu, BorderLayout.EAST); // Check for new release and display the icon if a new release is available SwingWorker sw = new SwingWorker() { @Override public Void doInBackground() { UpgradeManager.checkForUpdate(); return null; } @Override public void done() { // add the new release label if required if (UpgradeManager.getNewVersionName() != null) { jlUpdate = new JLabel(" ", IconLoader.getIcon(JajukIcons.UPDATE_MANAGER), SwingConstants.RIGHT); String newRelease = UpgradeManager.getNewVersionName(); if (newRelease != null) { jlUpdate.setToolTipText(Messages.getString("UpdateManager.0") + newRelease + Messages.getString("UpdateManager.1")); } add(Box.createHorizontalGlue()); add(jlUpdate); } } }; // Search online for upgrade if the option is set and if the none Internet // access option is not set if (Conf.getBoolean(Const.CONF_CHECK_FOR_UPDATE) && !Conf.getBoolean(Const.CONF_NETWORK_NONE_INTERNET_ACCESS)) { sw.execute(); } ObservationManager.register(this); } /** * Gets the single instance of JajukJMenuBar. * * @return single instance of JajukJMenuBar */ public static JajukJMenuBar getInstance() { return jjmb; } /* * (non-Javadoc) * * @see org.jajuk.events.Observer#getRegistrationKeys() */ @Override public Set getRegistrationKeys() { Set eventSubjectSet = new HashSet(); eventSubjectSet.add(JajukEvents.PARAMETERS_CHANGE); eventSubjectSet.add(JajukEvents.SLIMBAR_VISIBILTY_CHANGED); return eventSubjectSet; } /** * Apply all mnemonics for all menus (follow i18n). */ private void applyMnemonics() { for (int i = 0; i < mainmenu.getMenuCount(); i++) { JMenu menu = mainmenu.getMenu(i); if (menu != null && StringUtils.isNotBlank(menu.getText())) { String label = menu.getText(); int mnemonic = label.getBytes()[0]; menu.setMnemonic(mnemonic); } } } /* * (non-Javadoc) * * @see org.jajuk.ui.Observer#update(java.lang.String) */ @Override public void update(final JajukEvent event) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { if (JajukEvents.PARAMETERS_CHANGE.equals(event.getSubject()) || JajukEvents.SLIMBAR_VISIBILTY_CHANGED.equals(event.getSubject())) { jcbShowPopups.setSelected(Conf.getBoolean(Const.CONF_SHOW_POPUPS)); jmiUnmounted.setSelected(Conf.getBoolean(Const.CONF_OPTIONS_HIDE_UNMOUNTED)); jcbNoneInternetAccess.setSelected(Conf .getBoolean(Const.CONF_NETWORK_NONE_INTERNET_ACCESS)); } } }); } /** * Sets the repeat selected. * * @param b the new repeat selected */ public void setRepeatSelected(final boolean b) { jcbmiRepeat.setSelected(b); } /** * Sets the repeat all selected. * * @param b the new repeat all selected */ public void setRepeatAllSelected(final boolean b) { jcbmiRepeatAll.setSelected(b); } /** * Sets the shuffle selected. * * @param b the new shuffle selected */ public void setShuffleSelected(final boolean b) { jcbmiShuffle.setSelected(b); } /** * Sets the continue selected. * * @param b the new continue selected */ public void setContinueSelected(final boolean b) { jcbmiContinue.setSelected(b); } /** * Sets the intro selected. * * @param b the new intro selected */ public void setIntroSelected(final boolean b) { jcbmiIntro.setSelected(b); } /** * Sets the karaoke selected. * * @param b the new karaoke selected */ public void setKaraokeSelected(final boolean b) { jcbmiKaraoke.setSelected(b); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/helpers/0000755000175000017500000000000011720500104022062 5ustar drazzibdrazzibjajuk-1.9.6.orig/src/main/java/org/jajuk/ui/helpers/RefreshReporter.java0000644000175000017500000000775611720500104026065 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.helpers; import java.util.List; import org.jajuk.base.Device; import org.jajuk.base.Directory; import org.jajuk.base.DirectoryManager; import org.jajuk.util.Messages; import org.jajuk.util.log.Log; /** * Provides devices refresh report features
* Is responsible to manage various UI items changed during refreshing. */ public class RefreshReporter { /** DOCUMENT_ME. */ protected Device device; /** DOCUMENT_ME. */ protected int dirTotal; /** DOCUMENT_ME. */ protected int dirCount; /** Actual refresh date start*. */ protected long lRefreshDateStart; /** Number of new files found during refresh for stats. */ protected int iNbNewFiles; /** Number of corrupted files found during refresh for stats. */ protected int iNbCorruptedFiles; /** * Instantiates a new refresh reporter. * * @param device DOCUMENT_ME */ public RefreshReporter(Device device) { this.device = device; } /** * Startup. * DOCUMENT_ME */ public void startup() { // reset all values as this object is reused reset(); } /** * Reset all values. */ protected void reset() { this.dirTotal = -1; this.dirCount = 0; this.iNbNewFiles = 0; this.iNbCorruptedFiles = 0; this.lRefreshDateStart = System.currentTimeMillis(); List dirs = DirectoryManager.getInstance().getDirectories(); for (Directory dir : dirs) { if (dir.getDevice().equals(device)) { dirTotal++; } } // To avoid "freezing" at 100% if new files have been added since last // refresh, take 5 % of new files dirTotal *= 1.05; } /** * Notify corrupted file. * */ public void notifyCorruptedFile() { iNbCorruptedFiles++; } /** * Notify new file. * */ public void notifyNewFile() { iNbNewFiles++; } /** * Refresh started. * */ public void refreshStarted() { lRefreshDateStart = System.currentTimeMillis(); } /** * Builds the final message. * * * @param time DOCUMENT_ME * * @return the string */ protected String buildFinalMessage(long time) { StringBuilder sbOut = new StringBuilder("[").append(device.getName()).append( Messages.getString("Device.25")) .append(((time < 1000) ? time + " ms" : time / 1000 + " s")).append(" - ").append( iNbNewFiles).append(Messages.getString("Device.27")); if (iNbCorruptedFiles > 0) { sbOut.append(" - ").append(iNbCorruptedFiles).append(Messages.getString("Device.43")); } return sbOut.toString(); } /** * Callback method called at the end of the refresh. */ public void done() { long refreshTime = System.currentTimeMillis() - lRefreshDateStart; String message = buildFinalMessage(refreshTime); Log.debug(message); reset(); } /** * Callback method when old items cleanup is done. This method can be * overwritten for specific behaviors */ public void cleanupDone() { Log.debug("Cleanup done"); } /** * Callback method when an update state is required. Can be overwritten for * specific behaviors * * @param dir DOCUMENT_ME */ public void updateState(Directory dir) { // Intentionnal NOP } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/helpers/DefaultMouseWheelListener.java0000644000175000017500000000311711720500104030017 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.helpers; import java.awt.event.MouseWheelEvent; import java.awt.event.MouseWheelListener; import javax.swing.JSlider; /** * A basic Mouse wheel listener for jsliders. */ public class DefaultMouseWheelListener implements MouseWheelListener { /** DOCUMENT_ME. */ private JSlider js; /** * The Constructor. * * @param js associated jslider */ public DefaultMouseWheelListener(JSlider js) { super(); this.js = js; } /* * (non-Javadoc) * * @see java.awt.event.MouseWheelListener#mouseWheelMoved(java.awt.event.MouseWheelEvent) */ @Override public void mouseWheelMoved(MouseWheelEvent mwe) { int iOld = js.getValue(); int iNew = iOld - mwe.getWheelRotation(); if (js.isEnabled()) { js.setValue(iNew); } } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/helpers/package.html0000644000175000017500000000016011720500104024340 0ustar drazzibdrazzib

Various classes used by UI components (models, handlers, renderers..)

jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/helpers/PlaylistRepositoryTableModel.java0000644000175000017500000001435211720500104030564 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.helpers; import java.util.Date; import java.util.Iterator; import java.util.List; import java.util.Map; import org.apache.commons.collections.CollectionUtils; import org.jajuk.base.Device; import org.jajuk.base.Directory; import org.jajuk.base.Item; import org.jajuk.base.Playlist; import org.jajuk.base.PlaylistManager; import org.jajuk.base.PropertyMetaInformation; import org.jajuk.ui.widgets.IconLabel; import org.jajuk.util.Conf; import org.jajuk.util.Const; import org.jajuk.util.Filter; import org.jajuk.util.Messages; import org.jajuk.util.filters.JajukPredicates; /** * Table model used holding playlist repository data. */ public class PlaylistRepositoryTableModel extends JajukTableModel { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** * Model constructor. */ public PlaylistRepositoryTableModel() { super(5); setEditable(false); // Columns names // First column is play icon, need to set a space character // for proper display in some look and feel vColNames.add(" "); idList.add(Const.XML_PLAY); vColNames.add(Messages.getHumanPropertyName(Const.XML_NAME)); idList.add(Const.XML_NAME); vColNames.add(Messages.getHumanPropertyName(Const.XML_DEVICE)); idList.add(Const.XML_DEVICE); vColNames.add(Messages.getHumanPropertyName(Const.XML_DIRECTORY)); idList.add(Const.XML_DIRECTORY); vColNames.add(Messages.getHumanPropertyName(Const.XML_PATH)); idList.add(Const.XML_PATH); // custom properties now for (PropertyMetaInformation meta : PlaylistManager.getInstance().getCustomProperties()) { vColNames.add(meta.getName()); idList.add(meta.getName()); } } /** * Fill model with data using an optional filter property and pattern *

* For now, this table will not be editable (except for custom properties) for * complexity reasons. This may be implemented in the future if required *

* * @param sPropertyName DOCUMENT_ME * @param sPattern DOCUMENT_ME * @param columnsToShow DOCUMENT_ME */ @Override @SuppressWarnings("unchecked") public void populateModel(String sPropertyName, String sPattern, List columnsToShow) { List alToShow = PlaylistManager.getInstance().getPlaylists(); // OK, begin by filtering using any provided pattern Filter filter = new Filter(sPropertyName, sPattern, true, Conf.getBoolean(Const.CONF_REGEXP)); Filter.filterItems(alToShow, filter); // filter unavailable playlists if (Conf.getBoolean(Const.CONF_OPTIONS_HIDE_UNMOUNTED)) { CollectionUtils.filter(alToShow, new JajukPredicates.ReadyPlaylistPredicate()); } Iterator it = null; int iColNum = iNumberStandardCols + PlaylistManager.getInstance().getCustomProperties().size(); iRowNum = alToShow.size(); oValues = new Object[iRowNum][iColNum]; oItems = new Item[iRowNum]; bCellEditable = new boolean[iRowNum][iColNum]; // Allow only custom properties edition bEditable = true; // For perfs, prepare columns visibility boolean bName = (columnsToShow != null && columnsToShow.contains(Const.XML_NAME)); boolean bDevice = (columnsToShow != null && columnsToShow.contains(Const.XML_DEVICE)); boolean bDirectory = (columnsToShow != null && columnsToShow.contains(Const.XML_DIRECTORY)); boolean bPath = (columnsToShow != null && columnsToShow.contains(Const.XML_PATH)); it = alToShow.iterator(); for (int iRow = 0; it.hasNext(); iRow++) { Playlist plf = it.next(); setItemAt(iRow, plf); Map properties = plf.getProperties(); // Id oItems[iRow] = plf; // Play IconLabel il = null; if (plf.getDirectory().getDevice().isMounted()) { il = getIcon(false); } else { il = getIcon(true); } // Note: if you want to add an image, use an ImageIcon class and // change oValues[iRow][0] = il; bCellEditable[iRow][0] = false; // Playlist Name if (bName) { oValues[iRow][1] = plf.getName(); } else { oValues[iRow][1] = ""; } bCellEditable[iRow][1] = false; // Device if (bDevice) { Device device = plf.getDirectory().getDevice(); oValues[iRow][2] = device.getName(); } else { oValues[iRow][2] = ""; } bCellEditable[iRow][2] = false; // Directory if (bDirectory) { Directory directory = plf.getDirectory(); oValues[iRow][3] = directory.getName(); } else { oValues[iRow][3] = ""; } bCellEditable[iRow][3] = false; // PATH if (bPath) { String path = plf.getAbsolutePath(); oValues[iRow][4] = path; } else { oValues[iRow][4] = ""; } bCellEditable[iRow][4] = false; // Custom properties now Iterator it2 = PlaylistManager.getInstance().getCustomProperties().iterator(); for (int i = 0; it2.hasNext(); i++) { PropertyMetaInformation meta = (PropertyMetaInformation) it2.next(); Object o = properties.get(meta.getName()); if (o != null) { oValues[iRow][iNumberStandardCols + i] = o; } else { oValues[iRow][iNumberStandardCols + i] = meta.getDefaultValue(); } // Date values not editable, use properties panel instead to // edit bCellEditable[iRow][iNumberStandardCols + i] = !(meta.getType().equals(Date.class)); } } } }jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/helpers/PlaylistEditorTransferHandler.java0000644000175000017500000001444111720500104030704 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.helpers; import java.awt.datatransfer.DataFlavor; import java.awt.datatransfer.Transferable; import java.util.List; import javax.swing.JComponent; import org.jajuk.base.File; import org.jajuk.base.Item; import org.jajuk.base.Playlist; import org.jajuk.services.players.QueueModel; import org.jajuk.ui.views.PlaylistView; import org.jajuk.ui.widgets.JajukTable; import org.jajuk.util.Conf; import org.jajuk.util.Const; import org.jajuk.util.Messages; import org.jajuk.util.UtilFeatures; import org.jajuk.util.error.JajukException; import org.jajuk.util.log.Log; /** * DND handler for table. */ public class PlaylistEditorTransferHandler extends TableTransferHandler { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** * Constructor. * * @param jtable DOCUMENT_ME */ public PlaylistEditorTransferHandler(final JajukTable jtable) { super(jtable); } /** * Called when dropping. * * @param c DOCUMENT_ME * @param t DOCUMENT_ME * * @return true, if import data */ @SuppressWarnings("unchecked") @Override public boolean importData(JComponent c, Transferable t) { try { if (canImport(c, t.getTransferDataFlavors())) { // Note that component hierarchy is different between queue and playlist // view JComponent comp = (JComponent) c.getParent(); while (!(comp instanceof PlaylistView)) { comp = (JComponent) comp.getParent(); } PlaylistView view = ((PlaylistView) comp); JajukTable jtable = view.getTable(); // fetch the drop location int row = jtable.getDropRow(); Playlist plf = view.getCurrentPlaylist(); Object oData = null; DataFlavor flavor = t.getTransferDataFlavors()[0]; if (flavor.getHumanPresentableName().equals( TransferableTableRows.ROW_FLAVOR.getHumanPresentableName())) { TransferableTableRows ttr = (TransferableTableRows) t .getTransferData(TransferableTableRows.ROW_FLAVOR); oData = ttr.getUserObject(); } else if (flavor.getHumanPresentableName().equals( TransferableTreeNodes.NODE_FLAVOR.getHumanPresentableName())) { TransferableTreeNodes ttn = (TransferableTreeNodes) t .getTransferData(TransferableTreeNodes.NODE_FLAVOR); oData = ttn.getUserObject(); } else if (flavor.getHumanPresentableName().equals( TransferableAlbum.ALBUM_FLAVOR.getHumanPresentableName())) { TransferableAlbum ttn = (TransferableAlbum) t .getTransferData(TransferableAlbum.ALBUM_FLAVOR); oData = ttn.getUserObject(); } List alSelectedFiles = null; try { alSelectedFiles = UtilFeatures.getFilesForItems((List) oData); } catch (JajukException je) { Log.error(je); Messages.showErrorMessage(je.getCode()); return false; } // If we get zero playing files, just leave, do not display a dummy message in Queue code: if (alSelectedFiles.size() == 0) { return false; } // row = -1 if none item in the table or if we drop after the last row, // we set table's size as an index if (row < 0) { row = plf.getFiles().size(); } // queue case if (plf.getType() == Playlist.Type.QUEUE) { // If user selected "push on drop" option just push the selection if (Conf.getBoolean(Const.CONF_OPTIONS_PUSH_ON_DROP)) { QueueModel.push(UtilFeatures.createStackItems(UtilFeatures .applyPlayOption(alSelectedFiles), Conf.getBoolean(Const.CONF_STATE_REPEAT_ALL), true), true); } else { // Insert the selection at drop target QueueModel.insert(UtilFeatures.createStackItems(UtilFeatures .applyPlayOption(alSelectedFiles), Conf.getBoolean(Const.CONF_STATE_REPEAT_ALL), true), row); } } // normal or new playlist case else if (plf.getType() == Playlist.Type.NORMAL || plf.getType() == Playlist.Type.NEW || plf.getType() == Playlist.Type.BOOKMARK) { // By default, inset at the end of the playlist int position = plf.getNbOfTracks() - 1; if (position < 0) { position = 0; } if (!Conf.getBoolean(Const.CONF_OPTIONS_PUSH_ON_DROP)) { position = row; } view.importFiles(UtilFeatures.applyPlayOption(alSelectedFiles), position); } return true; } } catch (Exception e) { Log.error(e); } finally { jtable.getSelectionModel().setValueIsAdjusting(false); } return false; } /* (non-Javadoc) * @see javax.swing.TransferHandler#canImport(javax.swing.JComponent, java.awt.datatransfer.DataFlavor[]) */ @Override public boolean canImport(JComponent c, DataFlavor[] flavors) { String sFlavor = flavors[0].getHumanPresentableName(); if ("Node".equals(sFlavor) || "Row".equals(sFlavor) || "Album".equals(sFlavor)) { JComponent comp = (JComponent) c.getParent(); while (!(comp instanceof PlaylistView)) { comp = (JComponent) comp.getParent(); } PlaylistView view = ((PlaylistView) comp); Playlist plf = view.getCurrentPlaylist(); // Don't accept drop for novelties and bestof return (plf.getType() != Playlist.Type.NOVELTIES && plf.getType() != Playlist.Type.BESTOF); } return false; } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/helpers/JajukTimer.java0000644000175000017500000000767511720500104025011 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.helpers; import java.util.Iterator; import java.util.List; import org.jajuk.base.File; import org.jajuk.services.players.Player; import org.jajuk.services.players.StackItem; /** * This class is a convenient class to sum up the remaining playing time of tracks, mainly for UI *

* Singleton *

. */ public final class JajukTimer { /** Self instance. */ private static JajukTimer timer = new JajukTimer(); /** Total time to play in secs. */ private long lTimeToPlay = 0; /** A default heartbeat time in ms. */ public static final int DEFAULT_HEARTBEAT = 800; /** The heartbeat for the Track Position Slider Toolbar. */ public static final int D_MS_HEARTBEAT = 500; /** * Gets the instance. * * @return JajukTimer singleton */ public static JajukTimer getInstance() { return timer; } /** * Private constructor. */ private JajukTimer() { } /** * Add time of the given file. * * @param file The file to read the duration from. */ public void addTrackTime(File file) { if (file != null) { lTimeToPlay += file.getTrack().getDuration(); } } /** * Add time of the given set of files. * * @param alFiles The list of StackItems to get the duration from the contained files. */ public void addTrackTime(java.util.List alFiles) { Iterator it = alFiles.iterator(); while (it.hasNext()) { Object o = it.next(); // instanceof also checks for null by definition if (o instanceof File) { addTrackTime((File) o); } else if (o != null) { File file = ((StackItem) o).getFile(); addTrackTime(file); } } } /** * Remove time of the given file. * * @param file The file to read the duration to remove from overall playing time. */ public void removeTrackTime(File file) { if (file != null) { lTimeToPlay -= file.getTrack().getDuration(); } } /** * Remove time of the given set of files. * * @param alFiles The list of files which duration to remove from the overall playing time. */ public void removeTrackTime(List alFiles) { Iterator it = alFiles.iterator(); while (it.hasNext()) { File file = it.next(); if (file != null) { removeTrackTime(it.next()); } } } /** * Gets the current track elapsed time. * * @return Current track elapsed time in secs */ public long getCurrentTrackEllapsedTime() { return Player.getElapsedTimeMillis() / 1000; } /** * Gets the current track total time. * * @return Current track total time in secs */ public long getCurrentTrackTotalTime() { return Player.getDurationSec() / 1000; } /** * Gets the total time to play. * * @return FIFO total time to be played in secs ( includes current track time * to play). Returns -1 if repeat mode */ public long getTotalTimeToPlay() { return lTimeToPlay - getCurrentTrackEllapsedTime(); // total time to play equals total time to play - // current track elapsed time } /** * Reset timer. */ public void reset() { lTimeToPlay = 0; } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/helpers/PatternInputVerifier.java0000644000175000017500000000415111720500104027057 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.helpers; import java.util.Locale; import javax.swing.InputVerifier; import javax.swing.JComponent; import javax.swing.JFormattedTextField; import javax.swing.JOptionPane; import org.jajuk.ui.windows.JajukMainWindow; import org.jajuk.util.Messages; /** * Input verifier used for predefined patterns. Pattern should contain at least * one / as this pattern verifier is used for organizer and organizer need to * create at least one directory to avoid mess on disk */ public class PatternInputVerifier extends InputVerifier { /* * (non-Javadoc) * * @see javax.swing.InputVerifier#verify(javax.swing.JComponent) */ @Override public boolean verify(JComponent input) { JFormattedTextField tf = (JFormattedTextField) input; String sText = tf.getText().toLowerCase(Locale.getDefault()); // Check pattern contains at least one / if (sText.indexOf('/') == -1) { JOptionPane.showMessageDialog(JajukMainWindow.getInstance(), Messages.getString("Error.146"), Messages.getString("Error"), JOptionPane.ERROR_MESSAGE); return false; } return true; } /* * (non-Javadoc) * * @see javax.swing.InputVerifier#shouldYieldFocus(javax.swing.JComponent) */ @Override public boolean shouldYieldFocus(JComponent input) { return verify(input); } }jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/helpers/IndexHighlighterPredicate.java0000644000175000017500000000330011720500104027770 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.helpers; import java.awt.Component; import org.jajuk.services.players.QueueModel; import org.jdesktop.swingx.decorator.ComponentAdapter; import org.jdesktop.swingx.decorator.HighlightPredicate; /** * Jajuk playing highlighter used in some tables to change the cell background * if the index is at the given row. */ public class IndexHighlighterPredicate implements HighlightPredicate { /** * Instantiates a new index highlighter predicate. */ public IndexHighlighterPredicate() { } /* (non-Javadoc) * @see org.jdesktop.swingx.decorator.HighlightPredicate#isHighlighted(java.awt.Component, org.jdesktop.swingx.decorator.ComponentAdapter) */ @Override public boolean isHighlighted(Component renderer, ComponentAdapter adapter) { // always highlight the current index if (QueueModel.getIndex() == adapter.row) { return true; } return false; } }jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/helpers/CDDBTableModel.java0000644000175000017500000001022011720500104025345 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.helpers; import entagged.freedb.FreedbReadResult; import java.util.Iterator; import java.util.List; import org.jajuk.base.Item; import org.jajuk.base.Track; import org.jajuk.services.cddb.CDDBTrack; import org.jajuk.util.Const; import org.jajuk.util.Messages; import org.jajuk.util.UtilString; /** * DOCUMENT_ME. */ public class CDDBTableModel extends JajukTableModel { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** * Model constructor. */ public CDDBTableModel() { super(8); // Current Album title vColNames.add(Messages.getString("CDDBWizard.3")); idList.add("CDDBWizard.1"); // Filename vColNames.add(Messages.getString("CDDBWizard.1")); idList.add("CDDBWizard.2"); // Current Track title vColNames.add(Messages.getString("CDDBWizard.2")); idList.add("CDDBWizard.3"); // Proposed Track Name vColNames.add(Messages.getString("CDDBWizard.4")); idList.add("CDDBWizard.4"); // Proposed Track Artist vColNames.add(Messages.getHumanPropertyName(Const.XML_ARTIST)); idList.add(Const.XML_ARTIST); // Proposed Track genre vColNames.add(Messages.getHumanPropertyName(Const.XML_GENRE)); idList.add(Const.XML_GENRE); // Proposed Track year vColNames.add(Messages.getHumanPropertyName(Const.XML_YEAR)); idList.add(Const.XML_YEAR); // Proposed Track number vColNames.add(Messages.getHumanPropertyName(Const.XML_TRACK_ORDER)); idList.add(Const.XML_TRACK_ORDER); } /** * Fill model with tracks. * * @param currentTracks DOCUMENT_ME * @param fdbReader DOCUMENT_ME */ public void populateModel(List currentTracks, FreedbReadResult fdbReader) { iRowNum = currentTracks.size(); int iColNum = iNumberStandardCols; oValues = new Object[iRowNum][iColNum]; oItems = new Item[iRowNum]; bCellEditable = new boolean[iRowNum][iColNum]; Iterator it = currentTracks.iterator(); for (int iRow = 0; it.hasNext(); iRow++) { Track track = it.next().getTrack(); setItemAt(iRow, track); // Id oItems[iRow] = track; // Album name oValues[iRow][0] = track.getAlbum().getName2(); bCellEditable[iRow][0] = false; // files name oValues[iRow][1] = UtilString.getLimitedString(track.getFilesString(), 40); bCellEditable[iRow][1] = false; // Current Track name oValues[iRow][2] = track.getName(); bCellEditable[iRow][2] = false; // Proposed track name oValues[iRow][3] = fdbReader.getTrackTitle(iRow); bCellEditable[iRow][3] = false; // Proposed track artist oValues[iRow][4] = fdbReader.getArtist(); bCellEditable[iRow][4] = false; // Proposed track genre oValues[iRow][5] = fdbReader.getGenre(); bCellEditable[iRow][5] = false; // Proposed track year oValues[iRow][6] = fdbReader.getYear(); bCellEditable[iRow][6] = false; // Proposed track order oValues[iRow][7] = fdbReader.getTrackNumber(iRow); bCellEditable[iRow][7] = false; } } /* * (non-Javadoc) * * @see org.jajuk.ui.helpers.JajukTableModel#populateModel(java.lang.String, * java.lang.String, java.util.List) */ @Override public void populateModel(String property, String pattern, List columnsToShow) { // Doesn't apply here } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/helpers/PlayerStateMediator.java0000644000175000017500000002741111720500104026654 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.helpers; import static org.jajuk.ui.actions.JajukActions.FINISH_ALBUM; import static org.jajuk.ui.actions.JajukActions.FORWARD_TRACK; import static org.jajuk.ui.actions.JajukActions.NEXT_ALBUM; import static org.jajuk.ui.actions.JajukActions.NEXT_TRACK; import static org.jajuk.ui.actions.JajukActions.PAUSE_RESUME_TRACK; import static org.jajuk.ui.actions.JajukActions.PREVIOUS_ALBUM; import static org.jajuk.ui.actions.JajukActions.PREVIOUS_TRACK; import static org.jajuk.ui.actions.JajukActions.REWIND_TRACK; import static org.jajuk.ui.actions.JajukActions.STOP_TRACK; import java.util.HashSet; import java.util.Set; import javax.swing.SwingUtilities; import org.jajuk.base.File; import org.jajuk.base.FileManager; import org.jajuk.events.JajukEvent; import org.jajuk.events.JajukEvents; import org.jajuk.events.ObservationManager; import org.jajuk.events.Observer; import org.jajuk.services.notification.INotificator; import org.jajuk.services.notification.NotificatorFactory; import org.jajuk.services.players.Player; import org.jajuk.services.players.QueueModel; import org.jajuk.services.webradio.WebRadio; import org.jajuk.ui.actions.ActionManager; import org.jajuk.ui.actions.MuteAction; import org.jajuk.util.Conf; import org.jajuk.util.Const; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; import org.jajuk.util.UtilFeatures; import org.jajuk.util.log.Log; /** * This mediator observes events on player state and change actions (and player * buttons state) accordingly. */ public class PlayerStateMediator implements Observer { /** Singleton. */ private static PlayerStateMediator self = new PlayerStateMediator(); // Register this item, do not do this in the constructor as the instance is not yet available static { ObservationManager.register(self); // Update initial status UtilFeatures.updateStatus(self); } /** * Instantiates a new player state mediator. */ private PlayerStateMediator() { } /** * Gets the single instance of PlayerStateMediator. * * @return single instance of PlayerStateMediator */ public static PlayerStateMediator getInstance() { return self; } /* * (non-Javadoc) * * @see org.jajuk.events.Observer#getRegistrationKeys() */ @Override public Set getRegistrationKeys() { Set eventSubjectSet = new HashSet(); eventSubjectSet.add(JajukEvents.PLAYER_PLAY); eventSubjectSet.add(JajukEvents.PLAYER_STOP); eventSubjectSet.add(JajukEvents.PLAYER_PAUSE); eventSubjectSet.add(JajukEvents.PLAYER_RESUME); eventSubjectSet.add(JajukEvents.PLAY_OPENING); eventSubjectSet.add(JajukEvents.PLAY_ERROR); eventSubjectSet.add(JajukEvents.ZERO); eventSubjectSet.add(JajukEvents.WEBRADIO_LAUNCHED); eventSubjectSet.add(JajukEvents.VOLUME_CHANGED); eventSubjectSet.add(JajukEvents.MUTE_STATE); eventSubjectSet.add(JajukEvents.SHOW_CURRENTLY_PLAYING); // for notification display eventSubjectSet.add(JajukEvents.FILE_LAUNCHED); return eventSubjectSet; } /* * (non-Javadoc) * * @see org.jajuk.events.Observer#update(org.jajuk.events.Event) */ @Override public void update(final JajukEvent event) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { JajukEvents subject = event.getSubject(); if (JajukEvents.PLAYER_STOP.equals(subject)) { ActionManager.getAction(REWIND_TRACK).setEnabled(false); // Enable the play button to allow restarting the queue but disable if // the queue is void boolean bQueueNotVoid = (QueueModel.getQueue().size() > 0); ActionManager.getAction(PAUSE_RESUME_TRACK).setEnabled(bQueueNotVoid); ActionManager.getAction(NEXT_ALBUM).setEnabled(bQueueNotVoid); ActionManager.getAction(PREVIOUS_ALBUM).setEnabled(bQueueNotVoid); ActionManager.getAction(PREVIOUS_TRACK).setEnabled(bQueueNotVoid); ActionManager.getAction(NEXT_TRACK).setEnabled(bQueueNotVoid); setToPlay(); ActionManager.getAction(STOP_TRACK).setEnabled(false); ActionManager.getAction(FORWARD_TRACK).setEnabled(false); ActionManager.getAction(FINISH_ALBUM).setEnabled(false); // reset startup position Conf.setProperty(Const.CONF_STARTUP_LAST_POSITION, "0"); } else if (JajukEvents.ZERO.equals(subject)) { ActionManager.getAction(PREVIOUS_TRACK).setEnabled(false); ActionManager.getAction(NEXT_TRACK).setEnabled(false); ActionManager.getAction(REWIND_TRACK).setEnabled(false); ActionManager.getAction(PAUSE_RESUME_TRACK).setEnabled(false); ActionManager.getAction(STOP_TRACK).setEnabled(false); ActionManager.getAction(FORWARD_TRACK).setEnabled(false); ActionManager.getAction(NEXT_ALBUM).setEnabled(false); ActionManager.getAction(PREVIOUS_ALBUM).setEnabled(false); ActionManager.getAction(FINISH_ALBUM).setEnabled(false); setToPlay(); // reset startup position Conf.setProperty(Const.CONF_STARTUP_LAST_POSITION, "0"); ActionManager.getAction(FINISH_ALBUM).setEnabled(true); } else if (JajukEvents.PLAYER_PLAY.equals(subject)) { ActionManager.getAction(PREVIOUS_TRACK).setEnabled(true); ActionManager.getAction(NEXT_TRACK).setEnabled(true); ActionManager.getAction(REWIND_TRACK).setEnabled(true); ActionManager.getAction(PAUSE_RESUME_TRACK).setEnabled(true); ActionManager.getAction(STOP_TRACK).setEnabled(true); ActionManager.getAction(FORWARD_TRACK).setEnabled(true); ActionManager.getAction(NEXT_ALBUM).setEnabled(true); ActionManager.getAction(PREVIOUS_ALBUM).setEnabled(true); ActionManager.getAction(FINISH_ALBUM).setEnabled(true); // We need to set the icon here because the event can be // thrown by the information panel, not directly the // PlayPauseAction setToPause(); } else if (JajukEvents.PLAY_OPENING.equals(subject) || JajukEvents.PLAY_ERROR.equals(subject)) { ActionManager.getAction(PREVIOUS_TRACK).setEnabled(true); ActionManager.getAction(NEXT_TRACK).setEnabled(true); ActionManager.getAction(REWIND_TRACK).setEnabled(false); ActionManager.getAction(PAUSE_RESUME_TRACK).setEnabled(false); ActionManager.getAction(STOP_TRACK).setEnabled(true); ActionManager.getAction(FORWARD_TRACK).setEnabled(false); ActionManager.getAction(NEXT_ALBUM).setEnabled(true); ActionManager.getAction(PREVIOUS_ALBUM).setEnabled(true); ActionManager.getAction(FINISH_ALBUM).setEnabled(true); setToPlay(); } else if (JajukEvents.PLAYER_PAUSE.equals(subject)) { ActionManager.getAction(REWIND_TRACK).setEnabled(false); ActionManager.getAction(FORWARD_TRACK).setEnabled(false); // We need to set the icon here because the event can be // thrown by the information panel, not directly the // PlayPauseAction setToPlay(); } else if (JajukEvents.PLAYER_RESUME.equals(subject)) { // Enable the volume when resuming (fix a mplayer issue, see // above) ActionManager.getAction(REWIND_TRACK).setEnabled(true); ActionManager.getAction(FORWARD_TRACK).setEnabled(true); // We need to set the icon here because the event can be // thrown by the information panel, not directly the // PlayPauseAction setToPause(); } else if (JajukEvents.WEBRADIO_LAUNCHED.equals(subject)) { ActionManager.getAction(PREVIOUS_TRACK).setEnabled(true); ActionManager.getAction(NEXT_TRACK).setEnabled(true); ActionManager.getAction(PAUSE_RESUME_TRACK).setEnabled(true); setToPause(); ActionManager.getAction(STOP_TRACK).setEnabled(true); // display a system notification if specified INotificator notifier = NotificatorFactory.getNotificator(); if (notifier != null) { WebRadio radio = (WebRadio) (event.getDetails().get(Const.DETAIL_CONTENT)); Log.debug("Got update for new webradio launched, item: " + radio); notifier.notify(radio); } } else if (JajukEvents.VOLUME_CHANGED.equals(subject)) { MuteAction.setVolumeIcon(100 * Player.getCurrentVolume()); } else if (JajukEvents.MUTE_STATE.equals(subject) && // Update mute icon look when changing the volume !Player.isMuted()) { MuteAction.setVolumeIcon(Player.getCurrentVolume() * 100); } else if (subject.equals(JajukEvents.FILE_LAUNCHED)) { INotificator notifier = NotificatorFactory.getNotificator(); if (notifier != null) { String id = (String) ObservationManager.getDetail(event, Const.DETAIL_CURRENT_FILE_ID); if (id == null) { Log.debug("No id found on FILE_LAUNCHED"); return; } File file = FileManager.getInstance().getFileByID(id); Log.debug("Got update for new file launched, item: {{" + file + "}}. Sending text: {{" + QueueModel.getCurrentFileTitle() + "}}"); notifier.notify(file); } } else if (subject.equals(JajukEvents.SHOW_CURRENTLY_PLAYING)) { INotificator notifier = NotificatorFactory.getNotificator(); if (notifier != null) { if (QueueModel.getCurrentRadio() != null) { Log.debug("Got request to notify with current webradio information: {{" + QueueModel.getCurrentRadio() + "}}"); notifier.notify(QueueModel.getCurrentRadio()); } else { Log.debug("Got request to notify with current file information: {{" + QueueModel.getCurrentItem().getFile() + "}}"); notifier.notify(QueueModel.getCurrentItem().getFile()); } } } // For all events except Volume Change/Mute, refresh the queue if (!JajukEvents.VOLUME_CHANGED.equals(subject) && !JajukEvents.MUTE_STATE.equals(subject) && !JajukEvents.FILE_LAUNCHED.equals(subject) && !JajukEvents.SHOW_CURRENTLY_PLAYING.equals(subject)) { ObservationManager.notify(new JajukEvent(JajukEvents.QUEUE_NEED_REFRESH)); } } }); } /** * Set play/pause button label/icon to pause state. */ private void setToPause() { ActionManager.getAction(PAUSE_RESUME_TRACK) .setIcon(IconLoader.getIcon(JajukIcons.PLAYER_PAUSE)); ActionManager.getAction(PAUSE_RESUME_TRACK).setName(Messages.getString("JajukWindow.10")); } /** * Set play/pause button label/icon to play state. */ private void setToPlay() { ActionManager.getAction(PAUSE_RESUME_TRACK).setIcon(IconLoader.getIcon(JajukIcons.PLAYER_PLAY)); ActionManager.getAction(PAUSE_RESUME_TRACK).setName(Messages.getString("JajukWindow.12")); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/helpers/CatalogViewTransferHandler.java0000644000175000017500000000467111720500104030145 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.helpers; import java.awt.datatransfer.DataFlavor; import java.awt.datatransfer.Transferable; import javax.swing.JComponent; import javax.swing.TransferHandler; import org.jajuk.base.Album; import org.jajuk.ui.thumbnails.LocalAlbumThumbnail; /** * DND handler for table. */ public class CatalogViewTransferHandler extends TransferHandler { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** DOCUMENT_ME. */ private final LocalAlbumThumbnail item; /** * Constructor. * * @param item DOCUMENT_ME */ public CatalogViewTransferHandler(LocalAlbumThumbnail item) { this.item = item; } /** * Called when dragging. * * @param c DOCUMENT_ME * * @return the transferable */ @Override protected Transferable createTransferable(JComponent c) { Object o = item.getItem(); if (o != null) { return new TransferableAlbum((Album) o); } return null; } /** * return action type. * * @param c DOCUMENT_ME * * @return the source actions */ @Override public int getSourceActions(JComponent c) { return COPY_OR_MOVE; } /** * Called when dropping, no drop in catalog view for now. * * @param c DOCUMENT_ME * @param t DOCUMENT_ME * * @return true, if import data */ @Override public boolean importData(JComponent c, Transferable t) { return false; } /* (non-Javadoc) * @see javax.swing.TransferHandler#canImport(javax.swing.JComponent, java.awt.datatransfer.DataFlavor[]) */ @Override public boolean canImport(JComponent c, DataFlavor[] flavors) { return false; } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/helpers/TracksTableModel.java0000644000175000017500000002772411720500104026121 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.helpers; import java.util.Collections; import java.util.Date; import java.util.Iterator; import java.util.List; import java.util.Map; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.Predicate; import org.jajuk.base.File; import org.jajuk.base.Item; import org.jajuk.base.PropertyMetaInformation; import org.jajuk.base.Track; import org.jajuk.base.TrackComparator; import org.jajuk.base.TrackComparator.TrackComparatorType; import org.jajuk.base.TrackManager; import org.jajuk.base.Type; import org.jajuk.ui.widgets.IconLabel; import org.jajuk.util.Conf; import org.jajuk.util.Const; import org.jajuk.util.Filter; import org.jajuk.util.Messages; import org.jajuk.util.log.Log; /** * Table model used for logical table view. */ public class TracksTableModel extends JajukTableModel { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** Associated view ID. */ private String viewID; /** * Model constructor. * * @param viewID Associated view ID */ public TracksTableModel(String viewID) { super(15); this.viewID = viewID; setEditable(Conf.getBoolean(Const.CONF_TRACKS_TABLE_EDITION)); // Columns names // First column is play icon, need to set a space character // for proper display in some look and feel vColNames.add(" "); idList.add(Const.XML_PLAY); vColNames.add(Messages.getHumanPropertyName(Const.XML_NAME)); idList.add(Const.XML_NAME); vColNames.add(Messages.getHumanPropertyName(Const.XML_ALBUM)); idList.add(Const.XML_ALBUM); vColNames.add(Messages.getHumanPropertyName(Const.XML_ARTIST)); idList.add(Const.XML_ARTIST); vColNames.add(Messages.getHumanPropertyName(Const.XML_ALBUM_ARTIST)); idList.add(Const.XML_ALBUM_ARTIST); vColNames.add(Messages.getHumanPropertyName(Const.XML_GENRE)); idList.add(Const.XML_GENRE); vColNames.add(Messages.getHumanPropertyName(Const.XML_TRACK_RATE)); idList.add(Const.XML_TRACK_RATE); vColNames.add(Messages.getHumanPropertyName(Const.XML_TRACK_LENGTH)); idList.add(Const.XML_TRACK_LENGTH); vColNames.add(Messages.getHumanPropertyName(Const.XML_TRACK_COMMENT)); idList.add(Const.XML_TRACK_COMMENT); vColNames.add(Messages.getHumanPropertyName(Const.XML_TRACK_DISCOVERY_DATE)); idList.add(Const.XML_TRACK_DISCOVERY_DATE); vColNames.add(Messages.getHumanPropertyName(Const.XML_TRACK_ORDER)); idList.add(Const.XML_TRACK_ORDER); vColNames.add(Messages.getHumanPropertyName(Const.XML_TRACK_DISC_NUMBER)); idList.add(Const.XML_TRACK_DISC_NUMBER); vColNames.add(Messages.getHumanPropertyName(Const.XML_YEAR)); idList.add(Const.XML_YEAR); vColNames.add(Messages.getHumanPropertyName(Const.XML_TRACK_HITS)); idList.add(Const.XML_TRACK_HITS); vColNames.add(Messages.getHumanPropertyName(Const.XML_FILES)); idList.add(Const.XML_FILES); // custom properties now for (PropertyMetaInformation meta : TrackManager.getInstance().getCustomProperties()) { vColNames.add(meta.getName()); idList.add(meta.getName()); } } /* * (non-Javadoc) * * @see org.jajuk.ui.helpers.JajukTableModel#populateModel(java.lang.String, java.lang.String, * java.util.List) */ @Override public void populateModel(String property, String sPattern, List columnsToShow) { // This should be monitor file manager to avoid NPE when changing items List alToShow = TrackManager.getInstance().getTracks(); // / Filter mounted files if needed and apply sync table with tree // option if needed final boolean syncTreeTable = Conf.getBoolean(Const.CONF_SYNC_TABLE_TREE + "." + viewID); CollectionUtils.filter(alToShow, new Predicate() { @Override public boolean evaluate(Object o) { Track track = (Track) o; // show it if no sync option or if item is in the selection boolean bShowWithTree = !syncTreeTable // tree selection = null means none election have been // selected in tree so far || treeSelection == null // check if the tree selection contains the current file || (treeSelection.size() > 0 && treeSelection.contains(track)); return (!track.shouldBeHidden() && bShowWithTree); } }); // Filter values using given pattern Filter filter = new Filter(property, sPattern, true, Conf.getBoolean(Const.CONF_REGEXP)); Filter.filterItems(alToShow, filter); // sort by album long before = System.currentTimeMillis(); Collections.sort(alToShow, new TrackComparator(TrackComparatorType.ALBUM)); // Collections.sort(alToShow, new TrackComparator(TrackComparatorType.ALBUM)); Log.debug("Sorting of " + alToShow.size() + " elements took: " + (System.currentTimeMillis() - before) + " mseconds"); Iterator it = alToShow.iterator(); int iColNum = iNumberStandardCols + TrackManager.getInstance().getCustomProperties().size(); iRowNum = alToShow.size(); it = alToShow.iterator(); oValues = new Object[iRowNum][iColNum]; oItems = new Item[iRowNum]; bCellEditable = new boolean[iRowNum][iColNum]; // For perfs, prepare columns visibility boolean bName = (columnsToShow != null && columnsToShow.contains(Const.XML_NAME)); boolean bAlbum = (columnsToShow != null && columnsToShow.contains(Const.XML_ALBUM)); boolean bArtist = (columnsToShow != null && columnsToShow.contains(Const.XML_ARTIST)); boolean bAlbumArtist = (columnsToShow != null && columnsToShow.contains(Const.XML_ALBUM_ARTIST)); boolean bGenre = (columnsToShow != null && columnsToShow.contains(Const.XML_GENRE)); boolean bRate = (columnsToShow != null && columnsToShow.contains(Const.XML_TRACK_RATE)); boolean bLength = (columnsToShow != null && columnsToShow.contains(Const.XML_TRACK_LENGTH)); boolean bComment = (columnsToShow != null && columnsToShow.contains(Const.XML_TRACK_COMMENT)); boolean bDiscovery = (columnsToShow != null && columnsToShow .contains(Const.XML_TRACK_DISCOVERY_DATE)); boolean bOrder = (columnsToShow != null && columnsToShow.contains(Const.XML_TRACK_ORDER)); boolean bDiscNumber = (columnsToShow != null && columnsToShow .contains(Const.XML_TRACK_DISC_NUMBER)); boolean bYear = (columnsToShow != null && columnsToShow.contains(Const.XML_YEAR)); boolean bHits = (columnsToShow != null && columnsToShow.contains(Const.XML_TRACK_HITS)); boolean bFiles = (columnsToShow != null && columnsToShow.contains(Const.XML_FILES)); for (int iRow = 0; it.hasNext(); iRow++) { Track track = it.next(); setItemAt(iRow, track); Map properties = track.getProperties(); // Id oItems[iRow] = track; // Play IconLabel il = null; if (track.getBestFile(true) != null) { il = getIcon(false); } else { il = getIcon(true); } // Note: if you want to add an image, use an ImageIcon class and // change oValues[iRow][0] = il; bCellEditable[iRow][0] = false; // check track has an associated tag editor (not null) boolean bHasATagEditor = false; File file = track.getFiles().get(0); // all files have the same type Type type = file.getType(); if (type != null) { bHasATagEditor = (type.getTaggerClass() != null); } // Track name if (bName) { oValues[iRow][1] = track.getName(); } else { oValues[iRow][1] = ""; } bCellEditable[iRow][1] = bHasATagEditor; // Album if (bAlbum) { oValues[iRow][2] = track.getAlbum().getName2(); } else { oValues[iRow][2] = ""; } bCellEditable[iRow][2] = bHasATagEditor; // Artist if (bArtist) { oValues[iRow][3] = track.getArtist().getName2(); } else { oValues[iRow][3] = ""; } bCellEditable[iRow][3] = bHasATagEditor; // Album Artist if (bAlbumArtist) { oValues[iRow][4] = track.getAlbumArtist().getName2(); } else { oValues[iRow][4] = ""; } bCellEditable[iRow][4] = bHasATagEditor; // Genre if (bGenre) { oValues[iRow][5] = track.getGenre().getName2(); } else { oValues[iRow][5] = ""; } bCellEditable[iRow][5] = bHasATagEditor; // Rate if (bRate) { oValues[iRow][6] = StarsHelper.getStarIconLabel(track); } else { oValues[iRow][6] = ""; } bCellEditable[iRow][6] = false; // Length if (bLength) { oValues[iRow][7] = new Duration(track.getDuration()); } else { oValues[iRow][7] = ""; } bCellEditable[iRow][7] = false; // Comment if (bComment) { oValues[iRow][8] = track.getValue(Const.XML_TRACK_COMMENT); } else { oValues[iRow][8] = ""; } bCellEditable[iRow][8] = bHasATagEditor; // Date discovery if (bDiscovery) { oValues[iRow][9] = track.getDiscoveryDate(); // show date using // default local format // and not technical // representation bCellEditable[iRow][9] = false; } else { oValues[iRow][9] = ""; } // Order if (bOrder) { oValues[iRow][10] = track.getOrder(); } else { oValues[iRow][10] = ""; } bCellEditable[iRow][10] = bHasATagEditor; // Disc number if (bDiscNumber) { oValues[iRow][11] = track.getDiscNumber(); } else { oValues[iRow][11] = ""; } bCellEditable[iRow][11] = bHasATagEditor; // Year if (bYear) { oValues[iRow][12] = track.getYear().getValue(); } else { oValues[iRow][12] = ""; } bCellEditable[iRow][12] = bHasATagEditor; // Hits if (bHits) { oValues[iRow][13] = track.getHits(); } else { oValues[iRow][13] = ""; } bCellEditable[iRow][13] = false; // Files if (bFiles) { List alFiles = track.getFiles(); StringBuilder files = new StringBuilder(50); // for perfs, we manage differently single file tracks and multi-files // tracks if (alFiles.size() == 1) { files.append(alFiles.get(0).getAbsolutePath()); } else { for (File file2 : alFiles) { files.append(file2.getAbsolutePath()).append(','); } files.deleteCharAt(files.length() - 1); } oValues[iRow][14] = files.toString(); } else { oValues[iRow][14] = ""; } bCellEditable[iRow][14] = false; // Custom properties now Iterator it2 = TrackManager.getInstance().getCustomProperties() .iterator(); for (int i = 0; it2.hasNext(); i++) { PropertyMetaInformation meta = it2.next(); Object o = properties.get(meta.getName()); if (o != null) { oValues[iRow][iNumberStandardCols + i] = o; } else { oValues[iRow][iNumberStandardCols + i] = meta.getDefaultValue(); } // Date values not editable, use properties panel instead to // edit bCellEditable[iRow][iNumberStandardCols + i] = !(meta.getType().equals(Date.class)); } } } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/helpers/FontManager.java0000644000175000017500000002050311720500104025126 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.helpers; import java.awt.Font; import java.awt.FontMetrics; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import javax.swing.JLabel; import javax.swing.SwingUtilities; import javax.swing.UIDefaults; import javax.swing.plaf.FontUIResource; import org.jajuk.events.JajukEvent; import org.jajuk.events.JajukEvents; import org.jajuk.events.ObservationManager; import org.jajuk.events.Observer; import org.jajuk.util.Conf; import org.jajuk.util.Const; import org.jajuk.util.log.Log; import org.jvnet.substance.SubstanceLookAndFeel; import org.jvnet.substance.fonts.FontPolicy; import org.jvnet.substance.fonts.FontSet; /** * Manages Jajuk fonts, stores or update them. */ public final class FontManager implements Observer { /** The Constant SANS_SERIF. DOCUMENT_ME */ private static final String SANS_SERIF = "sans-serif"; /** * DOCUMENT_ME. */ public enum JajukFont { /** DOCUMENT_ME. */ DEFAULT, /** DOCUMENT_ME. */ PLAIN, /** DOCUMENT_ME. */ PLAIN_S, /** DOCUMENT_ME. */ PLAIN_L, /** DOCUMENT_ME. */ PLAIN_XL, /** DOCUMENT_ME. */ BOLD, /** DOCUMENT_ME. */ BOLD_L, /** DOCUMENT_ME. */ BOLD_XL, /** DOCUMENT_ME. */ BOLD_XXL, /** DOCUMENT_ME. */ BOLD_TITLE, /** DOCUMENT_ME. */ PERSPECTIVES, /** DOCUMENT_ME. */ PLANNED, /** DOCUMENT_ME. */ SEARCHBOX, /** DOCUMENT_ME. */ SPLASH, /** DOCUMENT_ME. */ SPLASH_PROGRESS, /** DOCUMENT_ME. */ VIEW_FONT } /** DOCUMENT_ME. */ private static Map fontCache = new HashMap(10); /** DOCUMENT_ME. */ private static FontManager self = new FontManager(); // No instantiation /** * Instantiates a new font manager. */ private FontManager() { registerFonts(); ObservationManager.register(this); } /** * Gets the single instance of FontManager. * * @return single instance of FontManager */ public static FontManager getInstance() { return self; } /** * Register fonts. * DOCUMENT_ME */ private void registerFonts() { // static fonts fontCache.put(JajukFont.BOLD_TITLE, new Font(SANS_SERIF, Font.PLAIN, 20)); fontCache.put(JajukFont.PERSPECTIVES, new Font(SANS_SERIF, Font.BOLD, 10)); fontCache.put(JajukFont.SEARCHBOX, new Font(SANS_SERIF, Font.BOLD, 12)); fontCache.put(JajukFont.SPLASH, new Font(SANS_SERIF, Font.PLAIN, 12)); fontCache.put(JajukFont.SPLASH_PROGRESS, new Font(SANS_SERIF, Font.BOLD, 12)); // Bold fontCache.put(JajukFont.BOLD, new Font(SANS_SERIF, Font.BOLD, Conf .getInt(Const.CONF_FONTS_SIZE))); fontCache.put(JajukFont.BOLD_L, new Font(SANS_SERIF, Font.BOLD, Conf .getInt(Const.CONF_FONTS_SIZE) + 2)); fontCache.put(JajukFont.BOLD_XL, new Font(SANS_SERIF, Font.BOLD, Conf .getInt(Const.CONF_FONTS_SIZE) + 4)); fontCache.put(JajukFont.BOLD_XXL, new Font(SANS_SERIF, Font.BOLD, Conf .getInt(Const.CONF_FONTS_SIZE) + 6)); // Plain fontCache.put(JajukFont.DEFAULT, new Font(SANS_SERIF, Font.PLAIN, Conf .getInt(Const.CONF_FONTS_SIZE))); fontCache.put(JajukFont.PLAIN, new Font(SANS_SERIF, Font.PLAIN, Conf .getInt(Const.CONF_FONTS_SIZE))); fontCache.put(JajukFont.PLAIN_S, new Font(SANS_SERIF, Font.PLAIN, Conf .getInt(Const.CONF_FONTS_SIZE) - 2)); fontCache.put(JajukFont.PLAIN_L, new Font(SANS_SERIF, Font.PLAIN, Conf .getInt(Const.CONF_FONTS_SIZE) + 2)); fontCache.put(JajukFont.PLAIN_XL, new Font(SANS_SERIF, Font.PLAIN, Conf .getInt(Const.CONF_FONTS_SIZE) + 4)); // Italic fontCache.put(JajukFont.PLANNED, new Font("serif", Font.ITALIC, Conf .getInt(Const.CONF_FONTS_SIZE))); Font font = new Font(SANS_SERIF, Font.PLAIN, Conf.getInt(Const.CONF_FONTS_SIZE)); fontCache.put(JajukFont.VIEW_FONT, font); } /** * Gets the font. * * @param font DOCUMENT_ME * * @return the font */ public Font getFont(JajukFont font) { return fontCache.get(font); } /** * Sets the default font. * DOCUMENT_ME */ public void setDefaultFont() { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { // Create the wrapper font set FontPolicy newFontPolicy = new FontPolicy() { @Override public FontSet getFontSet(String lafName, UIDefaults table) { return new CustomFontSet(fontCache.get(JajukFont.DEFAULT)); } }; try { // set the new font policy SubstanceLookAndFeel.setFontPolicy(newFontPolicy); } catch (Exception exc) { Log.error(exc); } } }); } /* * (non-Javadoc) * * @see org.jajuk.base.Observer#getRegistrationKeys() */ @Override public Set getRegistrationKeys() { Set subjects = new HashSet(2); // Register parameter changes to check new font size subjects.add(JajukEvents.PARAMETERS_CHANGE); return subjects; } /** * This method return the number of characters of a given string that fits in * the given size in pixels. * * @param text DOCUMENT_ME * @param font DOCUMENT_ME * @param maxSize DOCUMENT_ME * * @return the rows for text */ public static int getRowsForText(String text, Font font, int maxSize) { int resu = 0; int usedSize = 0; FontMetrics fm = new JLabel().getFontMetrics(font); for (int i = 0; i < text.length() - 1; i++) { usedSize = fm.stringWidth(text.substring(0, i)); resu++; if (usedSize >= maxSize) { break; } } return resu; } /* * (non-Javadoc) * * @see org.jajuk.base.Observer#update(org.jajuk.base.Event) */ @Override public void update(JajukEvent event) { JajukEvents subject = event.getSubject(); if (JajukEvents.PARAMETERS_CHANGE.equals(subject)) { // force to register again all fonts to get new sizes registerFonts(); } } /** * DOCUMENT_ME. */ private static class CustomFontSet implements FontSet { /** DOCUMENT_ME. */ protected FontUIResource font; /** * Instantiates a new custom font set. * * @param font DOCUMENT_ME */ public CustomFontSet(Font font) { this.font = new FontUIResource(font); } /* * (non-Javadoc) * * @see org.jvnet.substance.fonts.FontSet#getControlFont() */ @Override public FontUIResource getControlFont() { return this.font; } /* * (non-Javadoc) * * @see org.jvnet.substance.fonts.FontSet#getMenuFont() */ @Override public FontUIResource getMenuFont() { return this.font; } /* * (non-Javadoc) * * @see org.jvnet.substance.fonts.FontSet#getMessageFont() */ @Override public FontUIResource getMessageFont() { return this.font; } /* * (non-Javadoc) * * @see org.jvnet.substance.fonts.FontSet#getSmallFont() */ @Override public FontUIResource getSmallFont() { return this.font; } /* * (non-Javadoc) * * @see org.jvnet.substance.fonts.FontSet#getTitleFont() */ @Override public FontUIResource getTitleFont() { return this.font; } /* * (non-Javadoc) * * @see org.jvnet.substance.fonts.FontSet#getWindowTitleFont() */ @Override public FontUIResource getWindowTitleFont() { return this.font; } } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/helpers/ManualDirectoryRefreshReporter.java0000644000175000017500000000375211720500104031100 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.helpers; import org.jajuk.base.Device; import org.jajuk.base.Directory; import org.jajuk.util.Messages; import org.jajuk.util.log.Log; /** * Refresh reporter on directories with GUI special operations. */ public class ManualDirectoryRefreshReporter extends RefreshReporter { /** * Instantiates a new manual directory refresh reporter. * * @param device DOCUMENT_ME */ public ManualDirectoryRefreshReporter(Device device) { super(device); } /* (non-Javadoc) * @see org.jajuk.ui.helpers.RefreshReporter#cleanupDone() */ @Override public void cleanupDone() { Log.debug("Cleanup done"); } /* (non-Javadoc) * @see org.jajuk.ui.helpers.RefreshReporter#updateState(org.jajuk.base.Directory) */ @Override public void updateState(Directory dir) { // Intentionnal NOP } /* (non-Javadoc) * @see org.jajuk.ui.helpers.RefreshReporter#done() */ @Override public void done() { long refreshTime = System.currentTimeMillis() - lRefreshDateStart; String message = buildFinalMessage(refreshTime); Log.debug(message); reset(); // Display end of refresh message with stats Messages.showInfoMessage(message); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/helpers/PlaylistTableModel.java0000644000175000017500000003164611720500104026471 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.helpers; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Map; import org.jajuk.base.File; import org.jajuk.base.FileManager; import org.jajuk.base.Item; import org.jajuk.base.PropertyMetaInformation; import org.jajuk.base.TrackManager; import org.jajuk.services.players.QueueModel; import org.jajuk.services.players.StackItem; import org.jajuk.ui.widgets.IconLabel; import org.jajuk.util.Const; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; /** * Playlist model used in queue view or playlist view. */ public class PlaylistTableModel extends JajukTableModel { /** Values. */ private List alItems = new ArrayList(10); /** Values planned. */ private List alPlanned = new ArrayList(10); /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** Whether this model is used by a Queue View. */ private boolean bQueue = false; /** * Instantiates a new playlist table model. * * @param bQueue DOCUMENT_ME */ public PlaylistTableModel(boolean bQueue) { super(17); this.bQueue = bQueue; setEditable(false); // table not editable prepareColumns(); } /** * Need to overwrite this method for drag and drop. * * @param iRow DOCUMENT_ME * * @return the item at */ @Override public Item getItemAt(int iRow) { StackItem si = getStackItem(iRow); if (si != null) { return si.getFile(); } return null; } /** * Return all stack items from this value to the end of selection. * * @param index DOCUMENT_ME * * @return an arraylist of stack items or null if index is out of bounds */ public List getItemsFrom(int index) { if (index < alItems.size()) { return new ArrayList(alItems.subList(index, alItems.size())); } else { return null; } } /** * Return right stack item in normal or planned stacks. * * @param index DOCUMENT_ME * * @return the stack item */ public StackItem getStackItem(int index) { if (alItems.size() == 0) { return null; } if (index < alItems.size()) { return alItems.get(index); } else if (index < (alItems.size() + alPlanned.size())) { return alPlanned.get(index - alItems.size()); } else { return null; } } /** * Create columns configuration. */ public final void prepareColumns() { vColNames.clear(); idList.clear(); // State icon (play/repeat/planned) vColNames.add(""); idList.add(Const.XML_PLAY); // Track name // Note we display "title" and not "name" for this property for // clearness vColNames.add(Messages.getString("AbstractPlaylistEditorView.0")); idList.add(Const.XML_TRACK_NAME); // Album vColNames.add(Messages.getHumanPropertyName(Const.XML_TRACK_ALBUM)); idList.add(Const.XML_TRACK_ALBUM); // Artist vColNames.add(Messages.getHumanPropertyName(Const.XML_TRACK_ARTIST)); idList.add(Const.XML_TRACK_ARTIST); // Artist vColNames.add(Messages.getHumanPropertyName(Const.XML_ALBUM_ARTIST)); idList.add(Const.XML_ALBUM_ARTIST); // Genre vColNames.add(Messages.getHumanPropertyName(Const.XML_TRACK_GENRE)); idList.add(Const.XML_TRACK_GENRE); // Stars vColNames.add(Messages.getHumanPropertyName(Const.XML_TRACK_RATE)); idList.add(Const.XML_TRACK_RATE); // Year vColNames.add(Messages.getHumanPropertyName(Const.XML_YEAR)); idList.add(Const.XML_YEAR); // Length vColNames.add(Messages.getHumanPropertyName(Const.XML_TRACK_LENGTH)); idList.add(Const.XML_TRACK_LENGTH); // comments vColNames.add(Messages.getHumanPropertyName(Const.XML_TRACK_COMMENT)); idList.add(Const.XML_TRACK_COMMENT); // Added date vColNames.add(Messages.getHumanPropertyName(Const.XML_TRACK_DISCOVERY_DATE)); idList.add(Const.XML_TRACK_DISCOVERY_DATE); // Order vColNames.add(Messages.getHumanPropertyName(Const.XML_TRACK_ORDER)); idList.add(Const.XML_TRACK_ORDER); // Disc number vColNames.add(Messages.getHumanPropertyName(Const.XML_TRACK_DISC_NUMBER)); idList.add(Const.XML_TRACK_DISC_NUMBER); // Device vColNames.add(Messages.getHumanPropertyName(Const.XML_DEVICE)); idList.add(Const.XML_DEVICE); // Directory vColNames.add(Messages.getHumanPropertyName(Const.XML_DIRECTORY)); idList.add(Const.XML_DIRECTORY); // File name vColNames.add(Messages.getString("Property_filename")); idList.add(Const.XML_FILE); // Hits vColNames.add(Messages.getHumanPropertyName(Const.XML_TRACK_HITS)); idList.add(Const.XML_TRACK_HITS); // custom properties now // for tracks for (PropertyMetaInformation meta : TrackManager.getInstance().getCustomProperties()) { vColNames.add(meta.getName()); idList.add(meta.getName()); } // for files for (PropertyMetaInformation meta : FileManager.getInstance().getCustomProperties()) { vColNames.add(meta.getName()); idList.add(meta.getName()); } } /** * Fill model with data using an optional filter property. * * @param sPropertyName DOCUMENT_ME * @param sPattern DOCUMENT_ME * @param columnsToShow DOCUMENT_ME */ @Override public void populateModel(String sPropertyName, String sPattern, List columnsToShow) { iRowNum = alItems.size() + alPlanned.size(); oValues = new Object[iRowNum][iNumberStandardCols + TrackManager.getInstance().getCustomProperties().size() + FileManager.getInstance().getCustomProperties().size()]; // For perfs, prepare columns visibility boolean bName = (columnsToShow != null && columnsToShow.contains(Const.XML_NAME)); boolean bAlbum = (columnsToShow != null && columnsToShow.contains(Const.XML_ALBUM)); boolean bArtist = (columnsToShow != null && columnsToShow.contains(Const.XML_ARTIST)); boolean bAlbumArtist = (columnsToShow != null && columnsToShow.contains(Const.XML_ALBUM_ARTIST)); boolean bGenre = (columnsToShow != null && columnsToShow.contains(Const.XML_GENRE)); boolean bYear = (columnsToShow != null && columnsToShow.contains(Const.XML_YEAR)); boolean bRate = (columnsToShow != null && columnsToShow.contains(Const.XML_TRACK_RATE)); boolean bLength = (columnsToShow != null && columnsToShow.contains(Const.XML_TRACK_LENGTH)); boolean bComment = (columnsToShow != null && columnsToShow.contains(Const.XML_TRACK_COMMENT)); boolean bDiscovery = (columnsToShow != null && columnsToShow .contains(Const.XML_TRACK_DISCOVERY_DATE)); boolean bOrder = (columnsToShow != null && columnsToShow.contains(Const.XML_TRACK_ORDER)); boolean bDiscNumber = (columnsToShow != null && columnsToShow .contains(Const.XML_TRACK_DISC_NUMBER)); boolean bHits = (columnsToShow != null && columnsToShow.contains(Const.XML_TRACK_HITS)); boolean bDirectory = (columnsToShow != null && columnsToShow.contains(Const.XML_DIRECTORY)); boolean bDevice = (columnsToShow != null && columnsToShow.contains(Const.XML_DEVICE)); boolean bFileName = (columnsToShow != null && columnsToShow.contains(Const.XML_FILE)); for (int iRow = 0; iRow < iRowNum; iRow++) { StackItem item = getStackItem(iRow); // Play if (bQueue) { if (item.isPlanned()) { oValues[iRow][0] = IconLabel.getIconLabel(JajukIcons.TRACK_FIFO_PLANNED); } else if (item.isRepeat()) { // normal file, repeated oValues[iRow][0] = IconLabel.getIconLabel(JajukIcons.TRACK_FIFO_REPEAT); } else if (iRow == QueueModel.getIndex()) { // Played file oValues[iRow][0] = IconLabel.getIconLabel(JajukIcons.TRACK_FIFO_PLAYING); } else { // normal file, not repeated oValues[iRow][0] = IconLabel.getIconLabel(JajukIcons.TRACK_FIFO_NORM); } } else { oValues[iRow][0] = IconLabel.getIconLabel(JajukIcons.TRACK_FIFO_NORM); } File bf = item.getFile(); // Track name if (bName) { oValues[iRow][1] = bf.getTrack().getName(); } else { oValues[iRow][1] = ""; } // Album if (bAlbum) { oValues[iRow][2] = bf.getTrack().getAlbum().getName2(); } else { oValues[iRow][2] = ""; } // Artist if (bArtist) { oValues[iRow][3] = bf.getTrack().getArtist().getName2(); } else { oValues[iRow][3] = ""; } // AlbumArtist if (bAlbumArtist) { oValues[iRow][4] = bf.getTrack().getAlbumArtist().getName2(); } else { oValues[iRow][4] = ""; } // Genre if (bGenre) { oValues[iRow][5] = bf.getTrack().getGenre().getName2(); } else { oValues[iRow][5] = ""; } // Rate if (bRate) { oValues[iRow][6] = StarsHelper.getStarIconLabel(bf.getTrack()); } else { oValues[iRow][6] = ""; } // Year if (bYear) { oValues[iRow][7] = bf.getTrack().getYear(); } else { oValues[iRow][7] = ""; } // Length if (bLength) { oValues[iRow][8] = new Duration(bf.getTrack().getDuration()); } else { oValues[iRow][8] = ""; } // Comment if (bComment) { oValues[iRow][9] = bf.getTrack().getStringValue(Const.XML_TRACK_COMMENT); } else { oValues[iRow][9] = ""; } // Date discovery if (bDiscovery) { oValues[iRow][10] = bf.getTrack().getDiscoveryDate(); } else { oValues[iRow][10] = ""; } // Order if (bOrder) { oValues[iRow][11] = bf.getTrack().getOrder(); } else { oValues[iRow][11] = ""; } // Disc number if (bDiscNumber) { oValues[iRow][12] = bf.getTrack().getDiscNumber(); } else { oValues[iRow][12] = ""; } // Device name if (bDevice) { oValues[iRow][13] = bf.getDevice().getName(); } else { oValues[iRow][13] = ""; } // directory name if (bDirectory) { oValues[iRow][14] = bf.getDirectory().getName(); } else { oValues[iRow][14] = ""; } // file name if (bFileName) { oValues[iRow][15] = bf.getName(); } else { oValues[iRow][15] = ""; } // Hits if (bHits) { oValues[iRow][16] = bf.getTrack().getHits(); } else { oValues[iRow][16] = ""; } // Custom properties now // for tracks Iterator it2 = TrackManager.getInstance().getCustomProperties() .iterator(); for (int i = 0; it2.hasNext(); i++) { PropertyMetaInformation meta = it2.next(); Map properties = bf.getTrack().getProperties(); Object o = properties.get(meta.getName()); if (o != null) { oValues[iRow][iNumberStandardCols + i] = o; } else { oValues[iRow][iNumberStandardCols + i] = meta.getDefaultValue(); } } // for files it2 = FileManager.getInstance().getCustomProperties().iterator(); // note that index lust start at custom track properties size for (int i = TrackManager.getInstance().getCustomProperties().size(); it2.hasNext(); i++) { PropertyMetaInformation meta = it2.next(); Map properties = bf.getProperties(); Object o = properties.get(meta.getName()); if (o != null) { oValues[iRow][iNumberStandardCols + i] = o; } else { oValues[iRow][iNumberStandardCols + i] = meta.getDefaultValue(); } } } } /** * Gets the items. * * @return the items */ public List getItems() { return this.alItems; } /** * Sets the items. * * @param alItems the new items */ public void setItems(List alItems) { this.alItems = alItems; } /** * Gets the planned. * * @return the planned */ public List getPlanned() { return this.alPlanned; } /** * Sets the planned. * * @param alPlanned the new planned */ public void setPlanned(List alPlanned) { this.alPlanned = alPlanned; } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/helpers/TransferableAlbum.java0000644000175000017500000000530511720500104026321 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.helpers; import java.awt.datatransfer.DataFlavor; import java.awt.datatransfer.Transferable; import java.awt.datatransfer.UnsupportedFlavorException; import java.io.IOException; import java.util.Arrays; import org.jajuk.base.Album; import org.jajuk.base.TrackManager; /** * Transferable album ( for DND ). */ public class TransferableAlbum implements Transferable { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** The Constant ALBUM_FLAVOR. DOCUMENT_ME */ public static final DataFlavor ALBUM_FLAVOR = new DataFlavor( DataFlavor.javaJVMLocalObjectMimeType, "Album"); /** DOCUMENT_ME. */ private Album album; /** * Instantiates a new transferable album. * * @param album DOCUMENT_ME */ public TransferableAlbum(Album album) { this.album = album; } /** DOCUMENT_ME. */ private final DataFlavor[] flavors = { ALBUM_FLAVOR }; /* * (non-Javadoc) * * @see java.awt.datatransfer.Transferable#getTransferDataFlavors() */ @Override public DataFlavor[] getTransferDataFlavors() { return flavors; } /* * (non-Javadoc) * * @see java.awt.datatransfer.Transferable#isDataFlavorSupported(java.awt.datatransfer.DataFlavor) */ @Override public boolean isDataFlavorSupported(DataFlavor flavor) { return Arrays.asList(flavors).contains(flavor); } /* * (non-Javadoc) * * @see java.awt.datatransfer.Transferable#getTransferData(java.awt.datatransfer.DataFlavor) */ @Override public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, IOException { if (flavor == ALBUM_FLAVOR) { return this; } throw new UnsupportedFlavorException(flavor); } /** * Gets the user object. * * @return associated album */ public Object getUserObject() { return TrackManager.getInstance().getAssociatedTracks(this.album, true); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/helpers/ManualDeviceRefreshReporter.java0000644000175000017500000001160111720500104030323 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.helpers; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.lang.reflect.InvocationTargetException; import javax.swing.SwingUtilities; import javax.swing.Timer; import org.jajuk.base.Device; import org.jajuk.base.Directory; import org.jajuk.ui.wizard.RefreshDialog; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; import org.jajuk.util.log.Log; /** * Refresh reporter with GUI special operations. */ public class ManualDeviceRefreshReporter extends RefreshReporter { // Refresh dialog /** DOCUMENT_ME. */ private RefreshDialog rdialog; /** DOCUMENT_ME. */ private int progress; /** * Instantiates a new manual device refresh reporter. * * @param device DOCUMENT_ME */ public ManualDeviceRefreshReporter(Device device) { super(device); } /* * (non-Javadoc) * * @see org.jajuk.ui.helpers.RefreshReporter#startup() */ @Override public void startup() { super.startup(); try { SwingUtilities.invokeAndWait(new Runnable() { @Override public void run() { // if <0 directories count -> the progress bar is in indeterminate // state rdialog = new RefreshDialog((dirTotal < 0)); rdialog.setTitle(Messages.getString("RefreshDialog.2") + " " + device.getName()); rdialog.setAction(Messages.getString("RefreshDialog.3"), IconLoader .getIcon(JajukIcons.INFO)); } }); } catch (InterruptedException e) { throw new RuntimeException(e); } catch (InvocationTargetException e) { throw new RuntimeException(e); } } /* * (non-Javadoc) * * @see org.jajuk.ui.helpers.RefreshReporter#reset() */ @Override public void reset() { super.reset(); this.progress = 0; } /* * (non-Javadoc) * * @see org.jajuk.ui.helpers.RefreshReporter#cleanupDone() */ @Override public void cleanupDone() { // We estimate that cleanup represents about 20% of the total workload rdialog.setProgress(20); rdialog .setAction(Messages.getString("RefreshDialog.1"), IconLoader.getIcon(JajukIcons.REFRESH)); // Update counter only if final directory count is known if (dirTotal > 0) { updateDialogTitle.start(); } } /* * (non-Javadoc) * * @see * org.jajuk.ui.helpers.RefreshReporter#updateState(org.jajuk.base.Directory) */ @Override public void updateState(Directory dir) { if (rdialog != null) { rdialog.setRefreshing(new StringBuilder(Messages.getString("Device.44")).append(' ').append( dir.getRelativePath()).toString()); progress = 30 + (int) (70 * (float) dirCount / dirTotal); if (progress > 100) { progress = 100; } rdialog.setProgress(progress); } dirCount++; } /* * (non-Javadoc) * * @see org.jajuk.ui.helpers.RefreshReporter#done() */ @Override public void done() { done(true); } /** * Done. * * @param showInfoMessageDuration show info message with total duration when finished */ public void done(boolean showInfoMessageDuration) { long refreshTime = System.currentTimeMillis() - lRefreshDateStart; String message = buildFinalMessage(refreshTime); Log.debug(message); reset(); // Close refresh dialog rdialog.dispose(); // Close title timer updateDialogTitle.stop(); // Display end of refresh message with stats if (showInfoMessageDuration) { Messages.showInfoMessage(message); } } /** This timer limit dialog title changes (this can have side effect on performances or other in some window managers. Too many window title change causes others menu bar items freezes under KDE for ie) */ Timer updateDialogTitle = new Timer(1000, new ActionListener() { @Override public void actionPerformed(ActionEvent e) { String sTitle = Messages.getString("RefreshDialog.2") + " " + device.getName() + " (" + progress + " %)"; if (!sTitle.equals(rdialog.getTitle())) { rdialog.setTitle(sTitle); } } }); } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/helpers/TreeTransferHandler.java0000644000175000017500000000475511720500104026642 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.helpers; import java.awt.datatransfer.Transferable; import java.util.ArrayList; import java.util.List; import javax.swing.JComponent; import javax.swing.JTree; import javax.swing.TransferHandler; import javax.swing.tree.DefaultMutableTreeNode; import org.jajuk.base.Item; /** * DND handler for jtree. */ public class TreeTransferHandler extends TransferHandler { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** DOCUMENT_ME. */ final JTree jtree; /** * Constructor. * * @param jtree DOCUMENT_ME */ public TreeTransferHandler(final JTree jtree) { this.jtree = jtree; } /** * Called when dragging. * * @param c DOCUMENT_ME * * @return the transferable */ @SuppressWarnings("unchecked") @Override protected Transferable createTransferable(JComponent c) { List itemSelection = new ArrayList(); int[] selection = jtree.getSelectionRows(); for (int row : selection) { DefaultMutableTreeNode node = (DefaultMutableTreeNode) jtree.getPathForRow(row) .getLastPathComponent(); // We get a list of items in the case of period* dragging // * : period is used in TracksTreeView : "Less than 6 months" for ie if (node.getUserObject() instanceof List) { itemSelection.addAll((List) node.getUserObject()); } else { itemSelection.add((Item) node.getUserObject()); } } return new TransferableTreeNodes(itemSelection); } /** * return action type. * * @param c DOCUMENT_ME * * @return the source actions */ @Override public int getSourceActions(JComponent c) { return COPY_OR_MOVE; } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/helpers/TransferableTableRows.java0000644000175000017500000000522411720500104027163 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.helpers; import java.awt.datatransfer.DataFlavor; import java.awt.datatransfer.Transferable; import java.awt.datatransfer.UnsupportedFlavorException; import java.io.IOException; import java.util.Arrays; import java.util.List; import org.jajuk.base.Item; /** * Transferable table row ( for DND ). */ public class TransferableTableRows implements Transferable { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** The Constant ROW_FLAVOR. DOCUMENT_ME */ public static final DataFlavor ROW_FLAVOR = new DataFlavor(DataFlavor.javaJVMLocalObjectMimeType, "Row"); /** Transferable model. */ private List items; /** * Instantiates a new transferable table row. * * @param items DOCUMENT_ME */ public TransferableTableRows(List items) { this.items = items; } /** DOCUMENT_ME. */ private final DataFlavor[] flavors = { ROW_FLAVOR }; /* * (non-Javadoc) * * @see java.awt.datatransfer.Transferable#getTransferDataFlavors() */ @Override public DataFlavor[] getTransferDataFlavors() { return flavors; } /* * (non-Javadoc) * * @see java.awt.datatransfer.Transferable#isDataFlavorSupported(java.awt.datatransfer.DataFlavor) */ @Override public boolean isDataFlavorSupported(DataFlavor flavor) { return Arrays.asList(flavors).contains(flavor); } /* * (non-Javadoc) * * @see java.awt.datatransfer.Transferable#getTransferData(java.awt.datatransfer.DataFlavor) */ @Override public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, IOException { if (flavor == ROW_FLAVOR) { return this; } throw new UnsupportedFlavorException(flavor); } /** * Gets the user object. * * @return transferable model */ public Object getUserObject() { return items; } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/helpers/StarsHelper.java0000644000175000017500000000735511720500104025173 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.helpers; import java.util.HashMap; import java.util.Map; import javax.swing.ImageIcon; import org.jajuk.base.Album; import org.jajuk.base.AlbumManager; import org.jajuk.base.Item; import org.jajuk.base.Playlist; import org.jajuk.base.Track; import org.jajuk.ui.widgets.StarIconLabel; import org.jajuk.util.Const; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; /** * Manages stars against a item. * Stars are only visible from the GUI, they are never stored into collection itself */ public class StarsHelper { /** Cache iconLabel for each different rate to save memory and CPU. Map at index 0 stores banned tracks. */ @SuppressWarnings("unchecked") private static Map map[] = { new HashMap(), new HashMap(), new HashMap(), new HashMap(), new HashMap(), new HashMap() }; /** * Gets the icon. * * @param starsNumber DOCUMENT_ME * * @return the icon */ static public ImageIcon getIcon(int starsNumber) { switch (starsNumber) { case -1: return IconLoader.getIcon(JajukIcons.BAN); case 0: return IconLoader.getIcon(JajukIcons.STAR_0); case 1: return IconLoader.getIcon(JajukIcons.STAR_1); case 2: return IconLoader.getIcon(JajukIcons.STAR_2); case 3: return IconLoader.getIcon(JajukIcons.STAR_3); case 4: return IconLoader.getIcon(JajukIcons.STAR_4); default: return null; } } /** * Gets the stars number. * * @param item DOCUMENT_ME * * @return Number of stars based on the rate of this item */ static public int getStarsNumber(Item item) { long lInterval = 1; if (item instanceof Track) { lInterval = 100; } else if ((item instanceof Album) || (item instanceof Playlist)) { lInterval = AlbumManager.getInstance().getMaxRate(); } lInterval = lInterval / 4; long lRate = item.getRate(); if (lRate == 0) { return 0; } else if (lRate <= lInterval) { return 1; } else if (lRate <= 2 * lInterval) { return 2; } else if (lRate <= 3 * lInterval) { return 3; } else { return 4; } } /** * Gets the stars. * * @param item DOCUMENT_ME * * @return the stars icon or ban icon if banned */ @SuppressWarnings("unchecked") static public StarIconLabel getStarIconLabel(Item item) { long rate = item.getRate(); StarIconLabel sil = null; int starsNumber; if (item instanceof Track && item.getBooleanValue(Const.XML_TRACK_BANNED)) { starsNumber = -1; } else { starsNumber = getStarsNumber(item); } sil = (StarIconLabel) map[starsNumber + 1].get(rate); if (sil == null) { sil = new StarIconLabel(getIcon(starsNumber), "", null, null, null, (int) rate, starsNumber); map[starsNumber + 1].put(rate, sil); } return sil; } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/helpers/JajukCellRenderer.java0000644000175000017500000000734311720500104026267 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.helpers; import java.awt.Color; import java.awt.Component; import java.util.Date; import javax.swing.JLabel; import javax.swing.JTable; import javax.swing.SwingConstants; import org.jajuk.base.Year; import org.jajuk.ui.helpers.FontManager.JajukFont; import org.jajuk.ui.widgets.IconLabel; import org.jajuk.util.Const; import org.jajuk.util.UtilString; import org.jvnet.substance.api.renderers.SubstanceDefaultTableCellRenderer; /** * Cell renderer to support cells color and icons *

* Note that by swing design, this renderer applies to an entire column. It is * useless to change a specific cell rendering according row or column number * See * http://java.sun.com/docs/books/tutorial/uiswing/components/table.html#editrender *

*/ public class JajukCellRenderer extends SubstanceDefaultTableCellRenderer implements Const { /** Generated serialVersionUID. */ private static final long serialVersionUID = 154545454L; /** DOCUMENT_ME. */ private final Color color; /** * The Constructor. * * @param color background color for cells or null if default */ public JajukCellRenderer(Color color) { super(); this.color = color; } /** * Instantiates a new jajuk cell renderer. */ public JajukCellRenderer() { this(null); } /** DOCUMENT_ME. */ private final SubstanceDefaultTableCellRenderer.BooleanRenderer booleanRenderer = new SubstanceDefaultTableCellRenderer.BooleanRenderer(); /* (non-Javadoc) * @see org.jvnet.substance.api.renderers.SubstanceDefaultTableCellRenderer#getTableCellRendererComponent(javax.swing.JTable, java.lang.Object, boolean, boolean, int, int) */ @Override public Component getTableCellRendererComponent(JTable table, Object oValue, boolean selected, boolean focused, int row, int column) { Component c = super .getTableCellRendererComponent(table, oValue, selected, focused, row, column); if (oValue instanceof IconLabel) { ((JLabel) c).setOpaque(false); ((JLabel) c).setHorizontalAlignment(SwingConstants.LEFT); ((JLabel) c).setIcon(((IconLabel) oValue)); ((JLabel) c).setToolTipText(((IconLabel) oValue).getTooltip()); ((JLabel) c).setFont(((IconLabel) oValue).getFont()); ((JLabel) c).setText(((IconLabel) oValue).getText()); } else if (oValue instanceof Date) { ((JLabel) c).setText(UtilString.getLocaleDateFormatter().format(((Date) oValue))); } else if (oValue instanceof Boolean) { c = booleanRenderer.getTableCellRendererComponent(table, oValue, selected, focused, row, column); } else if (oValue instanceof Duration) { ((JLabel) c).setText(((Duration) oValue).toString()); } else if (oValue instanceof Year) { Long year = ((Year) oValue).getValue(); ((JLabel) c).setText(year.toString()); } c.setFont(FontManager.getInstance().getFont(JajukFont.PLAIN)); if (color != null) { c.setBackground(color); } return c; } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/helpers/ItemMoveManager.java0000644000175000017500000000434111720500104025747 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.helpers; import java.util.ArrayList; import java.util.List; import org.jajuk.base.Item; /** * Convenient class to manage Items to be moved using Cut/Copy/Paste Actions. */ public class ItemMoveManager { /** DOCUMENT_ME. */ private static ItemMoveManager singleton = new ItemMoveManager(); /** DOCUMENT_ME. */ private final List itemsToMove = new ArrayList(20); /** * DOCUMENT_ME. */ public enum MoveActions { /** DOCUMENT_ME. */ CUT, /** DOCUMENT_ME. */ COPY } /** DOCUMENT_ME. */ private MoveActions moveAction; /** * Gets the single instance of ItemMoveManager. * * @return single instance of ItemMoveManager */ public static ItemMoveManager getInstance() { return singleton; } /** * Adds the items. * DOCUMENT_ME * * @param items DOCUMENT_ME */ public void addItems(List items) { itemsToMove.addAll(items); } /** * Gets the all. * * @return the all */ public List getAll() { return itemsToMove; } /** * Removes the all. * DOCUMENT_ME */ public void removeAll() { itemsToMove.clear(); } /** * Sets the action. * * @param action the new action */ public void setAction(MoveActions action) { moveAction = action; } /** * Gets the action. * * @return the action */ public MoveActions getAction() { return moveAction; } }jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/helpers/ILaunchCommand.java0000644000175000017500000000205611720500104025552 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.helpers; /** * Command to be executed on a jajuk table after a left click. */ public interface ILaunchCommand { /** * Action on launch. * * @param nbClicks : * number of mouse clicks */ void launch(int nbClicks); } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/helpers/PreferencesJMenu.java0000644000175000017500000001324111720500104026126 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.helpers; import java.util.ArrayList; import java.util.List; import javax.swing.JMenu; import javax.swing.JMenuItem; import org.jajuk.base.Item; import org.jajuk.ui.actions.ActionManager; import org.jajuk.ui.actions.JajukActions; import org.jajuk.ui.helpers.FontManager.JajukFont; import org.jajuk.util.Const; import org.jajuk.util.Messages; import org.jajuk.util.UtilFeatures; /** * Preference menu item including ban/unban and preference choice. */ public class PreferencesJMenu extends JMenu { /** Generated serialVersionUID. */ private static final long serialVersionUID = -4041513018474249903L; /** DOCUMENT_ME. */ private JMenuItem jmiBan; /** DOCUMENT_ME. */ private JMenuItem jmiUnBan; /** DOCUMENT_ME. */ private JMenuItem jmiAdore; /** DOCUMENT_ME. */ private JMenuItem jmiLove; /** DOCUMENT_ME. */ private JMenuItem jmiLike; /** DOCUMENT_ME. */ private JMenuItem jmiUnset; /** DOCUMENT_ME. */ private JMenuItem jmiAverage; /** DOCUMENT_ME. */ private JMenuItem jmiPoor; /** DOCUMENT_ME. */ private JMenuItem jmiHate; /** * Constructs a Preference menu. * * @param item DOCUMENT_ME */ public PreferencesJMenu(Item item) { super(Messages.getString("Preference.7")); List selection = new ArrayList(1); selection.add(item); initUI(selection); } /** * Constructs a Preference menu. * * @param selection selection list bound to the actions */ public PreferencesJMenu(List selection) { super(Messages.getString("Preference.7")); initUI(selection); } /** * initUI. * * @param selection DOCUMENT_ME */ private void initUI(List selection) { // We compute preference of first item in selection to set right // item bold font long selectionPreference = UtilFeatures.getPreferenceForSelection(selection); jmiBan = new JMenuItem(ActionManager.getAction(JajukActions.BAN_SELECTION)); jmiBan.putClientProperty(Const.DETAIL_SELECTION, selection); jmiUnBan = new JMenuItem(ActionManager.getAction(JajukActions.UN_BAN_SELECTION)); jmiUnBan.putClientProperty(Const.DETAIL_SELECTION, selection); jmiAdore = new JMenuItem(ActionManager.getAction(JajukActions.PREFERENCE_ADORE)); jmiAdore.putClientProperty(Const.DETAIL_SELECTION, selection); if (selectionPreference == Const.PREFERENCE_ADORE) { jmiAdore.setFont(FontManager.getInstance().getFont(JajukFont.BOLD)); } jmiLove = new JMenuItem(ActionManager.getAction(JajukActions.PREFERENCE_LOVE)); jmiLove.putClientProperty(Const.DETAIL_SELECTION, selection); if (selectionPreference == Const.PREFERENCE_LOVE) { jmiLove.setFont(FontManager.getInstance().getFont(JajukFont.BOLD)); } jmiLike = new JMenuItem(ActionManager.getAction(JajukActions.PREFERENCE_LIKE)); jmiLike.putClientProperty(Const.DETAIL_SELECTION, selection); if (selectionPreference == Const.PREFERENCE_LIKE) { jmiLike.setFont(FontManager.getInstance().getFont(JajukFont.BOLD)); } jmiUnset = new JMenuItem(ActionManager.getAction(JajukActions.PREFERENCE_UNSET)); jmiUnset.putClientProperty(Const.DETAIL_SELECTION, selection); if (selectionPreference == Const.PREFERENCE_UNSET) { jmiUnset.setFont(FontManager.getInstance().getFont(JajukFont.BOLD)); } jmiAverage = new JMenuItem(ActionManager.getAction(JajukActions.PREFERENCE_AVERAGE)); jmiAverage.putClientProperty(Const.DETAIL_SELECTION, selection); if (selectionPreference == Const.PREFERENCE_AVERAGE) { jmiAverage.setFont(FontManager.getInstance().getFont(JajukFont.BOLD)); } jmiPoor = new JMenuItem(ActionManager.getAction(JajukActions.PREFERENCE_POOR)); jmiPoor.putClientProperty(Const.DETAIL_SELECTION, selection); if (selectionPreference == Const.PREFERENCE_POOR) { jmiPoor.setFont(FontManager.getInstance().getFont(JajukFont.BOLD)); } jmiHate = new JMenuItem(ActionManager.getAction(JajukActions.PREFERENCE_HATE)); jmiHate.putClientProperty(Const.DETAIL_SELECTION, selection); if (selectionPreference == Const.PREFERENCE_HATE) { jmiHate.setFont(FontManager.getInstance().getFont(JajukFont.BOLD)); } add(jmiBan); add(jmiUnBan); addSeparator(); add(jmiAdore); add(jmiLove); add(jmiLike); add(jmiUnset); add(jmiAverage); add(jmiPoor); add(jmiHate); } /** * Repaint the preference popup menu. This is a workaround for the listener * concurrency issue between mouse and selection listener in tables. When a * table selection change, the view that contains the table calls this method * in valueChanged() method as we can't build a popup menu in mouse adapter * methods because the selection is not always yet set * * @param selection DOCUMENT_ME */ public synchronized void resetUI(List selection) { removeAll(); initUI(selection); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/helpers/animations/0000755000175000017500000000000011720500104024224 5ustar drazzibdrazzibjajuk-1.9.6.orig/src/main/java/org/jajuk/ui/helpers/animations/AnimationCompletedEvent.java0000644000175000017500000000303711720500104031650 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.helpers.animations; import java.awt.Window; /** * Event thrown when the naimation is done. */ public class AnimationCompletedEvent { /** DOCUMENT_ME. */ private IAnimation source; /** DOCUMENT_ME. */ private Window window; /** * Instantiates a new animation completed event. * * @param source DOCUMENT_ME * @param window DOCUMENT_ME */ public AnimationCompletedEvent(IAnimation source, Window window) { this.source = source; this.window = window; } /** * Gets the source. * * @return the source */ public IAnimation getSource() { return source; } /** * Gets the window. * * @return the window */ public Window getWindow() { return window; } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/helpers/animations/package.html0000644000175000017500000000017111720500104026504 0ustar drazzibdrazzib DOCUMENT_ME jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/helpers/animations/AnimationCompletedListener.java0000644000175000017500000000211211720500104032345 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.helpers.animations; /** * Listener used to track for animation ending. */ public interface AnimationCompletedListener { /** * Animation completed. * DOCUMENT_ME * * @param e DOCUMENT_ME */ void animationCompleted(AnimationCompletedEvent e); } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/helpers/animations/SlideAnimation.java0000644000175000017500000005250511720500104027776 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.helpers.animations; import java.awt.Dimension; import java.awt.GraphicsEnvironment; import java.awt.Insets; import java.awt.Point; import java.awt.Rectangle; import java.awt.Toolkit; import java.awt.Window; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.SwingUtilities; import javax.swing.Timer; import org.jajuk.util.log.Log; /** * Slide animation implementation. */ public class SlideAnimation extends AbstractAnimation { /** DOCUMENT_ME. */ private ScreenPosition screenPosition; /** DOCUMENT_ME. */ private StartingPosition startingPosition; /** DOCUMENT_ME. */ private Direction direction; /** DOCUMENT_ME. */ private Timer animationTimer; /** DOCUMENT_ME. */ private long animationStart; /** DOCUMENT_ME. */ private Rectangle start; /** DOCUMENT_ME. */ private Rectangle windowBounds; /** Time (ms) of a frame displaying. */ private static final int FRAME_DURATION = 5; /** * Instantiates a new slide animation. * * @param window DOCUMENT_ME * @param screenPosition DOCUMENT_ME * @param startingPosition DOCUMENT_ME * @param direction DOCUMENT_ME */ public SlideAnimation(Window window, ScreenPosition screenPosition, StartingPosition startingPosition, Direction direction) { super(window); this.screenPosition = screenPosition; this.startingPosition = startingPosition; this.direction = direction; } /* * (non-Javadoc) * * @see org.jajuk.ui.helpers.animations.IAnimation#animate(int) */ @Override public void animate(final int animationTime) { window.pack(); windowBounds = window.getBounds(); start = startingPosition.getStartingPosition(screenPosition.getScreenPosition(windowBounds)); start.width = windowBounds.width; start.height = windowBounds.height; if (!AWTUtilities.isAvailable()) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { window.setLocation(direction.getCurrentLocation(start, 1)); new Thread(new Runnable() { @Override public void run() { try { Thread.sleep(animationTime); } catch (Exception ex) { Log.error(ex); } animationCompleted(); } }).start(); } }); return; } ActionListener animationLogic = new ActionListener() { @Override public void actionPerformed(ActionEvent e) { long elapsed = System.currentTimeMillis() - animationStart; if (elapsed > animationTime) { animationTimer.stop(); animationCompleted(); } else { float progress = (float) elapsed / animationTime; window.setLocation(direction.getCurrentLocation(start, progress)); window.setVisible(true); window.repaint(); } } }; animationTimer = new Timer(FRAME_DURATION, animationLogic); animationStart = System.currentTimeMillis(); animationTimer.start(); } /** * Gets the direction. * * @return the direction */ public Direction getDirection() { return direction; } /** * Gets the screen position. * * @return the screen position */ public ScreenPosition getScreenPosition() { return screenPosition; } /** * Gets the starting position. * * @return the starting position */ public StartingPosition getStartingPosition() { return startingPosition; } /** * DOCUMENT_ME. */ public interface ScreenPosition { /** * Gets the screen position. * * @param size DOCUMENT_ME * * @return the screen position */ Rectangle getScreenPosition(Rectangle size); } /** * DOCUMENT_ME. */ public interface StartingPosition { /** * Gets the starting position. * * @param position DOCUMENT_ME * * @return the starting position */ Rectangle getStartingPosition(Rectangle position); } /** * DOCUMENT_ME. */ public interface Direction { /** * Gets the current location. * * @param start DOCUMENT_ME * @param progress DOCUMENT_ME * * @return the current location */ Point getCurrentLocation(Rectangle start, float progress); /** * Gets the showing bounds. * * @param start DOCUMENT_ME * @param progress DOCUMENT_ME * * @return the showing bounds */ Rectangle getShowingBounds(Rectangle start, float progress); } /** * DOCUMENT_ME. */ public enum ScreenPositions implements ScreenPosition { /** DOCUMENT_ME. */ TOP_LEFT { @Override public Rectangle getScreenPosition(Rectangle size) { Rectangle bounds = getDesktopBounds(); Rectangle position = new Rectangle(); position.x = bounds.x; position.y = bounds.y; position.width = size.width; position.height = size.height; return position; } }, /** DOCUMENT_ME. */ TOP_RIGHT { @Override public Rectangle getScreenPosition(Rectangle size) { Rectangle bounds = getDesktopBounds(); Rectangle position = new Rectangle(); position.x = bounds.x + bounds.width - size.width; position.y = bounds.y; position.width = size.width; position.height = size.height; return position; } }, /** DOCUMENT_ME. */ BOTTOM_LEFT { @Override public Rectangle getScreenPosition(Rectangle size) { Rectangle bounds = getDesktopBounds(); Rectangle position = new Rectangle(); position.x = bounds.x; position.y = bounds.y + bounds.height - size.height; position.width = size.width; position.height = size.height; return position; } }, /** DOCUMENT_ME. */ BOTTOM_RIGHT { @Override public Rectangle getScreenPosition(Rectangle size) { Rectangle bounds = getDesktopBounds(); Rectangle position = new Rectangle(); position.x = bounds.x + bounds.width - size.width; position.y = bounds.y + bounds.height - size.height; position.width = size.width; position.height = size.height; return position; } }, /** DOCUMENT_ME. */ CURRENT { @Override public Rectangle getScreenPosition(Rectangle size) { return new Rectangle(size); } }; /** * Gets the desktop bounds. * * @return the desktop bounds */ protected Rectangle getDesktopBounds() { // Remove 50 px is useful under Linux as we can't get actual desktop // insets and popup is too low in most cases (see // http://forums.sun.com/thread.jspa?threadID=5169228) Insets insets = Toolkit.getDefaultToolkit().getScreenInsets( GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice() .getDefaultConfiguration()); if (insets.equals(new Insets(0, 0, 0, 0))) { insets.bottom = 50; } Dimension size = Toolkit.getDefaultToolkit().getScreenSize(); return new Rectangle(insets.left, insets.top, size.width - insets.left - insets.right, size.height - insets.top - insets.bottom); } } /** * DOCUMENT_ME. */ public enum StartingPositions implements StartingPosition { /** DOCUMENT_ME. */ TOP { @Override public Rectangle getStartingPosition(Rectangle position) { Rectangle size = new Rectangle(); size.x = position.x; size.y = position.y; size.width = position.width; size.height = 0; return size; } }, /** DOCUMENT_ME. */ BOTTOM { @Override public Rectangle getStartingPosition(Rectangle position) { Rectangle size = new Rectangle(); size.x = position.x; size.y = position.y + position.height; size.width = position.width; size.height = 0; return size; } }, /** DOCUMENT_ME. */ LEFT { @Override public Rectangle getStartingPosition(Rectangle position) { Rectangle size = new Rectangle(); size.x = position.x; size.y = position.y; size.width = 0; size.height = position.height; return size; } }, /** DOCUMENT_ME. */ RIGHT { @Override public Rectangle getStartingPosition(Rectangle position) { Rectangle size = new Rectangle(); size.x = position.x + position.width; size.y = position.y; size.width = 0; size.height = position.height; return size; } }, /** DOCUMENT_ME. */ TOP_LEFT { @Override public Rectangle getStartingPosition(Rectangle position) { Rectangle size = new Rectangle(); size.x = position.x; size.y = position.y; size.width = 0; size.height = 0; return size; } }, /** DOCUMENT_ME. */ TOP_RIGHT { @Override public Rectangle getStartingPosition(Rectangle position) { Rectangle size = new Rectangle(); size.x = position.x + position.width; size.y = position.y; size.width = 0; size.height = 0; return size; } }, /** DOCUMENT_ME. */ BOTTOM_LEFT { @Override public Rectangle getStartingPosition(Rectangle position) { Rectangle size = new Rectangle(); size.x = position.x; size.y = position.y + position.height; size.width = 0; size.height = 0; return size; } }, /** DOCUMENT_ME. */ BOTTOM_RIGHT { @Override public Rectangle getStartingPosition(Rectangle position) { Rectangle size = new Rectangle(); size.x = position.x + position.width; size.y = position.y + position.height; size.width = 0; size.height = 0; return size; } }, /** DOCUMENT_ME. */ FULL { @Override public Rectangle getStartingPosition(Rectangle position) { return new Rectangle(position); } }; } /** * DOCUMENT_ME. */ public enum InDirections implements Direction { /** DOCUMENT_ME. */ UP { @Override public Point getCurrentLocation(Rectangle start, float progress) { Point current = new Point(); current.x = start.x; current.y = start.y - (int) (start.height * progress); return current; } @Override public Rectangle getShowingBounds(Rectangle start, float progress) { Rectangle current = new Rectangle(); current.width = start.width; current.height = (int) (start.height * progress); current.x = 0; current.y = 0; return current; } }, /** DOCUMENT_ME. */ DOWN { @Override public Point getCurrentLocation(Rectangle start, float progress) { Point current = new Point(); current.x = start.x; current.y = start.y - (start.height - (int) (start.height * progress)); return current; } @Override public Rectangle getShowingBounds(Rectangle start, float progress) { Rectangle current = new Rectangle(); current.width = start.width; current.height = (int) (start.height * progress); current.x = 0; current.y = start.height - current.height; return current; } }, /** DOCUMENT_ME. */ LEFT { @Override public Point getCurrentLocation(Rectangle start, float progress) { Point current = new Point(); current.x = start.x - (int) (start.width * progress); current.y = start.y; return current; } @Override public Rectangle getShowingBounds(Rectangle start, float progress) { Rectangle current = new Rectangle(); current.width = (int) (start.width * progress); current.height = start.height; current.x = 0; current.y = 0; return current; } }, /** DOCUMENT_ME. */ RIGHT { @Override public Point getCurrentLocation(Rectangle start, float progress) { Point current = new Point(); current.x = start.x - (start.width - (int) (start.width * progress)); current.y = start.y; return current; } @Override public Rectangle getShowingBounds(Rectangle start, float progress) { Rectangle current = new Rectangle(); current.width = (int) (start.width * progress); current.height = start.height; current.x = start.width - current.width; current.y = 0; return current; } }, /** DOCUMENT_ME. */ UP_LEFT { @Override public Point getCurrentLocation(Rectangle start, float progress) { Point current = new Point(); current.x = start.x - (int) (start.width * progress); current.y = start.y - (int) (start.height * progress); return current; } @Override public Rectangle getShowingBounds(Rectangle start, float progress) { Rectangle current = new Rectangle(); current.width = (int) (start.width * progress); current.height = (int) (start.height * progress); current.x = 0; current.y = 0; return current; } }, /** DOCUMENT_ME. */ UP_RIGHT { @Override public Point getCurrentLocation(Rectangle start, float progress) { Point current = new Point(); current.x = start.x - (start.width - (int) (start.width * progress)); current.y = start.y - (int) (start.height * progress); return current; } @Override public Rectangle getShowingBounds(Rectangle start, float progress) { Rectangle current = new Rectangle(); current.width = (int) (start.width * progress); current.height = (int) (start.height * progress); current.x = start.width - current.width; current.y = 0; return current; } }, /** DOCUMENT_ME. */ DOWN_LEFT { @Override public Point getCurrentLocation(Rectangle start, float progress) { Point current = new Point(); current.x = start.x - (int) (start.width * progress); current.y = start.y - (start.height - (int) (start.height * progress)); return current; } @Override public Rectangle getShowingBounds(Rectangle start, float progress) { Rectangle current = new Rectangle(); current.width = (int) (start.width * progress); current.height = (int) (start.height * progress); current.x = 0; current.y = start.height - current.height; return current; } }, /** DOCUMENT_ME. */ DOWN_RIGHT { @Override public Point getCurrentLocation(Rectangle start, float progress) { Point current = new Point(); current.x = start.x - (start.width - (int) (start.width * progress)); current.y = start.y - (start.height - (int) (start.height * progress)); return current; } @Override public Rectangle getShowingBounds(Rectangle start, float progress) { Rectangle current = new Rectangle(); current.width = (int) (start.width * progress); current.height = (int) (start.height * progress); current.x = start.width - current.width; current.y = start.height - current.height; return current; } }; } /** * DOCUMENT_ME. */ public enum OutDirections implements Direction { /** DOCUMENT_ME. */ UP { @Override public Point getCurrentLocation(Rectangle start, float progress) { Point current = new Point(); current.x = start.x; current.y = start.y - (int) (start.height * progress); return current; } @Override public Rectangle getShowingBounds(Rectangle start, float progress) { Rectangle current = new Rectangle(); current.width = start.width; current.height = (int) (start.height * (1 - progress)); current.x = 0; current.y = start.height - current.height; return current; } }, /** DOCUMENT_ME. */ DOWN { @Override public Point getCurrentLocation(Rectangle start, float progress) { Point current = new Point(); current.x = start.x; current.y = start.y + (int) (start.height * progress); return current; } @Override public Rectangle getShowingBounds(Rectangle start, float progress) { Rectangle current = new Rectangle(); current.width = start.width; current.height = (int) (start.height * (1 - progress)); current.x = 0; current.y = 0; return current; } }, /** DOCUMENT_ME. */ LEFT { @Override public Point getCurrentLocation(Rectangle start, float progress) { Point current = new Point(); current.x = start.x - (int) (start.width * progress); current.y = start.y; return current; } @Override public Rectangle getShowingBounds(Rectangle start, float progress) { Rectangle current = new Rectangle(); current.width = (int) (start.width * (1 - progress)); current.height = start.height; current.x = start.width - current.width; current.y = 0; return current; } }, /** DOCUMENT_ME. */ RIGHT { @Override public Point getCurrentLocation(Rectangle start, float progress) { Point current = new Point(); current.x = start.x + (int) (start.width * progress); current.y = start.y; return current; } @Override public Rectangle getShowingBounds(Rectangle start, float progress) { Rectangle current = new Rectangle(); current.width = (int) (start.width * (1 - progress)); current.height = start.height; current.x = 0; current.y = 0; return current; } }, /** DOCUMENT_ME. */ UP_LEFT { @Override public Point getCurrentLocation(Rectangle start, float progress) { Point current = new Point(); current.x = start.x - (int) (start.width * progress); current.y = start.y - (int) (start.height * progress); return current; } @Override public Rectangle getShowingBounds(Rectangle start, float progress) { Rectangle current = new Rectangle(); current.width = (int) (start.width * (1 - progress)); current.height = (int) (start.height * (1 - progress)); current.x = start.width - current.width; current.y = start.height - current.height; return current; } }, /** DOCUMENT_ME. */ UP_RIGHT { @Override public Point getCurrentLocation(Rectangle start, float progress) { Point current = new Point(); current.x = start.x + (int) (start.width * progress); current.y = start.y - (int) (start.height * progress); return current; } @Override public Rectangle getShowingBounds(Rectangle start, float progress) { Rectangle current = new Rectangle(); current.width = (int) (start.width * (1 - progress)); current.height = (int) (start.height * (1 - progress)); current.x = 0; current.y = start.height - current.height; return current; } }, /** DOCUMENT_ME. */ DOWN_LEFT { @Override public Point getCurrentLocation(Rectangle start, float progress) { Point current = new Point(); current.x = start.x - (int) (start.width * progress); current.y = start.y + (int) (start.height * progress); return current; } @Override public Rectangle getShowingBounds(Rectangle start, float progress) { Rectangle current = new Rectangle(); current.width = (int) (start.width * (1 - progress)); current.height = (int) (start.height * (1 - progress)); current.x = start.width - current.width; current.y = 0; return current; } }, /** DOCUMENT_ME. */ DOWN_RIGHT { @Override public Point getCurrentLocation(Rectangle start, float progress) { Point current = new Point(); current.x = start.x + (int) (start.width * progress); current.y = start.y + (int) (start.height * progress); return current; } @Override public Rectangle getShowingBounds(Rectangle start, float progress) { Rectangle current = new Rectangle(); current.width = (int) (start.width * (1 - progress)); current.height = (int) (start.height * (1 - progress)); current.x = 0; current.y = 0; return current; } }; } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/helpers/animations/AbstractAnimation.java0000644000175000017500000000442011720500104030472 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.helpers.animations; import java.awt.Window; import java.util.concurrent.CopyOnWriteArrayList; /** * Base implementation of IAnimation. */ public abstract class AbstractAnimation implements IAnimation { /** DOCUMENT_ME. */ protected Window window; /** DOCUMENT_ME. */ private CopyOnWriteArrayList listeners = new CopyOnWriteArrayList(); /** * Instantiates a new abstract animation. * * @param window DOCUMENT_ME */ protected AbstractAnimation(Window window) { this.window = window; } /* (non-Javadoc) * @see org.jajuk.ui.helpers.animations.IAnimation#getWindow() */ @Override public Window getWindow() { return window; } /** * Adds the animation completed listener. * DOCUMENT_ME * * @param listener DOCUMENT_ME */ public void addAnimationCompletedListener(AnimationCompletedListener listener) { listeners.add(listener); } /** * Removes the animation completed listener. * DOCUMENT_ME * * @param listener DOCUMENT_ME */ public void removeAnimationCompletedListener(AnimationCompletedListener listener) { listeners.remove(listener); } /** * Animation completed. * DOCUMENT_ME */ protected void animationCompleted() { AnimationCompletedEvent event = new AnimationCompletedEvent(this, window); for (AnimationCompletedListener listener : listeners) { listener.animationCompleted(event); } } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/helpers/animations/AWTUtilities.java0000644000175000017500000000546711720500104027432 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.helpers.animations; import java.awt.Shape; import java.awt.Window; import java.lang.reflect.Method; /** * Wrapper class used to handle cases where JRE AWTUtilities class is not available. * * See https://trac.jajuk.info/ticket/1464 for more details */ public class AWTUtilities { /** * Checks if is available. * * @return true, if is available */ @SuppressWarnings("unchecked") public static boolean isAvailable() { try { @SuppressWarnings("unused") Class awtutil = Class.forName("com.sun.awt.AWTUtilities"); return true; } catch (Exception ex) { // Void on purpose, means that this JRE doesn't support the com.sun.awt.AWTUtilities class, do // nothing } return false; } /** * Sets the window shape. * DOCUMENT_ME * * @param window DOCUMENT_ME * @param shape DOCUMENT_ME */ @SuppressWarnings("unchecked") public static void setWindowShape(Window window, Shape shape) { try { Class awtutil = Class.forName("com.sun.awt.AWTUtilities"); Method setWindowShape = awtutil.getMethod("setWindowShape", Window.class, Shape.class); setWindowShape.invoke(null, window, shape); } catch (Exception ex) { // Void on purpose, means that this JRE doesn't support the com.sun.awt.AWTUtilities class, do // nothing } } /** * Sets the window opacity. * DOCUMENT_ME * * @param window DOCUMENT_ME * @param alpha DOCUMENT_ME */ @SuppressWarnings("unchecked") public static void setWindowOpacity(Window window, float alpha) { try { Class awtutil = Class.forName("com.sun.awt.AWTUtilities"); Method setWindowOpaque = awtutil.getMethod("setWindowOpacity", Window.class, float.class); setWindowOpaque.invoke(null, window, alpha); } catch (Exception ex) { // Void on purpose, means that this JRE doesn't support the com.sun.awt.AWTUtilities class, do // nothing } } /** * Instantiates a new aWT utilities. */ private AWTUtilities() { } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/helpers/animations/FadeAnimation.java0000644000175000017500000000543211720500104027572 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.helpers.animations; import java.awt.Window; import javax.swing.SwingUtilities; import org.jajuk.util.log.Log; /** * Fade animation implementation. */ public class FadeAnimation extends AbstractAnimation { /** DOCUMENT_ME. */ private Direction opacity; /** Number of frames. */ private static final int FRAME_NUMBER = 50; /** * Instantiates a new fade animation. * * @param window DOCUMENT_ME * @param opacity DOCUMENT_ME */ public FadeAnimation(Window window, Direction opacity) { super(window); this.opacity = opacity; } /* * (non-Javadoc) * @see org.jajuk.ui.helpers.animations.IAnimation#animate(int) */ @Override public void animate(final int animationTime) { new Thread(new Runnable() { @Override public void run() { try { window.setVisible(true); for (int i = 1; i < FRAME_NUMBER; i++) { final float progress = i / (float) FRAME_NUMBER; SwingUtilities.invokeLater(new Runnable() { @Override public void run() { AWTUtilities.setWindowOpacity(window, opacity.getOpacity(progress)); window.repaint(); } }); Thread.sleep(animationTime / FRAME_NUMBER); } } catch (Exception ex) { Log.error(ex); } animationCompleted(); } }).start(); } /** * DOCUMENT_ME. */ public interface Direction { /** * Gets the opacity. * * @param progress DOCUMENT_ME * * @return the opacity */ float getOpacity(float progress); } /** * DOCUMENT_ME. */ public enum Directions implements Direction { /** DOCUMENT_ME. */ IN { @Override public float getOpacity(float progress) { return progress; } }, /** DOCUMENT_ME. */ OUT { @Override public float getOpacity(float progress) { return 1 - progress; } }; } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/helpers/animations/IAnimation.java0000644000175000017500000000223411720500104027120 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.helpers.animations; import java.awt.Window; /** * Interface for any kind of animation. */ public interface IAnimation { /** * What the animation is supposed to do. * * @param animationTime DOCUMENT_ME */ void animate(int animationTime); /** * Parent window. * * @return Parent window */ Window getWindow(); } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/helpers/TransferableTreeNodes.java0000644000175000017500000000525411720500104027154 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.helpers; import java.awt.datatransfer.DataFlavor; import java.awt.datatransfer.Transferable; import java.awt.datatransfer.UnsupportedFlavorException; import java.io.IOException; import java.util.Arrays; import java.util.List; import org.jajuk.base.Item; /** * Transferable tree nodes ( for DND ). */ public class TransferableTreeNodes implements Transferable { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** The Constant NODE_FLAVOR. DOCUMENT_ME */ public static final DataFlavor NODE_FLAVOR = new DataFlavor( DataFlavor.javaJVMLocalObjectMimeType, "Node"); /** Transferable model. */ private List items; /** * Instantiates a new transferable tree node. * * @param items DOCUMENT_ME */ public TransferableTreeNodes(List items) { this.items = items; } /** DOCUMENT_ME. */ private final DataFlavor[] flavors = { NODE_FLAVOR }; /* * (non-Javadoc) * * @see java.awt.datatransfer.Transferable#getTransferDataFlavors() */ @Override public DataFlavor[] getTransferDataFlavors() { return flavors; } /* * (non-Javadoc) * * @see java.awt.datatransfer.Transferable#isDataFlavorSupported(java.awt.datatransfer.DataFlavor) */ @Override public boolean isDataFlavorSupported(DataFlavor flavor) { return Arrays.asList(flavors).contains(flavor); } /* * (non-Javadoc) * * @see java.awt.datatransfer.Transferable#getTransferData(java.awt.datatransfer.DataFlavor) */ @Override public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, IOException { if (flavor == NODE_FLAVOR) { return this; } else { throw new UnsupportedFlavorException(flavor); } } /** * Gets the user object. * * @return the tranferable data */ public Object getUserObject() { return items; } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/helpers/Duration.java0000644000175000017500000000443611720500104024521 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.helpers; import org.jajuk.util.UtilString; /** * A duration encapsulates a track or album length in secs, it is mainly used in * tables to ease the cell renderers recognition. */ public class Duration implements Comparable { /** DOCUMENT_ME. */ private final long duration; /** * The Constructor. * * @param duration item duration in secs */ public Duration(long duration) { this.duration = duration; } /** * Return a string representation of this duration with zero paddings. * * @return the string */ @Override public String toString() { return UtilString.formatTimeBySec(duration); } /* (non-Javadoc) * @see java.lang.Object#equals(java.lang.Object) */ @Override public boolean equals(Object obj) { // also exlcudes null obj if (obj instanceof Duration) { return duration == ((Duration) obj).duration; } return false; } /* (non-Javadoc) * @see java.lang.Comparable#compareTo(java.lang.Object) */ @Override public int compareTo(Duration other) { if (other == null) { // not equal if the other element is null return -1; } return (int) (duration - other.getDuration()); } /** * Gets the duration. * * @return the duration */ public long getDuration() { return this.duration; } /* (non-Javadoc) * @see java.lang.Object#hashCode() */ @Override public int hashCode() { return Long.valueOf(duration).hashCode(); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/helpers/TreeRootElement.java0000644000175000017500000000261511720500104026006 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.helpers; import javax.swing.tree.DefaultMutableTreeNode; /** * Flag class telling a tree node is a root element. */ public class TreeRootElement extends DefaultMutableTreeNode { /** Generated serialVersionUID. */ private static final long serialVersionUID = -3183130517695923747L; /** * Instantiates a new tree root element. */ public TreeRootElement() { super(); } /** * The Constructor. * * @param userObject DOCUMENT_ME */ public TreeRootElement(Object userObject) { super(userObject); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/helpers/LazyLoadingTreeNode.java0000644000175000017500000000470511720500104026576 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.helpers; import javax.swing.SwingUtilities; import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.DefaultTreeModel; import javax.swing.tree.MutableTreeNode; /** * Abstract class that is used to load TreeNodes lazily, i.e. in large trees * with many sub-branches this can reduce the number of nodes that are actually * created a lot. */ public abstract class LazyLoadingTreeNode extends DefaultMutableTreeNode { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** * Instantiates a new transferable tree node. * * @param userObject an Object provided by the user that constitutes the node's data */ public LazyLoadingTreeNode(Object userObject) { super(userObject); setAllowsChildren(true); } /** * Check if there are children loaded already. * * @return true if there are some childrens */ public boolean areChildrenLoaded() { return getChildCount() > 0 && getAllowsChildren(); } /** * If the. * * @return false, this node can't be a leaf * * @see #getAllowsChildren() */ @Override public boolean isLeaf() { return !getAllowsChildren(); } /** * This is the point where the actual implementation can create the actual * child nodes of the current node at the point when the node is expanded. * * This method will be executed in a background thread. If you have to do some * GUI stuff use {@link SwingUtilities#invokeLater(Runnable)} * * @param model DOCUMENT_ME * * @return The created nodes. */ public abstract MutableTreeNode[] loadChildren(DefaultTreeModel model); } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/helpers/TableTransferHandler.java0000644000175000017500000000536511720500104026770 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.helpers; import java.awt.datatransfer.Transferable; import java.awt.dnd.DnDConstants; import java.awt.dnd.DragGestureEvent; import java.awt.dnd.DragGestureListener; import java.awt.dnd.DragSource; import javax.swing.JComponent; import javax.swing.TransferHandler; import org.jajuk.ui.widgets.JajukTable; /** * DND handler for table. */ public class TableTransferHandler extends TransferHandler { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** DOCUMENT_ME. */ final JajukTable jtable; /** * Constructor. * * @param jtable DOCUMENT_ME */ public TableTransferHandler(final JajukTable jtable) { this.jtable = jtable; DragSource source = DragSource.getDefaultDragSource(); // Override the drag gesture recognizer as it doesn't work well when dragging from a jtable : // 1 select row 1 // 2 start dragging row 2 : the drag gesture is not recognized because the row 2 is not yet selected source.createDefaultDragGestureRecognizer(jtable, DnDConstants.ACTION_COPY, new DragGestureListener() { @Override public void dragGestureRecognized(DragGestureEvent dge) { Transferable transferable = createTransferable(jtable); //and this is the magic right here dge.startDrag(null, transferable); } }); } /** * Called when dragging. * * @param c DOCUMENT_ME * * @return the transferable */ @Override protected Transferable createTransferable(JComponent c) { // Force selection to update before beginning actual drag, otherwise, drag is done // against previously selected row. jtable.updateSelection(); return new TransferableTableRows(jtable.getSelection()); } /** * return action type. * * @param c DOCUMENT_ME * * @return the source actions */ @Override public int getSourceActions(JComponent c) { return COPY_OR_MOVE; } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/helpers/AlbumsTableModel.java0000644000175000017500000002241411720500104026104 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.helpers; import java.util.Date; import java.util.Iterator; import java.util.List; import java.util.Map; import org.jajuk.base.Album; import org.jajuk.base.AlbumManager; import org.jajuk.base.Artist; import org.jajuk.base.Genre; import org.jajuk.base.Item; import org.jajuk.base.PropertyMetaInformation; import org.jajuk.base.Year; import org.jajuk.ui.widgets.IconLabel; import org.jajuk.util.Conf; import org.jajuk.util.Const; import org.jajuk.util.Filter; import org.jajuk.util.Messages; /** * Table model used for albums table view. */ public class AlbumsTableModel extends JajukTableModel { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** * Model constructor. */ public AlbumsTableModel() { super(11); setEditable(Conf.getBoolean(Const.CONF_ALBUMS_TABLE_EDITION)); // Columns names // First column is play icon, need to set a space character // for proper display in some look and feel vColNames.add(" "); idList.add(Const.XML_PLAY); vColNames.add(Messages.getHumanPropertyName(Const.XML_ALBUM)); idList.add(Const.XML_ALBUM); // First track found artist. If different artists in album, will be // displayed in italic vColNames.add(Messages.getHumanPropertyName(Const.XML_ARTIST)); idList.add(Const.XML_ARTIST); // First track found genre. If different genres in album, will be // displayed in italic vColNames.add(Messages.getHumanPropertyName(Const.XML_GENRE)); idList.add(Const.XML_GENRE); // First found track year, italic if different values vColNames.add(Messages.getHumanPropertyName(Const.XML_YEAR)); idList.add(Const.XML_YEAR); // Album rate (average of its tracks rate) vColNames.add(Messages.getHumanPropertyName(Const.XML_TRACK_RATE)); idList.add(Const.XML_TRACK_RATE); // Total album length vColNames.add(Messages.getHumanPropertyName(Const.XML_TRACK_LENGTH)); idList.add(Const.XML_TRACK_LENGTH); // Number of tracks vColNames.add(Messages.getString("AlbumsTableView.1")); idList.add(Const.XML_TRACKS); // First found track discovery date vColNames.add(Messages.getHumanPropertyName(Const.XML_TRACK_DISCOVERY_DATE)); idList.add(Const.XML_TRACK_DISCOVERY_DATE); // Sum of all tracks hits vColNames.add(Messages.getHumanPropertyName(Const.XML_TRACK_HITS)); idList.add(Const.XML_TRACK_HITS); // Disc ID vColNames.add(Messages.getHumanPropertyName(Const.XML_ALBUM_DISC_ID)); idList.add(Const.XML_ALBUM_DISC_ID); // custom properties now for (PropertyMetaInformation meta : AlbumManager.getInstance().getCustomProperties()) { vColNames.add(meta.getName()); idList.add(meta.getName()); } } /** * Fill model with data using an optional filter property and pattern *

* For now, this table will not be editable (except for custom properties) for * complexity reasons. This may be implemented in the future if required *

* * @param sPropertyName DOCUMENT_ME * @param sPattern DOCUMENT_ME * @param columnsToShow DOCUMENT_ME */ @Override @SuppressWarnings("unchecked") public void populateModel(String sPropertyName, String sPattern, List columnsToShow) { List alToShow = AlbumManager.getInstance().getAlbums(); // OK, begin by filtering using any provided pattern Filter filter = new Filter(sPropertyName, sPattern, true, Conf.getBoolean(Const.CONF_REGEXP)); Filter.filterItems(alToShow, filter); // Filter unmounted files if required if (Conf.getBoolean(Const.CONF_OPTIONS_HIDE_UNMOUNTED)) { Iterator it = alToShow.iterator(); while (it.hasNext()) { Album album = it.next(); if (!album.containsReadyFiles()) { it.remove(); } } } // Sort the result int iColNum = iNumberStandardCols + AlbumManager.getInstance().getCustomProperties().size(); iRowNum = alToShow.size(); oValues = new Object[iRowNum][iColNum]; oItems = new Item[iRowNum]; bCellEditable = new boolean[iRowNum][iColNum]; // Allow only custom properties edition bEditable = true; Iterator it = alToShow.iterator(); // For perfs, prepare columns visibility boolean bAlbum = (columnsToShow != null && columnsToShow.contains(Const.XML_ALBUM)); boolean bArtist = (columnsToShow != null && columnsToShow.contains(Const.XML_ARTIST)); boolean bGenre = (columnsToShow != null && columnsToShow.contains(Const.XML_GENRE)); boolean bYear = (columnsToShow != null && columnsToShow.contains(Const.XML_YEAR)); boolean bRate = (columnsToShow != null && columnsToShow.contains(Const.XML_TRACK_RATE)); boolean bLength = (columnsToShow != null && columnsToShow.contains(Const.XML_TRACK_LENGTH)); boolean bTrackNb = (columnsToShow != null && columnsToShow.contains(Const.XML_TRACKS)); boolean bDiscovery = (columnsToShow != null && columnsToShow .contains(Const.XML_TRACK_DISCOVERY_DATE)); boolean bHits = (columnsToShow != null && columnsToShow.contains(Const.XML_TRACK_HITS)); boolean bAlbumDiscID = (columnsToShow != null && columnsToShow .contains(Const.XML_ALBUM_DISC_ID)); for (int iRow = 0; it.hasNext(); iRow++) { Album album = it.next(); setItemAt(iRow, album); Map properties = album.getProperties(); // Id oItems[iRow] = album; // Play IconLabel il = null; if (album.containsReadyFiles()) { il = getIcon(false); } else { il = getIcon(true); } // Note: if you want to add an image, use an ImageIcon class and // change oValues[iRow][0] = il; bCellEditable[iRow][0] = false; // Album name if (bAlbum) { oValues[iRow][1] = album.getName2(); } else { oValues[iRow][1] = ""; } bCellEditable[iRow][1] = false; // Artist if (bArtist) { Artist artist = album.getArtist(); if (artist != null) { oValues[iRow][2] = artist.getName2(); } else { oValues[iRow][2] = ""; } } else { oValues[iRow][2] = ""; } bCellEditable[iRow][2] = false; // Genre if (bGenre) { Genre genre = album.getGenre(); if (genre != null) { oValues[iRow][3] = genre.getName2(); } else { oValues[iRow][3] = ""; } } else { oValues[iRow][3] = ""; } bCellEditable[iRow][3] = false; // Year if (bYear) { Year year = album.getYear(); if (year != null) { oValues[iRow][4] = year.getValue(); } else { oValues[iRow][4] = 0l; } } else { oValues[iRow][4] = ""; } bCellEditable[iRow][4] = false; // Rate if (bRate) { oValues[iRow][5] = StarsHelper.getStarIconLabel(album); } else { oValues[iRow][5] = ""; } bCellEditable[iRow][5] = false; // Length if (bLength) { oValues[iRow][6] = new Duration(album.getDuration()); } else { oValues[iRow][6] = ""; } bCellEditable[iRow][6] = false; // Number of tracks if (bTrackNb) { oValues[iRow][7] = album.getNbOfTracks(); } else { oValues[iRow][7] = ""; } bCellEditable[iRow][7] = false; // Date discovery if (bDiscovery) { oValues[iRow][8] = album.getDiscoveryDate(); } else { oValues[iRow][8] = ""; } bCellEditable[iRow][8] = false; // Hits if (bHits) { oValues[iRow][9] = album.getHits(); } else { oValues[iRow][9] = ""; } bCellEditable[iRow][9] = false; // disc id if (bAlbumDiscID) { oValues[iRow][10] = Long.toHexString(album.getDiscID()); } else { oValues[iRow][10] = ""; } bCellEditable[iRow][10] = false; // Custom properties now Iterator it2 = AlbumManager.getInstance().getCustomProperties().iterator(); for (int i = 0; it2.hasNext(); i++) { PropertyMetaInformation meta = (PropertyMetaInformation) it2.next(); Object o = properties.get(meta.getName()); if (o != null) { oValues[iRow][iNumberStandardCols + i] = o; } else { oValues[iRow][iNumberStandardCols + i] = meta.getDefaultValue(); } // Date values not editable, use properties panel instead to // edit bCellEditable[iRow][iNumberStandardCols + i] = !(meta.getType().equals(Date.class)); } } } }jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/helpers/LazyLoadingTreeExpander.java0000644000175000017500000000712111720500104027452 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.helpers; import javax.swing.event.TreeExpansionEvent; import javax.swing.event.TreeWillExpandListener; import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.DefaultTreeModel; import javax.swing.tree.ExpandVetoException; import javax.swing.tree.MutableTreeNode; import javax.swing.tree.TreePath; /** * This class handles the lazy loading of nodes. It calls the necessary methods * on the current tree node to ask it for it's actual children. * * Note: This implementation is rather simple and targeted for the current use * in Jajuk where the expanding of the node is usually a quick (in-memory) * operation. This implementation is not fully usable for cases where it takes * some time to retrieve the data, e.g. when there are database or other remote * requests involved. */ public class LazyLoadingTreeExpander implements TreeWillExpandListener { /** Tree Model. */ private DefaultTreeModel model; /** * Default constructor. * * @param model Tree model */ public LazyLoadingTreeExpander(DefaultTreeModel model) { this.model = model; } /* (non-Javadoc) * @see javax.swing.event.TreeWillExpandListener#treeWillCollapse(javax.swing.event.TreeExpansionEvent) */ @Override public void treeWillCollapse(TreeExpansionEvent event) throws ExpandVetoException { // Do nothing on collapse. } /** * Invoked whenever a node in the tree is about to be expanded. * * If the Node is a LazyLoadingTreeNode load it's children. * * @param event DOCUMENT_ME * * @throws ExpandVetoException the expand veto exception */ @Override public void treeWillExpand(TreeExpansionEvent event) throws ExpandVetoException { TreePath path = event.getPath(); Object lastPathComponent = path.getLastPathComponent(); if (lastPathComponent instanceof LazyLoadingTreeNode) { LazyLoadingTreeNode lazyNode = (LazyLoadingTreeNode) lastPathComponent; if (!lazyNode.areChildrenLoaded()) { MutableTreeNode[] nodes = lazyNode.loadChildren(model); ((DefaultMutableTreeNode) lazyNode).setAllowsChildren(nodes != null && nodes.length > 0); setChildren(lazyNode, nodes); } } } /** * Define nodes children. * * @param lazyNode DOCUMENT_ME * @param nodes new nodes */ private void setChildren(LazyLoadingTreeNode lazyNode, MutableTreeNode... nodes) { int childCount = lazyNode.getChildCount(); if (childCount > 0) { for (int i = 0; i < childCount; i++) { model.removeNodeFromParent((MutableTreeNode) lazyNode.getChildAt(0)); } } for (int i = 0; nodes != null && i < nodes.length; i++) { model.insertNodeInto(nodes[i], lazyNode, i); } } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/helpers/TwoStepsDisplayable.java0000644000175000017500000000265111720500104026673 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.helpers; /** * A TwoStepsDisplayable wraps a SwingWorker without forcing user to extends * SwingWorker. *

The two methods own jajuk-specific names to be independent from * the swing worker implementation too.

*

This interface also breaks the SwingWorker generics useless in out case *

*/ public interface TwoStepsDisplayable { /** * Long call done in background in a dedicated thread. * * @return a resulting object (can be null) */ Object longCall(); /** * Fast call done in the EDT, must be fast !. * * @param in DOCUMENT_ME */ void shortCall(Object in); } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/helpers/PlayHighlighterPredicate.java0000644000175000017500000000444211720500104027636 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.helpers; import java.awt.Component; import java.util.List; import org.jajuk.base.File; import org.jajuk.base.Item; import org.jajuk.base.Track; import org.jajuk.services.players.QueueModel; import org.jdesktop.swingx.decorator.ComponentAdapter; import org.jdesktop.swingx.decorator.HighlightPredicate; /** * Jajuk playing highlighter used in some tables to change the cell background * if the item at given row is playing. */ public class PlayHighlighterPredicate implements HighlightPredicate { /** DOCUMENT_ME. */ private final JajukTableModel model; /** * Instantiates a new play highlighter predicate. * * @param model DOCUMENT_ME */ public PlayHighlighterPredicate(JajukTableModel model) { this.model = model; } /* (non-Javadoc) * @see org.jdesktop.swingx.decorator.HighlightPredicate#isHighlighted(java.awt.Component, org.jdesktop.swingx.decorator.ComponentAdapter) */ @Override public boolean isHighlighted(Component renderer, ComponentAdapter adapter) { if (QueueModel.isStopped()) { return false; } Item item = model.getItemAt(adapter.row); if (item instanceof File && QueueModel.getPlayingFile() != null) { File file = (File) item; if (file.equals(QueueModel.getPlayingFile())) { return true; } } else if (item instanceof Track) { List files = ((Track) item).getFiles(); if (files.contains(QueueModel.getPlayingFile())) { return true; } } return false; } }jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/helpers/FilesTableModel.java0000644000175000017500000003440611720500104025727 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.helpers; import java.util.Date; import java.util.Iterator; import java.util.List; import java.util.Map; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.Predicate; import org.jajuk.base.File; import org.jajuk.base.FileManager; import org.jajuk.base.Item; import org.jajuk.base.PropertyMetaInformation; import org.jajuk.base.TrackManager; import org.jajuk.base.Type; import org.jajuk.ui.widgets.IconLabel; import org.jajuk.util.Conf; import org.jajuk.util.Const; import org.jajuk.util.Filter; import org.jajuk.util.Messages; /** * Table model used for physical table view. */ public class FilesTableModel extends JajukTableModel { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** Associated view ID. */ private String viewID; /** * Model constructor. * * @param viewID Associated view ID */ public FilesTableModel(String viewID) { super(20); this.viewID = viewID; setEditable(Conf.getBoolean(Const.CONF_FILES_TABLE_EDITION)); // Columns names // First column is play icon, need to set a space character // for proper display in some look and feel vColNames.add(" "); idList.add(Const.XML_PLAY); vColNames.add(Messages.getHumanPropertyName(Const.XML_TRACK)); idList.add(Const.XML_TRACK); vColNames.add(Messages.getHumanPropertyName(Const.XML_ALBUM)); idList.add(Const.XML_ALBUM); vColNames.add(Messages.getHumanPropertyName(Const.XML_ARTIST)); idList.add(Const.XML_ARTIST); vColNames.add(Messages.getHumanPropertyName(Const.XML_ALBUM_ARTIST)); idList.add(Const.XML_ALBUM_ARTIST); vColNames.add(Messages.getHumanPropertyName(Const.XML_GENRE)); idList.add(Const.XML_GENRE); vColNames.add(Messages.getHumanPropertyName(Const.XML_TRACK_RATE)); idList.add(Const.XML_TRACK_RATE); vColNames.add(Messages.getHumanPropertyName(Const.XML_TRACK_LENGTH)); idList.add(Const.XML_TRACK_LENGTH); vColNames.add(Messages.getHumanPropertyName(Const.XML_DEVICE)); idList.add(Const.XML_DEVICE); vColNames.add(Messages.getString("Property_filename")); idList.add(Const.XML_NAME); vColNames.add(Messages.getHumanPropertyName(Const.XML_TRACK_COMMENT)); idList.add(Const.XML_TRACK_COMMENT); vColNames.add(Messages.getHumanPropertyName(Const.XML_QUALITY)); idList.add(Const.XML_QUALITY); vColNames.add(Messages.getHumanPropertyName(Const.XML_SIZE)); idList.add(Const.XML_SIZE); vColNames.add(Messages.getHumanPropertyName(Const.XML_TRACK_ORDER)); idList.add(Const.XML_TRACK_ORDER); vColNames.add(Messages.getHumanPropertyName(Const.XML_TRACK_DISC_NUMBER)); idList.add(Const.XML_TRACK_DISC_NUMBER); vColNames.add(Messages.getHumanPropertyName(Const.XML_YEAR)); idList.add(Const.XML_YEAR); vColNames.add(Messages.getHumanPropertyName(Const.XML_DIRECTORY)); idList.add(Const.XML_DIRECTORY); vColNames.add(Messages.getHumanPropertyName(Const.XML_FILE_DATE)); idList.add(Const.XML_FILE_DATE); vColNames.add(Messages.getHumanPropertyName(Const.XML_TRACK_HITS)); idList.add(Const.XML_TRACK_HITS); vColNames.add(Messages.getHumanPropertyName(Const.XML_TRACK_DISCOVERY_DATE)); idList.add(Const.XML_TRACK_DISCOVERY_DATE); // -- Custom properties now-- // for files Iterator it = FileManager.getInstance().getCustomProperties() .iterator(); while (it.hasNext()) { PropertyMetaInformation meta = it.next(); vColNames.add(meta.getName()); idList.add(meta.getName()); } // for tracks it = TrackManager.getInstance().getCustomProperties().iterator(); while (it.hasNext()) { PropertyMetaInformation meta = it.next(); vColNames.add(meta.getName()); idList.add(meta.getName()); } } /* * (non-Javadoc) * * @see org.jajuk.ui.helpers.JajukTableModel#populateModel(java.lang.String, java.lang.String, * java.util.List) */ @Override public void populateModel(String sPropertyName, String sPattern, List columnsToShow) { // This should be monitor file manager to avoid NPE when changing items List alToShow = FileManager.getInstance().getFiles(); // Filter mounted files if needed and apply sync table with tree // option if needed final boolean syncTreeTable = Conf.getBoolean(Const.CONF_SYNC_TABLE_TREE + "." + viewID); oItems = new Item[iRowNum]; CollectionUtils.filter(alToShow, new Predicate() { @Override public boolean evaluate(Object o) { File file = (File) o; // show it if no sync option or if item is in the selection boolean bShowWithTree = !syncTreeTable // tree selection = null means none selection have been // done in tree so far || treeSelection == null // check if the tree selection contains the current file || (treeSelection.size() > 0 && treeSelection.contains(file)); return (!file.shouldBeHidden() && bShowWithTree); } }); // Filter files Filter filter = new Filter(sPropertyName, sPattern, true, Conf.getBoolean(Const.CONF_REGEXP)); Filter.filterItems(alToShow, filter); Iterator it = alToShow.iterator(); int iColNum = iNumberStandardCols + FileManager.getInstance().getCustomProperties().size() + TrackManager.getInstance().getCustomProperties().size(); iRowNum = alToShow.size(); it = alToShow.iterator(); oValues = new Object[iRowNum][iColNum]; oItems = new Item[iRowNum]; bCellEditable = new boolean[iRowNum][iColNum]; // For perfs, prepare columns visibility boolean bTrackName = (columnsToShow != null && columnsToShow.contains(Const.XML_TRACK)); boolean bAlbum = (columnsToShow != null && columnsToShow.contains(Const.XML_ALBUM)); boolean bArtist = (columnsToShow != null && columnsToShow.contains(Const.XML_ARTIST)); boolean bAlbumArtist = (columnsToShow != null && columnsToShow.contains(Const.XML_ALBUM_ARTIST)); boolean bGenre = (columnsToShow != null && columnsToShow.contains(Const.XML_GENRE)); boolean bRate = (columnsToShow != null && columnsToShow.contains(Const.XML_TRACK_RATE)); boolean bLength = (columnsToShow != null && columnsToShow.contains(Const.XML_TRACK_LENGTH)); boolean bDevice = (columnsToShow != null && columnsToShow.contains(Const.XML_DEVICE)); boolean bFileName = (columnsToShow != null && columnsToShow.contains(Const.XML_NAME)); boolean bComment = (columnsToShow != null && columnsToShow.contains(Const.XML_TRACK_COMMENT)); boolean bQuality = (columnsToShow != null && columnsToShow.contains(Const.XML_QUALITY)); boolean bSize = (columnsToShow != null && columnsToShow.contains(Const.XML_SIZE)); boolean bDiscovery = (columnsToShow != null && columnsToShow .contains(Const.XML_TRACK_DISCOVERY_DATE)); boolean bOrder = (columnsToShow != null && columnsToShow.contains(Const.XML_TRACK_ORDER)); boolean bDiscNumber = (columnsToShow != null && columnsToShow .contains(Const.XML_TRACK_DISC_NUMBER)); boolean bYear = (columnsToShow != null && columnsToShow.contains(Const.XML_YEAR)); boolean bDirectory = (columnsToShow != null && columnsToShow.contains(Const.XML_DIRECTORY)); boolean bFileDate = (columnsToShow != null && columnsToShow.contains(Const.XML_FILE_DATE)); boolean bHits = (columnsToShow != null && columnsToShow.contains(Const.XML_TRACK_HITS)); for (int iRow = 0; it.hasNext(); iRow++) { File file = it.next(); setItemAt(iRow, file); Map properties = file.getProperties(); // Id oItems[iRow] = file; // Play IconLabel il = null; if (file.isReady()) { il = getIcon(false); } else { il = getIcon(true); } oValues[iRow][0] = il; bCellEditable[iRow][0] = false; // check track has an associated tag editor (not null) boolean bHasATagEditor = false; Type type = file.getType(); if (type != null) { bHasATagEditor = (type.getTaggerClass() != null); } // Track name if (bTrackName) { oValues[iRow][1] = file.getTrack().getName(); } else { oValues[iRow][1] = ""; } bCellEditable[iRow][1] = bHasATagEditor; // Album if (bAlbum) { oValues[iRow][2] = file.getTrack().getAlbum().getName2(); } else { oValues[iRow][2] = ""; } bCellEditable[iRow][2] = bHasATagEditor; // Artist if (bArtist) { oValues[iRow][3] = file.getTrack().getArtist().getName2(); } else { oValues[iRow][3] = ""; } bCellEditable[iRow][3] = bHasATagEditor; // AlbumArtist if (bAlbumArtist) { oValues[iRow][4] = file.getTrack().getAlbumArtist().getName2(); } else { oValues[iRow][4] = ""; } bCellEditable[iRow][4] = bHasATagEditor; // Genre if (bGenre) { oValues[iRow][5] = file.getTrack().getGenre().getName2(); } else { oValues[iRow][5] = ""; } bCellEditable[iRow][5] = bHasATagEditor; // Rate if (bRate) { oValues[iRow][6] = StarsHelper.getStarIconLabel(file.getTrack()); } else { oValues[iRow][6] = ""; } bCellEditable[iRow][6] = false; // Length if (bLength) { oValues[iRow][7] = new Duration(file.getTrack().getDuration()); } else { oValues[iRow][7] = ""; } bCellEditable[iRow][7] = false; // Device if (bDevice) { oValues[iRow][8] = file.getDirectory().getDevice().getName(); } else { oValues[iRow][8] = ""; } bCellEditable[iRow][8] = false; // File name if (bFileName) { oValues[iRow][9] = file.getName(); } else { oValues[iRow][9] = ""; } bCellEditable[iRow][9] = true; // Comment if (bComment) { oValues[iRow][10] = file.getTrack().getValue(Const.XML_TRACK_COMMENT); } else { oValues[iRow][10] = ""; } bCellEditable[iRow][10] = bHasATagEditor; // Quality if (bQuality) { long lQuality = file.getQuality(); oValues[iRow][11] = lQuality; } else { oValues[iRow][11] = 0l; } bCellEditable[iRow][11] = false; // Size, we want to keep 2 decimals to the value in MB if (bSize) { oValues[iRow][12] = Math.round(file.getSize() / 10485.76) / 100f; } else { oValues[iRow][12] = 0l; } bCellEditable[iRow][12] = false; // Order if (bOrder) { oValues[iRow][13] = file.getTrack().getOrder(); } else { oValues[iRow][13] = ""; } bCellEditable[iRow][13] = bHasATagEditor; // Disc number if (bDiscNumber) { oValues[iRow][14] = file.getTrack().getDiscNumber(); } else { oValues[iRow][14] = ""; } bCellEditable[iRow][14] = bHasATagEditor; // year if (bYear) { oValues[iRow][15] = file.getTrack().getYear().getValue(); } else { oValues[iRow][15] = ""; } bCellEditable[iRow][15] = bHasATagEditor; // directory full path if (bDirectory) { oValues[iRow][16] = file.getDirectory().getAbsolutePath(); } else { oValues[iRow][16] = ""; } bCellEditable[iRow][16] = false; // file date if (bFileDate) { oValues[iRow][17] = file.getDateValue(Const.XML_FILE_DATE); } else { oValues[iRow][17] = ""; } bCellEditable[iRow][17] = false; // Hits if (bHits) { oValues[iRow][18] = file.getTrack().getHits(); } else { oValues[iRow][18] = ""; } bCellEditable[iRow][18] = false; // Discovery date if (bDiscovery) { oValues[iRow][19] = file.getTrack().getDiscoveryDate(); } else { oValues[iRow][19] = ""; } bCellEditable[iRow][19] = false; // -- Custom properties now -- // files custom tags Iterator it2 = FileManager.getInstance().getCustomProperties() .iterator(); for (int i = 0; it2.hasNext(); i++) { PropertyMetaInformation meta = it2.next(); Object o = properties.get(meta.getName()); if (o != null) { oValues[iRow][iNumberStandardCols + i] = o; } else { oValues[iRow][iNumberStandardCols + i] = meta.getDefaultValue(); } // Date values not editable, use properties panel instead to // edit if (meta.getType().equals(Date.class)) { bCellEditable[iRow][iNumberStandardCols + i] = false; } else { bCellEditable[iRow][iNumberStandardCols + i] = true; } } // tracks custom properties it2 = TrackManager.getInstance().getCustomProperties().iterator(); for (int i = FileManager.getInstance().getCustomProperties().size(); it2.hasNext(); i++) { PropertyMetaInformation meta = it2.next(); properties = file.getTrack().getProperties(); Object o = properties.get(meta.getName()); if (o != null) { oValues[iRow][iNumberStandardCols + i] = properties.get(meta.getName()); } else { oValues[iRow][iNumberStandardCols + i] = meta.getDefaultValue(); } // Date values not editable, use properties panel instead to // edit if (meta.getType().equals(Date.class)) { bCellEditable[iRow][iNumberStandardCols + i] = false; } else { bCellEditable[iRow][iNumberStandardCols + i] = true; } } } } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/helpers/JajukTableModel.java0000644000175000017500000002013111720500104025717 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.helpers; import java.util.ArrayList; import java.util.List; import java.util.Set; import javax.swing.ImageIcon; import javax.swing.table.DefaultTableModel; import org.jajuk.base.Item; import org.jajuk.ui.widgets.IconLabel; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; /** * Jajuk table model, adds identifier to model. */ public abstract class JajukTableModel extends DefaultTableModel { /** Generated serialVersionUID. */ private static final long serialVersionUID = -7296786603161189590L; /** Column identifiers. */ volatile protected List idList = new ArrayList(10); /** Rows number. */ protected int iRowNum; /** Values table*. */ protected Object[][] oValues; // Play icon in cache /** The Constant PLAY_ICON. DOCUMENT_ME */ protected static final ImageIcon PLAY_ICON = IconLoader.getIcon(JajukIcons.PLAY_TABLE); // Unmount Play icon in cache /** The Constant UNMOUNT_PLAY_ICON. DOCUMENT_ME */ protected static final ImageIcon UNMOUNT_PLAY_ICON = IconLoader.getIcon(JajukIcons.UNKNOWN); /** Objects. */ protected Item[] oItems; /** Number of standard columns. */ protected int iNumberStandardCols; /** Cell editable flag. */ protected boolean[][] bCellEditable; /** Column names. */ protected List vColNames = new ArrayList(10); /** Last value used for undo. */ private Object oLast = null; /** Editable flag. */ boolean bEditable = false; /** Tree selection. */ protected Set treeSelection; /** DOCUMENT_ME. */ protected IconLabel play_icon = null; /** DOCUMENT_ME. */ protected IconLabel unmount_play_icon = null; /** Whether the model is refreshing so we must ignore selection changes events. */ private boolean refreshing = false; /** * Checks if is refreshing. * * @return the refreshing */ public boolean isRefreshing() { return this.refreshing; } /** * Sets the refreshing. * * @param refreshing the refreshing to set */ public void setRefreshing(boolean refreshing) { this.refreshing = refreshing; } /** * The Constructor. * * @param iNumberStandardCols Number of columns of this model (without custom properties) */ public JajukTableModel(int iNumberStandardCols) { super(); this.iNumberStandardCols = iNumberStandardCols; } /** * Default constructor. */ public JajukTableModel() { super(); this.iNumberStandardCols = 0; } /** * Gets the identifier. * * @param sColName DOCUMENT_ME * * @return Column identifier for a given column title */ public String getIdentifier(String sColName) { return idList.get(vColNames.indexOf(sColName)); } /** * Return item at given position. * * @param iRow DOCUMENT_ME * * @return the item at */ public Item getItemAt(int iRow) { return oItems[iRow]; } /** * Set item at given position. * * @param iRow DOCUMENT_ME * @param item DOCUMENT_ME */ public void setItemAt(int iRow, Item item) { oItems[iRow] = item; } /* * (non-Javadoc) * * @see javax.swing.table.DefaultTableModel#getValueAt(int, int) */ @Override public Object getValueAt(int rowIndex, int columnIndex) { // We need to test this as UI may request it before table is populated if (oValues == null || oValues.length == 0 || rowIndex >= oValues.length) { return null; } return oValues[rowIndex][columnIndex]; } /* * (non-Javadoc) * * @see javax.swing.table.DefaultTableModel#setValueAt(java.lang.Object, int, int) */ @Override public void setValueAt(Object oValue, int rowIndex, int columnIndex) { oLast = oValues[rowIndex][columnIndex]; oValues[rowIndex][columnIndex] = oValue; fireTableCellUpdated(rowIndex, columnIndex); } /* * (non-Javadoc) * * @see javax.swing.table.TableModel#getColumnCount() */ @Override public int getColumnCount() { return vColNames.size(); } /** * Undo last change. * * @param rowIndex DOCUMENT_ME * @param columnIndex DOCUMENT_ME */ public void undo(int rowIndex, int columnIndex) { if (oLast != null) { oValues[rowIndex][columnIndex] = oLast; } } /* * (non-Javadoc) * * @see javax.swing.table.DefaultTableModel#getColumnName(int) */ @Override public String getColumnName(int column) { return vColNames.get(column); } /** * Gets the identifier. * * @param column DOCUMENT_ME * * @return the identifier */ public String getIdentifier(int column) { return idList.get(column); } /* * (non-Javadoc) * * @see javax.swing.table.DefaultTableModel#getRowCount() */ @Override public int getRowCount() { // iRowNum is set in concrete classes return iRowNum; } /* * (non-Javadoc) * * @see javax.swing.table.DefaultTableModel#isCellEditable(int, int) */ @Override public boolean isCellEditable(int rowIndex, int columnIndex) { return bEditable && bCellEditable[rowIndex][columnIndex]; } /* * (non-Javadoc) * * @see javax.swing.table.AbstractTableModel#getColumnClass(int) */ @Override public Class getColumnClass(int columnIndex) { Object o = getValueAt(0, columnIndex); if (o != null) { return o.getClass(); } else { return Object.class; } } /** * Fill model with data using an optional filter property and pattern. * * @param sProperty Property (column) to filter * @param sPattern pattern * @param columnsToShow List of elements to show in the table (like files,hits...). This * is useful for models for memory performances as model doesn't fill * values for hidden columns */ public abstract void populateModel(String sProperty, String sPattern, List columnsToShow); /** * Fill model with data. * * @param columnsToShow DOCUMENT_ME */ public synchronized void populateModel(List columnsToShow) { populateModel(null, null, columnsToShow); } /** * Set this model editable state. * * @param b whether model is editable or not */ public void setEditable(boolean b) { this.bEditable = b; } /** * Gets the tree selection. * * @return the tree selection */ public Set getTreeSelection() { return this.treeSelection; } /** * Sets the tree selection. * * @param treeSelection the new tree selection */ public void setTreeSelection(Set treeSelection) { this.treeSelection = treeSelection; } /** * Clear the model. */ public void clear() { oValues = new Object[0][0]; iRowNum = 0; fireTableDataChanged(); } /** * Gets the icon. * * @param unmount DOCUMENT_ME * * @return the icon */ protected IconLabel getIcon(boolean unmount) { if (!unmount) { if (play_icon == null) { play_icon = new IconLabel(PLAY_ICON, "", null, null, null, Messages .getString("TracksTableView.7")); } return play_icon; } else { if (unmount_play_icon == null) { unmount_play_icon = new IconLabel(UNMOUNT_PLAY_ICON, "", null, null, null, Messages .getString("TracksTableView.7") + Messages.getString("AbstractTableView.10")); } return unmount_play_icon; } } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/helpers/JajukMouseAdapter.java0000644000175000017500000001076011720500104026307 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.helpers; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; /** * Specific implementation of a mouse adapter that handle properly the various * OS behaviors dealing with right/left click, isPopup ... *

*

  • We don't use mouseClicked() method as the event can be thrown or not * among different OS, specifications are not clear. It can be thrown in * addition with mousePressed and mouseReleased events, so we just don't use it * but mousePressed() and mouseReleased() methods instead.
  • *
  • Popup request detection cannot be simply handled by a right click * (Windows, Linux) as it can be thrown by others interactions like CTRL + click * under OS X with a classic one touch mouse, so we use the isPopupTrigger() * method to recognize such event.
  • *
  • We have to check mousePressed and mouseReleased() methods as the popup * request is recognized on the pressed event under most OS and on the release * event under Mac OS.
  • *

    */ public class JajukMouseAdapter extends MouseAdapter { /** Whether a popup request gesture has been recognized. */ private boolean popupTrigger = false; /* (non-Javadoc) * @see java.awt.event.MouseAdapter#mousePressed(java.awt.event.MouseEvent) */ @Override public void mousePressed(final MouseEvent e) { // Note that this method is not final as we sometimes need additional tests // or actions but overriding it is discouraged // reset the popup gesture state popupTrigger = false; // popupTrigger can be false here even if the user performed a right click // because the event returns true only when the button is released if (e.isPopupTrigger()) { popupTrigger = true; } } /* (non-Javadoc) * @see java.awt.event.MouseAdapter#mouseReleased(java.awt.event.MouseEvent) */ @Override public void mouseReleased(final MouseEvent e) { // Note that this method is not final as we sometimes need additional tests // or actions but overriding it is discouraged // Actual popup request is an 'or' between state during mousePressed and // mouseReleased methods to deal with every JRE implementation popupTrigger = popupTrigger || e.isPopupTrigger(); if (popupTrigger) { handlePopup(e); } else { handleAction(e); if (e.getClickCount() == 1) { handleActionSingleClick(e); } else if (e.getClickCount() > 1) { handleActionSeveralClicks(e); } } } /** * What do do when a popup has been required ?. * * @param e the mouse event */ public void handlePopup(final MouseEvent e) { // Not abstract as we don't want to force user to override every methods } /** * What do do when an action (left click under Windows/Linux) has been * required with a single click ?. * * @param e the mouse event */ public void handleActionSingleClick(final MouseEvent e) { // Not abstract as we don't want to force user to override every methods } /** * What do do when an action (left click under Windows/Linux) has been * required with several clicks ?. * * @param e the mouse event */ public void handleActionSeveralClicks(final MouseEvent e) { // Not abstract as we don't want to force user to override every methods } /** * What do do when an action (left click under Windows/Linux) has been * required with any number of clicks ? *

    * Beware : do not use this method in addition to handleActionSeveralClicks() * or handleActionSingleClick() as both will be executed. *

    * * @param e the mouse event */ public void handleAction(final MouseEvent e) { // Not abstract as we don't want to force user to override every methods } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/windows/0000755000175000017500000000000011720500104022112 5ustar drazzibdrazzibjajuk-1.9.6.orig/src/main/java/org/jajuk/ui/windows/IJajukWindow.java0000644000175000017500000000326311720500104025326 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.windows; /** * Global contract for jajuk frames (main window, fullscreen, tray, slimbar...) * A window has four states : *

    - Instanciated (the constructor contains general initialization or * nothing) *

    - Build (the initUI() method has been called ) *

    - Shown (the display(true) method has been called *

    - Hidden (the display(true) has not yet been called or the display(false) * has been called) *

    * These states are listed in the WindowState enum * * These states are managed by the WindowStateDecorator */ public interface IJajukWindow { /** * Build the GUI (widgets) *

    * Must be called from the EDT, called by the WindowstateDecorator only *

    . */ void initUI(); /** * Return the window state decorator*. * * @return the window state decorator */ public WindowStateDecorator getWindowStateDecorator(); } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/windows/JajukMainWindow.java0000644000175000017500000003677411720500104026037 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.windows; import com.vlsolutions.swing.docking.ui.DockingUISettings; import java.awt.BorderLayout; import java.awt.Frame; import java.awt.GraphicsConfiguration; import java.awt.GraphicsEnvironment; import java.awt.SystemTray; import java.awt.Toolkit; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.util.HashSet; import java.util.Set; import java.util.StringTokenizer; import javax.swing.BoxLayout; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.SwingUtilities; import javax.swing.UIManager; import javax.swing.WindowConstants; import net.miginfocom.swing.MigLayout; import org.jajuk.events.JajukEvent; import org.jajuk.events.JajukEvents; import org.jajuk.events.ObservationManager; import org.jajuk.events.Observer; import org.jajuk.services.players.QueueModel; import org.jajuk.services.webradio.WebRadio; import org.jajuk.ui.actions.ActionManager; import org.jajuk.ui.actions.JajukActions; import org.jajuk.ui.perspectives.PerspectiveManager; import org.jajuk.ui.widgets.CommandJPanel; import org.jajuk.ui.widgets.InformationJPanel; import org.jajuk.ui.widgets.JajukJMenuBar; import org.jajuk.ui.widgets.PerspectiveBarJPanel; import org.jajuk.ui.widgets.SearchJPanel; import org.jajuk.util.Conf; import org.jajuk.util.Const; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; import org.jajuk.util.UtilFeatures; import org.jajuk.util.UtilGUI; import org.jajuk.util.UtilSystem; import org.jajuk.util.error.JajukException; import org.jajuk.util.log.Log; import org.jdesktop.swingx.JXPanel; /** * Jajuk main window *

    * Singleton. */ public class JajukMainWindow extends JFrame implements IJajukWindow, Observer { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** Self instance. */ private static JajukMainWindow jw; /** Left side perspective selection panel. */ private PerspectiveBarJPanel perspectiveBar; /** Main frame panel. */ private JPanel jpFrame; /** specific perspective panel. */ private JPanel perspectivePanel; /** State decorator. */ private WindowStateDecorator decorator; /** * Get the window instance and create the specific WindowStateHandler. * * @return the instance */ public static JajukMainWindow getInstance() { if (jw == null) { jw = new JajukMainWindow(); // Install global keystrokes WindowGlobalKeystrokeManager.getInstance(); jw.decorator = new WindowStateDecorator(jw) { @Override public void specificBeforeShown() { jw.applyStoredSize(); if (UtilSystem.isUnderLinux()) { // hide and show again is a workaround for a toFront() issue // under Metacity, see // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6472274 jw.setVisible(false); } } @Override public void specificAfterShown() { // Apply size and location again // (required by Gnome for ie to fix the 0-sized maximized // frame) jw.applyStoredSize(); jw.toFront(); jw.setState(Frame.NORMAL); // Need focus for keystrokes jw.requestFocus(); // Make sure to display right title if a track or a webradio is launched at startup // Indeed, the window can appear after the track/webradio has been launched and miss this event UtilFeatures.updateStatus(jw); } @Override public void specificBeforeHidden() { // hide the window only if it is explicitely required jw.saveSize(); } @Override public void specificAfterHidden() { // Nothing particular } }; } return jw; } /** * Constructor. */ private JajukMainWindow() { } /* * (non-Javadoc) * * @see org.jajuk.ui.widgets.JajukWindow#getWindowStateDecorator() */ @Override public WindowStateDecorator getWindowStateDecorator() { return decorator; } /* * (non-Javadoc) * * @see org.jajuk.ui.windows.IJajukWindow#initUI() */ @Override public void initUI() { if (UtilSystem.isUnderOSX()) { // mac integration System.setProperty("apple.laf.useScreenMenuBar", "true"); System.setProperty("apple.laf.useScreenMenuBar", "true"); System.setProperty("apple.awt.showGrowBox", "false"); } setTitle(Messages.getString("JajukWindow.17")); setIconImage(IconLoader.getIcon(JajukIcons.LOGO).getImage()); setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE); // register for given events ObservationManager.register(this); addWindowListener(new WindowAdapter() { @Override public void windowClosing(WindowEvent we) { // Save windows position saveSize(); try { ActionManager.getAction(JajukActions.EXIT).perform(null); } catch (Exception e1) { Log.error(e1); } } @Override public void windowIconified(WindowEvent we) { // If user set the minimize to tray option and if the tray is supported, we // minimize to tray only if (Conf.getBoolean(Const.CONF_MINIMIZE_TO_TRAY) && SystemTray.isSupported()) { getWindowStateDecorator().display(false); } } @Override public void windowDeiconified(WindowEvent we) { getWindowStateDecorator().display(true); } }); // Light drag and drop for VLDocking UIManager.put("DragControler.paintBackgroundUnderDragRect", Boolean.FALSE); DockingUISettings.getInstance().installUI(); // Creates the panel jpFrame = (JPanel) getContentPane(); jpFrame.setOpaque(true); jpFrame.setLayout(new BorderLayout()); // create the command bar CommandJPanel command = CommandJPanel.getInstance(); command.initUI(); // Create the search bar SearchJPanel searchPanel = SearchJPanel.getInstance(); searchPanel.initUI(); // Add the search bar jpFrame.add(searchPanel, BorderLayout.NORTH); // Create and add the information bar panel InformationJPanel information = InformationJPanel.getInstance(); // Add the information panel jpFrame.add(information, BorderLayout.SOUTH); // Create the perspective manager try { PerspectiveManager.load(); } catch (JajukException e) { // problem loading the perspective, let Main to handle this Log.debug("Cannot create main window"); throw new RuntimeException(e); } perspectivePanel = new JXPanel(); // Make this panel extensible perspectivePanel.setLayout(new BoxLayout(perspectivePanel, BoxLayout.X_AXIS)); // Set menu bar to the frame JajukMainWindow.getInstance().setJMenuBar(JajukJMenuBar.getInstance()); // Create the perspective tool bar panel perspectiveBar = PerspectiveBarJPanel.getInstance(); jpFrame.add(perspectiveBar, BorderLayout.WEST); // Initialize and add the desktop PerspectiveManager.init(); // Add main container (contains toolbars + desktop) JPanel commandDesktop = new JPanel(new MigLayout("insets 0,gapy 0", "[grow]", "[grow][]")); commandDesktop.add(perspectivePanel, "grow,wrap"); commandDesktop.add(command, "grow"); jpFrame.add(commandDesktop, BorderLayout.CENTER); } /* * (non-Javadoc) * * @see org.jajuk.events.Observer#getRegistrationKeys() */ @Override public Set getRegistrationKeys() { Set eventSubjectSet = new HashSet(); eventSubjectSet.add(JajukEvents.FILE_LAUNCHED); eventSubjectSet.add(JajukEvents.WEBRADIO_LAUNCHED); eventSubjectSet.add(JajukEvents.ZERO); eventSubjectSet.add(JajukEvents.PLAYER_STOP); return eventSubjectSet; } /** * Save current window size and position. */ public void saveSize() { boolean maxmimized = false; if (Toolkit.getDefaultToolkit().isFrameStateSupported(Frame.MAXIMIZED_BOTH) && (getExtendedState() & Frame.MAXIMIZED_BOTH) == Frame.MAXIMIZED_BOTH) { Log.debug("Frame maximized"); maxmimized = true; } Conf.setProperty(Const.CONF_WINDOW_MAXIMIZED, Boolean.toString(maxmimized)); String sValue = (int) getLocationOnScreen().getX() + "," + (int) getLocationOnScreen().getY() + "," + getBounds().width + "," + getBounds().height; Log.debug("Frame moved or resized, new bounds=" + sValue); // Store the new position Conf.setProperty(Const.CONF_WINDOW_POSITION, sValue); } /** * Apply size and position stored as property. */ public void applyStoredSize() { // Note that defaults sizes (for very first startup) are set in // Conf.setDefaultProperties() method ,see // CONF_WINDOW_POSITION int iScreenWidth = (int) (Toolkit.getDefaultToolkit().getScreenSize().getWidth()); int iScreenHeight = (int) (Toolkit.getDefaultToolkit().getScreenSize().getHeight()); int iX = 0; int iY = 0; int iHorizSize = 0; int iVertSize = 0; // Forced frame position ? String sForcedValue = Conf.getString(Const.CONF_FRAME_POS_FORCED); if (sForcedValue != null && !sForcedValue.trim().equals("")) { try { StringTokenizer st = new StringTokenizer(sForcedValue, ","); iX = Integer.parseInt(st.nextToken()); iY = Integer.parseInt(st.nextToken()); iHorizSize = Integer.parseInt(st.nextToken()); iVertSize = Integer.parseInt(st.nextToken()); setBounds(iX, iY, iHorizSize, iVertSize); } catch (Exception e) { // Wrong forced value Log.error(e); setBounds(Const.FRAME_INITIAL_BORDER, Const.FRAME_INITIAL_BORDER, iScreenWidth - 2 * Const.FRAME_INITIAL_BORDER, iScreenHeight - 2 * Const.FRAME_INITIAL_BORDER); } return; } // Detect strange or buggy Window Manager like XGL using this test // and apply default size for them if (!Toolkit.getDefaultToolkit().isFrameStateSupported(Frame.MAXIMIZED_BOTH)) { setBounds(Const.FRAME_INITIAL_BORDER, Const.FRAME_INITIAL_BORDER, iScreenWidth - 2 * Const.FRAME_INITIAL_BORDER, iScreenHeight - 2 * Const.FRAME_INITIAL_BORDER); return; } // first get the stored position to get the correct display String sPosition = Conf.getString(Const.CONF_WINDOW_POSITION); // workaround: needed for old configuration files to avoid an exception in // the // StringTokenizer, since Jajuk 1.9 Jajuk stores in an extra property if it // is maximized if (sPosition.equals(Const.FRAME_MAXIMIZED)) { // Always set a size that is used when un-maximazing the frame setBounds(Const.FRAME_INITIAL_BORDER, Const.FRAME_INITIAL_BORDER, iScreenWidth - 2 * Const.FRAME_INITIAL_BORDER, iScreenHeight - 2 * Const.FRAME_INITIAL_BORDER); if (Toolkit.getDefaultToolkit().isFrameStateSupported(Frame.MAXIMIZED_BOTH)) { setExtendedState(Frame.MAXIMIZED_BOTH); } return; } // workaround: end // could be removed in future releases, also Const.FRAME_MAXIMIZED StringTokenizer st = new StringTokenizer(sPosition, ","); iX = Integer.parseInt(st.nextToken()); iY = Integer.parseInt(st.nextToken()); iHorizSize = Integer.parseInt(st.nextToken()); iVertSize = Integer.parseInt(st.nextToken()); // second set the stored position/size setLocation(iX, iY); setSize(iHorizSize, iVertSize); // get the display conf where the main frame is displayed, if the position // is outside, the default screen is returned GraphicsConfiguration gConf = UtilGUI.getGraphicsDeviceOfMainFrame().getDefaultConfiguration(); int iScreenXzero = (int) gConf.getBounds().getX(); int iScreenYzero = (int) gConf.getBounds().getY(); iScreenWidth = (int) gConf.getBounds().getWidth(); iScreenHeight = (int) gConf.getBounds().getHeight(); // check if position/size is correct // if X position is higher than screen width, set default if (iX < iScreenXzero || iX > iScreenXzero + iScreenWidth) { iX = Const.FRAME_INITIAL_BORDER; } // if Y position is higher than screen height, set default if (iY < iScreenYzero || iY > iScreenYzero + iScreenHeight) { iY = Const.FRAME_INITIAL_BORDER; } // if zero horiz size or // if height > to screen height (switching from a dual to a single head // for ie), // set max size available (minus some space to deal with task bars) if (iHorizSize <= 0 || iHorizSize > iScreenWidth) { iHorizSize = iScreenWidth - 2 * Const.FRAME_INITIAL_BORDER; } // Same for width if (iVertSize <= 0 || iVertSize > iScreenHeight) { iVertSize = iScreenHeight - 2 * Const.FRAME_INITIAL_BORDER; } setLocation(iX, iY); setSize(iHorizSize, iVertSize); // was the frame maximized if (Conf.getBoolean(Const.CONF_WINDOW_MAXIMIZED)) { if (Toolkit.getDefaultToolkit().isFrameStateSupported(Frame.MAXIMIZED_BOTH)) { // are we on the primary display if (gConf.getBounds().equals( GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice() .getDefaultConfiguration().getBounds())) { // default size, if frame is unmaximized setSize(iScreenWidth - 2 * Const.FRAME_INITIAL_BORDER, iScreenHeight - 2 * Const.FRAME_INITIAL_BORDER); if (Toolkit.getDefaultToolkit().isFrameStateSupported(Frame.MAXIMIZED_BOTH)) setExtendedState(Frame.MAXIMIZED_BOTH); } else { // setExtendedState not be used on the other displays, because Java // takes always the solution of the primary display... setBounds(gConf.getBounds()); } } } } /* * (non-Javadoc) * * @see org.jajuk.ui.Observer#update(java.lang.String) */ @Override public final void update(JajukEvent event) { final JajukEvents subject = event.getSubject(); SwingUtilities.invokeLater(new Runnable() { @Override public void run() { if (subject.equals(JajukEvents.FILE_LAUNCHED)) { String title = QueueModel.getPlayingFileTitle(); if (title != null) { setTitle(title); } } else if (subject.equals(JajukEvents.ZERO) || subject.equals(JajukEvents.PLAYER_STOP)) { setTitle(Messages.getString("JajukWindow.17")); } else if (subject.equals(JajukEvents.WEBRADIO_LAUNCHED)) { WebRadio radio = QueueModel.getCurrentRadio(); if (radio != null) { // We use vertical bar to allow scripting like MSN plugins to // detect jajuk frames and extract current track setTitle("\\ " + radio.getName() + " /"); } } } }); } /** * Gets the perspective panel. * * @return the perspective panel */ public JPanel getPerspectivePanel() { return perspectivePanel; } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/windows/package.html0000644000175000017500000000020411720500104024367 0ustar drazzibdrazzib

    Main Jajuk containers (slimbar, systray, full screen, main window) and associated classes

    jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/windows/JajukSlimbar.java0000644000175000017500000005511711720500104025344 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.windows; import static org.jajuk.ui.actions.JajukActions.MUTE_STATE; import static org.jajuk.ui.actions.JajukActions.NEXT_TRACK; import static org.jajuk.ui.actions.JajukActions.PAUSE_RESUME_TRACK; import static org.jajuk.ui.actions.JajukActions.PREVIOUS_TRACK; import static org.jajuk.ui.actions.JajukActions.QUEUE_TO_SLIM; import static org.jajuk.ui.actions.JajukActions.STOP_TRACK; import ext.DropDownButton; import java.awt.Color; import java.awt.Dimension; import java.awt.EventQueue; import java.awt.Point; import java.awt.Toolkit; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseEvent; import java.awt.event.MouseMotionAdapter; import java.awt.event.MouseWheelEvent; import java.awt.event.MouseWheelListener; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.util.HashSet; import java.util.Set; import java.util.StringTokenizer; import javax.swing.Action; import javax.swing.BorderFactory; import javax.swing.Box; import javax.swing.JButton; import javax.swing.JComponent; import javax.swing.JDialog; import javax.swing.JFrame; import javax.swing.JMenuItem; import javax.swing.JPopupMenu; import javax.swing.JRootPane; import javax.swing.JToolBar; import javax.swing.JWindow; import javax.swing.SwingUtilities; import org.jajuk.base.File; import org.jajuk.events.JajukEvent; import org.jajuk.events.JajukEvents; import org.jajuk.events.ObservationManager; import org.jajuk.events.Observer; import org.jajuk.services.players.Player; import org.jajuk.services.players.QueueModel; import org.jajuk.ui.actions.ActionManager; import org.jajuk.ui.actions.JajukActions; import org.jajuk.ui.actions.MuteAction; import org.jajuk.ui.helpers.JajukMouseAdapter; import org.jajuk.ui.helpers.PlayerStateMediator; import org.jajuk.ui.views.QueueView; import org.jajuk.ui.widgets.AmbienceComboBox; import org.jajuk.ui.widgets.JajukButton; import org.jajuk.ui.widgets.JajukInformationDialog; import org.jajuk.ui.widgets.JajukJToolbar; import org.jajuk.ui.widgets.PreferenceToolbar; import org.jajuk.ui.widgets.SearchBox; import org.jajuk.ui.widgets.SizedButton; import org.jajuk.util.Conf; import org.jajuk.util.Const; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; import org.jajuk.util.UtilFeatures; import org.jajuk.util.UtilString; import org.jajuk.util.error.JajukException; import org.jajuk.util.log.Log; /** * Jajuk Slim Interface *

    * Singleton *

    * . */ public final class JajukSlimbar extends JFrame implements IJajukWindow, Observer, MouseWheelListener, ActionListener { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** A queue view to be used by the show queue view slimbar switch button. Don't use it directly, use the getQueueWindow() method instead that lazy-load it. */ private JWindow queueViewWindow; /** DOCUMENT_ME. */ private JButton jbInfo; /** DOCUMENT_ME. */ private SizedButton jbPrevious; /** DOCUMENT_ME. */ private SizedButton jbNext; /** DOCUMENT_ME. */ private SizedButton jbPlayPause; /** DOCUMENT_ME. */ private SizedButton jbStop; /** DOCUMENT_ME. */ private PreferenceToolbar preferences; /** DOCUMENT_ME. */ private DropDownButton jddbSmart; /** DOCUMENT_ME. */ private JPopupMenu jpmSmart; /** DOCUMENT_ME. */ private JMenuItem jbBestof; /** DOCUMENT_ME. */ private JMenuItem jbNovelties; /** DOCUMENT_ME. */ private JMenuItem jbRandom; /** DOCUMENT_ME. */ private SizedButton jbFinishAlbum; /** DOCUMENT_ME. */ private JButton jbMaximize; /** DOCUMENT_ME. */ private SizedButton jbVolume; /** DOCUMENT_ME. */ private SearchBox sbSearch; /** DOCUMENT_ME. */ private JToolBar slimJajuk; /** DOCUMENT_ME. */ private JToolBar jtbPlay; /** DOCUMENT_ME. */ private String title = ""; /** State decorator. */ private WindowStateDecorator decorator; /** DOCUMENT_ME. */ JajukInformationDialog balloon; /** DOCUMENT_ME. */ private static JajukSlimbar self; /** * Gets the single instance of JajukSlimbar. * * @return single instance of JajukSlimbar */ public static JajukSlimbar getInstance() { if (self == null) { self = new JajukSlimbar(); self.decorator = new WindowStateDecorator(self) { @Override public void specificAfterHidden() { // Nothing particular to do here } @Override public void specificBeforeHidden() { // Nothing particular to do here } @Override public void specificAfterShown() { // Need focus for keystrokes self.requestFocus(); } @Override public void specificBeforeShown() { self.pack(); } }; } return self; } /** * Sets the display queue. * * @param display the new display queue */ public void setDisplayQueue(boolean display) { if (display) { // Set position of queue dialog. We display the queue window either above or bellow the slimbar // according to remaining vertical space. int yLocation = this.getLocation().y; if (this.getLocation().y + queueViewWindow.getSize().height + this.getSize().height > Toolkit .getDefaultToolkit().getScreenSize().getHeight()) { yLocation -= queueViewWindow.getSize().height; } else { yLocation += this.getSize().height; } getQueueWindow().setLocation(this.getLocation().x, yLocation); getQueueWindow().setSize(this.getSize().width, queueViewWindow.getSize().height); } getQueueWindow().setVisible(display); Conf.setProperty(Const.CONF_SLIMBAR_DISPLAY_QUEUE, Boolean.toString(isDisplayQueue())); } /** * Checks if is display queue. * * @return true, if is display queue */ public boolean isDisplayQueue() { return getQueueWindow().isVisible(); } /* * (non-Javadoc) * * @see org.jajuk.ui.widgets.JajukWindow#getWindowStateDecorator() */ @Override public WindowStateDecorator getWindowStateDecorator() { return decorator; } /** This mouse motion listener allows the whole slim bar dragging. */ private final MouseMotionAdapter motionAdapter = new MouseMotionAdapter() { @Override public void mouseDragged(MouseEvent e) { Point point = e.getLocationOnScreen(); // compute coordinates of the event relative to the frame, not the screen // so we can compensate the frame size to avoid it to jump when applying // the new location Point relativePoint = SwingUtilities.convertPoint(((JComponent) e.getSource()).getParent(), ((JComponent) e.getSource()).getLocation(), JajukSlimbar.this.getRootPane()); point = new Point((int) (point.getX() - relativePoint.getX()), (int) (point.getY() - relativePoint.getY())); setLocation(point); setDisplayQueue(isDisplayQueue()); Conf.setProperty(Const.CONF_SLIMBAR_POSITION, (int) point.getX() + "," + (int) point.getY()); } }; /** DOCUMENT_ME. */ private SizedButton jbQueue; /** * Instantiates a new jajuk slimbar. */ private JajukSlimbar() { setUndecorated(true); setAlwaysOnTop(true); // Set windows decoration to look and feel JFrame.setDefaultLookAndFeelDecorated(true); JDialog.setDefaultLookAndFeelDecorated(true); } /* * (non-Javadoc) * * @see org.jajuk.ui.windows.IJajukWindow#initUI() */ @Override public void initUI() { // Instanciate the PlayerStateMediator to listen for player basic controls PlayerStateMediator.getInstance(); setIconImage(IconLoader.getIcon(JajukIcons.LOGO).getImage()); addWindowListener(new WindowAdapter() { @Override public void windowClosing(WindowEvent e) { try { ActionManager.getAction(JajukActions.EXIT).perform(null); } catch (Exception e1) { Log.error(e1); } } }); jbInfo = new JButton(IconLoader.getIcon(JajukIcons.INFO)); jbInfo.addActionListener(this); // Listen for dragging jbInfo.addMouseMotionListener(motionAdapter); // Listen for balloon displaying jbInfo.addMouseMotionListener(new MouseMotionAdapter() { @Override public void mouseMoved(MouseEvent e) { super.mouseMoved(e); showBalloon(); } }); jtbPlay = new JajukJToolbar(); jbPrevious = new SizedButton(ActionManager.getAction(PREVIOUS_TRACK), false); jbPrevious.addMouseMotionListener(motionAdapter); // Manage right click : replay the track (this not triggers an action so we use a MouseAdapter here) jbPrevious.addMouseListener(new JajukMouseAdapter() { @Override public void handlePopup(final MouseEvent me) { // Create an ActionEvent from this MouseEvent with a custom modifier : the right click ActionEvent ae = new ActionEvent(jbPrevious, 0, PREVIOUS_TRACK.name(), 4332424); try { ActionManager.getAction(PREVIOUS_TRACK).perform(ae); } catch (Exception e) { Log.error(e); } } }); jbNext = new SizedButton(ActionManager.getAction(NEXT_TRACK), false); jbNext.addMouseMotionListener(motionAdapter); jbPlayPause = new SizedButton(ActionManager.getAction(PAUSE_RESUME_TRACK), false); jbPlayPause.addMouseMotionListener(motionAdapter); jbStop = new SizedButton(ActionManager.getAction(STOP_TRACK), false); jbStop.addMouseMotionListener(motionAdapter); jbQueue = new SizedButton(ActionManager.getAction(QUEUE_TO_SLIM), false); jbQueue.addMouseMotionListener(motionAdapter); jtbPlay.add(jbPrevious); jtbPlay.add(jbPlayPause); jtbPlay.add(jbStop); jtbPlay.add(jbNext); jtbPlay.add(jbQueue); JToolBar jtbSmart = new JajukJToolbar(); jddbSmart = new DropDownButton(IconLoader.getIcon(JajukIcons.INC_RATING)) { private static final long serialVersionUID = 1L; @Override protected JPopupMenu getPopupMenu() { return jpmSmart; } }; jbBestof = new JMenuItem(ActionManager.getAction(JajukActions.BEST_OF)); jbBestof.setIcon(IconLoader.getIcon(JajukIcons.BESTOF_16X16)); jbBestof.addActionListener(this); jbNovelties = new JMenuItem(ActionManager.getAction(JajukActions.NOVELTIES)); jbNovelties.setIcon(IconLoader.getIcon(JajukIcons.NOVELTIES_16X16)); jbNovelties.addActionListener(this); jbRandom = new JMenuItem(ActionManager.getAction(JajukActions.SHUFFLE_GLOBAL)); jbRandom.setIcon(IconLoader.getIcon(JajukIcons.SHUFFLE_GLOBAL_16X16)); jbRandom.addActionListener(this); jpmSmart = new JPopupMenu(); jpmSmart.add(jbRandom); jpmSmart.add(jbBestof); jpmSmart.add(jbNovelties); jddbSmart.addToToolBar(jtbSmart); jddbSmart.addMouseMotionListener(motionAdapter); if (JajukActions.SHUFFLE_GLOBAL.toString() .equals(Conf.getString(Const.CONF_SLIMBAR_SMART_MODE))) { jddbSmart.setAction(ActionManager.getAction(JajukActions.SHUFFLE_GLOBAL)); jddbSmart.setIcon(IconLoader.getIcon(JajukIcons.SHUFFLE_GLOBAL_16X16)); } else if (JajukActions.BEST_OF.toString() .equals(Conf.getString(Const.CONF_SLIMBAR_SMART_MODE))) { jddbSmart.setAction(ActionManager.getAction(JajukActions.BEST_OF)); jddbSmart.setIcon(IconLoader.getIcon(JajukIcons.BESTOF_16X16)); } else if (JajukActions.NOVELTIES.toString().equals( Conf.getString(Const.CONF_SLIMBAR_SMART_MODE))) { jddbSmart.setAction(ActionManager.getAction(JajukActions.NOVELTIES)); jddbSmart.setIcon(IconLoader.getIcon(JajukIcons.NOVELTIES_16X16)); } preferences = new PreferenceToolbar(); jtbSmart.add(preferences); JToolBar jtbTools = new JajukJToolbar(); int iVolume = (int) (100 * Conf.getFloat(Const.CONF_VOLUME)); if (iVolume > 100) { // can occur in some undefined cases iVolume = 100; } jbVolume = new SizedButton(ActionManager.getAction(MUTE_STATE), false); jbVolume.addMouseMotionListener(motionAdapter); jbVolume.addMouseWheelListener(this); jbVolume.setText(null); jbVolume.addMouseMotionListener(new MouseMotionAdapter() { @Override public void mouseMoved(MouseEvent e) { super.mouseMoved(e); // Request focus to allow volume change jbVolume.requestFocus(); toFront(); } }); MuteAction.setVolumeIcon(iVolume); jbMaximize = new JajukButton(ActionManager.getAction(JajukActions.SLIM_JAJUK)); jbMaximize.addMouseMotionListener(motionAdapter); jtbTools.add(jbVolume); jtbTools.addSeparator(); jtbTools.add(jbMaximize); jtbTools.add(new SizedButton(ActionManager.getAction(JajukActions.EXIT), false)); // Continue jbFinishAlbum = new SizedButton(ActionManager.getAction(JajukActions.FINISH_ALBUM)); // Search sbSearch = new SearchBox(); sbSearch.setPreferredSize(new Dimension(75, 20)); sbSearch.setMaximumSize(new Dimension(75, 20)); sbSearch.addMouseMotionListener(motionAdapter); slimJajuk = new JajukJToolbar(); AmbienceComboBox ambienceCombo = new AmbienceComboBox(); ambienceCombo.setPreferredSize(new Dimension(42, 20)); ambienceCombo.addMouseMotionListener(motionAdapter); slimJajuk.add(Box.createHorizontalStrut(4)); slimJajuk.add(jbInfo); slimJajuk.addSeparator(); slimJajuk.add(sbSearch); slimJajuk.addSeparator(); slimJajuk.add(jtbSmart); slimJajuk.add(jbFinishAlbum); slimJajuk.addSeparator(); slimJajuk.add(ambienceCombo); slimJajuk.addSeparator(); slimJajuk.add(jtbPlay); slimJajuk.addSeparator(); slimJajuk.add(jtbTools); slimJajuk.add(Box.createHorizontalStrut(2)); slimJajuk.setBorder(BorderFactory.createRaisedBevelBorder()); getRootPane().setToolTipText(getPlayerInfo()); add(slimJajuk); ObservationManager.register(this); getRootPane().setWindowDecorationStyle(JRootPane.NONE); updateCurrentTitle(); setVisible(true); setAlwaysOnTop(true); // Set location String lastPosition = Conf.getString(Const.CONF_SLIMBAR_POSITION); int iScreenWidth = (int) (Toolkit.getDefaultToolkit().getScreenSize().getWidth()); int iScreenHeight = (int) (Toolkit.getDefaultToolkit().getScreenSize().getHeight()); int x = iScreenWidth / 2; int y = iScreenHeight / 2; try { StringTokenizer st = new StringTokenizer(lastPosition, ","); x = Integer.parseInt(st.nextToken()); y = Integer.parseInt(st.nextToken()); // Reset if position are out of bounds (after a resolution changing for // eg) if (x < 0 || x > iScreenWidth) { x = 0; } if (y < 0 || y > iScreenHeight) { y = 0; } Point point = new Point(x, y); setLocation(point); } catch (Exception e) { Log.debug("Cannot restore slimbar position"); Log.error(e); } // Force initial message refresh UtilFeatures.updateStatus(this); // Install global keystrokes WindowGlobalKeystrokeManager.getInstance(); } /** * Returns or create a queue window to be displayed though the queue view slimbar button. * * @return the queue window */ private JWindow getQueueWindow() { if (queueViewWindow == null) { QueueView queueView = new QueueView(); queueView.initUI(); queueView.setBorder(BorderFactory.createLineBorder(Color.BLACK)); queueViewWindow = new JWindow(this); queueViewWindow.getContentPane().add(queueView); queueViewWindow.pack(); // Set position of queue dialog queueViewWindow.setLocation(this.getLocation().x, this.getLocation().y + this.getSize().height); queueViewWindow.setSize(this.getSize().width, queueViewWindow.getSize().height / 2); queueViewWindow.setVisible(Conf.getBoolean(Const.CONF_SLIMBAR_DISPLAY_QUEUE)); } return queueViewWindow; } /** * Update current title. DOCUMENT_ME */ private void updateCurrentTitle() { File file = QueueModel.getPlayingFile(); if (QueueModel.isPlayingRadio()) { title = QueueModel.getCurrentRadio().getName(); } else if (file != null && !QueueModel.isStopped()) { title = QueueModel.getPlayingFileTitle(); } else { title = Messages.getString("JajukWindow.18"); } // Update window title SwingUtilities.invokeLater(new Runnable() { @Override public void run() { setTitle(title); } }); } /** * Gets the player info. * * @return Player Info : current and next track */ public String getPlayerInfo() { try { String currentTrack = QueueModel.getPlayingFileTitle(); String nextFileTitle = ""; File nextFile; try { nextFile = QueueModel.getItem(QueueModel.getIndex() + 1).getFile(); } catch (Exception e) { nextFile = QueueModel.getPlanned().get(0).getFile(); } String pattern = Conf.getString(Const.CONF_PATTERN_FRAME_TITLE); try { nextFileTitle = UtilString.applyPattern(nextFile, pattern, false, false); } catch (JajukException e) { Log.error(e); } return " | Playing: " + currentTrack + " | Next: " + nextFileTitle; } catch (Exception e) { return Messages.getString("JajukWindow.17"); } } /* * (non-Javadoc) * * @seejava.awt.event.MouseWheelListener#mouseWheelMoved(java.awt.event. MouseWheelEvent) */ @Override public void mouseWheelMoved(MouseWheelEvent e) { if (e.getSource().equals(jbVolume)) { int oldVolume = (int) (100 * Player.getCurrentVolume()); int newVolume = oldVolume - (e.getUnitsToScroll() * 3); if (Player.isMuted()) { Player.mute(false); } if (newVolume > 100) { newVolume = 100; } else if (newVolume < 0) { newVolume = 0; } Player.setVolume((float) newVolume / 100); jbVolume.setToolTipText(newVolume + " %"); // Force tooltip refresh live hideToolTip(jbVolume); postToolTip(jbVolume); MuteAction.setVolumeIcon(newVolume); } } /** * Force tooltip refresh Thanks Santhosh Kumar * http://www.jroller.com/santhosh/entry/tooltips_can_say_more * * @param comp DOCUMENT_ME */ public static void postToolTip(JComponent comp) { Action action = comp.getActionMap().get("postTip"); if (action == null) { // no tooltip return; } ActionEvent ae = new ActionEvent(comp, ActionEvent.ACTION_PERFORMED, "postTip", EventQueue.getMostRecentEventTime(), 0); action.actionPerformed(ae); } /** * Remove tooltip Thanks Santhosh Kumar * http://www.jroller.com/santhosh/entry/tooltips_can_say_more * * @param comp DOCUMENT_ME */ public static void hideToolTip(JComponent comp) { Action action = comp.getActionMap().get("hideTip"); if (action == null) { // no tooltip return; } ActionEvent ae = new ActionEvent(comp, ActionEvent.ACTION_PERFORMED, "hideTip", EventQueue.getMostRecentEventTime(), 0); action.actionPerformed(ae); } /* * (non-Javadoc) * * @see org.jajuk.events.Observer#getRegistrationKeys() */ @Override public Set getRegistrationKeys() { Set eventSubjectSet = new HashSet(); eventSubjectSet.add(JajukEvents.FILE_LAUNCHED); eventSubjectSet.add(JajukEvents.WEBRADIO_LAUNCHED); eventSubjectSet.add(JajukEvents.QUEUE_NEED_REFRESH); eventSubjectSet.add(JajukEvents.PLAYER_STOP); return eventSubjectSet; } /* * (non-Javadoc) * * @see org.jajuk.events.Observer#update(org.jajuk.events.JajukEvent) */ @Override public void update(final JajukEvent event) { JajukEvents subject = event.getSubject(); if (JajukEvents.FILE_LAUNCHED.equals(subject) || JajukEvents.WEBRADIO_LAUNCHED.equals(subject) || JajukEvents.PLAYER_STOP.equals(subject)) { updateCurrentTitle(); } } /* * (non-Javadoc) * * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent) */ @Override public void actionPerformed(final ActionEvent ae) { if (ae.getSource() == jbBestof) { jddbSmart.setAction(ActionManager.getAction(JajukActions.BEST_OF)); jddbSmart.setIcon(IconLoader.getIcon(JajukIcons.BESTOF_16X16)); Conf.setProperty(Const.CONF_SLIMBAR_SMART_MODE, JajukActions.BEST_OF.toString()); } else if (ae.getSource() == jbNovelties) { jddbSmart.setAction(ActionManager.getAction(JajukActions.NOVELTIES)); jddbSmart.setIcon(IconLoader.getIcon(JajukIcons.NOVELTIES_16X16)); Conf.setProperty(Const.CONF_SLIMBAR_SMART_MODE, JajukActions.NOVELTIES.toString()); } else if (ae.getSource() == jbRandom) { jddbSmart.setAction(ActionManager.getAction(JajukActions.SHUFFLE_GLOBAL)); jddbSmart.setIcon(IconLoader.getIcon(JajukIcons.SHUFFLE_GLOBAL_16X16)); Conf.setProperty(Const.CONF_SLIMBAR_SMART_MODE, JajukActions.SHUFFLE_GLOBAL.toString()); } else if (ae.getSource() == jbInfo) { showBalloon(); } } /** * Display the current playing album balloon when moving mouse over jbInfo or * when clicking on it. */ private void showBalloon() { // Leave if balloon already visible if (balloon != null && balloon.isVisible()) { return; } balloon = new JajukInformationDialog(QueueModel.getCurrentFileTitle(), this); Point buttonLocation = jbInfo.getLocationOnScreen(); Point location = null; // If slimbar is too height in the screen, display the popup bellow it if (buttonLocation.y < balloon.getHeight() + 10) { location = new Point(buttonLocation.x, buttonLocation.y + 25); } else { location = new Point(buttonLocation.x, buttonLocation.y - (5 + balloon.getHeight())); } balloon.setLocation(location); balloon.display(); } /* * (non-Javadoc) * * @see java.awt.Window#dispose() */ @Override public void dispose() { // there are some resources to close in the Search-Box that I could not get // rid of with any of the default dispose-methods in Swing... sbSearch.close(); super.dispose(); } }jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/windows/WindowState.java0000644000175000017500000000213511720500104025226 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.windows; /** * Possible states for a Jajuk window. */ public enum WindowState { // Not yet build /** DOCUMENT_ME. */ NOT_BUILT, // Build but not yet displayed /** DOCUMENT_ME. */ BUILT_NOT_DISPLAYED, // Build and displayed /** DOCUMENT_ME. */ BUILT_DISPLAYED, } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/windows/WindowStateDecorator.java0000644000175000017500000001031711720500104027072 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.windows; import java.awt.Component; import org.jajuk.util.log.Log; /** * Add display and state storage functionalities to jajuk windows (main window, * fullscreen, tray, slimbar...) */ public abstract class WindowStateDecorator { /** Current state. */ private WindowState state = WindowState.NOT_BUILT; /** Decorated window *. */ private IJajukWindow window; /** * Builds the decorator. * * @param window decorated window */ public WindowStateDecorator(IJajukWindow window) { this.window = window; } /** * Gets the window state. * * @return Returns the bVisible. */ public WindowState getWindowState() { return state; } /** * Set the display state to the window. * * @param state Window state */ public void setWindowState(WindowState state) { this.state = state; } /** * Show or hide the frame *

    * Must be called within the EDT *

    . * * @param show whether the window should be shown or hidden */ public void display(boolean show) { try { // mode is already ok, leave if ((!show && state != WindowState.BUILT_DISPLAYED) || (show && state == WindowState.BUILT_DISPLAYED)) { return; } // Build the GUI is not already done, executes window-specific behavior if (show && state == WindowState.NOT_BUILT) { window.initUI(); } // Show or hide specific code before the window is made visible if (show) { window.getWindowStateDecorator().specificBeforeShown(); ((Component) window).validate(); } else { window.getWindowStateDecorator().specificBeforeHidden(); } // Display or hide the window ((Component) window).setVisible(show); // Show or hide specific code after the window is made visible if (show) { window.getWindowStateDecorator().specificAfterShown(); ((Component) window).validate(); } else { window.getWindowStateDecorator().specificAfterHidden(); } // store the new state if (show) { state = WindowState.BUILT_DISPLAYED; } else { state = WindowState.BUILT_NOT_DISPLAYED; } } catch (Exception e) { Log.error(e); } } /** * convenient method to get build status of the window. * * @return whether the initUI() has run successfully or not */ public boolean isInitialized() { return getWindowState() == WindowState.BUILT_DISPLAYED || getWindowState() == WindowState.BUILT_NOT_DISPLAYED; } /** * convenient method to get visible status of the window. * * @return whether the window is displayed */ public boolean isDisplayed() { return getWindowState() == WindowState.BUILT_DISPLAYED; } /** * Specific actions before the window is shown To be overridden in each Window * class WindowDecorator. */ abstract public void specificBeforeShown(); /** * Specific actions after the window is shown To be overridden in each Window * class WindowDecorator. */ abstract public void specificAfterShown(); /** * Specific actions before the window is hidden To be overridden in each * Window class WindowDecorator. */ abstract public void specificBeforeHidden(); /** * Specific actions after the window is hidden To be overridden in each Window * class WindowDecorator. */ abstract public void specificAfterHidden(); } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/windows/JajukFullScreenWindow.java0000644000175000017500000003114511720500104027200 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.windows; import static org.jajuk.ui.actions.JajukActions.NEXT_TRACK; import static org.jajuk.ui.actions.JajukActions.PAUSE_RESUME_TRACK; import static org.jajuk.ui.actions.JajukActions.PREVIOUS_TRACK; import static org.jajuk.ui.actions.JajukActions.STOP_TRACK; import java.awt.Cursor; import java.awt.Dimension; import java.awt.GraphicsDevice; import java.awt.Point; import java.awt.Toolkit; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.MouseMotionAdapter; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.JPopupMenu; import javax.swing.JWindow; import javax.swing.Timer; import net.miginfocom.swing.MigLayout; import org.jajuk.ui.actions.ActionManager; import org.jajuk.ui.actions.JajukActions; import org.jajuk.ui.helpers.JajukMouseAdapter; import org.jajuk.ui.substance.CircleButtonShaper; import org.jajuk.ui.substance.LeftConcaveButtonShaper; import org.jajuk.ui.substance.RightConcaveButtonShaper; import org.jajuk.ui.substance.RoundRectButtonShaper; import org.jajuk.ui.views.AnimationView; import org.jajuk.ui.views.CoverView; import org.jajuk.ui.widgets.JajukButton; import org.jajuk.ui.widgets.TrackPositionSliderToolbar; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; import org.jajuk.util.UtilGUI; import org.jajuk.util.UtilSystem; import org.jajuk.util.log.Log; import org.jvnet.substance.SubstanceLookAndFeel; /** * The full screen window Note that not all operating support full screen mode. * If the OS doesn't support it, the user cannot access to it so we have not to * handle any errors. */ public class JajukFullScreenWindow extends JWindow implements IJajukWindow { /** Generated serialVersionUID. */ private static final long serialVersionUID = -2859302706462954993L; /** DOCUMENT_ME. */ private static JajukFullScreenWindow instance = null; /** DOCUMENT_ME. */ private GraphicsDevice graphicsDevice; /** DOCUMENT_ME. */ private JButton jbPrevious; /** DOCUMENT_ME. */ private JButton jbNext; /** DOCUMENT_ME. */ private JButton jbPlayPause; /** DOCUMENT_ME. */ private JButton jbStop; /** DOCUMENT_ME. */ private JajukButton jbFull; /** DOCUMENT_ME. */ private JajukButton jbExit; /** DOCUMENT_ME. */ private CoverView coverView; /** State decorator. */ private WindowStateDecorator decorator; /** DOCUMENT_ME. */ private AnimationView animationView; /** DOCUMENT_ME. */ private JPanel jtbPlay; /** DOCUMENT_ME. */ private Timer hideMouseTimer; /** Owning frame, see bellow for explanations *. */ private static JFrame owner; /** * See http://java.sun.com/docs/books/tutorial/uiswing/misc/focus.html We have * to use a frame owner of this jwindow to allow full screen mode to respond * to key events */ static { owner = new JFrame(); owner.setSize(new Dimension(0, 0)); owner.setUndecorated(true); owner.requestFocus(); // Add escape listening to exit full-screen mode owner.addKeyListener(new KeyAdapter() { @Override public void keyPressed(KeyEvent e) { if (e.getKeyCode() == KeyEvent.VK_ESCAPE) { try { ActionManager.getAction(JajukActions.FULLSCREEN_JAJUK).perform(null); } catch (Exception e1) { Log.error(e1); } } } }); // Install global keystrokes WindowGlobalKeystrokeManager.getInstance(); } /** * Return whether we should try to switch to fullscreen mode (and lose keystrokes controls) * @return whether we should try to switch to fullscreen mode */ private static boolean shouldTryNativeFullScreenmode() { return // Check full screen mode is actually supported (instance.graphicsDevice.isFullScreenSupported() && // Use real full screen mode only under OSX to override the task bar, otherwise, // we only maximize the frame to make keystrokes working. UtilSystem.isUnderOSX()); } /** * Gets the single instance of JajukFullScreenWindow. * * @return single instance of JajukFullScreenWindow */ public static JajukFullScreenWindow getInstance() { if (instance == null) { instance = new JajukFullScreenWindow(); instance.decorator = new WindowStateDecorator(instance) { @Override public void specificBeforeShown() { instance.graphicsDevice = UtilGUI.getGraphicsDeviceOfMainFrame(); if (shouldTryNativeFullScreenmode()) { instance.graphicsDevice.setFullScreenWindow(instance); } } @Override public void specificAfterShown() { if (!shouldTryNativeFullScreenmode()) { Dimension dimension = null; Point point = null; // Probably due to JRE bug #6921661, instance.graphicsDevice.getDisplayMode() sometimes // returns null under some OS like Fedora as a VMWare guest OS. Then, we can enter properly // into fullscreen mode but we we cannot leave it anymore // (java.lang.IllegalArgumentException: Invalid display mode ). // So we try to detect defunct configurations and we use Toolkit (dual screen unaware) // To find single screen size. if (instance.graphicsDevice.getDisplayMode() != null) { // No full screen mode but no JRE bug dimension = new Dimension(instance.graphicsDevice.getDisplayMode().getWidth(), instance.graphicsDevice.getDisplayMode().getHeight()); point = new Point(instance.graphicsDevice.getDefaultConfiguration().getBounds() .getLocation()); } else { // No full screen mode AND JRE bug dimension = Toolkit.getDefaultToolkit().getScreenSize(); point = new Point(0, 0); } instance.setSize(dimension); instance.setLocation(point); owner.setVisible(true); owner.requestFocus(); } } @Override public void specificAfterHidden() { if (shouldTryNativeFullScreenmode()) { instance.graphicsDevice.setFullScreenWindow(null); } owner.setVisible(false); instance.dispose(); } @Override public void specificBeforeHidden() { if (instance.graphicsDevice.isFullScreenSupported()) { // Make sure to reset everything like it was before entering fullscreen mode // (even if it wasn't the case) instance.graphicsDevice.setFullScreenWindow(null); } } }; } return instance; } /** * Hide mouse timer. * */ private void hideMouseTimer() { setCursor(Cursor.getDefaultCursor()); if (hideMouseTimer != null) { hideMouseTimer.restart(); } else { initMouseTimer(); } } /** * Inits the mouse timer. * */ private void initMouseTimer() { hideMouseTimer = new Timer(3000, new ActionListener() { @Override public void actionPerformed(ActionEvent e) { setCursor(Toolkit.getDefaultToolkit().createCustomCursor( IconLoader.getIcon(JajukIcons.NONE).getImage(), new Point(0, 0), "invisibleCursor")); } }); hideMouseTimer.start(); } /** * Instantiates a new jajuk full screen window. */ public JajukFullScreenWindow() { super(owner); setAlwaysOnTop(true); // Add Mouse Listener to disable mouse cursor addMouseListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { hideMouseTimer(); } }); addMouseMotionListener(new MouseMotionAdapter() { @Override public void mouseMoved(MouseEvent e) { hideMouseTimer(); } }); // activate Timer hideMouseTimer(); } /* * (non-Javadoc) * * @see org.jajuk.ui.windows.IJajukWindow#initUI() */ @Override public void initUI() { // Full screen switch button jbFull = new JajukButton(ActionManager.getAction(JajukActions.FULLSCREEN_JAJUK)); // Exit button jbExit = new JajukButton(ActionManager.getAction(JajukActions.EXIT)); // Animation view animationView = new AnimationView(); animationView.initUI(); // Cover view coverView = new CoverView(); coverView.initUI(false); // Player toolbar jtbPlay = getPlayerPanel(); // Information panel TrackPositionSliderToolbar tpst = new TrackPositionSliderToolbar(); // Add items setLayout(new MigLayout("ins 0", "[grow]", "[][grow][70%!][][]")); add(jbFull, "right,split 2,gapright 5"); add(jbExit, "right,wrap"); add(animationView, "alignx center,aligny top,grow,gap bottom 20,wrap"); add(coverView, "alignx center, grow,gap bottom 20,wrap"); add(jtbPlay, "alignx center,gap bottom 20,wrap"); add(tpst, "alignx center,width 50%!,aligny bottom,gap bottom 10"); // Add a contextual menu to leave full screen mode or quit, see also // issue #1492 // TODO : For some reasons, the popup doesn't appears over the cover pic, // I have no idea of the reason so far. final JPopupMenu popup = new JPopupMenu(); popup.add(ActionManager.getAction(JajukActions.FULLSCREEN_JAJUK)); popup.add(ActionManager.getAction(JajukActions.EXIT)); addMouseListener(new JajukMouseAdapter() { @Override public void handlePopup(MouseEvent e) { popup.show(e.getComponent(), e.getX(), e.getY()); } @Override public void handleAction(MouseEvent e) { // Void on purpose } }); } /** * Gets the player panel. * * @return the player panel */ private JPanel getPlayerPanel() { JPanel jPanelPlay = new JPanel(); jPanelPlay.setLayout(new MigLayout("insets 5", "[grow][grow][grow]")); // previous jbPrevious = new JajukButton(ActionManager.getAction(PREVIOUS_TRACK)); int concavity = IconLoader.getIcon(JajukIcons.PLAYER_PLAY).getIconHeight(); jbPrevious.putClientProperty(SubstanceLookAndFeel.BUTTON_SHAPER_PROPERTY, new RightConcaveButtonShaper(concavity)); jbPrevious.setBorderPainted(true); jbPrevious.setContentAreaFilled(true); jbPrevious.setFocusPainted(true); jbPrevious.addMouseListener(new JajukMouseAdapter() { @Override public void handlePopup(final MouseEvent me) { // Create an ActionEvent from this MouseEvent with a custom modifier : the right click ActionEvent ae = new ActionEvent(jbPrevious, 0, PREVIOUS_TRACK.name(), 4332424); try { ActionManager.getAction(PREVIOUS_TRACK).perform(ae); } catch (Exception e) { Log.error(e); } } }); // next jbNext = new JajukButton(ActionManager.getAction(NEXT_TRACK)); jbNext.putClientProperty(SubstanceLookAndFeel.BUTTON_SHAPER_PROPERTY, new LeftConcaveButtonShaper(concavity)); // play pause jbPlayPause = new JajukButton(ActionManager.getAction(PAUSE_RESUME_TRACK)); jbPlayPause.putClientProperty(SubstanceLookAndFeel.BUTTON_SHAPER_PROPERTY, new CircleButtonShaper()); // stop jbStop = new JajukButton(ActionManager.getAction(STOP_TRACK)); jbStop.putClientProperty(SubstanceLookAndFeel.BUTTON_SHAPER_PROPERTY, new RoundRectButtonShaper()); jPanelPlay.add(jbStop, "center,split 6,width 40!,height 30,gapright 5!"); jPanelPlay.add(jbPrevious, "center,width 62!,height 30!,gapright 0"); jPanelPlay.add(jbPlayPause, "center,width 45!,height 45!,gapright 0"); jPanelPlay.add(jbNext, "center,width 62!,height 30!,gapright 3"); return jPanelPlay; } /* * (non-Javadoc) * * @see org.jajuk.ui.widgets.JajukWindow#getWindowStateDecorator() */ @Override public WindowStateDecorator getWindowStateDecorator() { return decorator; } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/windows/JajukSystray.java0000644000175000017500000004251111720500104025423 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.windows; import ext.JXTrayIcon; import java.awt.AWTException; import java.awt.Point; import java.awt.SystemTray; import java.awt.TrayIcon; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.MouseMotionAdapter; import java.awt.event.MouseWheelEvent; import java.util.HashSet; import java.util.Set; import javax.swing.JLabel; import javax.swing.JMenu; import javax.swing.JMenuItem; import javax.swing.JPanel; import javax.swing.JPopupMenu; import javax.swing.SwingUtilities; import net.miginfocom.swing.MigLayout; import org.jajuk.events.JajukEvent; import org.jajuk.events.JajukEvents; import org.jajuk.events.ObservationManager; import org.jajuk.services.dj.Ambience; import org.jajuk.services.dj.AmbienceManager; import org.jajuk.services.players.Player; import org.jajuk.services.players.QueueModel; import org.jajuk.ui.actions.ActionManager; import org.jajuk.ui.actions.JajukActions; import org.jajuk.ui.actions.MuteAction; import org.jajuk.ui.helpers.FontManager; import org.jajuk.ui.helpers.FontManager.JajukFont; import org.jajuk.ui.helpers.JajukMouseAdapter; import org.jajuk.ui.helpers.PlayerStateMediator; import org.jajuk.ui.widgets.CommandJPanel; import org.jajuk.ui.widgets.JajukInformationDialog; import org.jajuk.ui.widgets.SearchBox; import org.jajuk.ui.widgets.SizedJMenuItem; import org.jajuk.util.Conf; import org.jajuk.util.Const; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; import org.jajuk.util.UtilFeatures; import org.jajuk.util.UtilGUI; import org.jajuk.util.UtilSystem; import org.jajuk.util.log.Log; /** * Jajuk systray
    * Extends CommandJPanel for volume slider heritage only. */ public class JajukSystray extends CommandJPanel implements IJajukWindow { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** State decorator. */ private WindowStateDecorator decorator; // Systray variables /** DOCUMENT_ME. */ SystemTray stray; /** DOCUMENT_ME. */ JXTrayIcon trayIcon; /** DOCUMENT_ME. */ JPopupMenu jmenu; /** DOCUMENT_ME. */ JMenuItem jmiExit; /** DOCUMENT_ME. */ JMenuItem jmiMute; /** DOCUMENT_ME. */ JMenuItem jmiShuffle; /** DOCUMENT_ME. */ JMenuItem jmiBestof; /** DOCUMENT_ME. */ JMenuItem jmiDJ; /** DOCUMENT_ME. */ JMenuItem jmiNovelties; /** DOCUMENT_ME. */ JMenuItem jmiFinishAlbum; /** DOCUMENT_ME. */ JMenuItem jmiPlayPause; /** DOCUMENT_ME. */ JMenuItem jmiStop; /** DOCUMENT_ME. */ JMenuItem jmiPrevious; /** DOCUMENT_ME. */ JMenuItem jmiNext; /** DOCUMENT_ME. */ JMenu jmAmbience; /** Self instance singleton. */ private static JajukSystray jsystray; /** HTML Tooltip. */ JajukInformationDialog balloon; /** * Checks if is loaded. * * @return whether the tray is loaded */ public static boolean isLoaded() { return (jsystray != null); } /** * Gets the instance. * * @return singleton */ public static JajukSystray getInstance() { if (jsystray == null) { jsystray = new JajukSystray(); jsystray.decorator = new WindowStateDecorator(jsystray) { @Override public void specificAfterHidden() { if (jsystray != null) { jsystray.closeSystray(); jsystray = null; } } @Override public void specificBeforeHidden() { // Nothing particular to do here } @Override public void specificAfterShown() { // Force initial message refresh UtilFeatures.updateStatus(jsystray); } @Override public void specificBeforeShown() { // Nothing particular to do here } }; } return jsystray; } /* * (non-Javadoc) * * @see org.jajuk.ui.widgets.JajukWindow#getWindowStateDecorator() */ @Override public WindowStateDecorator getWindowStateDecorator() { return decorator; } /** * Systray constructor. */ public JajukSystray() { super(); if (SystemTray.isSupported()) { stray = SystemTray.getSystemTray(); } } /* * (non-Javadoc) * * @see org.jajuk.ui.widgets.CommandJPanel#initUI() */ @Override public final void initUI() { // Instanciate the PlayerStateMediator to listen for player basic controls PlayerStateMediator.getInstance(); jmenu = new JPopupMenu(Messages.getString("JajukWindow.3")); jmiExit = new JMenuItem(ActionManager.getAction(JajukActions.EXIT)); // force icon to be display in 16x16 jmiMute = new SizedJMenuItem(ActionManager.getAction(JajukActions.MUTE_STATE)); jmiMute.addMouseWheelListener(this); jmiShuffle = new SizedJMenuItem(ActionManager.getAction(JajukActions.SHUFFLE_GLOBAL)); jmiBestof = new SizedJMenuItem(ActionManager.getAction(JajukActions.BEST_OF)); jmiDJ = new SizedJMenuItem(ActionManager.getAction(JajukActions.DJ)); jmiFinishAlbum = new SizedJMenuItem(ActionManager.getAction(JajukActions.FINISH_ALBUM)); jmiNovelties = new SizedJMenuItem(ActionManager.getAction(JajukActions.NOVELTIES)); jmiPlayPause = new SizedJMenuItem(ActionManager.getAction(JajukActions.PAUSE_RESUME_TRACK)); jmiStop = new SizedJMenuItem(ActionManager.getAction(JajukActions.STOP_TRACK)); jmiPrevious = new SizedJMenuItem(ActionManager.getAction(JajukActions.PREVIOUS_TRACK)); jmiNext = new SizedJMenuItem(ActionManager.getAction(JajukActions.NEXT_TRACK)); JLabel jlTitle = new JLabel("Jajuk"); jlTitle.addMouseListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { if (e.getButton() == MouseEvent.BUTTON1) { // show main window if it is not visible and hide it if it is visible WindowState mainWindowState = JajukMainWindow.getInstance().getWindowStateDecorator() .getWindowState(); boolean bShouldDisplayMainWindow = !(mainWindowState == WindowState.BUILT_DISPLAYED); JajukMainWindow.getInstance().getWindowStateDecorator().display(bShouldDisplayMainWindow); } } }); jlTitle.setFont(FontManager.getInstance().getFont(JajukFont.BOLD_TITLE)); SearchBox searchBox = new SearchBox(); JPanel jpTitle = new JPanel(new MigLayout("ins 5", "[][grow]")); jpTitle.add(jlTitle, "left,gapx 20px"); jpTitle.add(searchBox, "right,grow"); // Ambiences menu Ambience defaultAmbience = AmbienceManager.getInstance().getSelectedAmbience(); jmAmbience = new JMenu(Messages.getString("JajukWindow.36") + " " + ((defaultAmbience == null) ? Messages.getString("DigitalDJWizard.64") : defaultAmbience .getName())); populateAmbiences(); jmenu.add(jpTitle); jmenu.addSeparator(); jmenu.add(jmAmbience); jmenu.addSeparator(); jmenu.add(jmiPlayPause); jmenu.add(jmiStop); jmenu.add(jmiPrevious); jmenu.add(jmiNext); jmenu.addSeparator(); jmenu.add(jmiShuffle); jmenu.add(jmiBestof); jmenu.add(jmiDJ); jmenu.add(jmiNovelties); jmenu.add(jmiFinishAlbum); jmenu.addSeparator(); jmenu.add(jmiMute); jmenu.addSeparator(); jmenu.add(jmiExit); // Add a row under Linux to fix an issue : sometimes, when left-clicking on // the tray, the exit menu item is executed and then close Jajuk accidently if (UtilSystem.isUnderLinux()) { jmenu.add(""); } trayIcon = new JXTrayIcon(IconLoader.getIcon(JajukIcons.TRAY).getImage()); if (!UtilSystem.isUnderLinux()) { // auto-resize looks OK under Windows but is ugly under Linux/KDE trayIcon.setImageAutoSize(true); } trayIcon.addMouseMotionListener(new MouseMotionAdapter() { long dateLastMove = 0; @Override public void mouseMoved(MouseEvent e) { // [PERF] Consider only a single event per second if (System.currentTimeMillis() - dateLastMove < 1000) { return; } dateLastMove = System.currentTimeMillis(); String title = QueueModel.getCurrentFileTitle(); if (balloon != null && balloon.isVisible()) { return; } // Useful for #1582 ([Linux] Void entry in task bar for information dialog) if (UtilGUI.getActiveWindow() != null //can happen if tray only && UtilGUI.getActiveWindow().equals(JajukMainWindow.getInstance())) { balloon = new JajukInformationDialog(title, null); } else { balloon = new JajukInformationDialog(title, UtilGUI.getActiveWindow()); } Point location = new Point(e.getX() - balloon.getWidth(), e.getY() - (20 + balloon.getHeight())); balloon.setLocation(location); balloon.display(); } }); trayIcon.setJPopuMenu(jmenu); // Note that under OSX, popup gesture recognition is inverted : a left click return true if (UtilSystem.isUnderOSX()) { // Don't use a JajukMouseAdapter here because tray has specific behavior under OSX trayIcon.addMouseListener(new MouseAdapter() { // Under OSX, the event to consider is PRESSED, not RELEASED, // see http://developer.apple.com/mac/library/documentation/Java/Conceptual/Java14Development/07-NativePlatformIntegration/NativePlatformIntegration.html @Override public void mousePressed(MouseEvent e) { if (!e.isPopupTrigger()) { //we invert here because it is a systray item // popup gesture recognized, display the jdialog trayIcon.showJPopupMenu(e); } else { showHideWindow(e); } } }); } else { trayIcon.addMouseListener(new JajukMouseAdapter() { @Override public void handleActionSingleClick(MouseEvent e) { showHideWindow(e); } @Override public void handlePopup(final MouseEvent e) { trayIcon.showJPopupMenu(e); } }); } try { stray.add(trayIcon); } catch (AWTException e) { Log.error(e); return; } // Register needed events ObservationManager.register(this); } /** * Invert current window visibility with a left click on the tray icon. * * @param e DOCUMENT_ME */ private void showHideWindow(MouseEvent e) { WindowStateDecorator windowDecorator = null; if (Conf.getInt(Const.CONF_STARTUP_DISPLAY) == Const.DISPLAY_MODE_MAIN_WINDOW) { windowDecorator = JajukMainWindow.getInstance().getWindowStateDecorator(); } else if (Conf.getInt(Const.CONF_STARTUP_DISPLAY) == Const.DISPLAY_MODE_SLIMBAR_TRAY) { windowDecorator = JajukSlimbar.getInstance().getWindowStateDecorator(); } else if (Conf.getInt(Const.CONF_STARTUP_DISPLAY) == Const.DISPLAY_MODE_FULLSCREEN) { windowDecorator = JajukFullScreenWindow.getInstance().getWindowStateDecorator(); } // show Main if no other found, i.e. only Systray is displayed if (windowDecorator == null) { windowDecorator = JajukMainWindow.getInstance().getWindowStateDecorator(); } // Invert visibility for the current window boolean bShouldDisplay = !(windowDecorator.getWindowState() == WindowState.BUILT_DISPLAYED); windowDecorator.display(bShouldDisplay); } /* * (non-Javadoc) * * @see org.jajuk.ui.widgets.CommandJPanel#getRegistrationKeys() */ @Override public Set getRegistrationKeys() { Set eventSubjectSet = new HashSet(); eventSubjectSet.add(JajukEvents.ZERO); eventSubjectSet.add(JajukEvents.FILE_LAUNCHED); eventSubjectSet.add(JajukEvents.PLAYER_PLAY); eventSubjectSet.add(JajukEvents.PLAYER_STOP); eventSubjectSet.add(JajukEvents.AMBIENCES_CHANGE); eventSubjectSet.add(JajukEvents.AMBIENCES_SELECTION_CHANGE); return eventSubjectSet; } /* * (non-Javadoc) * * @see org.jajuk.ui.Observer#update(java.lang.String) */ @Override public final void update(final JajukEvent event) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { JajukEvents subject = event.getSubject(); if (JajukEvents.FILE_LAUNCHED.equals(subject)) { jmiPlayPause.setEnabled(true); jmiStop.setEnabled(true); jmiNext.setEnabled(true); jmiPrevious.setEnabled(true); jmiFinishAlbum.setEnabled(true); } else if (JajukEvents.PLAYER_STOP.equals(subject)) { // Enable the play button to allow restarting the queue but disable if // the queue is void boolean bQueueNotVoid = (QueueModel.getQueue().size() > 0); jmiPlayPause.setEnabled(bQueueNotVoid); jmiNext.setEnabled(bQueueNotVoid); jmiPrevious.setEnabled(bQueueNotVoid); jmiStop.setEnabled(false); jmiFinishAlbum.setEnabled(false); } else if (JajukEvents.ZERO.equals(subject)) { jmiPlayPause.setEnabled(false); jmiStop.setEnabled(false); jmiNext.setEnabled(false); jmiPrevious.setEnabled(false); jmiFinishAlbum.setEnabled(false); } else if (JajukEvents.PLAYER_PLAY.equals(subject)) { jmiPlayPause.setEnabled(true); jmiStop.setEnabled(true); jmiNext.setEnabled(true); jmiFinishAlbum.setEnabled(true); } else if (JajukEvents.VOLUME_CHANGED.equals(event.getSubject())) { JajukSystray.super.update(event); } else if (JajukEvents.AMBIENCES_CHANGE.equals(subject) || JajukEvents.AMBIENCES_SELECTION_CHANGE.equals(subject)) { Ambience ambience = AmbienceManager.getInstance().getSelectedAmbience(); if (ambience != null) { jmAmbience.setText(Messages.getString("JajukWindow.36") + " " + AmbienceManager.getInstance().getSelectedAmbience().getName()); } else { jmAmbience.setText(Messages.getString("JajukWindow.37")); } populateAmbiences(); } } }); } /** * Hide systray. */ public void closeSystray() { if (stray != null && trayIcon != null) { stray.remove(trayIcon); } } /** * Populate ambiences. */ final void populateAmbiences() { // Ambience selection listener ActionListener al = new ActionListener() { @Override public void actionPerformed(ActionEvent ae) { JMenuItem jmi = (JMenuItem) ae.getSource(); // Selected 'Any" ambience JMenuItem all = jmAmbience.getItem(0); if (jmi.equals(all)) { // reset default ambience Conf.setProperty(Const.CONF_DEFAULT_AMBIENCE, ""); } else {// Selected an ambience Ambience ambience = AmbienceManager.getInstance().getAmbienceByName( jmi.getActionCommand()); Conf.setProperty(Const.CONF_DEFAULT_AMBIENCE, ambience.getID()); } jmi.setFont(FontManager.getInstance().getFont(JajukFont.BOLD)); ObservationManager.notify(new JajukEvent(JajukEvents.AMBIENCES_SELECTION_CHANGE)); } }; // Remove all item jmAmbience.removeAll(); // Add "all" ambience JMenuItem jmiAll = new JMenuItem("" + Messages.getString("DigitalDJWizard.64") + ""); jmiAll.setFont(FontManager.getInstance().getFont(JajukFont.BOLD)); jmiAll.addActionListener(al); jmAmbience.add(jmiAll); // Add available ambiences for (Ambience ambience : AmbienceManager.getInstance().getAmbiences()) { JMenuItem jmi = new JMenuItem(ambience.getName()); if (Conf.getString(Const.CONF_DEFAULT_AMBIENCE).equals(ambience.getID())) { jmiAll.setFont(FontManager.getInstance().getFont(JajukFont.PLAIN)); jmi.setFont(FontManager.getInstance().getFont(JajukFont.BOLD)); } jmi.addActionListener(al); jmAmbience.add(jmi); } } /** * Gets the menu. * * @return the menu */ public JPopupMenu getMenu() { return this.jmenu; } /** * Gets the tray icon. * * @return the trayIcon */ public TrayIcon getTrayIcon() { return this.trayIcon; } /* * (non-Javadoc) * * @seejava.awt.event.MouseWheelListener#mouseWheelMoved(java.awt.event. MouseWheelEvent) */ @Override public void mouseWheelMoved(MouseWheelEvent e) { if (e.getSource().equals(jmiMute)) { int oldVolume = (int) (100 * Player.getCurrentVolume()); int newVolume = oldVolume - (e.getUnitsToScroll() * 3); if (Player.isMuted()) { Player.mute(false); } if (newVolume > 100) { newVolume = 100; } else if (newVolume < 0) { newVolume = 0; } Player.setVolume((float) newVolume / 100); MuteAction.setVolumeIcon(newVolume); } } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/windows/WindowGlobalKeystrokeManager.java0000644000175000017500000000732111720500104030544 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.windows; import static org.jajuk.ui.actions.JajukActions.DECREASE_VOLUME; import static org.jajuk.ui.actions.JajukActions.FORWARD_TRACK; import static org.jajuk.ui.actions.JajukActions.HELP_REQUIRED; import static org.jajuk.ui.actions.JajukActions.INCREASE_VOLUME; import static org.jajuk.ui.actions.JajukActions.MUTE_STATE; import static org.jajuk.ui.actions.JajukActions.NEXT_ALBUM; import static org.jajuk.ui.actions.JajukActions.NEXT_TRACK; import static org.jajuk.ui.actions.JajukActions.PAUSE_RESUME_TRACK; import static org.jajuk.ui.actions.JajukActions.PREVIOUS_ALBUM; import static org.jajuk.ui.actions.JajukActions.PREVIOUS_TRACK; import static org.jajuk.ui.actions.JajukActions.REPEAT_MODE; import static org.jajuk.ui.actions.JajukActions.REWIND_TRACK; import static org.jajuk.ui.actions.JajukActions.SHUFFLE_MODE; import static org.jajuk.ui.actions.JajukActions.STOP_TRACK; import java.awt.KeyEventDispatcher; import java.awt.KeyboardFocusManager; import java.awt.event.KeyEvent; import org.jajuk.ui.actions.ActionManager; import org.jajuk.ui.actions.ActionUtil; import org.jajuk.ui.actions.JajukAction; import org.jajuk.ui.actions.JajukActions; import org.jajuk.util.log.Log; /** * Keystrokes manager for any window type *

    * Singleton *

    . */ public class WindowGlobalKeystrokeManager { /** Self instance. */ private static WindowGlobalKeystrokeManager self; /** List of actions to enable globaly *. */ private JajukActions[] globalActions = new JajukActions[] { NEXT_ALBUM, PREVIOUS_ALBUM, PREVIOUS_TRACK, NEXT_TRACK, MUTE_STATE, PAUSE_RESUME_TRACK, STOP_TRACK, DECREASE_VOLUME, INCREASE_VOLUME, SHUFFLE_MODE, REPEAT_MODE, REWIND_TRACK, FORWARD_TRACK, HELP_REQUIRED }; /** * Gets the single instance of WindowGlobalKeystrokeManager. * * @return single instance of WindowGlobalKeystrokeManager */ static WindowGlobalKeystrokeManager getInstance() { if (self == null) { self = new WindowGlobalKeystrokeManager(); } return self; } /** * Instantiates a new window global keystroke manager. */ public WindowGlobalKeystrokeManager() { KeyEventDispatcher ked = new KeyEventDispatcher() { @Override public boolean dispatchKeyEvent(KeyEvent ke) { // Add all global keys to this dispatcher for (JajukActions actionName : globalActions) { JajukAction action = ActionManager.getAction(actionName); if (ActionUtil.matches(action, ke)) { try { action.perform(null); // No need to dispatch to others keystroke managers return true; } catch (Exception e) { Log.error(e); } } } // Unknown keystroke : let the others KeystrokeManager handle it return false; } }; // Attach the event dispatcher KeyboardFocusManager.getCurrentKeyboardFocusManager().addKeyEventDispatcher(ked); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/substance/0000755000175000017500000000000011720500104022407 5ustar drazzibdrazzibjajuk-1.9.6.orig/src/main/java/org/jajuk/ui/substance/RightConcaveButtonShaper.java0000644000175000017500000000434411720500104030172 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.substance; import java.awt.Insets; import java.awt.Shape; import java.awt.geom.Area; import java.awt.geom.Ellipse2D; import java.awt.geom.GeneralPath; import java.awt.geom.RoundRectangle2D; import javax.swing.AbstractButton; /* * based on code from Xtreme Media Player */ /** * The Class RightConcaveButtonShaper. */ public class RightConcaveButtonShaper extends ButtonShaper { /** DOCUMENT_ME. */ private int concaveDiameter; /** * Instantiates a new right concave button shaper. * * @param concaveDiameter DOCUMENT_ME */ public RightConcaveButtonShaper(int concaveDiameter) { super(); this.concaveDiameter = concaveDiameter; } /* (non-Javadoc) * @see org.jvnet.substance.shaper.SubstanceButtonShaper#getDisplayName() */ @Override public String getDisplayName() { return "RightConcave"; } /* (non-Javadoc) * @see org.jvnet.substance.shaper.SubstanceButtonShaper#getButtonOutline(javax.swing.AbstractButton, java.awt.Insets, int, int, boolean) */ @Override public Shape getButtonOutline(AbstractButton button, Insets insets, int w, int h, boolean isInner) { int width = w - 1; int height = h - 1; int z = concaveDiameter / 3; Shape shape = new Ellipse2D.Double(width - z, 0, z, height); Area area = new Area(new RoundRectangle2D.Double(z / 2d, 0, width - z, height, z, z)); area.subtract(new Area(shape)); return new GeneralPath(area); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/substance/package.html0000644000175000017500000000013311720500104024665 0ustar drazzibdrazzib

    Helper class to use with substance look and feel

    jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/substance/RoundRectButtonShaper.java0000644000175000017500000000345311720500104027523 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.substance; import java.awt.Insets; import java.awt.Shape; import java.awt.geom.GeneralPath; import java.awt.geom.RoundRectangle2D; import javax.swing.AbstractButton; /* * based on code from Xtreme Media Player */ /** * The Class RoundRectButtonShaper. */ public class RoundRectButtonShaper extends ButtonShaper { /* (non-Javadoc) * @see org.jvnet.substance.shaper.SubstanceButtonShaper#getDisplayName() */ @Override public String getDisplayName() { return "RoundRect"; } /* (non-Javadoc) * @see org.jvnet.substance.shaper.SubstanceButtonShaper#getButtonOutline(javax.swing.AbstractButton, java.awt.Insets, int, int, boolean) */ @Override public Shape getButtonOutline(AbstractButton button, Insets insets, int w, int h, boolean isInner) { int width = w - 1; int height = h - 1; Shape shape = new RoundRectangle2D.Double(0, 0, width, height, width / 3d, height / 3d); GeneralPath generalPath = new GeneralPath(shape); return generalPath; } }jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/substance/LeftConcaveButtonShaper.java0000644000175000017500000000433011720500104030002 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.substance; import java.awt.Insets; import java.awt.Shape; import java.awt.geom.Area; import java.awt.geom.Ellipse2D; import java.awt.geom.GeneralPath; import java.awt.geom.RoundRectangle2D; import javax.swing.AbstractButton; /* * based on code from Xtreme Media Player */ /** * The Class LeftConcaveButtonShaper. */ public class LeftConcaveButtonShaper extends ButtonShaper { /** DOCUMENT_ME. */ private int concaveDiameter; /** * Instantiates a new left concave button shaper. * * @param concaveDiameter DOCUMENT_ME */ public LeftConcaveButtonShaper(int concaveDiameter) { super(); this.concaveDiameter = concaveDiameter; } /* (non-Javadoc) * @see org.jvnet.substance.shaper.SubstanceButtonShaper#getDisplayName() */ @Override public String getDisplayName() { return "LeftConcave"; } /* (non-Javadoc) * @see org.jvnet.substance.shaper.SubstanceButtonShaper#getButtonOutline(javax.swing.AbstractButton, java.awt.Insets, int, int, boolean) */ @Override public Shape getButtonOutline(AbstractButton button, Insets insets, int w, int h, boolean isInner) { int width = w - 1; int height = h - 1; int z = concaveDiameter / 3; Shape shape = new Ellipse2D.Double(0, 0, z, height); Area area = new Area(new RoundRectangle2D.Double(z / 2d, 0, width - z, height, z, z)); area.subtract(new Area(shape)); return new GeneralPath(area); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/substance/CircleButtonShaper.java0000644000175000017500000000337411720500104027021 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.substance; import java.awt.Insets; import java.awt.Shape; import java.awt.geom.Ellipse2D; import java.awt.geom.GeneralPath; import javax.swing.AbstractButton; /* * based on code from Xtreme Media Player */ /** * The Class CircleButtonShaper. */ public class CircleButtonShaper extends ButtonShaper { /* (non-Javadoc) * @see org.jvnet.substance.shaper.SubstanceButtonShaper#getDisplayName() */ @Override public String getDisplayName() { return "Circle"; } /* (non-Javadoc) * @see org.jvnet.substance.shaper.SubstanceButtonShaper#getButtonOutline(javax.swing.AbstractButton, java.awt.Insets, int, int, boolean) */ @Override public Shape getButtonOutline(AbstractButton button, Insets insets, int w, int h, boolean isInner) { int width = w - 1; int height = h - 1; Shape shape = new Ellipse2D.Double(0, 0, width, height); GeneralPath generalPath = new GeneralPath(shape); return generalPath; } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/substance/ButtonShaper.java0000644000175000017500000000742411720500104025677 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.substance; import java.awt.Component; import java.awt.Dimension; import java.awt.Insets; import java.awt.Shape; import java.awt.geom.GeneralPath; import javax.swing.AbstractButton; import javax.swing.border.Border; import org.jvnet.substance.SubstanceButtonUI; import org.jvnet.substance.shaper.StandardButtonShaper; import org.jvnet.substance.shaper.SubstanceButtonShaper; import org.jvnet.substance.utils.border.SubstanceButtonBorder; /* * based on code from Xtreme Media Player */ /** * The Class ButtonShaper. */ public abstract class ButtonShaper implements SubstanceButtonShaper { /* (non-Javadoc) * @see org.jvnet.substance.shaper.SubstanceButtonShaper#getButtonOutline(javax.swing.AbstractButton) */ @Override public Shape getButtonOutline(AbstractButton button) { return getButtonOutline(button, null, button.getWidth(), button.getHeight(), true); } /* (non-Javadoc) * @see org.jvnet.substance.shaper.SubstanceButtonShaper#getButtonOutline(javax.swing.AbstractButton, java.awt.Insets) */ @Override public GeneralPath getButtonOutline(AbstractButton button, Insets insets) { throw new UnsupportedOperationException(); } /* (non-Javadoc) * @see org.jvnet.substance.shaper.SubstanceButtonShaper#getButtonOutline(javax.swing.AbstractButton, java.awt.Insets, int, int) */ @Override public GeneralPath getButtonOutline(AbstractButton button, Insets insets, int width, int height) { throw new UnsupportedOperationException(); } /* (non-Javadoc) * @see org.jvnet.substance.shaper.SubstanceButtonShaper#getPreferredSize(javax.swing.AbstractButton, java.awt.Dimension) */ @Override public Dimension getPreferredSize(AbstractButton button, Dimension uiPreferredSize) { if (button.getClientProperty(SubstanceButtonUI.BORDER_COMPUTED) == null) { boolean isBorderComputing = (button.getClientProperty(SubstanceButtonUI.BORDER_COMPUTING) != null); Border border = button.getBorder(); int uiw = uiPreferredSize.width; int uih = uiPreferredSize.height; Insets bi = border.getBorderInsets(button); if (!isBorderComputing) { button.setBorder(null); } uiPreferredSize.setSize(uiw - bi.left - bi.right, uih - bi.top - bi.bottom); if (!isBorderComputing) { button.setBorder(this.getButtonBorder(button)); button.putClientProperty(SubstanceButtonUI.BORDER_COMPUTED, ""); } } return uiPreferredSize; } /* (non-Javadoc) * @see org.jvnet.substance.shaper.SubstanceButtonShaper#getButtonBorder(javax.swing.AbstractButton) */ @Override public Border getButtonBorder(AbstractButton button) { return new SubstanceButtonBorder(StandardButtonShaper.class) { @Override public Insets getBorderInsets(Component c) { return new Insets(0, 0, 0, 0); } }; } /* (non-Javadoc) * @see org.jvnet.substance.shaper.SubstanceButtonShaper#isProportionate() */ @Override public boolean isProportionate() { return true; } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/wizard/0000755000175000017500000000000011720500104021720 5ustar drazzibdrazzibjajuk-1.9.6.orig/src/main/java/org/jajuk/ui/wizard/AmbienceWizard.java0000644000175000017500000003366711720500104025466 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.wizard; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; import javax.swing.ButtonGroup; import javax.swing.JButton; import javax.swing.JComponent; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JRadioButton; import javax.swing.JScrollPane; import javax.swing.JTextField; import javax.swing.event.CaretEvent; import javax.swing.event.CaretListener; import net.miginfocom.swing.MigLayout; import org.jajuk.base.Genre; import org.jajuk.events.JajukEvent; import org.jajuk.events.JajukEvents; import org.jajuk.events.ObservationManager; import org.jajuk.services.dj.Ambience; import org.jajuk.services.dj.AmbienceDigitalDJ; import org.jajuk.services.dj.AmbienceManager; import org.jajuk.ui.helpers.FontManager; import org.jajuk.ui.helpers.FontManager.JajukFont; import org.jajuk.ui.windows.JajukMainWindow; import org.jajuk.util.Conf; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; import org.jajuk.util.LocaleManager; import org.jajuk.util.Messages; import org.jajuk.util.log.Log; import org.qdwizard.Screen; import org.qdwizard.Wizard; /** * Ambiences management wizard. */ public class AmbienceWizard extends Wizard { /** * DOCUMENT_ME. */ public static class AmbiencePanel extends Screen implements ActionListener { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** All dynamic widgets. */ private JComponent[][] widgets; /** DOCUMENT_ME. */ private JButton jbNew; /** DOCUMENT_ME. */ private JButton jbDelete; /** DOCUMENT_ME. */ private JButton jbDefaults; /** DJ*. */ private AmbienceDigitalDJ dj = null; /** Selected ambience index. */ private int ambienceIndex = 0; /* * (non-Javadoc) * * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent) */ @Override public void actionPerformed(final ActionEvent ae) { if (ae.getSource() == jbNew) { // create a void ambience AmbienceWizard.ambiences.add(new Ambience(Long.toString(System.currentTimeMillis()), "")); Collections.sort(AmbienceWizard.ambiences); // refresh screen refreshScreen(); // select new row final JRadioButton jrb = (JRadioButton) widgets[AmbienceWizard.ambiences.size() - 1][0]; jrb.setSelected(true); ambienceIndex = AmbienceWizard.ambiences.size() - 1; setProblem(Messages.getString("DigitalDJWizard.39")); jbNew.setEnabled(false); jbDelete.setEnabled(true); final JTextField jtf = (JTextField) widgets[ambienceIndex][1]; jtf.requestFocusInWindow(); } else if (ae.getSource() == jbDelete) { final Ambience ambience = AmbienceWizard.ambiences.get(ambienceIndex); AmbienceWizard.ambiences.remove(ambience); AmbienceManager.getInstance().removeAmbience(ambience.getID()); if (AmbienceManager.getInstance().getAmbiences().size() == 0) { jbDelete.setEnabled(false); } if (ambienceIndex > 0) { ambienceIndex--; final JRadioButton jrb = (JRadioButton) widgets[ambienceIndex][0]; jrb.setSelected(true); } // refresh screen refreshScreen(); } else if (ae.getSource() == jbDefaults) { AmbienceManager.getInstance().createDefaultAmbiences(); AmbienceWizard.ambiences = new ArrayList(AmbienceManager.getInstance() .getAmbiences()); Collections.sort(AmbienceWizard.ambiences); // refresh screen refreshScreen(); } // in all cases, notify command panel ObservationManager.notify(new JajukEvent(JajukEvents.AMBIENCES_CHANGE)); } /** * Add a genre to a proportion. * * @param row row */ private void addGenre(final int row) { final Ambience ambience = AmbienceWizard.ambiences.get(row); // create list of genres used in current selection final GenresSelectionDialog dialog = new GenresSelectionDialog(null); dialog.setSelection(ambience.getGenres()); dialog.setVisible(true); final Set genres = dialog.getSelectedGenres(); // check if at least one genre has been selected if (genres.size() == 0) { return; } StringBuilder sText = new StringBuilder(); // reset old genres ambience.setGenres(new HashSet(10)); for (final Genre genre : genres) { ambience.addGenre(genre); sText.append(genre.getName2()).append(','); } sText.deleteCharAt(sText.length() - 1); // Set button text ((JButton) widgets[row][2]).setText(sText.toString()); // if we have ambience name and some genres, register the // ambience if ((ambience.getName().length() > 0) && (ambience.getGenres().size() > 0)) { // no more error message if at least one ambience setProblem(null); jbNew.setEnabled(true); } } /* (non-Javadoc) * @see org.qdwizard.Screen#getDescription() */ @Override public String getDescription() { return Messages.getString("DigitalDJWizard.47"); } /* (non-Javadoc) * @see org.qdwizard.Screen#getName() */ @Override public String getName() { return Messages.getString("DigitalDJWizard.57"); } /** * Gets the panel. * * @return a panel containing all items */ private JScrollPane getPanel() { widgets = new JComponent[AmbienceWizard.ambiences.size()][3]; final JPanel out = new JPanel(); // Delete|Genre name|genres list final ButtonGroup group = new ButtonGroup(); // now add all ambiences for (int index = 0; index < AmbienceWizard.ambiences.size(); index++) { // Ambience name final JTextField jtfName = new JTextField(); jtfName.setText(AmbienceWizard.ambiences.get(index).getName()); jtfName.addCaretListener(new CaretListener() { @Override public void caretUpdate(final CaretEvent arg0) { final int index = AmbienceWizard.getWidgetIndex(widgets, (JComponent) arg0.getSource()); final String s = jtfName.getText(); // Check this name is not already token for (int i = 0; i < widgets.length; i++) { if (i == index) { continue; } final JTextField jtf = (JTextField) widgets[i][1]; if (jtf.getText().equals(s)) { setProblem(Messages.getString("DigitalDJWizard.60")); return; } } // reset previous problems if ((s.length() == 0) || (((JButton) widgets[index][2]).getText().length() == 0)) { setProblem(Messages.getString("DigitalDJWizard.39")); } else { setProblem(null); } final JButton jb = (JButton) widgets[index][2]; final Ambience ambience = AmbienceWizard.ambiences.get(index); ambience.setName(s); jb.setEnabled(s.length() > 0); } }); jtfName.setToolTipText(Messages.getString("DigitalDJWizard.36")); widgets[index][1] = jtfName; // radio button final JRadioButton jrbAmbience = new JRadioButton(); group.add(jrbAmbience); jrbAmbience.addActionListener(new ActionListener() { @Override public void actionPerformed(final ActionEvent ae) { ((JTextField) widgets[AmbienceWizard.getWidgetIndex(widgets, jrbAmbience)][1]) .getText(); ambienceIndex = AmbienceWizard.getWidgetIndex(widgets, jrbAmbience); } }); widgets[index][0] = jrbAmbience; if (index == ambienceIndex) { jrbAmbience.setSelected(true); } final Ambience ambience = AmbienceWizard.ambiences.get(index); // genre list final JButton jbGenre = new JButton(IconLoader.getIcon(JajukIcons.GENRE)); if (ambience.getName().length() == 0) { jbGenre.setEnabled(false); } if ((ambience.getGenres() != null) && (ambience.getGenres().size() > 0)) { jbGenre.setText(ambience.getGenresDesc()); jbGenre.setToolTipText(ambience.getGenresDesc()); } jbGenre.addActionListener(new ActionListener() { @Override public void actionPerformed(final ActionEvent ae) { final int row = AmbienceWizard.getWidgetIndex(widgets, (JComponent) ae.getSource()); addGenre(row); // refresh ambience (force an action event) final JRadioButton jrb = (JRadioButton) widgets[row][0]; jrb.doClick(); } }); jbGenre.setToolTipText(Messages.getString("DigitalDJWizard.27")); widgets[index][2] = jbGenre; } // Create layout out.setLayout(new MigLayout("insets 5,gapx 5", "[][][grow]")); // Create header final JLabel jlHeader1 = new JLabel(Messages.getString("DigitalDJWizard.37")); jlHeader1.setFont(FontManager.getInstance().getFont(JajukFont.BOLD)); final JLabel jlHeader2 = new JLabel(Messages.getString("DigitalDJWizard.27")); jlHeader2.setFont(FontManager.getInstance().getFont(JajukFont.BOLD)); out.add(jlHeader1, "center,span 2"); out.add(jlHeader2, "center,wrap"); // Add widgets for (int i = 0; i < widgets.length; i++) { out.add(widgets[i][0], "grow,center,width 25!"); out.add(widgets[i][1], "grow,center,width 120!"); out.add(widgets[i][2], "center,grow,wrap,width 270:270"); } final JScrollPane jsp = new JScrollPane(out); // select first ambiance found if (AmbienceWizard.ambiences.size() > 0) { final JRadioButton jrb = (JRadioButton) widgets[0][0]; jrb.doClick(); } return jsp; } /** * Create panel UI. */ @Override public void initUI() { AmbienceWizard.ambiences = new ArrayList(AmbienceManager.getInstance() .getAmbiences()); Collections.sort(AmbienceWizard.ambiences); setCanFinish(true); jbNew = new JButton(Messages.getString("DigitalDJWizard.32"), IconLoader .getIcon(JajukIcons.NEW)); jbNew.addActionListener(this); jbNew.setToolTipText(Messages.getString("DigitalDJWizard.33")); jbDelete = new JButton(Messages.getString("DigitalDJWizard.34"), IconLoader .getIcon(JajukIcons.DELETE)); jbDelete.addActionListener(this); jbDelete.setToolTipText(Messages.getString("DigitalDJWizard.35")); jbDefaults = new JButton(Messages.getString("DigitalDJWizard.62"), IconLoader .getIcon(JajukIcons.DEFAULTS)); jbDefaults.addActionListener(this); jbDefaults.setToolTipText(Messages.getString("DigitalDJWizard.63")); // Add items refreshScreen(); } /** * Refresh panel. */ private void refreshScreen() { setLayout(new MigLayout("insets 5,gapy 15", "[center,grow]")); removeAll(); // refresh panel add(getPanel(), "grow,wrap"); add(jbNew, "split 3"); add(jbDelete); add(jbDefaults); revalidate(); repaint(); } } /** Ambiences*. */ static List ambiences; /** * Gets the widget index. * * @param widgets DOCUMENT_ME * @param widget DOCUMENT_ME * @return index of a given widget row in the widget table */ private static int getWidgetIndex(final JComponent[][] widgets, final JComponent widget) { for (int row = 0; row < widgets.length; row++) { for (int col = 0; col < widgets[0].length; col++) { if (widget.equals(widgets[row][col])) { return row; } } } return -1; } /** * Instantiates a new ambience wizard. */ public AmbienceWizard() { super(Messages.getString("DigitalDJWizard.56"), AmbiencePanel.class, null, JajukMainWindow .getInstance(), LocaleManager.getLocale(), 500, 600); setHeaderIcon(IconLoader.getIcon(JajukIcons.AMBIENCE)); } /* * (non-Javadoc) * * @see org.jajuk.ui.wizard.Wizard#finish() */ @Override public void finish() { for (final Ambience ambience : AmbienceWizard.ambiences) { AmbienceManager.getInstance().registerAmbience(ambience); } // commit it to avoid it is lost before the app close AmbienceManager.getInstance().commit(); try { Conf.commit(); } catch (final Exception e) { Log.error(113, e); Messages.showErrorMessage(113); } // Refresh UI ObservationManager.notify(new JajukEvent(JajukEvents.AMBIENCES_CHANGE)); } /* * (non-Javadoc) * * @see org.jajuk.ui.wizard.Wizard#getNextScreen(java.lang.Class) */ @Override public Class getNextScreen( final Class screen) { return null; } /* * (non-Javadoc) * * @see org.jajuk.ui.wizard.Wizard#getPreviousScreen(java.lang.Class) */ @Override public Class getPreviousScreen( final Class screen) { return null; } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/wizard/TipOfTheDayWizard.java0000644000175000017500000001453511720500104026074 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.wizard; import java.awt.BorderLayout; import java.awt.Dimension; import java.awt.FlowLayout; import java.awt.Font; import java.awt.Insets; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.BorderFactory; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTextArea; import javax.swing.SwingConstants; import org.jajuk.util.Conf; import org.jajuk.util.Const; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; import org.jajuk.util.UtilGUI; import org.jajuk.util.UtilSystem; /** * Small dialog which displays the "Tip of the Day" from a list of useful hints. */ public class TipOfTheDayWizard extends JFrame { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** The Constant TIPS. DOCUMENT_ME */ private static final String[] TIPS = Messages.getAll("TipOfTheDay"); /** DOCUMENT_ME. */ private final JCheckBox cbShow; /** DOCUMENT_ME. */ private final JTextArea tipArea; /** DOCUMENT_ME. */ private final JLabel lCounter; /** DOCUMENT_ME. */ private int currentIndex = 0; /** * Instantiates a new tip of the day wizard. */ public TipOfTheDayWizard() { super(Messages.getString("TipOfTheDayView.0")); setAlwaysOnTop(true); setIconImage(IconLoader.getIcon(JajukIcons.LOGO).getImage()); cbShow = new JCheckBox(Messages.getString("TipOfTheDayView.2")); cbShow.setSelected(Conf.getBoolean(Const.CONF_SHOW_TIP_ON_STARTUP)); tipArea = new JTextArea(); tipArea.setWrapStyleWord(true); tipArea.setLineWrap(true); tipArea.setEditable(false); lCounter = new JLabel("999/999"); JButton bNext = new JButton(IconLoader.getIcon(JajukIcons.PLAYER_NEXT_SMALL)); bNext.setMargin(new Insets(1, 1, 1, 1)); bNext.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent actionevent) { incIndex(); updateTip(); } }); JButton bPrevious = new JButton(IconLoader.getIcon(JajukIcons.PLAYER_PREVIOUS_SMALL)); bPrevious.setMargin(new Insets(1, 1, 1, 1)); bPrevious.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent actionevent) { decIndex(); updateTip(); } }); JButton bClose = new JButton(IconLoader.getIcon(JajukIcons.OK)); bClose.setMaximumSize(bClose.getPreferredSize()); bClose.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent actionevent) { setVisible(false); } }); JScrollPane scroll = new JScrollPane(tipArea); scroll.setPreferredSize(new Dimension(200, 100)); JLabel lTitle = new JLabel(Messages.getString("TipOfTheDayView.1"), SwingConstants.LEFT); Font fTitle = lTitle.getFont(); lTitle.setFont(new Font(fTitle.getName(), fTitle.getStyle(), (int) (fTitle.getSize() * 1.3))); JLabel lIcon = new JLabel(IconLoader.getIcon(JajukIcons.TIP), SwingConstants.LEFT); JPanel pTop = new JPanel(new BorderLayout()); pTop.add(lIcon, BorderLayout.WEST); pTop.add(lTitle, BorderLayout.CENTER); UtilGUI.setEscapeKeyboardAction(this, pTop); JPanel pCenter = new JPanel(new BorderLayout()); pCenter.setBorder(BorderFactory.createEmptyBorder(10, 10, 3, 10)); pCenter.add(scroll, BorderLayout.CENTER); UtilGUI.setEscapeKeyboardAction(this, pCenter); JPanel pPrevNext = new JPanel(new FlowLayout(FlowLayout.RIGHT, 10, 10)); pPrevNext.add(bPrevious); pPrevNext.add(lCounter); pPrevNext.add(bNext); JPanel pControls = new JPanel(new BorderLayout()); pControls.setBorder(BorderFactory.createEmptyBorder(0, 20, 0, 0)); pControls.add(cbShow, BorderLayout.WEST); pControls.add(pPrevNext); JPanel pButton = new JPanel(new FlowLayout(FlowLayout.RIGHT)); pButton.add(bClose); JPanel pBottom = new JPanel(new BorderLayout()); pBottom.add(pControls, BorderLayout.NORTH); pBottom.add(pButton); UtilGUI.setEscapeKeyboardAction(this, pBottom); add(pTop, BorderLayout.NORTH); add(pCenter, BorderLayout.CENTER); add(pBottom, BorderLayout.SOUTH); // Display a shuffled tip of the day shuffleIndex(); updateTip(); pack(); if (getWidth() < 400) { setSize(400, getHeight()); } } /** * Show random TOTD. */ private void shuffleIndex() { currentIndex = (int) (UtilSystem.getRandom().nextFloat() * (TIPS.length - 1)); } /** * Increment the TOTD index. */ private void incIndex() { currentIndex = (currentIndex + 1) % TIPS.length; } /** * Decrement the TOTD index. */ private void decIndex() { if (currentIndex == 0) { currentIndex = TIPS.length - 1; } else { currentIndex--; } } /** * Update the TOTD with index from Conf. */ private final void updateTip() { tipArea.setText(TIPS[currentIndex]); lCounter.setText(new StringBuilder().append("").append(currentIndex + 1).append("/").append( TIPS.length).toString()); tipArea.setCaretPosition(0); } /* * (non-Javadoc) * * @see java.awt.Window#setVisible(boolean) */ @Override public void setVisible(boolean flag) { super.setVisible(flag); if (flag) { toFront(); } else { // Called when closing the window, inc the totd index for next display Conf.setProperty(Const.CONF_SHOW_TIP_ON_STARTUP, String.valueOf(cbShow.isSelected())); } } }jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/wizard/package.html0000644000175000017500000000007511720500104024203 0ustar drazzibdrazzib

    Wizard and dialogs

    jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/wizard/DigitalDJWizard.java0000644000175000017500000014406611720500104025552 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.wizard; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.IOException; import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; import javax.swing.ButtonGroup; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JComponent; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JRadioButton; import javax.swing.JScrollPane; import javax.swing.JSlider; import javax.swing.JSpinner; import javax.swing.JTextField; import javax.swing.SpinnerNumberModel; import javax.swing.border.BevelBorder; import javax.swing.event.CaretEvent; import javax.swing.event.CaretListener; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import net.miginfocom.swing.MigLayout; import org.jajuk.base.Genre; import org.jajuk.base.GenreManager; import org.jajuk.events.JajukEvent; import org.jajuk.events.JajukEvents; import org.jajuk.events.ObservationManager; import org.jajuk.services.dj.Ambience; import org.jajuk.services.dj.AmbienceDigitalDJ; import org.jajuk.services.dj.AmbienceManager; import org.jajuk.services.dj.DigitalDJ; import org.jajuk.services.dj.DigitalDJManager; import org.jajuk.services.dj.Proportion; import org.jajuk.services.dj.ProportionDigitalDJ; import org.jajuk.services.dj.Transition; import org.jajuk.services.dj.TransitionDigitalDJ; import org.jajuk.ui.helpers.DefaultMouseWheelListener; import org.jajuk.ui.helpers.FontManager; import org.jajuk.ui.helpers.FontManager.JajukFont; import org.jajuk.ui.windows.JajukMainWindow; import org.jajuk.util.Conf; import org.jajuk.util.Const; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; import org.jajuk.util.LocaleManager; import org.jajuk.util.Messages; import org.jajuk.util.log.Log; import org.qdwizard.ClearPoint; import org.qdwizard.Screen; import org.qdwizard.Wizard; /** * DJ creation wizard. */ public class DigitalDJWizard extends Wizard { /** Wizard action. */ private static final String KEY_ACTION = "ACTION"; /** DJ type variable name. */ private static final String KEY_DJ_TYPE = "TYPE"; /** DJ name variable name. */ private static final String KEY_DJ_NAME = "NAME"; /** Track unicity. */ private static final String KEY_UNICITY = "UNICITY"; /** Ratings level. */ private static final String KEY_RATINGS_LEVEL = "RATING_LEVEL"; /** Fade duration. */ private static final String KEY_FADE_DURATION = "FADE_DURATION"; /** Transitions. */ private static final String KEY_TRANSITIONS = "TRANSITIONS"; /** Proportions. */ private static final String KEY_PROPORTIONS = "PROPORTIONS"; /** Ambience. */ private static final String KEY_AMBIENCE = "AMBIENCE"; /** DJ to remove. */ private static final String KEY_REMOVE = "REMOVE"; /** DJ to change. */ private static final String KEY_CHANGE = "CHANGE"; /** Max number of tracks to queue. */ private static final String KEY_MAX_TRACKS = "MAXTRACKS"; /** * DJ type choice. */ public static class TypeSelectionPanel extends Screen implements ActionListener { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** Transition DJ code. */ private static final String DJ_TYPE_TRANSITION = "0"; /** Proportions DJ code. */ private static final String DJ_TYPE_PROPORTION = "1"; /** Ambience DJ code. */ private static final String DJ_TYPE_AMBIENCE = "2"; /** DOCUMENT_ME. */ ButtonGroup bgTypes; /** DOCUMENT_ME. */ JRadioButton jrbTransitions; /** DOCUMENT_ME. */ JRadioButton jrbProp; /** DOCUMENT_ME. */ JRadioButton jrbAmbiance; /** * Create panel UI. */ @Override public void initUI() { setLayout(new MigLayout("insets 10,gapx 10,gapy 15")); bgTypes = new ButtonGroup(); jrbTransitions = new JRadioButton(Messages.getString("DigitalDJWizard.1")); jrbTransitions.addActionListener(this); jrbTransitions.doClick(); // default selection jrbProp = new JRadioButton(Messages.getString("DigitalDJWizard.2")); jrbProp.addActionListener(this); jrbAmbiance = new JRadioButton(Messages.getString("DigitalDJWizard.3")); jrbAmbiance.addActionListener(this); // can select ambience DJ only if at least one ambience defined jrbAmbiance.setEnabled(AmbienceManager.getInstance().getAmbiences().size() > 0); bgTypes.add(jrbProp); bgTypes.add(jrbTransitions); bgTypes.add(jrbAmbiance); add(jrbTransitions, "left,wrap"); add(jrbProp, "left,wrap"); add(jrbAmbiance, "left,wrap"); } /* * (non-Javadoc) * * @see * java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent) */ public void actionPerformed(ActionEvent e) { if (e.getSource() == jrbTransitions) { data.put(KEY_DJ_TYPE, DJ_TYPE_TRANSITION); } else if (e.getSource() == jrbProp) { data.put(KEY_DJ_TYPE, DJ_TYPE_PROPORTION); } else if (e.getSource() == jrbAmbiance) { data.put(KEY_DJ_TYPE, DJ_TYPE_AMBIENCE); } } /* (non-Javadoc) * @see org.qdwizard.Screen#getDescription() */ @Override public String getDescription() { return Messages.getString("DigitalDJWizard.0"); } /* (non-Javadoc) * @see org.qdwizard.Screen#getName() */ @Override public String getName() { return Messages.getString("DigitalDJWizard.46"); } } /** * DJ removal. */ public static class RemovePanel extends Screen implements ActionListener { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** DOCUMENT_ME. */ JComponent[][] widgets; /** DOCUMENT_ME. */ ButtonGroup bgDJS; /** DOCUMENT_ME. */ List djs; /** * Create panel UI. */ @Override public void initUI() { djs = new ArrayList(DigitalDJManager.getInstance().getDJs()); Collections.sort(djs); widgets = new JComponent[djs.size()][1]; // We use an inner panel for scrolling purpose JPanel jp = new JPanel(); jp.setLayout(new MigLayout("insets 0,gapx 0,gapy 10")); bgDJS = new ButtonGroup(); setCanFinish(true); int index = 0; for (DigitalDJ dj : djs) { JRadioButton jrb = new JRadioButton(dj.getName()); jrb.addActionListener(this); bgDJS.add(jrb); widgets[index][0] = jrb; jp.add(jrb, "left gap 5,wrap"); index++; } setProblem(Messages.getString("DigitalDJWizard.40")); // select first ambience found JRadioButton jrb = (JRadioButton) widgets[0][0]; jrb.doClick(); setLayout(new MigLayout("insets 10,gapx 5", "[grow]")); JScrollPane jsp = new JScrollPane(jp); jsp.setBorder(null); add(jsp, "grow"); } /* * (non-Javadoc) * * @see * java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent) */ public void actionPerformed(ActionEvent e) { int row = getWidgetIndex(widgets, (JComponent) e.getSource()); data.put(KEY_REMOVE, djs.get(row)); setProblem(null); } /* (non-Javadoc) * @see org.qdwizard.Screen#getDescription() */ @Override public String getDescription() { return Messages.getString("DigitalDJWizard.40"); } /* (non-Javadoc) * @see org.qdwizard.Screen#getName() */ @Override public String getName() { return Messages.getString("DigitalDJWizard.51"); } } /** * DJ Selection for change. */ public static class ChangePanel extends Screen implements ActionListener { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** DOCUMENT_ME. */ JComponent[][] widgets; /** DOCUMENT_ME. */ ButtonGroup bgDJS; /** DOCUMENT_ME. */ List djs; /** * Create panel UI. */ @Override public void initUI() { djs = DigitalDJManager.getInstance().getDJsSorted(); // We use an inner panel for scrolling purpose JPanel jp = new JPanel(); jp.setLayout(new MigLayout("insets 0,gapx 0,gapy 10")); widgets = new JComponent[djs.size()][1]; setLayout(new MigLayout("insets 10,gapx 10,gapy 15")); bgDJS = new ButtonGroup(); int index = 0; for (DigitalDJ dj : djs) { JRadioButton jrb = new JRadioButton(dj.getName()); jrb.addActionListener(this); bgDJS.add(jrb); widgets[index][0] = jrb; jp.add(jrb, "left gap 5,wrap"); index++; } // If more than one DJ, select first if (djs.size() > 0) { JRadioButton jrb = (JRadioButton) widgets[0][0]; jrb.doClick(); } else { setProblem(Messages.getString("DigitalDJWizard.40")); } setLayout(new MigLayout("insets 10,gapx 5", "[grow]")); JScrollPane jsp = new JScrollPane(jp); jsp.setBorder(null); add(jsp, "grow"); } /* * (non-Javadoc) * * @see * java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent) */ public void actionPerformed(ActionEvent e) { int row = getWidgetIndex(widgets, (JComponent) e.getSource()); // set DJ type useful for screen choice DigitalDJ dj = djs.get(row); data.put(KEY_CHANGE, dj); if (dj instanceof AmbienceDigitalDJ) { data.put(KEY_DJ_TYPE, TypeSelectionPanel.DJ_TYPE_AMBIENCE); } if (dj instanceof ProportionDigitalDJ) { data.put(KEY_DJ_TYPE, TypeSelectionPanel.DJ_TYPE_PROPORTION); } if (dj instanceof TransitionDigitalDJ) { data.put(KEY_DJ_TYPE, TypeSelectionPanel.DJ_TYPE_TRANSITION); } setProblem(null); } /* (non-Javadoc) * @see org.qdwizard.Screen#getDescription() */ @Override public String getDescription() { return Messages.getString("DigitalDJWizard.44"); } /* (non-Javadoc) * @see org.qdwizard.Screen#getName() */ @Override public String getName() { return Messages.getString("DigitalDJWizard.43"); } } /** * Action type (new or alter). */ public static class ActionSelectionPanel extends Screen implements ClearPoint, ActionListener { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** NEW code. */ public static final String ACTION_CREATION = "0"; /** CHANGE code. */ public static final String ACTION_CHANGE = "1"; /** DELETE code. */ public static final String ACTION_DELETE = "2"; /** DOCUMENT_ME. */ ButtonGroup bgActions; /** DOCUMENT_ME. */ JRadioButton jrbNew; /** DOCUMENT_ME. */ JRadioButton jrbChange; /** DOCUMENT_ME. */ JRadioButton jrbDelete; /** * Create panel UI. */ @Override public void initUI() { setLayout(new MigLayout("insets 10,gapx 10,gapy 15")); bgActions = new ButtonGroup(); jrbNew = new JRadioButton(Messages.getString("DigitalDJWizard.17")); jrbNew.addActionListener(this); jrbNew.doClick(); jrbChange = new JRadioButton(Messages.getString("DigitalDJWizard.18")); jrbChange.addActionListener(this); jrbDelete = new JRadioButton(Messages.getString("DigitalDJWizard.19")); jrbDelete.addActionListener(this); // disabled change and remove if none dj if (DigitalDJManager.getInstance().getDJs().size() == 0) { jrbChange.setEnabled(false); jrbDelete.setEnabled(false); } bgActions.add(jrbNew); bgActions.add(jrbChange); bgActions.add(jrbDelete); add(jrbNew, "left,wrap"); add(jrbChange, "left,wrap"); add(jrbDelete, "left,wrap"); } /* * (non-Javadoc) * * @see * java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent) */ public void actionPerformed(ActionEvent e) { if (e.getSource() == jrbNew) { data.put(KEY_ACTION, ACTION_CREATION); } else if (e.getSource() == jrbChange) { data.put(KEY_ACTION, ACTION_CHANGE); } else if (e.getSource() == jrbDelete) { data.put(KEY_ACTION, ACTION_DELETE); } } /* (non-Javadoc) * @see org.qdwizard.Screen#getDescription() */ @Override public String getDescription() { return Messages.getString("DigitalDJWizard.16"); } /* (non-Javadoc) * @see org.qdwizard.Screen#getName() */ @Override public String getName() { return Messages.getString("DigitalDJWizard.45"); } } /** * General options panel. */ public static class GeneralOptionsPanel extends Screen implements ActionListener, CaretListener, ChangeListener { /** The Constant NO_MAX_TRACKS. DOCUMENT_ME */ private static final String NO_MAX_TRACKS = " "; /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** DOCUMENT_ME. */ JLabel jlName; /** DOCUMENT_ME. */ JTextField jtfName; /** DOCUMENT_ME. */ JLabel jlRatingLevel; /** DOCUMENT_ME. */ JSlider jsRatingLevel; /** DOCUMENT_ME. */ JLabel jlFadeDuration; /** DOCUMENT_ME. */ JSlider jsFadeDuration; /** DOCUMENT_ME. */ JCheckBox jcbMaxTracks; /** DOCUMENT_ME. */ JSlider jsMaxTracks; /** DOCUMENT_ME. */ JLabel jnMaxTracks; /** DOCUMENT_ME. */ JCheckBox jcbUnicity; /* (non-Javadoc) * @see org.qdwizard.Screen#getDescription() */ @Override public String getDescription() { return Messages.getString("DigitalDJWizard.49"); } /* (non-Javadoc) * @see org.qdwizard.Screen#getName() */ @Override public String getName() { return Messages.getString("DigitalDJWizard.48"); } /** * Create panel UI. */ @Override public void initUI() { if (ActionSelectionPanel.ACTION_CREATION.equals(data.get(KEY_ACTION))) { // default values data.put(KEY_FADE_DURATION, 10); data.put(KEY_RATINGS_LEVEL, 0); // all tracks by default data.put(KEY_UNICITY, false); data.put(KEY_MAX_TRACKS, -1); } else if (ActionSelectionPanel.ACTION_CHANGE.equals(data.get(KEY_ACTION))) { // keep existing DJ values DigitalDJ dj = (DigitalDJ) data.get(KEY_CHANGE); data.put(KEY_FADE_DURATION, dj.getFadingDuration()); data.put(KEY_RATINGS_LEVEL, dj.getRatingLevel()); data.put(KEY_UNICITY, dj.isTrackUnicity()); data.put(KEY_MAX_TRACKS, dj.getMaxTracks()); } jlName = new JLabel(Messages.getString("DigitalDJWizard.6")); jtfName = new JTextField(); jtfName.setToolTipText(Messages.getString("DigitalDJWizard.6")); jtfName.addCaretListener(this); jtfName.requestFocusInWindow(); jlRatingLevel = new JLabel(Messages.getString("DigitalDJWizard.8")); jlRatingLevel.setToolTipText(Messages.getString("DigitalDJWizard.53")); jsRatingLevel = new JSlider(0, 4, (Integer) data.get(KEY_RATINGS_LEVEL)); jsRatingLevel.setMajorTickSpacing(1); jsRatingLevel.setMinorTickSpacing(1); jsRatingLevel.setPaintTicks(true); jsRatingLevel.setSnapToTicks(true); jsRatingLevel.setPaintLabels(true); jsRatingLevel.setToolTipText(Messages.getString("DigitalDJWizard.53")); jsRatingLevel.addMouseWheelListener(new DefaultMouseWheelListener(jsRatingLevel)); jsRatingLevel.addChangeListener(this); jlFadeDuration = new JLabel(Messages.getString("DigitalDJWizard.9")); jlFadeDuration.setToolTipText(Messages.getString("DigitalDJWizard.54")); jsFadeDuration = new JSlider(0, 30, (Integer) data.get(KEY_FADE_DURATION)); jsFadeDuration.addMouseWheelListener(new DefaultMouseWheelListener(jsFadeDuration)); jsFadeDuration.addChangeListener(this); jsFadeDuration.setMajorTickSpacing(10); jsFadeDuration.setMinorTickSpacing(1); jsFadeDuration.setPaintTicks(true); jsFadeDuration.setPaintLabels(true); jsFadeDuration.setToolTipText(Messages.getString("DigitalDJWizard.54")); // CheckBox for enabling/disabling slider, jsMaxTrack int nMaxTracks = (Integer) data.get(KEY_MAX_TRACKS); jcbMaxTracks = new JCheckBox(Messages.getString("DigitalDJWizard.67"), nMaxTracks != -1); jcbMaxTracks.setToolTipText(Messages.getString("DigitalDJWizard.68")); // initialize the slider based if max track is enabled or not if (nMaxTracks != -1) { jsMaxTracks = new JSlider(0, 5000, nMaxTracks); jsMaxTracks.setEnabled(true); jnMaxTracks = new JLabel(Integer.toString(nMaxTracks)); } else { jsMaxTracks = new JSlider(0, 5000, 100); jsMaxTracks.setEnabled(false); jnMaxTracks = new JLabel(NO_MAX_TRACKS); } jnMaxTracks.setBorder(new BevelBorder(BevelBorder.LOWERED)); jsMaxTracks.addMouseWheelListener(new DefaultMouseWheelListener(jsMaxTracks)); jsMaxTracks.addChangeListener(this); jsMaxTracks.setMajorTickSpacing(100); jsMaxTracks.setMinorTickSpacing(10); jsMaxTracks.setPaintTicks(false); jsMaxTracks.setPaintLabels(false); jsMaxTracks.setToolTipText(Messages.getString("DigitalDJWizard.68")); // enable/disable slider depending on checkbox jcbMaxTracks.addActionListener(this); jcbUnicity = new JCheckBox(Messages.getString("DigitalDJWizard.10"), (Boolean) data .get(KEY_UNICITY)); jcbUnicity.setToolTipText(Messages.getString("DigitalDJWizard.55")); jcbUnicity.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent arg0) { data.put(KEY_UNICITY, jcbUnicity.isSelected()); } }); // DJ change, set default values if (ActionSelectionPanel.ACTION_CHANGE.equals(data.get(KEY_ACTION))) { DigitalDJ dj = (DigitalDJ) data.get(KEY_CHANGE); jtfName.setText(dj.getName()); jsFadeDuration.setValue((Integer) data.get(KEY_FADE_DURATION)); jsRatingLevel.setValue((Integer) data.get(KEY_RATINGS_LEVEL)); jcbUnicity.setSelected((Boolean) data.get(KEY_UNICITY)); if (((Integer) data.get(KEY_MAX_TRACKS)) != -1) { jsMaxTracks.setValue((Integer) data.get(KEY_MAX_TRACKS)); } else { jsMaxTracks.setValue(100); } } else { // new dj, dj name is required setProblem(Messages.getString("DigitalDJWizard.41")); } setLayout(new MigLayout("insets 10,gapx 10,gapy 15", "[][grow]")); add(jlName); add(jtfName, "grow,wrap"); add(jlRatingLevel); add(jsRatingLevel, "grow,wrap"); add(jlFadeDuration); add(jsFadeDuration, "grow,wrap"); add(jcbMaxTracks); { JPanel panel = new JPanel(); panel.setLayout(new MigLayout("", "[grow][]")); panel.add(jsMaxTracks, "grow"); panel.add(jnMaxTracks); add(panel, "grow,wrap"); } add(jcbUnicity, "wrap"); } /* * (non-Javadoc) * * @see * java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent) */ public void actionPerformed(ActionEvent ae) { if (ae.getSource() == jcbUnicity) { data.put(KEY_UNICITY, jcbUnicity.isSelected()); } else if (ae.getSource() == jcbMaxTracks) { jsMaxTracks.setEnabled(jcbMaxTracks.isSelected()); updateMaxTracks(); } } /* * (non-Javadoc) * * @see * javax.swing.event.CaretListener#caretUpdate(javax.swing.event.CaretEvent) */ public void caretUpdate(CaretEvent ce) { if (ce.getSource() == jtfName) { data.put(KEY_DJ_NAME, jtfName.getText()); String sName = jtfName.getText(); // string length = 0 if (sName.length() == 0) { setProblem(Messages.getString("DigitalDJWizard.41")); } // display an error message if the dj already exists and not in // "change" mode else if (DigitalDJManager.getInstance().getDJNames().contains(sName)) { // if we are in change mode and the name is still the // same, no error if (ActionSelectionPanel.ACTION_CHANGE.equals(data.get(KEY_ACTION)) && ((DigitalDJ) data.get(KEY_CHANGE)).getName().equals(sName)) { setProblem(null); return; } setProblem(Messages.getString("DigitalDJWizard.42")); } else { setProblem(null); // no more problem } } } /* * (non-Javadoc) * * @see * javax.swing.event.ChangeListener#stateChanged(javax.swing.event.ChangeEvent * ) */ public void stateChanged(ChangeEvent ie) { if (ie.getSource() == jsFadeDuration && !jsFadeDuration.getValueIsAdjusting()) { data.put(KEY_FADE_DURATION, jsFadeDuration.getValue()); } else if (ie.getSource() == jsRatingLevel && !jsRatingLevel.getValueIsAdjusting()) { data.put(KEY_RATINGS_LEVEL, jsRatingLevel.getValue()); } else if (ie.getSource() == jsMaxTracks) { updateMaxTracks(); } } /** * Update all items related to the Max Track feature. */ private void updateMaxTracks() { // store -1 if checkbox is not enabled and update the label accordingly if (jcbMaxTracks.isSelected()) { if (!jsMaxTracks.getValueIsAdjusting()) { data.put(KEY_MAX_TRACKS, jsMaxTracks.getValue()); } jnMaxTracks.setText(Integer.toString(jsMaxTracks.getValue())); } else { if (!jsMaxTracks.getValueIsAdjusting()) { data.put(KEY_MAX_TRACKS, -1); } jnMaxTracks.setText(NO_MAX_TRACKS); } } } /** * Transitions panel. */ public static class TransitionsPanel extends Screen { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** All dynamic widgets. */ JComponent[][] widgets; /** Transitions*. */ List alTransitions; /* (non-Javadoc) * @see org.qdwizard.Screen#getDescription() */ @Override public String getDescription() { return Messages.getString("DigitalDJWizard.52"); } /* (non-Javadoc) * @see org.qdwizard.Screen#getName() */ @Override public String getName() { return Messages.getString("DigitalDJWizard.20"); } /** * Gets the cleaned transitions. * * @return Filled transitions only */ private List getCleanedTransitions() { List out = new ArrayList(alTransitions.size()); for (Transition transition : alTransitions) { if (transition.getFrom() != null && transition.getTo() != null && transition.getFrom().getGenres().size() > 0 && transition.getTo().getGenres().size() > 0) { out.add(transition); } } return out; } /** * Create panel UI. */ @Override @SuppressWarnings("unchecked") public void initUI() { if (ActionSelectionPanel.ACTION_CHANGE.equals(data.get(KEY_ACTION))) { TransitionDigitalDJ dj = (TransitionDigitalDJ) data.get(KEY_CHANGE); alTransitions = (List) ((ArrayList) dj.getTransitions()).clone(); data.put(KEY_TRANSITIONS, getCleanedTransitions()); // add a void transition alTransitions.add(new Transition(Const.DEFAULT_TRANSITION_TRACK_NUMBER)); } else { // DJ creation alTransitions = new ArrayList(10); // add a void transition alTransitions.add(new Transition(Const.DEFAULT_TRANSITION_TRACK_NUMBER)); setProblem(Messages.getString("DigitalDJWizard.26")); } setCanFinish(true); // set layout setLayout(new MigLayout("insets 10,gapx 5", "[grow]")); add(getTransitionsPanel(), "grow"); } /** * Gets the transitions panel. * * @return a panel containing all transitions */ private JScrollPane getTransitionsPanel() { widgets = new JComponent[alTransitions.size()][4]; JPanel out = new JPanel(); // Delete|FROM list| To list|nb tracks // now add all known transitions for (int index = 0; index < alTransitions.size(); index++) { // Delete button JButton jbDelete = new JButton(IconLoader.getIcon(JajukIcons.DELETE)); jbDelete.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent ae) { alTransitions.remove(getWidgetIndex(widgets, (JComponent) ae.getSource())); refreshScreen(); data.put(KEY_TRANSITIONS, getCleanedTransitions()); } }); // cannot delete if void selection if (alTransitions.size() == 1) { jbDelete.setEnabled(false); } jbDelete.setToolTipText(Messages.getString("DigitalDJWizard.21")); widgets[index][0] = jbDelete; // From genre list JButton jbFrom = new JButton(IconLoader.getIcon(JajukIcons.LIST)); Transition transition = alTransitions.get(index); if (transition.getFrom().getGenres().size() > 0) { jbFrom.setText(transition.getFromString()); jbFrom.setToolTipText(transition.getFromString()); } jbFrom.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent ae) { int row = getWidgetIndex(widgets, (JComponent) ae.getSource()); addGenre(row, true); } }); jbFrom.setToolTipText(Messages.getString("DigitalDJWizard.22")); widgets[index][1] = jbFrom; // To genre list JButton jbTo = new JButton(IconLoader.getIcon(JajukIcons.LIST)); if (transition.getTo().getGenres().size() > 0) { jbTo.setText(transition.getToString()); jbTo.setToolTipText(transition.getToString()); } jbTo.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent ae) { int row = getWidgetIndex(widgets, (JComponent) ae.getSource()); addGenre(row, false); } }); jbTo.setToolTipText(Messages.getString("DigitalDJWizard.23")); widgets[index][2] = jbTo; // Nb of tracks JSpinner jsNb = new JSpinner(new SpinnerNumberModel(transition.getNbTracks(), 1, 10, 1)); jsNb.addChangeListener(new ChangeListener() { public void stateChanged(ChangeEvent ce) { int row = getWidgetIndex(widgets, (JComponent) ce.getSource()); int nb = Integer.parseInt(((JSpinner) ce.getSource()).getValue().toString()); Transition transition = alTransitions.get(row); transition.setNb(nb); } }); jsNb.setToolTipText(Messages.getString("DigitalDJWizard.24")); widgets[index][3] = jsNb; } // Create layout out.setLayout(new MigLayout("insets 5,gapx 10,gapy 10", "[][270!][270!][]")); // Create header JLabel jlHeader2 = new JLabel(Messages.getString("DigitalDJWizard.22")); jlHeader2.setFont(FontManager.getInstance().getFont(JajukFont.BOLD)); JLabel jlHeader3 = new JLabel(Messages.getString("DigitalDJWizard.23")); jlHeader3.setFont(FontManager.getInstance().getFont(JajukFont.BOLD)); JLabel jlHeader4 = new JLabel(Messages.getString("DigitalDJWizard.24")); jlHeader4.setFont(FontManager.getInstance().getFont(JajukFont.BOLD)); out.add(jlHeader2, "cell 1 0, center"); out.add(jlHeader3, "cell 2 0,center"); out.add(jlHeader4, "cell 3 0,center,wrap"); // Add widgets for (int i = 0; i < widgets.length; i++) { out.add(widgets[i][0]); out.add(widgets[i][1], "grow,width ::270"); out.add(widgets[i][2], "grow,width ::270"); out.add(widgets[i][3], "grow,center,wrap"); } JScrollPane jsp = new JScrollPane(out); jsp.setBorder(null); return jsp; } /** * Add a genre to a transition. * * @param row row * @param bFrom is it a from button ? */ private void addGenre(int row, boolean bFrom) { synchronized (GenreManager.getInstance()) { Transition transition = alTransitions.get(row); // create list of genres used in existing transitions Set disabledGenres = new HashSet(); for (int i = 0; i < alTransitions.size(); i++) { Transition t = alTransitions.get(i); // ignore all genres expect those from current button if (bFrom && i != row) { disabledGenres.addAll(t.getFrom().getGenres()); } } GenresSelectionDialog dialog = new GenresSelectionDialog(disabledGenres); if (bFrom) { dialog.setSelection(transition.getFrom().getGenres()); } else { dialog.setSelection(transition.getTo().getGenres()); } dialog.setVisible(true); Set genres = dialog.getSelectedGenres(); // check if at least one genre has been selected if (genres.size() == 0) { return; } String sText = ""; for (Genre genre : genres) { sText += genre.getName2() + ','; } sText = sText.substring(0, sText.length() - 1); int nb = Integer.parseInt(((JSpinner) widgets[row][3]).getValue().toString()); // Set button text if (bFrom) { ((JButton) widgets[row][1]).setText(sText); } else { ((JButton) widgets[row][2]).setText(sText); } // set selected genre in transition object if (bFrom) { transition.setFrom(new Ambience(Long.toString(System.currentTimeMillis()), "", genres)); } else { transition.setTo(new Ambience(Long.toString(System.currentTimeMillis()), "", genres)); } // check if the transaction is fully selected now if (transition.getFrom().getGenres().size() > 0 && transition.getTo().getGenres().size() > 0) { // Make sure current delete button is now enabled ((JButton) widgets[row][0]).setEnabled(true); // Reset wizard error message setProblem(null); // Fill wizard data data.put(KEY_TRANSITIONS, getCleanedTransitions()); // create a new void proportion if needed if (!containsVoidItem()) { // we duplicate the nb for new row alTransitions.add(new Transition(nb)); } // Refresh screen to add a new void row refreshScreen(); } } } /** * Contains void item. * * @return whether a void item already exist (used to avoid creating several * void items) */ private boolean containsVoidItem() { for (JComponent[] element : widgets) { JButton jbFrom = (JButton) element[1]; JButton jbTo = (JButton) element[2]; if (jbFrom.getText().equals("") || jbTo.getText().equals("")) { return true; } } return false; } /** * Refresh panel. */ private void refreshScreen() { removeAll(); // refresh panel add(getTransitionsPanel(), "grow"); revalidate(); repaint(); } } /** * Proportion panel. */ public static class ProportionsPanel extends Screen { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** All dynamic widgets. */ JComponent[][] widgets; /** Proportions*. */ List proportions; /* (non-Javadoc) * @see org.qdwizard.Screen#getDescription() */ @Override public String getDescription() { return Messages.getString("DigitalDJWizard.50"); } /* (non-Javadoc) * @see org.qdwizard.Screen#getName() */ @Override public String getName() { return Messages.getString("DigitalDJWizard.29"); } /** * Create panel UI. */ @Override @SuppressWarnings("unchecked") public void initUI() { if (ActionSelectionPanel.ACTION_CHANGE.equals(data.get(KEY_ACTION))) { DigitalDJ dj = (DigitalDJ) data.get(KEY_CHANGE); proportions = (List) ((ArrayList) ((ProportionDigitalDJ) dj) .getProportions()).clone(); data.put(KEY_PROPORTIONS, getCleanedProportions()); proportions.add(new Proportion()); // add a void item } else { proportions = new ArrayList(10); proportions.add(new Proportion()); // add a void item setProblem(Messages.getString("DigitalDJWizard.30")); } setCanFinish(true); // set layout setLayout(new MigLayout("insets 10,gapx 5", "[grow]")); add(getProportionsPanel(), "grow"); } /** * Gets the cleaned proportions. * * @return Filled proportions only */ private List getCleanedProportions() { List out = new ArrayList(proportions.size()); for (Proportion proportion : proportions) { if (proportion.getGenres() != null && proportion.getGenres().size() > 0) { out.add(proportion); } } return out; } /** * Gets the proportions panel. * * @return a panel containing all proportions */ private JScrollPane getProportionsPanel() { widgets = new JComponent[proportions.size()][3]; JPanel out = new JPanel(); // Delete|Genre list|proportion in % // now add all known proportions for (int index = 0; index < proportions.size(); index++) { // Delete button JButton jbDelete = new JButton(IconLoader.getIcon(JajukIcons.DELETE)); jbDelete.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent ae) { proportions.remove(getWidgetIndex(widgets, (JComponent) ae.getSource())); data.put(KEY_PROPORTIONS, getCleanedProportions()); refreshScreen(); } }); // cannot delete if void selection if (proportions.size() == 1) { jbDelete.setEnabled(false); } jbDelete.setToolTipText(Messages.getString("DigitalDJWizard.21")); widgets[index][0] = jbDelete; // genre list JButton jbGenre = new JButton(IconLoader.getIcon(JajukIcons.LIST)); Proportion proportion = proportions.get(index); if (proportion.getGenres() != null) { jbGenre.setText(proportion.getGenresDesc()); jbGenre.setToolTipText(proportion.getGenresDesc()); } jbGenre.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent ae) { int row = getWidgetIndex(widgets, (JComponent) ae.getSource()); addGenre(row); } }); jbGenre.setToolTipText(Messages.getString("DigitalDJWizard.27")); widgets[index][1] = jbGenre; // Proportion JSpinner jsNb = new JSpinner(new SpinnerNumberModel( (int) (proportion.getProportion() * 100), 1, 100, 1)); jsNb.addChangeListener(new ChangeListener() { public void stateChanged(ChangeEvent ce) { if (getTotalValue() > 100) { setProblem(Messages.getString("DigitalDJWizard.59")); return; } else { setProblem(null); } int row = getWidgetIndex(widgets, (JComponent) ce.getSource()); int nb = Integer.parseInt(((JSpinner) ce.getSource()).getValue().toString()); Proportion proportion = proportions.get(row); proportion.setProportion(((float) nb) / 100); } }); jsNb.setToolTipText(Messages.getString("DigitalDJWizard.28")); widgets[index][2] = jsNb; } // Create layout out.setLayout(new MigLayout("insets 5,gapx 10,gapy 10", "[][530!][]")); // Create header JLabel jlHeader1 = new JLabel(Messages.getString("DigitalDJWizard.27")); jlHeader1.setFont(FontManager.getInstance().getFont(JajukFont.BOLD)); JLabel jlHeader2 = new JLabel(Messages.getString("DigitalDJWizard.28")); jlHeader2.setFont(FontManager.getInstance().getFont(JajukFont.BOLD)); out.add(jlHeader1, "cell 1 0, center"); out.add(jlHeader2, "cell 2 0, center,wrap"); // Add widgets for (int i = 0; i < widgets.length; i++) { out.add(widgets[i][0], "left"); out.add(widgets[i][1], "grow,width ::530"); out.add(widgets[i][2], "wrap"); } // Display an error message if sum of proportion is > 100% if (getTotalValue() > 100) { setProblem(Messages.getString("DigitalDJWizard.59")); } JScrollPane jsp = new JScrollPane(out); jsp.setBorder(null); return jsp; } /** * Gets the total value. * * @return Sum of all proportions */ private int getTotalValue() { int total = 0; for (JComponent[] element : widgets) { JSpinner jsp = (JSpinner) element[2]; // Only filled proportions are token into account JButton jb = (JButton) element[1]; if (jb.getText() == null || jb.getText().equals("")) { continue; } total += Integer.parseInt(jsp.getValue().toString()); } return total; } /** * Add a genre to a proportion. * * @param row row */ private void addGenre(int row) { synchronized (GenreManager.getInstance()) { Proportion proportion = proportions.get(row); // create list of genres used in existing transitions Set disabledGenres = new HashSet(); for (int i = 0; i < proportions.size(); i++) { if (i != row) { // do not exclude current proportion that // will be selected disabledGenres.addAll(proportions.get(i).getGenres()); } } GenresSelectionDialog dialog = new GenresSelectionDialog(disabledGenres); dialog.setSelection(proportion.getGenres()); dialog.setVisible(true); Set genres = dialog.getSelectedGenres(); // check if at least one genre has been selected if (genres.size() == 0) { return; } // reset genres proportion.setGenre(new Ambience()); String sText = ""; for (Genre genre : genres) { // handle null if (genre == null) { Log.warn("Could not add genre, got an empty genre from the Wizard Dialog!"); continue; } proportion.addGenre(genre); sText += genre.getName2() + ','; } sText = sText.substring(0, sText.length() - 1); // Set button text ((JButton) widgets[row][1]).setText(sText); // check if the proportion is fully selected now if (proportion.getGenres().size() > 0) { // Make sure current delete button is now enabled ((JButton) widgets[row][0]).setEnabled(true); // Reset wizard error message setProblem(null); // Fill wizard data data.put(KEY_PROPORTIONS, getCleanedProportions()); // create a new void proportion if needed if (!containsVoidItem()) { proportions.add(new Proportion()); } // Refresh screen to add a new void row refreshScreen(); } } } /** * Contains void item. * * @return whether a void item already exist (used to avoid creating several * void items) */ private boolean containsVoidItem() { for (JComponent[] element : widgets) { JButton jb = (JButton) element[1]; if (jb.getText().equals("")) { return true; } } return false; } /** * Refresh panel. */ private void refreshScreen() { removeAll(); // refresh panel add(getProportionsPanel(), "grow"); revalidate(); repaint(); } } /** * Ambience based. */ public static class AmbiencePanel extends Screen implements ActionListener { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** All dynamic widgets. */ JComponent[][] widgets; /** Ambiences*. */ List ambiences; /** DJ*. */ AmbienceDigitalDJ dj = null; /** Selected ambience index. */ int ambienceIndex = 0; /* (non-Javadoc) * @see org.qdwizard.Screen#getDescription() */ @Override public String getDescription() { return Messages.getString("DigitalDJWizard.47"); } /* (non-Javadoc) * @see org.qdwizard.Screen#getName() */ @Override public String getName() { return Messages.getString("DigitalDJWizard.31"); } /** * Create panel UI. */ @Override public void initUI() { // the returned list is sorted by name ambiences = AmbienceManager.getInstance().getAmbiences(); // We need at least one ambience if (ambiences.size() == 0) { setProblem(Messages.getString("DigitalDJWizard.38")); } setCanFinish(true); // Get DJ dj = (AmbienceDigitalDJ) DigitalDJManager.getInstance().getDJByName( (String) data.get(KEY_DJ_NAME)); setLayout(new MigLayout("insets 10,gapx 5", "[grow]")); add(getAmbiencesPanel(), "grow"); } /** * Gets the ambiences panel. * * @return a panel containing all ambiences */ private JScrollPane getAmbiencesPanel() { ButtonGroup bg = new ButtonGroup(); widgets = new JComponent[ambiences.size()][3]; JPanel out = new JPanel(); out.setLayout(new MigLayout("insets 0,gapx 10,gapy 10", "[grow]")); int index = 0; for (Ambience ambience : ambiences) { JRadioButton jrb = new JRadioButton(ambience.getName()); jrb.addActionListener(this); bg.add(jrb); widgets[index][0] = jrb; out.add(jrb, "left gap 5,wrap"); index++; } // DJ change, set right ambience if (ActionSelectionPanel.ACTION_CHANGE.equals(data.get(KEY_ACTION))) { DigitalDJ lDJ = (DigitalDJ) data.get(KEY_CHANGE); Ambience ambience = ((AmbienceDigitalDJ) lDJ).getAmbience(); index = 0; for (Ambience a : ambiences) { if (a.equals(ambience)) { JRadioButton jrb = (JRadioButton) widgets[index][0]; jrb.doClick();// select right ambience, it will set // right value into data break; } index++; } } else { // select first ambience found JRadioButton jrb = (JRadioButton) widgets[0][0]; jrb.doClick(); } JScrollPane jsp = new JScrollPane(out); jsp.setBorder(null); return jsp; } /* * (non-Javadoc) * * @see * java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent) */ public void actionPerformed(ActionEvent e) { int row = getWidgetIndex(widgets, (JComponent) e.getSource()); data.put(KEY_AMBIENCE, ambiences.get(row)); setProblem(null); } } /** * Gets the widget index. * * @param widgets DOCUMENT_ME * @param widget DOCUMENT_ME * @return index of a given widget row in the widget table */ private static int getWidgetIndex(JComponent[][] widgets, JComponent widget) { for (int row = 0; row < widgets.length; row++) { for (int col = 0; col < widgets[0].length; col++) { if (widget.equals(widgets[row][col])) { return row; } } } return -1; } /* * (non-Javadoc) * * @see org.jajuk.ui.wizard.Wizard#getPreviousScreen(java.lang.Class) */ @Override public Class getPreviousScreen( Class screen) { if (ActionSelectionPanel.class.equals(getCurrentScreen())) { return null; } else if (TypeSelectionPanel.class.equals(getCurrentScreen())) { return ActionSelectionPanel.class; } else if (GeneralOptionsPanel.class.equals(getCurrentScreen())) { if (ActionSelectionPanel.ACTION_CREATION.equals(data.get(KEY_ACTION))) { return TypeSelectionPanel.class; } else { return ChangePanel.class; } } else if (TransitionsPanel.class.equals(getCurrentScreen()) || ProportionsPanel.class.equals(getCurrentScreen()) || AmbiencePanel.class.equals(getCurrentScreen())) { return GeneralOptionsPanel.class; } else if (RemovePanel.class.equals(getCurrentScreen())) { return ActionSelectionPanel.class; } else if (ChangePanel.class.equals(getCurrentScreen())) { return ActionSelectionPanel.class; } return null; } /* * (non-Javadoc) * * @see org.jajuk.ui.wizard.Wizard#getNextScreen(java.lang.Class) */ @Override public Class getNextScreen( Class screen) { if (ActionSelectionPanel.class.equals(getCurrentScreen())) { String sAction = (String) data.get(KEY_ACTION); if (ActionSelectionPanel.ACTION_CREATION.equals(sAction)) { return TypeSelectionPanel.class; } else if (ActionSelectionPanel.ACTION_CHANGE.equals(sAction)) { return ChangePanel.class; } else if (ActionSelectionPanel.ACTION_DELETE.equals(sAction)) { return RemovePanel.class; } } else if (TypeSelectionPanel.class.equals(getCurrentScreen())) { return GeneralOptionsPanel.class; } else if (GeneralOptionsPanel.class.equals(getCurrentScreen())) { String sType = (String) data.get(KEY_DJ_TYPE); if (TypeSelectionPanel.DJ_TYPE_AMBIENCE.equals(sType)) { return AmbiencePanel.class; } else if (TypeSelectionPanel.DJ_TYPE_PROPORTION.equals(sType)) { return ProportionsPanel.class; } else if (TypeSelectionPanel.DJ_TYPE_TRANSITION.equals(sType)) { return TransitionsPanel.class; } } else if (RemovePanel.class.equals(getCurrentScreen())) { return null; } else if (ChangePanel.class.equals(getCurrentScreen())) { return GeneralOptionsPanel.class; } return null; } /** * Instantiates a new digital dj wizard. */ public DigitalDJWizard() { super(Messages.getString("DigitalDJWizard.4"), ActionSelectionPanel.class, null, JajukMainWindow.getInstance(), LocaleManager.getLocale()); super.setHeaderIcon(IconLoader.getIcon(JajukIcons.DIGITAL_DJ)); } /* * (non-Javadoc) * * @see org.jajuk.ui.wizard.Wizard#finish() */ @SuppressWarnings("unchecked") @Override public void finish() { DigitalDJ dj = null; String sAction = (String) data.get(KEY_ACTION); if (ActionSelectionPanel.ACTION_DELETE.equals(sAction)) { try { DigitalDJManager.getInstance().remove((DigitalDJ) data.get(KEY_REMOVE)); } catch (IOException e) { Log.error(e); } } else if (ActionSelectionPanel.ACTION_CREATION.equals(sAction)) { String sType = (String) data.get(KEY_DJ_TYPE); // create a unique ID for this DJ, simply use current time in ms String sID = Long.toString(System.currentTimeMillis()); if (TypeSelectionPanel.DJ_TYPE_AMBIENCE.equals(sType)) { Ambience ambience = (Ambience) data.get(KEY_AMBIENCE); dj = new AmbienceDigitalDJ(sID); ((AmbienceDigitalDJ) dj).setAmbience(ambience); } else if (TypeSelectionPanel.DJ_TYPE_PROPORTION.equals(sType)) { dj = new ProportionDigitalDJ(sID); List proportions = (List) data.get(KEY_PROPORTIONS); ((ProportionDigitalDJ) dj).setProportions(proportions); } else if (TypeSelectionPanel.DJ_TYPE_TRANSITION.equals(sType)) { List transitions = (List) data.get(KEY_TRANSITIONS); dj = new TransitionDigitalDJ(sID); ((TransitionDigitalDJ) dj).setTransitions(transitions); } else { throw new IllegalArgumentException("Unknown type of DJ: " + sType); } setProperties(dj); DigitalDJManager.getInstance().register(dj); // commit the DJ right now DigitalDJManager.commit(dj); // If first DJ, select it as default if (DigitalDJManager.getInstance().getDJs().size() == 1) { Conf.setProperty(Const.CONF_DEFAULT_DJ, dj.getID()); } } else if (ActionSelectionPanel.ACTION_CHANGE.equals(sAction)) { String sType = (String) data.get(KEY_DJ_TYPE); dj = (DigitalDJ) data.get(KEY_CHANGE); if (TypeSelectionPanel.DJ_TYPE_AMBIENCE.equals(sType)) { Ambience ambience = (Ambience) data.get(KEY_AMBIENCE); ((AmbienceDigitalDJ) dj).setAmbience(ambience); } else if (TypeSelectionPanel.DJ_TYPE_PROPORTION.equals(sType)) { List proportions = (List) data.get(KEY_PROPORTIONS); ((ProportionDigitalDJ) dj).setProportions(proportions); } else if (TypeSelectionPanel.DJ_TYPE_TRANSITION.equals(sType)) { List transitions = (List) data.get(KEY_TRANSITIONS); ((TransitionDigitalDJ) dj).setTransitions(transitions); } setProperties(dj); // commit the DJ right now DigitalDJManager.commit(dj); } // Refresh command panel (useful for ie if DJ names changed) ObservationManager.notify(new JajukEvent(JajukEvents.DJS_CHANGE)); } /** * Store the properties from the Wizard to the specified DJ. * * @param dj The DJ to populate. */ private void setProperties(DigitalDJ dj) { String sName = (String) data.get(KEY_DJ_NAME); int iFadeDuration = (Integer) data.get(KEY_FADE_DURATION); int iRateLevel = (Integer) data.get(KEY_RATINGS_LEVEL); boolean bUnicity = (Boolean) data.get(KEY_UNICITY); int iMaxTracks = (Integer) data.get(KEY_MAX_TRACKS); dj.setName(sName); dj.setFadingDuration(iFadeDuration); dj.setRatingLevel(iRateLevel); dj.setTrackUnicity(bUnicity); dj.setMaxTracks(iMaxTracks); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/wizard/DuplicateTracksDialog.java0000644000175000017500000002013211720500104026763 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.wizard; import java.awt.BorderLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.ArrayList; import java.util.List; import javax.swing.BorderFactory; import javax.swing.DefaultListModel; import javax.swing.JButton; import javax.swing.JList; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import net.miginfocom.swing.MigLayout; import org.jajuk.base.File; import org.jajuk.base.FileManager; import org.jajuk.events.JajukEvent; import org.jajuk.events.JajukEvents; import org.jajuk.events.ObservationManager; import org.jajuk.util.Messages; import org.jajuk.util.UtilSystem; import org.jajuk.util.log.Log; /** * DOCUMENT_ME. */ public class DuplicateTracksDialog extends JPanel implements ListSelectionListener { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** DOCUMENT_ME. */ private final JList list; /** DOCUMENT_ME. */ private final JScrollPane listScrollPane; /** DOCUMENT_ME. */ private final DefaultListModel listModel = new DefaultListModel(); /** DOCUMENT_ME. */ private final List> allFiles; /** DOCUMENT_ME. */ private List flatFilesList; /** DOCUMENT_ME. */ private final JButton deleteButton; /** DOCUMENT_ME. */ private final JButton selectAllButton; /** DOCUMENT_ME. */ private final JButton closeButton; /** * Instantiates a new duplicate tracks list. * * @param files DOCUMENT_ME * @param jbClose DOCUMENT_ME */ public DuplicateTracksDialog(List> files, JButton jbClose) { super(new BorderLayout()); allFiles = files; closeButton = jbClose; populateList(files); list = new JList(listModel); list.setVisibleRowCount(20); listScrollPane = new JScrollPane(list); deleteButton = new JButton(Messages.getString("Delete")); deleteButton.setActionCommand(Messages.getString("Delete")); deleteButton.addActionListener(new DeleteListener()); selectAllButton = new JButton(Messages.getString("FindDuplicateTracksAction.4")); selectAllButton.setActionCommand(Messages.getString("FindDuplicateTracksAction.4")); selectAllButton.addActionListener(new SelectAllListener()); JPanel buttonPane = new JPanel(new MigLayout("ins 5,right")); buttonPane.add(deleteButton, "sg buttons,center"); buttonPane.add(selectAllButton, "sg buttons,center"); buttonPane.add(closeButton, "sg buttons,center"); buttonPane.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); add(listScrollPane, BorderLayout.CENTER); add(buttonPane, BorderLayout.PAGE_END); } /** * Populate list. * DOCUMENT_ME * * @param allFiles DOCUMENT_ME */ public final void populateList(List> allFiles) { flatFilesList = new ArrayList(); for (List lFiles : allFiles) { for (File f : lFiles) { flatFilesList.add(f); } } listModel.removeAllElements(); for (List dups : allFiles) { // dups's size can be 0 if dups are found among unmounted devices listModel.addElement(dups.get(0).getName() + " ( " + dups.get(0).getDirectory().getAbsolutePath() + " ) "); for (int i = 1; i < dups.size(); i++) { listModel.addElement(" + " + dups.get(i).getName() + " ( " + dups.get(i).getDirectory().getAbsolutePath() + " ) "); } } } /** * DOCUMENT_ME. */ class DeleteListener implements ActionListener { /* (non-Javadoc) * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent) */ @Override public void actionPerformed(ActionEvent e) { int indices[] = list.getSelectedIndices(); String sFiles = getSelectedFiles(indices); int iResu = Messages.getChoice(Messages.getString("Confirmation_delete_files") + " : \n\n" + sFiles + "\n" + indices.length + " " + Messages.getString("Confirmation_file_number"), JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE); if (iResu != JOptionPane.YES_OPTION) { return; } // Delete physically files from disk and from collection for (int i : indices) { try { UtilSystem.deleteFile(flatFilesList.get(i).getFIO()); FileManager.getInstance().removeFile(flatFilesList.get(i)); } catch (Exception ioe) { Log.error(131, ioe); } } // Remove table rows int deletedRows = 0; for (int i : indices) { listModel.removeElement(i - deletedRows); flatFilesList.remove(i - deletedRows); deleteFilefromList(i - deletedRows); deletedRows++; } populateList(allFiles); ObservationManager.notify(new JajukEvent(JajukEvents.DEVICE_REFRESH)); } /** * Delete filefrom list. * DOCUMENT_ME * * @param index DOCUMENT_ME */ private void deleteFilefromList(int index) { // first iterate over all Lists of files, counting the overall index int count = 0; for (int r = 0; r < allFiles.size(); r++) { // for each list of files, iterate over in an inner loop for (int c = 0; c < allFiles.get(r).size(); c++) { // check if we reached the correct position in the list now if (count == index) { if (allFiles.get(r).size() <= 2) { // if only one file is left now, remove the whole element allFiles.remove(r); // done, the required index was removed return; } else { // remove the file that is removed allFiles.get(r).remove(c); // done, the required index was removed return; } } count++; } } } /** * Gets the selected files. * * @param indices DOCUMENT_ME * * @return the selected files */ private String getSelectedFiles(int indices[]) { String sFiles = ""; for (int k : indices) { sFiles += "* " + flatFilesList.get(k).getAbsolutePath() + "\n"; } return sFiles; } } /** * DOCUMENT_ME. */ class SelectAllListener implements ActionListener { /* (non-Javadoc) * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent) */ @Override public void actionPerformed(ActionEvent e) { List iList = new ArrayList(); int i = 0; for (List lFiles : allFiles) { i++; for (int k = 1; k < lFiles.size(); k++) { iList.add(i++); } } int[] indices = new int[iList.size()]; for (int k = 0; k < iList.size(); k++) { indices[k] = iList.get(k); } list.setSelectedIndices(indices); } } /* (non-Javadoc) * @see javax.swing.event.ListSelectionListener#valueChanged(javax.swing.event.ListSelectionEvent) */ @Override public void valueChanged(ListSelectionEvent e) { if (!e.getValueIsAdjusting()) { if (list.getSelectedIndex() == -1) { // No selection, disable delete button. deleteButton.setEnabled(false); } else { // Selection, enable the delete button. deleteButton.setEnabled(true); } } } }jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/wizard/DeviceWizard.java0000644000175000017500000004701711720500104025154 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.wizard; import java.awt.HeadlessException; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.io.File; import java.text.NumberFormat; import java.text.ParseException; import java.util.Iterator; import java.util.List; import javax.swing.BorderFactory; import javax.swing.ButtonGroup; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JComboBox; import javax.swing.JFileChooser; import javax.swing.JLabel; import javax.swing.JRadioButton; import javax.swing.JTextField; import net.miginfocom.swing.MigLayout; import org.jajuk.base.Device; import org.jajuk.base.DeviceManager; import org.jajuk.base.DirectoryManager; import org.jajuk.events.JajukEvent; import org.jajuk.events.JajukEvents; import org.jajuk.events.ObservationManager; import org.jajuk.ui.widgets.InformationJPanel; import org.jajuk.ui.widgets.JajukFileChooser; import org.jajuk.ui.widgets.JajukJDialog; import org.jajuk.ui.widgets.OKCancelPanel; import org.jajuk.ui.windows.JajukMainWindow; import org.jajuk.util.Const; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukFileFilter; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; import org.jajuk.util.filters.DirectoryFilter; import org.jajuk.util.log.Log; import org.netbeans.validation.api.Problem; import org.netbeans.validation.api.Problems; import org.netbeans.validation.api.Severity; import org.netbeans.validation.api.Validator; import org.netbeans.validation.api.builtin.Validators; import org.netbeans.validation.api.ui.ValidationGroup; import org.netbeans.validation.api.ui.ValidationPanel; /** * Device creation wizard. */ public class DeviceWizard extends JajukJDialog implements ActionListener, Const { /** The Constant WRAP. */ private static final String WRAP = "wrap"; /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** Device type combo. */ private final JComboBox jcbType; /** Device name text field. */ private final JTextField jtfName; /** Device url text field. */ private final JTextField jtfUrl; /** Device url path selector button. */ private final JButton jbUrl; /** Auto-refresh device checkbox. */ private final JCheckBox jcbRefresh; /** Auto-mount checkbox. */ private final JCheckBox jcbAutoMount; /** Auto-refresh interval. */ private final JTextField jtfAutoRefresh; /** Device sync checkbox. */ private final JCheckBox jcboxSynchronized; /** Other device combo. */ private final JComboBox jcbSynchronized; /** Bidi sync choice. */ private final JRadioButton jrbBidirSynchro; /** Unidir sync choice. */ private final JRadioButton jrbUnidirSynchro; /** Ok Cancel panel. */ private final OKCancelPanel okp; /** New device flag. */ private boolean bNew = true; /** Current device. */ private Device device; /** All devices expect itself. */ private final List devices; /** Initial URL*. */ private String sInitialURL; /** A convenient NumberFormat instance. */ private NumberFormat nformat = NumberFormat.getInstance(); /** Validation group. */ private ValidationGroup vg; /** * Device wizard by default, is used for void configuration. */ public DeviceWizard() { super(); devices = DeviceManager.getInstance().getDevices(); addWindowListener(new WindowAdapter() { @Override public void windowActivated(final WindowEvent e) { jtfName.requestFocusInWindow(); } }); setTitle(Messages.getString("DeviceWizard.0")); setModal(true); setLocation(JajukMainWindow.getInstance().getX() + 100, JajukMainWindow.getInstance().getY() + 100); JLabel jlType = new JLabel(Messages.getString("DeviceWizard.1")); jcbType = new JComboBox(); final Iterator itDevicesTypes = DeviceManager.getInstance().getDeviceTypes(); while (itDevicesTypes.hasNext()) { jcbType.addItem(itDevicesTypes.next()); } JLabel jlName = new JLabel(Messages.getString("DeviceWizard.2")); jtfName = new JTextField(); jtfName.setToolTipText(Messages.getString("DeviceWizard.45")); JLabel jlUrl = new JLabel(Messages.getString("DeviceWizard.3")); jtfUrl = new JTextField(); jtfUrl.setToolTipText(Messages.getString("DeviceWizard.46")); jbUrl = new JButton(IconLoader.getIcon(JajukIcons.OPEN_FILE)); jbUrl.setToolTipText(Messages.getString("DeviceWizard.43")); jbUrl.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); jbUrl.addActionListener(this); // we disable focus for url and mount url buttons to facilitate // navigation jbUrl.setFocusable(false); jcbRefresh = new JCheckBox(Messages.getString("DeviceWizard.7")); jcbRefresh.setToolTipText(Messages.getString("DeviceWizard.48")); jcbRefresh.addActionListener(this); jcbAutoMount = new JCheckBox(Messages.getString("DeviceWizard.8")); jcbAutoMount.setToolTipText(Messages.getString("DeviceWizard.49")); jcbAutoMount.addActionListener(this); JLabel jlAutoRefresh = new JLabel(Messages.getString("DeviceWizard.53")); jlAutoRefresh.setToolTipText(Messages.getString("DeviceWizard.50")); JLabel jlMinutes = new JLabel(Messages.getString("DeviceWizard.54")); /* jtfAutoRefresh rules : Minimum delay is half a minute */ jtfAutoRefresh = new JTextField(); jtfAutoRefresh.setName(Messages.getString("DeviceWizard.54")); jtfAutoRefresh.setToolTipText(Messages.getString("DeviceWizard.50")); jcboxSynchronized = new JCheckBox(Messages.getString("DeviceWizard.10")); jcboxSynchronized.setToolTipText(Messages.getString("DeviceWizard.51")); jcboxSynchronized.addActionListener(this); jcbSynchronized = new JComboBox(); // populate combo for (Device device1 : devices) { jcbSynchronized.addItem(device1.getName()); } jcbSynchronized.setEnabled(false); jcbSynchronized.setToolTipText(Messages.getString("DeviceWizard.52")); // Default automount behavior jcbType.addActionListener(this); ButtonGroup bgSynchro = new ButtonGroup(); jrbUnidirSynchro = new JRadioButton(Messages.getString("DeviceWizard.11")); jrbUnidirSynchro.setToolTipText(Messages.getString("DeviceWizard.12")); jrbUnidirSynchro.setBorder(BorderFactory.createEmptyBorder(0, 25, 0, 0)); jrbUnidirSynchro.setEnabled(false); jrbUnidirSynchro.addActionListener(this); jrbBidirSynchro = new JRadioButton(Messages.getString("DeviceWizard.13")); jrbBidirSynchro.setToolTipText(Messages.getString("DeviceWizard.14")); jrbBidirSynchro.setBorder(BorderFactory.createEmptyBorder(0, 25, 0, 0)); jrbBidirSynchro.setEnabled(false); jrbBidirSynchro.addActionListener(this); bgSynchro.add(jrbBidirSynchro); bgSynchro.add(jrbUnidirSynchro); // Validation ValidationPanel vp = new ValidationPanel(); vg = vp.getValidationGroup(); installValidators(); // buttons okp = new OKCancelPanel(this); okp.getOKButton().setEnabled(false); // Add items setLayout(new MigLayout("insets 10,gapx 10, gapy 15", "[][grow]")); add(jlType); add(jcbType, "grow,wrap"); add(jlName); add(jtfName, "grow,wrap"); add(jlUrl); add(jtfUrl, "split 2,growx"); add(jbUrl, WRAP); add(jlAutoRefresh); add(jtfAutoRefresh, "grow,split 2"); add(jlMinutes, WRAP); add(jcbRefresh, WRAP); add(jcbAutoMount, WRAP); add(jcboxSynchronized); add(jcbSynchronized, "grow,wrap"); add(jrbUnidirSynchro, "left,gap left 20,span,wrap"); add(jrbBidirSynchro, "left,gap left 20,span,wrap"); add(vp, "height 50!,span,wrap"); add(okp, "span,right"); // Set default behaviors if (jcbSynchronized.getItemCount() == 0) { jcboxSynchronized.setEnabled(false); jcbSynchronized.setEnabled(false); jrbBidirSynchro.setEnabled(false); } getRootPane().setDefaultButton(okp.getOKButton()); pack(); okp.getOKButton().requestFocusInWindow(); } /** * Install validators. */ @SuppressWarnings("unchecked") private void installValidators() { // Auto-refresh interval validation : should be 0 or a double >= 0.5 vg.add(jtfAutoRefresh, Validators.REQUIRE_NON_NEGATIVE_NUMBER, Validators.NO_WHITESPACE, Validators.REQUIRE_VALID_NUMBER, new Validator() { @Override public boolean validate(Problems problems, String compName, String model) { try { double value = nformat.parse(model).doubleValue(); // If value is zero, validate the user input boolean resu = (value == 0 || value >= 0.5d); // If a problem occurred, add this problem to the problem stack if (!resu) { Problem problem = new Problem(Messages.getString("DeviceWizard.55"), Severity.FATAL); problems.add(problem); } // Disable the wizard OK button if user selection is not in the // right interval or if previous validators thrown an error // already okp.getOKButton().setEnabled(resu && problems.isEmpty()); return resu; } catch (Exception e) { // This happen when the text field is not yet populated (model is // void). Note that wrong number format issues are already handled // by the previous Validators okp.getOKButton().setEnabled(false); return true; } } }); // Validate device name vg.add(jtfName, Validators.REQUIRE_NON_EMPTY_STRING); vg.add(jtfName, new Validator() { @Override public boolean validate(Problems problems, String compName, String model) { // By default, we disable the OK button, we re-enable it only if the // name is OK okp.getOKButton().setEnabled(false); for (Device deviceToCheck : DeviceManager.getInstance().getDevices()) { // check for a new device with an existing name if (bNew && (jtfName.getText().equalsIgnoreCase(deviceToCheck.getName()))) { problems.add(new Problem(Messages.getErrorMessage(19), Severity.FATAL)); return false; } } okp.getOKButton().setEnabled(problems.isEmpty()); return true; } }); } /* * (non-Javadoc) * * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent) */ @Override public void actionPerformed(final ActionEvent e) { if (e.getSource() == jcboxSynchronized) { handleSynchronized(); } else if (e.getSource() == okp.getOKButton()) { handleOk(); } else if (e.getSource() == okp.getCancelButton()) { dispose(); // close window } else if (e.getSource() == jbUrl) { handleUrl(); } else if (e.getSource() == jcbType) { handleType(); } } /** * Handle type. DOCUMENT_ME */ private void handleType() { switch (jcbType.getSelectedIndex()) { case 0: // directory jcbAutoMount.setSelected(true); if (bNew) { jtfAutoRefresh.setText(nformat.format(Const.DEFAULT_REFRESH_INTERVAL_DIRECTORY)); } break; case 1: // file cd jcbAutoMount.setSelected(false); if (bNew) { jtfAutoRefresh.setText(nformat.format(Const.DEFAULT_REFRESH_INTERVAL_CD)); } break; case 2: // network drive jcbAutoMount.setSelected(true); // no auto-refresh by default for network drive if (bNew) { jtfAutoRefresh.setText(nformat.format(Const.DEFAULT_REFRESH_INTERVAL_NETWORK_DRIVE)); } break; case 3: // ext dd jcbAutoMount.setSelected(true); if (bNew) { jtfAutoRefresh.setText(nformat.format(Const.DEFAULT_REFRESH_INTERVAL_EXTERNAL_DRIVE)); } break; case 4: // player jcbAutoMount.setSelected(false); if (bNew) { jtfAutoRefresh.setText(nformat.format(Const.DEFAULT_REFRESH_INTERVAL_PLAYER)); } break; } } /** * Handle url. * * @throws HeadlessException the headless exception */ private void handleUrl() throws HeadlessException { final JajukFileChooser jfc = new JajukFileChooser(new JajukFileFilter(DirectoryFilter .getInstance())); jfc.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); jfc.setDialogTitle(Messages.getString("DeviceWizard.43")); jfc.setMultiSelectionEnabled(false); final String sUrl = jtfUrl.getText(); if (!"".equals(sUrl)) { // if url is already set, use it as root directory jfc.setCurrentDirectory(new File(sUrl)); } final int returnVal = jfc.showOpenDialog(this); if (returnVal == JFileChooser.APPROVE_OPTION) { final java.io.File file = jfc.getSelectedFile(); jtfUrl.setText(file.getAbsolutePath()); } } /** * Handle ok. DOCUMENT_ME */ private void handleOk() { new Thread("Device Wizard Action Thread") { @Override public void run() { if (bNew) { device = DeviceManager.getInstance().registerDevice(jtfName.getText(), jcbType.getSelectedIndex(), jtfUrl.getText()); } device.setProperty(Const.XML_DEVICE_AUTO_MOUNT, jcbAutoMount.isSelected()); try { device.setProperty(Const.XML_DEVICE_AUTO_REFRESH, nformat.parse(jtfAutoRefresh.getText()) .doubleValue()); } catch (ParseException e) { // Should not happen thanks GUI validators Log.error(e); } device.setProperty(Const.XML_TYPE, Long.valueOf(jcbType.getSelectedIndex())); device.setUrl(jtfUrl.getText()); if (jcbSynchronized.isEnabled() && (jcbSynchronized.getSelectedItem() != null)) { Device selected = DeviceManager.getInstance().getDeviceByName( (String) jcbSynchronized.getSelectedItem()); device.setProperty(Const.XML_DEVICE_SYNCHRO_SOURCE, selected.getID()); if (jrbBidirSynchro.isSelected()) { device.setProperty(Const.XML_DEVICE_SYNCHRO_MODE, Const.DEVICE_SYNCHRO_MODE_BI); } else { device.setProperty(Const.XML_DEVICE_SYNCHRO_MODE, Const.DEVICE_SYNCHRO_MODE_UNI); } } else { // no synchro device.removeProperty(Const.XML_DEVICE_SYNCHRO_MODE); device.removeProperty(Const.XML_DEVICE_SYNCHRO_SOURCE); } // Force deep refresh if it is a new device or if URL changed if (jcbRefresh.isSelected() && bNew) { try { // Drop existing directory to avoid phantom directories if // existing device DirectoryManager.getInstance().removeDirectory(device.getID()); device.refresh(true, false, false, null); } catch (final Exception e2) { Log.error(112, device.getName(), e2); Messages.showErrorMessage(112, device.getName()); } } else if (sInitialURL != null && !sInitialURL.equals(jtfUrl.getText())) { // If user changed the URL, force refresh try { // try to remount the device if (!device.isMounted()) { boolean mounted = device.mount(true); // Leave if user canceled device mounting if (!mounted) { dispose(); return; } } // Keep previous references when changing device url device.refresh(true, false, true, null); ObservationManager.notify(new JajukEvent(JajukEvents.DEVICE_REFRESH)); } catch (final Exception e2) { Log.error(112, device.getName(), e2); Messages.showErrorMessage(112, device.getName()); } } ObservationManager.notify(new JajukEvent(JajukEvents.DEVICE_REFRESH)); dispose(); if (bNew) { InformationJPanel.getInstance().setMessage(Messages.getString("DeviceWizard.44"), InformationJPanel.MessageType.INFORMATIVE); } } }.start(); } /** * Handle synchronized. DOCUMENT_ME */ private void handleSynchronized() { if (jcboxSynchronized.isSelected()) { jcbSynchronized.setEnabled(true); jrbBidirSynchro.setEnabled(true); jrbUnidirSynchro.setEnabled(true); } else { jcbSynchronized.setEnabled(false); jrbBidirSynchro.setEnabled(false); jrbUnidirSynchro.setEnabled(false); } } /** * Update widgets for device property state. * * @param device1 DOCUMENT_ME */ public void updateWidgets(final Device device1) { bNew = false; setTitle(Messages.getString("DeviceWizard.0") + " : " + device1.getName()); this.device = device1; jcbSynchronized.removeAllItems(); devices.clear(); // set default values for widgets updateWidgetsDefault(); List devices2 = DeviceManager.getInstance().getDevices(); for (Device device2 : devices2) { if (!device2.equals(device1)) { devices.add(device2); jcbSynchronized.addItem(device2.getName()); } } // then, specifics jcbType.setSelectedItem(device1.getDeviceTypeS()); jtfName.setText(device1.getName()); jtfName.setEnabled(false); // device name cannot be changed jtfUrl.setText(device1.getUrl()); sInitialURL = device1.getUrl(); jcbRefresh.setEnabled(false); // no instant refresh for updates jcbRefresh.setSelected(false); jcbAutoMount.setSelected(true); if (device1.getBooleanValue(Const.XML_DEVICE_AUTO_MOUNT)) { jcbAutoMount.setSelected(true); } else { jcbAutoMount.setSelected(false); } jtfAutoRefresh.setText(nformat.format(device1.getDoubleValue(Const.XML_DEVICE_AUTO_REFRESH))); if (jcbSynchronized.getItemCount() == 0) { jcboxSynchronized.setEnabled(false); jcbSynchronized.setEnabled(false); jrbBidirSynchro.setEnabled(false); } if (device1.containsProperty(Const.XML_DEVICE_SYNCHRO_SOURCE)) { final String sSynchroSource = device1.getStringValue(Const.XML_DEVICE_SYNCHRO_SOURCE); jrbBidirSynchro.setEnabled(true); jrbUnidirSynchro.setEnabled(true); jcboxSynchronized.setSelected(true); jcboxSynchronized.setEnabled(true); jcbSynchronized.setEnabled(true); Device toBeSelected = DeviceManager.getInstance().getDeviceByID(sSynchroSource); jcbSynchronized.setSelectedItem(toBeSelected.getName()); if (Const.DEVICE_SYNCHRO_MODE_BI.equals(device1.getValue(Const.XML_DEVICE_SYNCHRO_MODE))) { jrbBidirSynchro.setSelected(true); } else { jrbUnidirSynchro.setSelected(true); } } } /** * Update widgets for default state. */ public void updateWidgetsDefault() { jcbRefresh.setSelected(true); jcbAutoMount.setSelected(true); jtfAutoRefresh.setText(nformat.format(Const.DEFAULT_REFRESH_INTERVAL_DIRECTORY)); jcboxSynchronized.setSelected(false); jrbUnidirSynchro.setSelected(true);// default synchro mode jrbBidirSynchro.setEnabled(false); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/wizard/CDDBWizard.java0000644000175000017500000003011111720500104024434 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.wizard; import entagged.freedb.Freedb; import entagged.freedb.FreedbAlbum; import entagged.freedb.FreedbException; import entagged.freedb.FreedbQueryResult; import entagged.freedb.FreedbReadResult; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.ArrayList; import java.util.List; import java.util.Locale; import javax.swing.DefaultComboBoxModel; import javax.swing.JLabel; import javax.swing.JScrollPane; import javax.swing.SwingWorker; import net.miginfocom.swing.MigLayout; import org.jajuk.base.FileManager; import org.jajuk.base.Track; import org.jajuk.base.TrackManager; import org.jajuk.events.JajukEvent; import org.jajuk.events.JajukEvents; import org.jajuk.events.ObservationManager; import org.jajuk.services.cddb.CDDBTrack; import org.jajuk.ui.helpers.CDDBTableModel; import org.jajuk.ui.widgets.InformationJPanel; import org.jajuk.ui.widgets.JajukJDialog; import org.jajuk.ui.widgets.JajukTable; import org.jajuk.ui.widgets.OKCancelPanel; import org.jajuk.ui.widgets.SteppedComboBox; import org.jajuk.ui.windows.JajukMainWindow; import org.jajuk.util.Messages; import org.jajuk.util.UtilGUI; import org.jajuk.util.UtilString; import org.jajuk.util.error.JajukException; import org.jajuk.util.log.Log; /** * DOCUMENT_ME. */ public class CDDBWizard extends JajukJDialog implements ActionListener { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** DOCUMENT_ME. */ private SteppedComboBox jcbAlbum; /** DOCUMENT_ME. */ private JajukTable jtable; /** DOCUMENT_ME. */ private CDDBTableModel model; /** OK/Cancel panel. */ private OKCancelPanel okc; /** Items to be retagged. */ private List alCddbTracks; /** Freedb Items. */ private Freedb fdb; /** DOCUMENT_ME. */ private FreedbQueryResult[] foundAlbums; /** DOCUMENT_ME. */ private FreedbReadResult fdbReader; /** DOCUMENT_ME. */ private List jcbFoundAlbums; /** * CDDB wizard. * * @param tracks DOCUMENT_ME */ public CDDBWizard(final List tracks) { super(); UtilGUI.waiting(); // windows title: absolute path name of the given directory setTitle(Messages.getString("CDDBWizard.19")); setModal(true); SwingWorker sw = new SwingWorker() { @Override public Void doInBackground() { try { // Put an error message if no tracks were found if (tracks.size() == 0) { return null; } else { // Convert given tracks into CDDBTracks alCddbTracks = new ArrayList(tracks.size()); for (Track t : tracks) { CDDBTrack track = new CDDBTrack(t); if (!alCddbTracks.contains(track)) { alCddbTracks.add(track); } } // Perform CDDB Query and display an error message if CDDB query // don't found any match CDDBTrack[] cddbtracks = alCddbTracks.toArray(new CDDBTrack[alCddbTracks.size()]); int results = performQuery(cddbtracks); if (results == 0) { Messages.showInfoMessage(Messages.getString("CDDBWizard.12")); return null; } } } catch (Exception e) { Log.error(e); } finally { UtilGUI.stopWaiting(); } return null; } @Override public void done() { if (foundAlbums != null && foundAlbums.length > 0) { jtable = populateTable(); initUI(); } } }; sw.execute(); } /** * Fill the table. * * @return the jajuk table */ public JajukTable populateTable() { model = populateModel(); jtable = new JajukTable(model, true, null); jtable.selectAll(); jtable.packAll(); return jtable; } /** * Populate model. DOCUMENT_ME * * @return the cDDB table model */ public CDDBTableModel populateModel() { try { // Display first result found when the frame opens, then select the combo // index int index = 0; if (jcbAlbum != null) { index = jcbAlbum.getSelectedIndex(); } fdbReader = fdb.read(foundAlbums[index]); // Can sometimes be null for some reasons if (fdbReader == null) { throw new FreedbException("Void Freereader, please retry"); } } catch (FreedbException e) { Messages.showDetailedErrorMessage(174, e.getLocalizedMessage(), null); Log.debug("CDDB error ! " + e.getLocalizedMessage()); dispose(); } // Re-populate model model = new CDDBTableModel(); model.populateModel(alCddbTracks, fdbReader); // Force table refreshing model.fireTableDataChanged(); return model; } /** * Inits the ui. DOCUMENT_ME */ public void initUI() { okc = new OKCancelPanel(CDDBWizard.this, Messages.getString("Apply"), Messages.getString("Close")); // Albums List jcbAlbum = new SteppedComboBox(); // add all matches jcbAlbum.setModel(new DefaultComboBoxModel(jcbFoundAlbums.toArray())); jcbAlbum.setSelectedIndex(jcbAlbum.getSelectedIndex()); jcbAlbum.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent arg0) { // Update table model = populateModel(); jtable.setModel(model); jtable.selectAll(); } }); // Show the number of matches found JLabel jlCurrent = new JLabel(foundAlbums.length + " " + Messages.getString("CDDBWizard.18")); // Add items setLayout(new MigLayout("insets 10,gapx 15,gapy 15", "[grow,800:800:]")); add(new JLabel(Messages.getString("CDDBWizard.5")), "split 3"); add(jcbAlbum, "grow"); add(jlCurrent, "wrap"); add(new JScrollPane(jtable), "grow,wrap"); add(okc, "span,right"); getRootPane().setDefaultButton(okc.getOKButton()); pack(); setLocationRelativeTo(JajukMainWindow.getInstance()); setVisible(true); } /** * Perform the actual freedb query. * * @param cddbtracks DOCUMENT_ME * * @return number of results (0 if no result). -1 if a technical problem * occurred. */ public int performQuery(CDDBTrack[] cddbtracks) { fdb = new Freedb(); FreedbAlbum fdbAlbum = new FreedbAlbum(cddbtracks); try { foundAlbums = fdb.query(fdbAlbum); jcbFoundAlbums = new ArrayList(foundAlbums.length); for (FreedbQueryResult foundAlbum : foundAlbums) { jcbFoundAlbums.add("[" + foundAlbum.getDiscId() + "] " + UtilString.getLimitedString((foundAlbum.getArtist() + " / " + foundAlbum.getAlbum()), 40)); if (foundAlbum.isExactMatch()) { InformationJPanel.getInstance().setMessage(Messages.getString("CDDBWizard.17"), InformationJPanel.MessageType.INFORMATIVE); } } return foundAlbums.length; } catch (FreedbException e) { Log.debug(e.getLocalizedMessage()); // freedb throws a Freedb exception for network problem or no match found // we want to display an error message only in the first case if (e.getMessage().toLowerCase(Locale.getDefault()).indexOf("no match") == -1) { Messages.showErrorMessage(174, e.getLocalizedMessage()); return -1; } return 0; } catch (Exception e) { Log.debug(e.getLocalizedMessage()); Messages.showErrorMessage(174, e.getLocalizedMessage()); return -1; } } /** * Retag files. DOCUMENT_ME */ public void retagFiles() { int[] aIdxToTag = jtable.getSelectedRows(); if (aIdxToTag.length == 0) { dispose(); } else { for (int iRow : aIdxToTag) { // Unset autocommit to tags so we write to file only once for all // changed tags for a single file TrackManager.getInstance().setAutocommit(false); Track track = alCddbTracks.get(iRow).getTrack(); try { track = retagInternal(iRow, track); // Commit all tags for a single file (we prefer this to make sure some // tracks will be changed, so we don't commit all tags for all files) TrackManager.getInstance().commit(); } catch (JajukException e) { Log.error(e); Messages.showErrorMessage(155, track.getName()); dispose(); // Stop retagging if one track cannot be written to avoid displaying // several error messages // TODO a better handling could be to finish all tag writes and // displaying a grouped list of failed items like in properties panel break; } finally { TrackManager.getInstance().setAutocommit(true); } } InformationJPanel.getInstance().setMessage(Messages.getString("Success"), InformationJPanel.MessageType.INFORMATIVE); // Force files resorting to ensure the sorting consistency, indeed, // files are sorted by name *and* track order and we need to force a files // resort after an order change (this is already done in case of file name // change) FileManager.getInstance().forceSorting(); ObservationManager.notify(new JajukEvent(JajukEvents.DEVICE_REFRESH)); } } /** * Retag internal. * * @param iRow DOCUMENT_ME * @param trackin DOCUMENT_ME * * @return the track * * @throws JajukException the jajuk exception */ private Track retagInternal(final int iRow, final Track trackin) throws JajukException { Track track = trackin; String sValue = fdbReader.getAlbum(); if (sValue != null && sValue.trim().length() > 0) { track = TrackManager.getInstance().changeTrackAlbum(track, sValue, null); } sValue = fdbReader.getArtist(); if (sValue != null && sValue.trim().length() > 0) { track = TrackManager.getInstance().changeTrackArtist(track, sValue, null); } sValue = fdbReader.getTrackTitle(iRow); if (sValue != null && sValue.trim().length() > 0) { track = TrackManager.getInstance().changeTrackName(track, sValue, null); } sValue = fdbReader.getGenre(); if (sValue != null && sValue.trim().length() > 0) { track = TrackManager.getInstance().changeTrackGenre(track, sValue, null); } // Track# can be absent from CDDB database, ignore if not provided try { long lValue = fdbReader.getTrackNumber(iRow); if (lValue > 0) { track = TrackManager.getInstance().changeTrackOrder(track, lValue, null); } } catch (NumberFormatException e) { Log.debug(e); } // Same for year try { long lValue = Long.parseLong(fdbReader.getYear()); if (lValue > 0 && lValue < 3000) { // Review this after year 3000 // Fry ;-) track = TrackManager.getInstance().changeTrackYear(track, fdbReader.getYear(), null); } } catch (NumberFormatException e) { Log.debug(e); } return track; } /* * (non-Javadoc) * * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent) */ @Override public void actionPerformed(ActionEvent e) { if (e.getSource() == okc.getCancelButton()) { dispose(); } if (e.getSource() == okc.getOKButton()) { dispose(); new Thread("CDDBWizard Action Thread") { @Override public void run() { retagFiles(); } }.start(); } } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/wizard/RefreshDialog.java0000644000175000017500000001154611720500104025310 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.wizard; import javax.swing.Icon; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JProgressBar; import javax.swing.SwingUtilities; import net.miginfocom.swing.MigLayout; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; import org.jdesktop.swingx.JXBusyLabel; /** * Refresh dialog. */ public class RefreshDialog extends JFrame { /** Generated serialVersionUID. */ private static final long serialVersionUID = -7883506101436294760L; /** DOCUMENT_ME. */ private JXBusyLabel jlAction; /** DOCUMENT_ME. */ private JProgressBar progress; /** DOCUMENT_ME. */ private JLabel jlRefreshing; /** DOCUMENT_ME. */ private boolean indeterminate = false; /** DOCUMENT_ME. */ private long dateLastUpdateRefresh; /** DOCUMENT_ME. */ private long dateLastUpdateProgress; /** Minimum dialog refresh interval in ms, avoid to saturate the EDT*. */ private static int MIN_REFRESH_INTERVAL = 100; /** * Refresh dialog (labels and a progress bar). * * @param indeterminate whether the progress is indeterminate or not */ public RefreshDialog(final boolean indeterminate) { this.indeterminate = indeterminate; SwingUtilities.invokeLater(new Runnable() { @Override public void run() { setUndecorated(true); setIconImage(IconLoader.getIcon(JajukIcons.LOGO).getImage()); jlAction = new JXBusyLabel(); progress = new JProgressBar(0, 100); progress.setIndeterminate(indeterminate); jlRefreshing = new JLabel(); setLayout(new MigLayout("insets 10,gapx 5, gapy 5", "[500!]")); add(jlAction, "center,wrap"); add(progress, "center,grow,wrap"); add(jlRefreshing, "center,wrap"); pack(); setLocationRelativeTo(RefreshDialog.this); setVisible(true); } }); } /** * Sets the action. * DOCUMENT_ME * * @param action DOCUMENT_ME * @param icon DOCUMENT_ME */ public void setAction(final String action, final Icon icon) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { // check if the dialog is still visible, may be closed before this code is executed if (jlAction != null) { jlAction.setText(action); jlAction.setIcon(icon); jlAction.setBusy(true); } } }); } /** * Sets the refreshing. * * @param path the new refreshing */ public void setRefreshing(final String path) { // No more than one GUI refresh every 100 ms if ((System.currentTimeMillis() - dateLastUpdateRefresh) < MIN_REFRESH_INTERVAL) { return; } dateLastUpdateRefresh = System.currentTimeMillis(); SwingUtilities.invokeLater(new Runnable() { @Override public void run() { // check if the dialog is still visible, may be closed before this code is executed if (jlRefreshing != null) { jlRefreshing.setText(path); jlRefreshing.setToolTipText(path); } } }); } /** * Sets the progress. * * @param pos position from 0 to 100 */ public void setProgress(final int pos) { if (!this.indeterminate) { // No more than one GUI refresh every 100 ms if ((System.currentTimeMillis() - dateLastUpdateProgress) < MIN_REFRESH_INTERVAL) { return; } dateLastUpdateProgress = System.currentTimeMillis(); SwingUtilities.invokeLater(new Runnable() { @Override public void run() { // check if the dialog is still visible, may be closed before this code is executed if (progress != null) { progress.setValue(pos); } } }); } } /* (non-Javadoc) * @see java.awt.Window#dispose() */ @Override public void dispose() { if (jlAction != null) { jlAction.setBusy(false); jlAction = null; } super.dispose(); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/wizard/PreparePartyWizard.java0000644000175000017500000013652511720500104026376 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.wizard; import java.awt.Desktop; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.io.File; import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; import java.text.SimpleDateFormat; import java.util.Collections; import java.util.Comparator; import java.util.Date; import java.util.List; import java.util.Locale; import javax.swing.ButtonGroup; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JComboBox; import javax.swing.JFileChooser; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JRadioButton; import javax.swing.JSlider; import javax.swing.SwingConstants; import javax.swing.border.BevelBorder; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import net.miginfocom.swing.MigLayout; import org.apache.commons.lang.StringUtils; import org.jajuk.base.Playlist; import org.jajuk.base.PlaylistManager; import org.jajuk.base.Type; import org.jajuk.base.TypeManager; import org.jajuk.services.bookmark.Bookmarks; import org.jajuk.services.dj.Ambience; import org.jajuk.services.dj.AmbienceManager; import org.jajuk.services.dj.DigitalDJ; import org.jajuk.services.dj.DigitalDJManager; import org.jajuk.services.players.QueueModel; import org.jajuk.ui.helpers.DefaultMouseWheelListener; import org.jajuk.ui.widgets.JajukFileChooser; import org.jajuk.ui.windows.JajukMainWindow; import org.jajuk.util.Conf; import org.jajuk.util.Const; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukFileFilter; import org.jajuk.util.JajukIcons; import org.jajuk.util.LocaleManager; import org.jajuk.util.Messages; import org.jajuk.util.UtilPrepareParty; import org.jajuk.util.error.JajukException; import org.jajuk.util.filters.DirectoryFilter; import org.jajuk.util.log.Log; import org.qdwizard.ClearPoint; import org.qdwizard.Screen; import org.qdwizard.Wizard; /** * Wizard to select a set of files and write them to a separate directory * outside of the collection in order to use them in a MP3 device or any other * media player. * * TODO: progress bar is not done yet * * TODO: a "cancel" button in the progress bar would be nice to let the user * cancel if he finds out that too many were selected */ public class PreparePartyWizard extends Wizard { /** For MigLayout. */ private static final String GROW_WRAP = "grow,wrap"; /** For MigLayout. */ private static final String LEFT_WRAP = "left,wrap"; /** For MigLayout. */ private static final String LEFT = "left"; /** Which source to use for the tracks. */ private static final String KEY_MODE = "MODE"; /** Which item was selected in the first page of the wizard. */ private static final String KEY_ITEM = "ITEM"; /** Where to put the files. */ private static final String KEY_DEST_PATH = "DEST_PATH"; /** Max number of tracks to use. */ private static final String KEY_MAX_TRACKS_ON = "MAXTRACKS_ENABLED"; /** Key for max. number of track */ private static final String KEY_MAX_TRACKS = "MAXTRACKS"; /** Max size to use. */ private static final String KEY_MAX_SIZE_ON = "MAXSIZE_ENABLED"; /** Key for max. size of party */ private static final String KEY_MAX_SIZE = "MAXSIZE"; /** Max playing length of tracks to use. */ private static final String KEY_MAX_LENGTH_ON = "MAXLENGTH_ENABLED"; /** Key for max length of party. */ private static final String KEY_MAX_LENGTH = "MAXLENGTH"; /** Max number of tracks to queue. */ private static final String KEY_ONE_MEDIA_ON = "ONE_MEDIA_ENABLED"; /** Key for limit to one audio type. */ private static final String KEY_MEDIA = "ONE_MEDIA"; /** Key for audio type conversion. */ private static final String KEY_CONVERT_MEDIA = "CONVERT_MEDIA"; /** Key for the command to use for audio conversion. */ private static final String KEY_CONVERT_COMMAND = "CONVERT_COMMAND"; /** Used to enable replacing characters outside the normal range. */ private static final String KEY_NORMALIZE_FILENAME_ON = "NORMALIZE_FILENAME"; /** Ratings level. */ private static final String KEY_RATINGS_LEVEL = "RATING_LEVEL"; /** store a temporary playlist that is provided by the PlaylistView without storing it in the PlaylistManager we keep it here to be able to re-display it in the Pages later on We need to keep it outside the ActionSelectionPanel because the panel is re-created during back-forward operations. */ private static Playlist tempPlaylist; /** Indicator to only restore properties once and not overwrite them again later. */ private static boolean bPropertiesRestored = false; /** Indicates if the PACPL tool for audio conversion is available. */ private static boolean bPACPLAvailable = false; /** * The source of the Party. */ private enum Mode { /** Use one of the available DJs. */ DJ, /** Use one of hte available Ambiences. */ Ambience, /** Use random tracks from all available track. */ Shuffle, /** Use a playlist. */ Playlist, /** Use songs from the BestOf list. */ BestOf, /** Use songs from the Novelties list. */ Novelties, /** Use songs from the current play queue. */ Queue, /** Use the available bookmarks. */ Bookmarks, /** Special mode for when the dialog is invoked with a newly created playlist. */ ProvidedPlaylist } /** * Default constructor that lets the user choose where the tracks are taken * from. * * @param bProvidedPlaylist Indicates that a playlist was provided to the dialog and thus the * first page is not displayed */ public PreparePartyWizard(boolean bProvidedPlaylist) { super(Messages.getString("PreparePartyWizard.1"), bProvidedPlaylist ? GeneralOptionsPanel.class : ActionSelectionPanel.class, null, JajukMainWindow.getInstance(), LocaleManager .getLocale(), 800, 550); super.setHeaderIcon(IconLoader.getIcon(JajukIcons.PREPARE_PARTY_32X32)); // check if pacpl can be used, do it every time the dialog starts as the // user might have installed it by now bPACPLAvailable = UtilPrepareParty.checkPACPL((String) data.get(KEY_CONVERT_COMMAND)); } /** * Set the provided playlist so that the first page can be skipped if wanted. * * This needs to be done as static method as the Wizard-constructor already * needs to have this data available! * * @param playlist The playlist to use for the party */ public static void setPlaylist(Playlist playlist) { // store playlist and the mode that we are now having tempPlaylist = playlist; // store the mode and the playlist in the data as well data.put(KEY_MODE, Mode.ProvidedPlaylist); data.put(KEY_ITEM, playlist.getName()); } /** * Return if the specified element is true in the data-map. * * @param key The key to look up in the data-object. * * @return true if the value was stored as boolean true, false otherwise. */ private static final boolean isTrue(final String key) { return data.containsKey(key) && Boolean.TRUE.equals(data.get(key)); } /* * (non-Javadoc) * * @see org.qdwizard.Wizard#finish() */ @Override public void finish() { // write properties to keep the selected directory try { storeProperties(); Conf.commit(); } catch (IOException e1) { Log.error(e1); } // retrieve the full list of files according to the selected mode List files = getFiles(); if (files == null) { return; } // define the target directory final Date curDate = new Date(); // Do not use ':' character in destination directory, it's // forbidden under Windows final SimpleDateFormat stamp = new SimpleDateFormat("yyyyMMdd-HHmm", Locale.getDefault()); final String dirName = "Party-" + stamp.format(curDate); final java.io.File destDir = new java.io.File(((String) data.get(KEY_DEST_PATH)), dirName); if (!destDir.mkdir()) { Log.warn("Could not create destination directory " + destDir); } Log.debug("Going to copy " + files.size() + " files to directory {{" + destDir.getAbsolutePath() + "}}"); // perform the actual copying UtilPrepareParty.copyFiles(files, destDir, isTrue(KEY_NORMALIZE_FILENAME_ON), isTrue(KEY_ONE_MEDIA_ON) && isTrue(KEY_CONVERT_MEDIA), (String) data.get(KEY_MEDIA), (String) data.get(KEY_CONVERT_COMMAND)); } /** * Gets the list of files to copy depending on the current mode. * * @return the files */ private List getFiles() { List files; if (Mode.DJ.equals(data.get(KEY_MODE))) { files = UtilPrepareParty.getDJFiles((String) data.get(KEY_ITEM)); } else if (Mode.Ambience.equals(data.get(KEY_MODE))) { files = UtilPrepareParty.getAmbienceFiles((String) data.get(KEY_ITEM)); } else if (Mode.Playlist.equals(data.get(KEY_MODE)) || Mode.ProvidedPlaylist.equals(data.get(KEY_MODE))) { try { files = UtilPrepareParty.getPlaylistFiles((String) data.get(KEY_ITEM), tempPlaylist); } catch (JajukException e1) { Log.error(e1); return null; } } else if (Mode.Shuffle.equals(data.get(KEY_MODE))) { files = UtilPrepareParty.getShuffleFiles(); } else if (Mode.BestOf.equals(data.get(KEY_MODE))) { try { files = UtilPrepareParty.getBestOfFiles(); } catch (JajukException e1) { Log.error(e1); return null; } } else if (Mode.Queue.equals(data.get(KEY_MODE))) { try { files = UtilPrepareParty.getQueueFiles(); } catch (JajukException e1) { Log.error(e1); return null; } } else if (Mode.Bookmarks.equals(data.get(KEY_MODE))) { try { files = UtilPrepareParty.getBookmarkFiles(); } catch (JajukException e1) { Log.error(e1); return null; } } else if (Mode.Novelties.equals(data.get(KEY_MODE))) { try { files = UtilPrepareParty.getNoveltiesFiles(); } catch (JajukException e1) { Log.error(e1); return null; } } else { throw new IllegalArgumentException("Unknown mode in PreparePartyWizard: " + data.get(KEY_MODE)); } // filter by media first if (isTrue(KEY_ONE_MEDIA_ON) && !isTrue(KEY_CONVERT_MEDIA)) { files = UtilPrepareParty.filterMedia(files, (String) data.get(KEY_MEDIA)); } // then filter out by rating if (data.containsKey(KEY_RATINGS_LEVEL)) { files = UtilPrepareParty.filterRating(files, (Integer) data.get(KEY_RATINGS_LEVEL)); } // filter max length if (isTrue(KEY_MAX_LENGTH_ON)) { files = UtilPrepareParty.filterMaxLength(files, (Integer) data.get(KEY_MAX_LENGTH)); } // filter max size if (isTrue(KEY_MAX_SIZE_ON)) { files = UtilPrepareParty.filterMaxSize(files, (Integer) data.get(KEY_MAX_SIZE)); } // filter max tracks if (isTrue(KEY_MAX_TRACKS_ON)) { files = UtilPrepareParty.filterMaxTracks(files, (Integer) data.get(KEY_MAX_TRACKS)); } return files; } /** * Stores all the values that are stored in the data-map to the Conf-system. */ private static void storeProperties() { storeValue(KEY_MODE); storeValue(KEY_ITEM); storeValue(KEY_DEST_PATH); storeValue(KEY_MAX_TRACKS_ON); storeValue(KEY_MAX_TRACKS); storeValue(KEY_MAX_SIZE_ON); storeValue(KEY_MAX_SIZE); storeValue(KEY_MAX_LENGTH_ON); storeValue(KEY_MAX_LENGTH); storeValue(KEY_ONE_MEDIA_ON); storeValue(KEY_MEDIA); storeValue(KEY_CONVERT_MEDIA); storeValue(KEY_CONVERT_COMMAND); storeValue(KEY_NORMALIZE_FILENAME_ON); storeValue(KEY_RATINGS_LEVEL); } /** * Store one value as String. * * @param key The name of the property to store in the overall configuration */ private static void storeValue(final String key) { // nothing to do? if (data.get(key) == null) { return; } Conf.setProperty(Const.CONF_PREPARE_PARTY + key, data.get(key).toString()); } /** * Restore all the values that are potentially stored in the configuration * system. */ private static void restoreProperties() { // only restore once to not overwrite, due to the Wizard implementation we // don't know for sure when this is called; if (bPropertiesRestored) { return; } bPropertiesRestored = true; restoreModeAndItemValue(); restoreStringValue(KEY_DEST_PATH); restoreBooleanValue(KEY_MAX_TRACKS_ON); restoreIntValue(KEY_MAX_TRACKS); restoreBooleanValue(KEY_MAX_SIZE_ON); restoreIntValue(KEY_MAX_SIZE); restoreBooleanValue(KEY_MAX_LENGTH_ON); restoreIntValue(KEY_MAX_LENGTH); restoreBooleanValue(KEY_ONE_MEDIA_ON); restoreStringValue(KEY_MEDIA); restoreBooleanValue(KEY_CONVERT_MEDIA); restoreStringValue(KEY_CONVERT_COMMAND); if (StringUtils.isBlank((String) data.get(KEY_CONVERT_COMMAND))) { data.put(KEY_CONVERT_COMMAND, "pacpl"); // use default value if none set // yet } restoreBooleanValue(KEY_NORMALIZE_FILENAME_ON); restoreIntValue(KEY_RATINGS_LEVEL); } /** * Restore one string value from the configuration. * * @param key The key to restore. */ private static void restoreStringValue(final String key) { String sValue = Conf.getString(Const.CONF_PREPARE_PARTY + key); // nothing to do if not set if (sValue == null) { return; } data.put(key, sValue); } /** * Restore one integer value from the configuration. * * @param key The key to restore. */ private static void restoreIntValue(final String key) { // do nothing if not available yet if (Conf.getString(Const.CONF_PREPARE_PARTY + key) == null) { return; } data.put(key, Conf.getInt(Const.CONF_PREPARE_PARTY + key)); } /** * Restore one boolean value from the configuration. * * @param key The key to restore. */ private static void restoreBooleanValue(final String key) { // do nothing if not available yet if (Conf.getString(Const.CONF_PREPARE_PARTY + key) == null) { return; } data.put(key, Conf.getBoolean(Const.CONF_PREPARE_PARTY + key)); } /** * Restore mode and item values, they may require some special handling. */ private static void restoreModeAndItemValue() { String sMode = Conf.getString(Const.CONF_PREPARE_PARTY + KEY_MODE); // nothing to do if not set if (sMode == null) { return; } data.put(KEY_MODE, Mode.valueOf(sMode)); switch ((Mode) data.get(KEY_MODE)) { // restore the value for the ones where we have a selection case Ambience: case DJ: case Playlist: data.put(KEY_ITEM, Conf.getString(Const.CONF_PREPARE_PARTY + KEY_ITEM)); break; // nothing to do case BestOf: case Bookmarks: case Shuffle: case Novelties: case Queue: // we usually are not able to restore this, therefore don't do anything case ProvidedPlaylist: default: break; } } /* * (non-Javadoc) * * @see org.qdwizard.Wizard#getNextScreen(java.lang.Class) */ @Override public Class getNextScreen(Class screen) { if (ActionSelectionPanel.class.equals(getCurrentScreen())) { return GeneralOptionsPanel.class; } else if (GeneralOptionsPanel.class.equals(getCurrentScreen())) { return PathSelectionPanel.class; } return null; } /* * (non-Javadoc) * * @see org.qdwizard.Wizard#getPreviousScreen(java.lang.Class) */ @Override public Class getPreviousScreen(Class screen) { // there is no "back" if we got a playlist passed in if (GeneralOptionsPanel.class.equals(getCurrentScreen()) && !Mode.ProvidedPlaylist.equals(data.get(KEY_MODE))) { return ActionSelectionPanel.class; } else if (PathSelectionPanel.class.equals(getCurrentScreen())) { return GeneralOptionsPanel.class; } return null; } /* (non-Javadoc) * @see org.qdwizard.Wizard#onCancel() */ @Override public boolean onCancel() { // this also clears "data", so we need to reset the restore-state bPropertiesRestored = false; return super.onCancel(); } /** * First Panel of the Wizard, it shows a selection of sources where the user can choose one, e.g. DJs, Ambiences, ... */ public static class ActionSelectionPanel extends Screen implements ActionListener, ClearPoint { /** Generated serialVersionUID. */ private static final long serialVersionUID = -6981770030816500259L; /** The group for the various sources. */ private ButtonGroup bgActions; /** DJ. */ private JRadioButton jrbDJ; /** DJ. */ private JComboBox jcbDJ; /** Ambience. */ private JRadioButton jrbAmbience; /** Ambience. */ private JComboBox jcbAmbience; /** Playlist. */ private JRadioButton jrbPlaylist; /** Playlist. */ private JComboBox jcbPlaylist; /** Shuffle. */ private JRadioButton jrbShuffle; /** Shuffle. */ private JRadioButton jrbBestOf; /** Novelties. */ private JRadioButton jrbNovelties; /** Queue. */ private JRadioButton jrbQueue; /** Bookmarks. */ private JRadioButton jrbBookmark; /** * Create panel UI. */ @Override public void initUI() { // workaround as the dialog is initialized before the constructor of // PreparePartyWizard fully executes restoreProperties(); bgActions = new ButtonGroup(); jrbDJ = new JRadioButton(Messages.getString("PreparePartyWizard.6")); jrbDJ.addActionListener(this); // populate DJs List djs = DigitalDJManager.getInstance().getDJsSorted(); jcbDJ = new JComboBox(); for (DigitalDJ dj : djs) { jcbDJ.addItem(dj.getName()); } jcbDJ.addActionListener(this); jrbAmbience = new JRadioButton(Messages.getString("PreparePartyWizard.7")); jrbAmbience.addActionListener(this); List ambiences = AmbienceManager.getInstance().getAmbiences(); jcbAmbience = new JComboBox(); for (Ambience amb : ambiences) { jcbAmbience.addItem(amb.getName()); } jcbAmbience.addActionListener(this); jrbPlaylist = new JRadioButton(Messages.getString("PreparePartyWizard.8")); jrbPlaylist.addActionListener(this); jcbPlaylist = new JComboBox(); if (tempPlaylist != null) { // check if this is a "temporary" playlist that is provided by the // PlaylistView (i.e. not yet stored in PlaylistManager) jcbPlaylist.addItem(tempPlaylist.getName()); } List playlists = PlaylistManager.getInstance().getPlaylists(); for (Playlist pl : playlists) { jcbPlaylist.addItem(pl.getName()); } jcbPlaylist.addActionListener(this); jrbShuffle = new JRadioButton(Messages.getString("PreparePartyWizard.9")); jrbShuffle.addActionListener(this); jrbBestOf = new JRadioButton(Messages.getString("PreparePartyWizard.24")); jrbBestOf.addActionListener(this); jrbNovelties = new JRadioButton(Messages.getString("PreparePartyWizard.25")); jrbNovelties.addActionListener(this); jrbQueue = new JRadioButton(Messages.getString("PreparePartyWizard.32")); jrbQueue.addActionListener(this); jrbBookmark = new JRadioButton(Messages.getString("PreparePartyWizard.33")); jrbBookmark.addActionListener(this); bgActions.add(jrbDJ); bgActions.add(jrbAmbience); bgActions.add(jrbPlaylist); bgActions.add(jrbBestOf); bgActions.add(jrbNovelties); bgActions.add(jrbQueue); bgActions.add(jrbBookmark); bgActions.add(jrbShuffle); // populate items from the stored static data readData(); // populate the screen setLayout(new MigLayout("insets 10,gapx 10,gapy 15", "[][grow]")); add(jrbDJ, LEFT); add(jcbDJ, GROW_WRAP); add(jrbAmbience, LEFT); add(jcbAmbience, GROW_WRAP); add(jrbPlaylist, LEFT); add(jcbPlaylist, GROW_WRAP); add(jrbBestOf, LEFT_WRAP); add(jrbNovelties, LEFT_WRAP); add(jrbQueue, LEFT_WRAP); add(jrbBookmark, LEFT_WRAP); add(jrbShuffle, LEFT_WRAP); // store initial values, done here as well to have them stored if "next" // is pressed immediately // and there was no data stored before (an hence nothing was read in // readData()) updateData(); } /** * Initialize the UI items of the panel with values from the static data * object. */ private void readData() { if (data.containsKey(KEY_MODE)) { // read values set before switch ((Mode) data.get(KEY_MODE)) { case DJ: bgActions.setSelected(jrbDJ.getModel(), true); jcbDJ.setSelectedItem(data.get(KEY_ITEM)); break; case Ambience: bgActions.setSelected(jrbAmbience.getModel(), true); jcbAmbience.setSelectedItem(data.get(KEY_ITEM)); break; case Playlist: case ProvidedPlaylist: // we did a "PrepareParty" from a Playlist // before, in this case show the Playlist again // here bgActions.setSelected(jrbPlaylist.getModel(), true); jcbPlaylist.setSelectedItem(data.get(KEY_ITEM)); break; case Shuffle: bgActions.setSelected(jrbShuffle.getModel(), true); // no combo box for shuffle... break; case BestOf: bgActions.setSelected(jrbBestOf.getModel(), true); // no combo box for bestof... break; case Novelties: bgActions.setSelected(jrbNovelties.getModel(), true); // no combo box for novelties... break; case Queue: bgActions.setSelected(jrbQueue.getModel(), true); // no combo box for queue... break; case Bookmarks: bgActions.setSelected(jrbBookmark.getModel(), true); // no combo box for bookmarks... break; default: throw new IllegalArgumentException("Unexpected value in switch!"); } } else { // no values set yet, select a useful radio button at least // select Ambience as default selection if there is no DJ available if (jcbDJ.getItemCount() == 0) { bgActions.setSelected(jrbAmbience.getModel(), true); } else { // otherwise select DJ as default option bgActions.setSelected(jrbDJ.getModel(), true); } } // finally disable some items if there is nothing in there if (jcbDJ.getItemCount() == 0) { jrbDJ.setEnabled(false); jcbDJ.setEnabled(false); } // disable Playlist UI if there is no Playlist-Mode already selected by // the incoming data... if (jcbPlaylist.getItemCount() == 0 && !(Mode.Playlist.equals(data.get(KEY_MODE)) || Mode.ProvidedPlaylist.equals(data .get(KEY_MODE)))) { jrbPlaylist.setEnabled(false); jcbPlaylist.setEnabled(false); } // check if we have queue-entries or bookmarks if (QueueModel.getQueue().isEmpty()) { jrbQueue.setEnabled(false); } if (Bookmarks.getInstance().getFiles().isEmpty()) { jrbBookmark.setEnabled(false); } } /* * (non-Javadoc) * * @see * java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent) */ @Override public void actionPerformed(ActionEvent e) { // Update all the values that are needed later updateData(); } /** * Store the current values from the UI items into the static data object. */ private void updateData() { // depending on the selected radio button read the combo box value and set // the selected MODE if (jrbDJ.isSelected()) { data.put(KEY_MODE, Mode.DJ); data.put(KEY_ITEM, jcbDJ.getSelectedItem()); } else if (jrbAmbience.isSelected()) { data.put(KEY_MODE, Mode.Ambience); data.put(KEY_ITEM, jcbAmbience.getSelectedItem()); } else if (jrbPlaylist.isSelected()) { data.put(KEY_MODE, Mode.Playlist); data.put(KEY_ITEM, jcbPlaylist.getSelectedItem()); } else if (jrbShuffle.isSelected()) { data.put(KEY_MODE, Mode.Shuffle); data.remove(KEY_ITEM); } else if (jrbBestOf.isSelected()) { data.put(KEY_MODE, Mode.BestOf); data.remove(KEY_ITEM); } else if (jrbNovelties.isSelected()) { data.put(KEY_MODE, Mode.Novelties); data.remove(KEY_ITEM); } else if (jrbQueue.isSelected()) { data.put(KEY_MODE, Mode.Queue); data.remove(KEY_ITEM); } else if (jrbBookmark.isSelected()) { data.put(KEY_MODE, Mode.Bookmarks); data.remove(KEY_ITEM); } } /* (non-Javadoc) * @see org.qdwizard.Screen#getDescription() */ @Override public String getDescription() { return Messages.getString("PreparePartyWizard.3"); } /* (non-Javadoc) * @see org.qdwizard.Screen#getName() */ @Override public String getName() { return Messages.getString("PreparePartyWizard.2"); } } /** * General options panel. */ public static class GeneralOptionsPanel extends Screen implements ActionListener, ChangeListener, ClearPoint, MouseListener { /** Constant for MigLayout. */ private static final String GROW = "grow"; /** Constant for MigLayout. */ private static final String GROW_TWO_COL = "[grow][]"; /** Constant for MigLayout. */ private static final String LABEL_WIDTH = "width 40:40:"; /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** Empty value. */ private static final String NO_VALUE = " "; /** Enable limit on number of tracks. */ private JCheckBox jcbMaxTracks; /** The max. number of tracks */ private JSlider jsMaxTracks; /** The max. number of tracks */ private JLabel jnMaxTracks; /** Enable limit on max size. */ private JCheckBox jcbMaxSize; /** Max size (in MB) of party. */ private JSlider jsMaxSize; /** Max size (in MB) of party. */ private JLabel jnMaxSize; /** Enable limit on max playing length. */ private JCheckBox jcbMaxLength; /** Max playing length of party (in minutes). */ private JSlider jsMaxLength; /** Max playing length of party (in minutes). */ private JLabel jnMaxLength; /** Enable limit on specific audio type. */ private JCheckBox jcbOneMedia; /** Limit to one type of audo file. */ private JComboBox jcbMedia; /** Enable conversion to the selected audio type. */ private JCheckBox jcbConvertMedia; /** Audio conversion. */ private JLabel jlConvertMedia; /** Button to configure audio conversion. */ private JButton jbConvertConfig; /** Limit on rate of tracks. */ private JLabel jlRatingLevel; /** The min. number of stars a track needs to have */ private JSlider jsRatingLevel; /** Enable normalizing filenames so they can be stored on windows fileshares. */ private JCheckBox jcbNormalizeFilename; /* (non-Javadoc) * @see org.qdwizard.Screen#getDescription() */ @Override public String getDescription() { return Messages.getString("PreparePartyWizard.5"); } /* (non-Javadoc) * @see org.qdwizard.Screen#getName() */ @Override public String getName() { return Messages.getString("PreparePartyWizard.4"); } /** * Create panel UI. */ @Override public void initUI() { // workaround as the dialog is initialized before the constructor of // PreparePartyWizard fully executes restoreProperties(); { // Max Tracks jcbMaxTracks = new JCheckBox(Messages.getString("PreparePartyWizard.10")); jcbMaxTracks.setToolTipText(Messages.getString("PreparePartyWizard.11")); jsMaxTracks = new JSlider(0, 5000, 100); jnMaxTracks = new JLabel(NO_VALUE); jnMaxTracks.setBorder(new BevelBorder(BevelBorder.LOWERED)); jnMaxTracks.setHorizontalAlignment(SwingConstants.RIGHT); jsMaxTracks.setMajorTickSpacing(100); jsMaxTracks.setMinorTickSpacing(10); jsMaxTracks.setPaintTicks(false); jsMaxTracks.setPaintLabels(false); jsMaxTracks.setToolTipText(Messages.getString("PreparePartyWizard.11")); } { // Max Size jcbMaxSize = new JCheckBox(Messages.getString("PreparePartyWizard.12")); jcbMaxSize.setToolTipText(Messages.getString("PreparePartyWizard.13")); jsMaxSize = new JSlider(0, 5000, 100); jnMaxSize = new JLabel(NO_VALUE); jnMaxSize.setBorder(new BevelBorder(BevelBorder.LOWERED)); jnMaxSize.setHorizontalAlignment(SwingConstants.RIGHT); jsMaxSize.setMajorTickSpacing(100); jsMaxSize.setMinorTickSpacing(10); jsMaxSize.setPaintTicks(false); jsMaxSize.setPaintLabels(false); jsMaxSize.setToolTipText(Messages.getString("PreparePartyWizard.13")); } { // Max Length jcbMaxLength = new JCheckBox(Messages.getString("PreparePartyWizard.14")); jcbMaxLength.setToolTipText(Messages.getString("PreparePartyWizard.15")); jsMaxLength = new JSlider(0, 5000, 100); jnMaxLength = new JLabel(NO_VALUE); jnMaxLength.setBorder(new BevelBorder(BevelBorder.LOWERED)); jnMaxLength.setHorizontalAlignment(JLabel.RIGHT); jsMaxLength.setMajorTickSpacing(100); jsMaxLength.setMinorTickSpacing(10); jsMaxLength.setPaintTicks(false); jsMaxLength.setPaintLabels(false); jsMaxLength.setToolTipText(Messages.getString("PreparePartyWizard.15")); } { // Choose Media jcbOneMedia = new JCheckBox(Messages.getString("PreparePartyWizard.16")); jcbOneMedia.setToolTipText(Messages.getString("PreparePartyWizard.17")); jcbMedia = new JComboBox(); List types = TypeManager.getInstance().getTypes(); // sort the list on extension here Collections.sort(types, new TypeComparator()); for (Type type : types) { // exclude playlists and web-radios from selection as we cannot copy // those. if (!type.getExtension().equals(Const.EXT_PLAYLIST) && !type.getExtension().equals(Const.EXT_RADIO)) { jcbMedia.addItem(type.getExtension()); } } jcbMedia.setToolTipText(Messages.getString("PreparePartyWizard.17")); jcbConvertMedia = new JCheckBox(Messages.getString("PreparePartyWizard.34")); jcbConvertMedia.setToolTipText(Messages.getString("PreparePartyWizard.35")); // to show help and allow clicking for viewing the related web-page jlConvertMedia = new JLabel(Messages.getString("PreparePartyWizard.37")); jbConvertConfig = new JButton(Messages.getString("PreparePartyWizard.40")); } { // Rating Level jlRatingLevel = new JLabel(Messages.getString("DigitalDJWizard.8")); jlRatingLevel.setToolTipText(Messages.getString("DigitalDJWizard.53")); jsRatingLevel = new JSlider(0, 4, 0); jsRatingLevel.setMajorTickSpacing(1); jsRatingLevel.setMinorTickSpacing(1); jsRatingLevel.setPaintTicks(true); jsRatingLevel.setSnapToTicks(true); jsRatingLevel.setPaintLabels(true); jsRatingLevel.setToolTipText(Messages.getString("DigitalDJWizard.53")); } jcbNormalizeFilename = new JCheckBox(Messages.getString("PreparePartyWizard.26")); jcbNormalizeFilename.setToolTipText(Messages.getString("PreparePartyWizard.27")); // populate the UI items with values from the static data object readData(); // add listeners after reading initial data to not overwrite them with // init-state-change actions // enable/disable slider depending on checkbox jcbMaxTracks.addActionListener(this); jsMaxTracks.addMouseWheelListener(new DefaultMouseWheelListener(jsMaxTracks)); jsMaxTracks.addChangeListener(this); // enable/disable slider depending on checkbox jcbMaxSize.addActionListener(this); jsMaxSize.addMouseWheelListener(new DefaultMouseWheelListener(jsMaxSize)); jsMaxSize.addChangeListener(this); // enable/disable slider depending on checkbox jcbMaxLength.addActionListener(this); jsMaxLength.addMouseWheelListener(new DefaultMouseWheelListener(jsMaxLength)); jsMaxLength.addChangeListener(this); // enable/disable combobox depending on checkbox jcbOneMedia.addActionListener(this); jcbMedia.addActionListener(this); jcbConvertMedia.addActionListener(this); jlConvertMedia.addMouseListener(this); jbConvertConfig.addActionListener(this); // get informed about rating level slider changes jsRatingLevel.addMouseWheelListener(new DefaultMouseWheelListener(jsRatingLevel)); jsRatingLevel.addChangeListener(this); jcbNormalizeFilename.addActionListener(this); setLayout(new MigLayout("insets 10,gapx 10,gapy 15", "[][grow]")); add(jcbMaxTracks); { JPanel panel = new JPanel(); panel.setLayout(new MigLayout("", GROW_TWO_COL)); panel.add(jsMaxTracks, GROW); panel.add(jnMaxTracks, LABEL_WIDTH); add(panel, GROW_WRAP); } add(jcbMaxSize); { JPanel panel = new JPanel(); panel.setLayout(new MigLayout("", GROW_TWO_COL)); panel.add(jsMaxSize, GROW); panel.add(jnMaxSize, LABEL_WIDTH); add(panel, GROW_WRAP); } add(jcbMaxLength); { JPanel panel = new JPanel(); panel.setLayout(new MigLayout("", GROW_TWO_COL)); panel.add(jsMaxLength, GROW); panel.add(jnMaxLength, LABEL_WIDTH); add(panel, GROW_WRAP); } add(jcbOneMedia); add(jcbMedia, GROW_WRAP); // dummy-Label to get the CheckBox for "convert" into the second column add(new JLabel()); add(jcbConvertMedia, GROW_WRAP); add(new JLabel()); { JPanel panel = new JPanel(); panel.setLayout(new MigLayout("", GROW_TWO_COL)); panel.add(jlConvertMedia, GROW); panel.add(jbConvertConfig); add(panel, GROW_WRAP); } add(jcbNormalizeFilename, GROW_WRAP); add(jlRatingLevel); add(jsRatingLevel, GROW_WRAP); // store initial values and adjust values updateData(); } /** * Populate the UI items with values from the static data object. */ private void readData() { // set the values from the stored data // initially these are not set, so we need to query for "containsKey"... if (isTrue(KEY_MAX_TRACKS_ON)) { jsMaxTracks.setEnabled(true); jcbMaxTracks.setSelected(true); } else { jsMaxTracks.setEnabled(false); jcbMaxTracks.setSelected(false); } if (data.containsKey(KEY_MAX_TRACKS)) { jsMaxTracks.setValue((Integer) data.get(KEY_MAX_TRACKS)); } if (isTrue(KEY_MAX_SIZE_ON)) { jsMaxSize.setEnabled(true); jcbMaxSize.setSelected(true); } else { jsMaxSize.setEnabled(false); jcbMaxSize.setSelected(false); } if (data.containsKey(KEY_MAX_SIZE)) { jsMaxSize.setValue((Integer) data.get(KEY_MAX_SIZE)); } if (isTrue(KEY_MAX_LENGTH_ON)) { jsMaxLength.setEnabled(true); jcbMaxLength.setSelected(true); } else { jsMaxLength.setEnabled(false); jcbMaxLength.setSelected(false); } if (data.containsKey(KEY_MAX_LENGTH)) { jsMaxLength.setValue((Integer) data.get(KEY_MAX_LENGTH)); } if (isTrue(KEY_ONE_MEDIA_ON)) { jcbMedia.setEnabled(true); jcbOneMedia.setSelected(true); jcbConvertMedia.setEnabled(true); } else { jcbMedia.setEnabled(false); jcbOneMedia.setSelected(false); jcbConvertMedia.setEnabled(false); } // disable media conversion if pacpl is not found if (!bPACPLAvailable) { jcbConvertMedia.setEnabled(false); } // don't set Convert to on from data if PACPL became unavailable if (isTrue(KEY_CONVERT_MEDIA) && bPACPLAvailable) { jcbConvertMedia.setSelected(true); } else { jcbConvertMedia.setSelected(false); } if (data.containsKey(KEY_MEDIA)) { jcbMedia.setSelectedItem(data.get(KEY_MEDIA)); } else { // default to MP3 initially jcbMedia.setSelectedItem("mp3"); } if (data.containsKey(KEY_RATINGS_LEVEL)) { jsRatingLevel.setValue((Integer) data.get(KEY_RATINGS_LEVEL)); } if (isTrue(KEY_NORMALIZE_FILENAME_ON)) { jcbNormalizeFilename.setSelected(true); } else { jcbNormalizeFilename.setSelected(false); } } /** * Write the data from the UI items to the static data object. */ private void updateData() { // store if checkbox is enabled and update the label accordingly updateOneItem(jcbMaxTracks, jsMaxTracks, jnMaxTracks, KEY_MAX_TRACKS, KEY_MAX_TRACKS_ON); updateOneItem(jcbMaxSize, jsMaxSize, jnMaxSize, KEY_MAX_SIZE, KEY_MAX_SIZE_ON); updateOneItem(jcbMaxLength, jsMaxLength, jnMaxLength, KEY_MAX_LENGTH, KEY_MAX_LENGTH_ON); if (jcbOneMedia.isSelected()) { data.put(KEY_MEDIA, jcbMedia.getSelectedItem()); data.put(KEY_ONE_MEDIA_ON, Boolean.TRUE); } else { // keep old value... data.remove(KEY_MEDIA); data.put(KEY_ONE_MEDIA_ON, Boolean.FALSE); } data.put(KEY_CONVERT_MEDIA, jcbConvertMedia.isSelected()); data.put(KEY_RATINGS_LEVEL, jsRatingLevel.getValue()); data.put(KEY_NORMALIZE_FILENAME_ON, jcbNormalizeFilename.isSelected()); } /** * Helper to handle a checkbox/slider combination. It also updates an * associated Label with the value from the Slider. * * @param cb The checkbox to check for selected/deselected state * @param slider The slider to get the value from * @param label The Label to populate with the current value from the Slider. * @param key The key in the static data object for the value of the Slider. * @param keyOn The key in the static data object to store the enabled/disabled * state. */ private void updateOneItem(JCheckBox cb, JSlider slider, JLabel label, String key, String keyOn) { if (cb.isSelected()) { if (!slider.getValueIsAdjusting()) { data.put(key, slider.getValue()); data.put(keyOn, Boolean.TRUE); } label.setText(Integer.toString(slider.getValue())); } else { if (!slider.getValueIsAdjusting()) { // keep value... data.remove(key); data.put(keyOn, Boolean.FALSE); } label.setText(NO_VALUE); } } /* * (non-Javadoc) * * @see * java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent) */ public void actionPerformed(ActionEvent ae) { // if a checkbox is selected/deselected, enable/disable the // sliders/comboboxes accordingly if (ae.getSource() == jcbMaxTracks) { jsMaxTracks.setEnabled(jcbMaxTracks.isSelected()); } else if (ae.getSource() == jcbMaxSize) { jsMaxSize.setEnabled(jcbMaxSize.isSelected()); } else if (ae.getSource() == jcbMaxLength) { jsMaxLength.setEnabled(jcbMaxLength.isSelected()); } else if (ae.getSource() == jcbOneMedia) { jcbMedia.setEnabled(jcbOneMedia.isSelected()); jcbConvertMedia.setEnabled(jcbOneMedia.isSelected()); } else if (ae.getSource() == jbConvertConfig) { // create the settings dialog, it will display itself and inform us when // the value is changed with "Ok" new PreparePartyConvertSettings(new ChangeListener() { @Override public void stateChanged(ChangeEvent e) { // no need for re-checking if the same command is chosen as before if (e.getSource().toString().equals(data.get(KEY_CONVERT_COMMAND))) { Log.debug("Same pacpl-command as before: " + e.getSource().toString()); return; } Log.debug("New pacpl-command: " + e.getSource().toString()); data.put(KEY_CONVERT_COMMAND, e.getSource().toString()); // re-check if pacpl can be called now bPACPLAvailable = UtilPrepareParty.checkPACPL((String) data.get(KEY_CONVERT_COMMAND)); // disable media conversion if pacpl is not found if (bPACPLAvailable) { Log.debug("Updated settings for media conversion allow pacpl to be used."); jcbConvertMedia.setEnabled(true); } else { Log.warn("Updated settings for media conversion do not allow pacpl to be used!"); jcbConvertMedia.setEnabled(false); jcbConvertMedia.setSelected(false); } } }, (String) data.get(KEY_CONVERT_COMMAND), JajukMainWindow.getInstance()); } updateData(); } /* * (non-Javadoc) * * @see * javax.swing.event.ChangeListener#stateChanged(javax.swing.event.ChangeEvent * ) */ public void stateChanged(ChangeEvent ie) { // just update the stored static data whenever we receive an interesting // event if (ie.getSource() == jsMaxTracks) { updateData(); } else if (ie.getSource() == jsMaxSize) { updateData(); } else if (ie.getSource() == jsMaxLength) { updateData(); } else if (ie.getSource() == jcbMedia) { updateData(); } else if (ie.getSource() == jsRatingLevel) { updateData(); } } /* * (non-Javadoc) * * @see java.awt.event.MouseListener#mouseClicked(java.awt.event.MouseEvent) */ @Override public void mouseClicked(MouseEvent e) { if (e.getSource() == jlConvertMedia) { try { Desktop.getDesktop().browse( new URI("http://jajuk.info/index.php/Installing_Perl_Audio_Converter")); } catch (IOException ex) { Log.error(ex); } catch (URISyntaxException ex) { Log.error(ex); } } } /* * (non-Javadoc) * * @see java.awt.event.MouseListener#mouseEntered(java.awt.event.MouseEvent) */ @Override public void mouseEntered(MouseEvent e) { // nothing to do here... } /* * (non-Javadoc) * * @see java.awt.event.MouseListener#mouseExited(java.awt.event.MouseEvent) */ @Override public void mouseExited(MouseEvent e) { // nothing to do here... } /* * (non-Javadoc) * * @see java.awt.event.MouseListener#mousePressed(java.awt.event.MouseEvent) */ @Override public void mousePressed(MouseEvent e) { // nothing to do here... } /* * (non-Javadoc) * * @see * java.awt.event.MouseListener#mouseReleased(java.awt.event.MouseEvent) */ @Override public void mouseReleased(MouseEvent e) { // nothing to do here... } } /** * Panel for selecting the location in the filesystem. */ public static class PathSelectionPanel extends Screen implements ActionListener { /** Generated serialVersionUID. */ private static final long serialVersionUID = -236180699495019177L; /** Button for file chooser dialog. */ JButton jbFileSelection; /** The selected file. */ JLabel jlSelectedFile; /** Selected directory. */ private File fDir; /* * (non-Javadoc) * * @see org.qdwizard.Screen#initUI() */ @Override public void initUI() { JLabel jlFileSelection = new JLabel(Messages.getString("PreparePartyWizard.20")); jbFileSelection = new JButton(IconLoader.getIcon(JajukIcons.OPEN_DIR)); jbFileSelection.addActionListener(this); JLabel jlSelectedFileText = new JLabel(Messages.getString("PreparePartyWizard.21")); jlSelectedFile = new JLabel(Messages.getString("FirstTimeWizard.9")); jlSelectedFile.setBorder(new BevelBorder(BevelBorder.LOWERED)); // previous value if available if (data.containsKey(KEY_DEST_PATH)) { jlSelectedFile.setText((String) data.get(KEY_DEST_PATH)); // we also can finish the dialog setCanFinish(true); } else { setProblem(Messages.getString("PreparePartyWizard.22")); // now we can not finish the dialog setCanFinish(false); } // Add items setLayout(new MigLayout("insets 10,gapx 10,gapy 15", "[][grow]")); add(jlFileSelection); add(jbFileSelection, "wrap,center"); add(jlSelectedFileText); add(jlSelectedFile, "grow,wrap"); } /* * (non-Javadoc) * * @see * java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent) */ @Override public void actionPerformed(ActionEvent e) { // display a FileChooser if (e.getSource() == jbFileSelection) { // TODO: for some reason the passing of the existing directory does not // work here, seems the implementation in JajukFileChooser does not do // this correctly final JajukFileChooser jfc = new JajukFileChooser(new JajukFileFilter(DirectoryFilter .getInstance()), fDir); jfc.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); jfc.setDialogTitle(Messages.getString("PreparePartyWizard.22")); jfc.setMultiSelectionEnabled(false); final int returnVal = jfc.showOpenDialog(this); if (returnVal == JFileChooser.APPROVE_OPTION) { // retrieve selected directory and update it in all necessary places fDir = jfc.getSelectedFile(); jlSelectedFile.setText(fDir.getAbsolutePath()); data.put(KEY_DEST_PATH, fDir.getAbsolutePath()); // we can finish the wizard now setProblem(null); // now we can finish the dialog setCanFinish(true); } } } /* (non-Javadoc) * @see org.qdwizard.Screen#getDescription() */ @Override public String getDescription() { return Messages.getString("PreparePartyWizard.19"); } /* (non-Javadoc) * @see org.qdwizard.Screen#getName() */ @Override public String getName() { return Messages.getString("PreparePartyWizard.18"); } } /** * Compare two types. */ private static final class TypeComparator implements Comparator { /* (non-Javadoc) * @see java.util.Comparator#compare(java.lang.Object, java.lang.Object) */ @Override public int compare(Type o1, Type o2) { // handle null, always equal if (o1 == null || o2 == null) { return 0; } // otherwise sort on extension here return o1.getExtension().compareTo(o2.getExtension()); } } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/wizard/ExtraTagsConfigurationWizard.java0000644000175000017500000002112111720500104030373 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.wizard; import java.awt.Color; import java.awt.Dimension; import java.awt.Graphics; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.ArrayList; import java.util.List; import java.util.Properties; import javax.swing.BorderFactory; import javax.swing.DefaultListModel; import javax.swing.JButton; import javax.swing.JDialog; import javax.swing.JLabel; import javax.swing.JList; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTextArea; import javax.swing.WindowConstants; import net.miginfocom.swing.MigLayout; import org.jajuk.base.Device; import org.jajuk.base.DeviceManager; import org.jajuk.base.PropertyMetaInformation; import org.jajuk.base.TrackManager; import org.jajuk.events.JajukEvent; import org.jajuk.events.JajukEvents; import org.jajuk.events.ObservationManager; import org.jajuk.services.tags.Tag; import org.jajuk.ui.widgets.JajukJDialog; import org.jajuk.ui.widgets.OKCancelPanel; import org.jajuk.ui.windows.JajukMainWindow; import org.jajuk.util.Const; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; import org.jdesktop.swingx.VerticalLayout; /** * Wizard allowing user to select the extra tags to be displayed by jajuk. */ public class ExtraTagsConfigurationWizard extends JajukJDialog { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** DOCUMENT_ME. */ private JList availableTagsJList; /** DOCUMENT_ME. */ private JList activatedTagsJList; /** OK/Cancel buttons. */ private OKCancelPanel okp; /** DOCUMENT_ME. */ private List availableList = new ArrayList(); /** DOCUMENT_ME. */ private List activatedList = new ArrayList(); /** * Instantiates a new extra tags configuration wizard. */ public ExtraTagsConfigurationWizard() { super(JajukMainWindow.getInstance(), true); setTitle(Messages.getString("JajukWindow.40")); setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); initUI(); refreshList(); populate(); setLocationByPlatform(true); setPreferredSize(new Dimension(600, 600)); pack(); setVisible(true); } /** * Refresh list. * DOCUMENT_ME */ private void refreshList() { availableList.clear(); for (String s : Tag.getSupportedTagFields()) { if (!Tag.getActivatedExtraTags().contains(s)) { availableList.add(s); } } activatedList.clear(); for (String s : Tag.getActivatedExtraTags()) { activatedList.add(s); } } /** * Populate. * DOCUMENT_ME */ private void populate() { availableTagsJList.clearSelection(); DefaultListModel model = (DefaultListModel) availableTagsJList.getModel(); model.clear(); for (String s : availableList) { model.addElement(s); } availableTagsJList.setModel(model); activatedTagsJList.clearSelection(); model = (DefaultListModel) activatedTagsJList.getModel(); model.clear(); for (String s : activatedList) { model.addElement(s); } activatedTagsJList.setModel(model); } /** * Inits the ui. * DOCUMENT_ME */ private void initUI() { JTextArea jta = new JTextArea() { private static final long serialVersionUID = 1L; /** * Display an info label in the text area * * @param g * DOCUMENT_ME */ @Override public void paint(Graphics g) { super.paint(g); g.drawImage(IconLoader.getIcon(JajukIcons.INFO).getImage(), 4, 3, 16, 16, null); } }; jta.setTabSize(2); jta.setText('\t' + Messages.getString("ActiveTagsWizard.3")); jta.setLineWrap(true); jta.setEditable(false); jta.setWrapStyleWord(true); jta.setBorder(BorderFactory.createLineBorder(Color.LIGHT_GRAY)); // available tags availableTagsJList = new JList(new DefaultListModel()); // control buttons JButton addButton = new JButton(IconLoader.getIcon(JajukIcons.PLAYER_NEXT)); addButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { for (Object o : availableTagsJList.getSelectedValues()) { activatedList.add(availableList.remove(availableList.indexOf(o))); } populate(); } }); JButton removeButton = new JButton(IconLoader.getIcon(JajukIcons.PLAYER_PREVIOUS)); removeButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { for (Object o : activatedTagsJList.getSelectedValues()) { availableList.add(activatedList.remove(activatedList.indexOf(o))); } populate(); } }); // activated tags activatedTagsJList = new JList(); activatedTagsJList.setModel(new DefaultListModel()); // confirm buttons okp = new OKCancelPanel(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { if (e.getSource() == okp.getOKButton()) { okAction(); } else { setVisible(false); dispose(); } } }); JPanel jpButtons = new JPanel(new VerticalLayout(5)); jpButtons.add(addButton); jpButtons.add(removeButton); // Add items setLayout(new MigLayout("ins 5,gapx 5,gapy 5", "[grow][20][grow]", "[grow 5][][grow 95][]")); // Keep the pad : it fixes a known "issue/feature" with some text component. MigLayout manual // (see http://migcalendar.com/miglayout/whitepaper.html) says "Note! Padding multi-line // components derived from JTextComponent (such as JTextArea) without setting a explicit minimum // size may result in an continuous size escalation (animated!)" add(jta, "grow,span,wrap,pad 5 5 -5 -5"); add(new JLabel(Messages.getString("ActiveTagsWizard.1"))); add(new JLabel()); add(new JLabel(Messages.getString("ActiveTagsWizard.2")), "wrap"); add(new JScrollPane(availableTagsJList), "grow,left,sg list"); add(jpButtons, "center"); add(new JScrollPane(activatedTagsJList), "grow,right,sg list,wrap"); add(okp, "span,right"); } /** * Ok action. * DOCUMENT_ME */ private void okAction() { TrackManager tm = TrackManager.getInstance(); // cleanup removed tags for (PropertyMetaInformation m : tm.getCustomProperties()) { if (Tag.getSupportedTagFields().contains(m.getName()) && !activatedList.contains(m.getName())) { tm.removeProperty(m.getName()); Properties properties = new Properties(); properties.put(Const.DETAIL_CONTENT, m.getName()); JajukEvent event = new JajukEvent(JajukEvents.CUSTOM_PROPERTIES_REMOVE, properties); ObservationManager.notify(event); } } boolean deepScanNeeded = false; for (String s : activatedList) { // check if it is already active boolean skip = false; for (PropertyMetaInformation m : tm.getCustomProperties()) { if (m.getName().equals(s)) { skip = true; break; } } if (skip) continue; deepScanNeeded = true; // activate new tag tm.registerProperty(new PropertyMetaInformation(s, true, false, true, false, false, String.class, null)); Properties properties = new Properties(); properties.put(Const.DETAIL_CONTENT, s); JajukEvent event = new JajukEvent(JajukEvents.CUSTOM_PROPERTIES_ADD, properties); ObservationManager.notify(event); } if (deepScanNeeded) { // we are inside the EDT new Thread(new Runnable() { @Override public void run() { for (Device d : DeviceManager.getInstance().getDevices()) { if (d.isReady()) { d.manualRefreshDeep(); } } } }).start(); } setVisible(false); dispose(); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/wizard/GenresSelectionDialog.java0000644000175000017500000001475711720500104027012 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.wizard; import java.awt.Dimension; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.ArrayList; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; import javax.swing.AbstractListModel; import javax.swing.JComboBox; import javax.swing.JLabel; import javax.swing.JList; import javax.swing.JScrollPane; import net.miginfocom.swing.MigLayout; import org.jajuk.base.Genre; import org.jajuk.base.GenreManager; import org.jajuk.services.dj.Ambience; import org.jajuk.services.dj.AmbienceManager; import org.jajuk.ui.widgets.JajukJDialog; import org.jajuk.ui.widgets.OKCancelPanel; import org.jajuk.util.Const; import org.jajuk.util.Messages; import org.jajuk.util.log.Log; /** * Allow a user to select a list of genres. */ public class GenresSelectionDialog extends JajukJDialog implements ActionListener { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** DOCUMENT_ME. */ JComboBox jcbAmbiences; /** DOCUMENT_ME. */ JList jlist; /** DOCUMENT_ME. */ OKCancelPanel okc; /** DOCUMENT_ME. */ Set selectedGenres; /** DOCUMENT_ME. */ Set disabledGenres; /** DOCUMENT_ME. */ List list; /** * The Constructor. * * @param disabledGenres DOCUMENT_ME */ @SuppressWarnings("unchecked") public GenresSelectionDialog(Set disabledGenres) { super(); this.selectedGenres = new HashSet(); this.disabledGenres = disabledGenres; setLocationByPlatform(true); setTitle(Messages.getString("DigitalDJWizard.14")); setModal(true); setAlwaysOnTop(true); initUI(); pack(); } /** * Set selected item. * * @param selection or null to void it */ public void setSelection(Set selection) { if (selection != null) { int[] indices = new int[selection.size()]; // reset all indices to -1 to avoid selecting zero th item for (int i = 0; i < selection.size(); i++) { indices[i] = -1; } // find all matching items int comp = 0; for (int i = 0; i < jlist.getModel().getSize(); i++) { String modelGenre = (String) jlist.getModel().getElementAt(i); for (Genre genre : selection) { if (genre.getName2().equals(modelGenre)) { indices[comp] = i; comp++; } } } // select item in the list jlist.setSelectedIndices(indices); } } /** * Gets the selected genres. * * @return selected genres */ public Set getSelectedGenres() { return selectedGenres; } /** * Inits the ui. * DOCUMENT_ME */ @SuppressWarnings("unchecked") private void initUI() { list = (List) (GenreManager.getInstance().getGenresList()).clone(); // remove disabled items if (disabledGenres != null) { Iterator it = list.iterator(); while (it.hasNext()) { String testedGenre = (String) it.next(); for (Genre disabledGenre : disabledGenres) { if (disabledGenre.getName2().equals(testedGenre)) { it.remove(); } } } } // main part of the dialog // populate ambience combo jcbAmbiences = new JComboBox(); for (Ambience ambience : AmbienceManager.getInstance().getAmbiences()) { jcbAmbiences.addItem(ambience.getName()); } // none ambience selected by default jcbAmbiences.setSelectedIndex(-1); jcbAmbiences.addActionListener(this); setLayout(new MigLayout("insets 15,gapx 10, gapy 15", "[grow]")); JLabel jlAmbience = new JLabel(Messages.getString("DigitalDJWizard.58")); jlist = new JList(new AbstractListModel() { private static final long serialVersionUID = 1L; @Override public int getSize() { return list.size(); } @Override public Object getElementAt(int i) { return list.get(i); } }); jlist.setLayoutOrientation(JList.VERTICAL_WRAP); JScrollPane jsp = new JScrollPane(jlist); jsp.setPreferredSize(new Dimension(600, 600)); jlist.setVisibleRowCount(-1); okc = new OKCancelPanel(new ActionListener() { @Override public void actionPerformed(ActionEvent ae) { if (ae.getSource() == okc.getOKButton()) { int[] selection = jlist.getSelectedIndices(); for (int element : selection) { String name = (String) jlist.getModel().getElementAt(element); Genre genre = GenreManager.getInstance().getGenreByName(name); if (genre == null) { if (name.equals(Messages.getString(Const.UNKNOWN_GENRE))) { Log.warn("Use '" + Const.UNKNOWN_GENRE + "' instead of '" + name); selectedGenres.add(GenreManager.getInstance().getGenreByName(Const.UNKNOWN_GENRE)); } else { Log.warn("Could not read genre for name: " + name); } } else { selectedGenres.add(genre); } } } dispose(); } }); add(jlAmbience, "split 2"); add(jcbAmbiences, "grow,wrap"); add(jsp, "grow,wrap"); add(okc, "right,span"); getRootPane().setDefaultButton(okc.getOKButton()); } /* * (non-Javadoc) * * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent) */ @Override public void actionPerformed(ActionEvent ae) { if (ae.getSource().equals(jcbAmbiences)) { List alAmbiences = new ArrayList(AmbienceManager.getInstance() .getAmbiences()); Ambience ambience = alAmbiences.get(jcbAmbiences.getSelectedIndex()); // select all genres for this ambience setSelection(ambience.getGenres()); } } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/wizard/DonateWindow.java0000644000175000017500000000734711720500104025200 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.wizard; import java.awt.Container; import java.awt.Desktop; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; import javax.swing.JButton; import javax.swing.JDialog; import javax.swing.JLabel; import javax.swing.SwingUtilities; import javax.swing.WindowConstants; import net.miginfocom.swing.MigLayout; import org.jajuk.ui.widgets.JajukJDialog; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; import org.jajuk.util.UtilGUI; import org.jajuk.util.log.Log; /** * View used to show the Jajuk about and contributors. *

    * Help perspective * */ public class DonateWindow extends JajukJDialog { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** The Constant BUDGET_LINK. DOCUMENT_ME */ private static final String BUDGET_LINK = "http://jajuk.info/index.php/Project_budget"; /** The Constant DONATE_LINK. DOCUMENT_ME */ private static final String DONATE_LINK = "http://jajuk.info/index.php/Donate"; /** * Constructor. */ public DonateWindow() { super(); SwingUtilities.invokeLater(new Runnable() { @Override public void run() { setTitle(Messages.getString("JajukDonate.1")); initUI(); pack(); UtilGUI.centerWindow(DonateWindow.this); setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); setResizable(false); setVisible(true); } }); } /* * (non-Javadoc) * * @see org.jajuk.ui.IView#display() */ /** * Inits the ui. * DOCUMENT_ME */ public void initUI() { Container cp = this.getContentPane(); cp.setLayout(new MigLayout("", "center", "center")); cp.add(new JLabel(IconLoader.getIcon(JajukIcons.LOGO)), "wrap"); cp.add(new JLabel(Messages.getString("JajukDonate.2")), "wrap"); JButton jbBudget = new JButton(Messages.getString("JajukDonate.3")); jbBudget.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { try { Desktop.getDesktop().browse(new URI(BUDGET_LINK)); dispose(); } catch (IOException e1) { Log.error(e1); } catch (URISyntaxException e1) { Log.error(e1); } } }); cp.add(jbBudget, "wrap"); cp.add(new JLabel(Messages.getString("JajukDonate.4")), "wrap"); JButton jbDonation = new JButton(Messages.getString("JajukDonate.1")); jbDonation.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { try { Desktop.getDesktop().browse(new URI(DONATE_LINK)); dispose(); } catch (IOException e1) { Log.error(e1); } catch (URISyntaxException e1) { Log.error(e1); } } }); cp.add(jbDonation, "wrap"); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/wizard/NewPropertyWizard.java0000644000175000017500000002111411720500104026241 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.wizard; import java.awt.event.ActionEvent; import java.awt.event.ItemEvent; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.util.Date; import java.util.Properties; import javax.swing.JCheckBox; import javax.swing.JComboBox; import javax.swing.JLabel; import javax.swing.JTextField; import net.miginfocom.swing.MigLayout; import org.jajuk.base.ItemManager; import org.jajuk.base.PropertyMetaInformation; import org.jajuk.events.JajukEvent; import org.jajuk.events.JajukEvents; import org.jajuk.events.ObservationManager; import org.jajuk.util.Const; import org.jajuk.util.Messages; import org.jajuk.util.UtilString; import org.jdesktop.swingx.JXDatePicker; /** * New property wizard. */ public class NewPropertyWizard extends CustomPropertyWizard implements KeyListener { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** DOCUMENT_ME. */ private final JTextField jtfName; /** DOCUMENT_ME. */ private final JComboBox jcbClass; /** DOCUMENT_ME. */ private final JTextField jtfDefault; /** DOCUMENT_ME. */ private final JCheckBox jcbDefault; /** DOCUMENT_ME. */ private final JXDatePicker jdpDefault; // Types /** The Constant STRING. DOCUMENT_ME */ private static final int STRING = 0; /** The Constant LONG. DOCUMENT_ME */ private static final int LONG = 1; /** The Constant DOUBLE. DOCUMENT_ME */ private static final int DOUBLE = 2; /** The Constant BOOLEAN. DOCUMENT_ME */ private static final int BOOLEAN = 3; /** The Constant DATE. DOCUMENT_ME */ private static final int DATE = 4; /** * Constructor. */ public NewPropertyWizard() { super(Messages.getString("NewPropertyWizard.0")); populate();// create default UI // Name jtfName = new JTextField(); jtfName.addKeyListener(this); // Type, class JLabel jlClass = new JLabel(Messages.getString("NewPropertyWizard.3")); jcbClass = new JComboBox(); jcbClass.addItem(Messages.getString(Const.FORMAT_STRING)); jcbClass.addItem(Messages.getString(Const.FORMAT_NUMBER)); jcbClass.addItem(Messages.getString(Const.FORMAT_FLOAT)); jcbClass.addItem(Messages.getString(Const.FORMAT_BOOLEAN)); jcbClass.addItem(Messages.getString(Const.FORMAT_DATE)); jcbClass.addItemListener(this); // Default JLabel jlDefault = new JLabel(Messages.getString("NewPropertyWizard.5")); jtfDefault = new JTextField(20); jcbDefault = new JCheckBox(); jcbDefault.setEnabled(false); jdpDefault = new JXDatePicker(); jdpDefault.setEnabled(false); // Add items setLayout(new MigLayout("insets 15,gapx 10,gapy 15", "[][grow]")); add(jlItemChoice); add(jcbItemChoice, "grow,wrap"); add(jlName); add(jtfName, "grow,wrap"); add(jlClass); add(jcbClass, "grow,wrap"); add(jlDefault); add(jtfDefault, "split 3,grow"); add(jcbDefault, "grow"); add(jdpDefault, "grow,wrap"); add(okp, "cell 1 4, span,right"); addWindowListener(new WindowAdapter() { @Override public void windowActivated(WindowEvent e) { jtfName.requestFocusInWindow(); } }); getRootPane().setDefaultButton(okp.getOKButton()); } /* * (non-Javadoc) * * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent) */ @Override public void actionPerformed(ActionEvent ae) { if (ae.getSource().equals(this.okp.getOKButton())) { // check the property is not already used internally for (String element : Const.XML_RESERVED_ATTRIBUTE_NAMES) { /* * check user can't create a property that is the localized name of an * existing standard attribute. Note that a potential bug can occur if * user change language */ if (element.equalsIgnoreCase(jtfName.getText()) || jtfName.getText().matches(",")) { Messages.showErrorMessage(110); return; } } ItemManager im = getItemManager(); // check if this property is not already used for (PropertyMetaInformation meta : im.getCustomProperties()) { if (meta.getName().equals(jtfName.getText())) { Messages.showErrorMessage(162); return; } } // check format if (!UtilString.isXMLValid(jtfName.getText())) { Messages.showErrorMessage(140); return; } // OK, store it // get selected format Class cType = null; switch (jcbClass.getSelectedIndex()) { case STRING: cType = String.class; break; case LONG: cType = Long.class; break; case DOUBLE: cType = Double.class; break; case BOOLEAN: cType = Boolean.class; break; case DATE: cType = Date.class; break; default: return; } String sProperty = jtfName.getText(); Object oDefault = jtfDefault.getText(); // Check number and float formats (others are safe) try { if (cType.equals(Long.class)) { Long.parseLong(jtfDefault.getText()); } else if (cType.equals(Double.class)) { Double.parseDouble(jtfDefault.getText()); } } catch (Exception e) { Messages.showErrorMessage(137); return; } // set default if (cType.equals(Boolean.class)) { oDefault = jcbDefault.isSelected(); } else if (cType.equals(Date.class)) { oDefault = jdpDefault.getDate(); } PropertyMetaInformation meta = new PropertyMetaInformation(sProperty, true, false, true, true, true, cType, oDefault); im.registerProperty(meta); im.applyNewProperty(meta); Properties properties = new Properties(); properties.put(Const.DETAIL_CONTENT, sProperty); JajukEvent event = new JajukEvent(JajukEvents.CUSTOM_PROPERTIES_ADD, properties); ObservationManager.notify(event); dispose(); } else if (ae.getSource().equals(this.okp.getCancelButton())) { dispose(); } } /* * (non-Javadoc) * * @see java.awt.event.ItemListener#itemStateChanged(java.awt.event.ItemEvent) */ @Override public void itemStateChanged(ItemEvent e) { // Date format if (jcbClass.getSelectedIndex() == DATE) { jdpDefault.setEnabled(true); } else { jdpDefault.setEnabled(false); } // Boolean format if (jcbClass.getSelectedIndex() == BOOLEAN) { jcbDefault.setEnabled(true); } else { jcbDefault.setEnabled(false); } // Others formats if (jcbClass.getSelectedIndex() != BOOLEAN && jcbClass.getSelectedIndex() != DATE) { jtfDefault.setEnabled(true); } else { jtfDefault.setEnabled(false); } // Ok button if (jcbItemChoice.getSelectedIndex() != -1 && jcbClass.getSelectedIndex() != -1 && jtfName.getText().length() > 0) { okp.getOKButton().setEnabled(true); } else { okp.getOKButton().setEnabled(false); } } /* * (non-Javadoc) * * @see java.awt.event.KeyListener#keyTyped(java.awt.event.KeyEvent) */ @Override public void keyTyped(KeyEvent e) { // required by interface, but nothing to do here... } /* * (non-Javadoc) * * @see java.awt.event.KeyListener#keyPressed(java.awt.event.KeyEvent) */ @Override public void keyPressed(KeyEvent e) { // required by interface, but nothing to do here... } /* * (non-Javadoc) * * @see java.awt.event.KeyListener#keyReleased(java.awt.event.KeyEvent) */ @Override public void keyReleased(KeyEvent e) { if (jcbItemChoice.getSelectedIndex() != -1 && jcbClass.getSelectedIndex() != -1 && jtfName.getText().length() > 0) { okp.getOKButton().setEnabled(true); } else { okp.getOKButton().setEnabled(false); } } }jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/wizard/PropertiesDialog.java0000644000175000017500000010361611720500104026046 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.wizard; import ext.AutoCompleteDecorator; import java.awt.Color; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.StringTokenizer; import java.util.Vector; import javax.swing.BorderFactory; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JComboBox; import javax.swing.JComponent; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTextField; import javax.swing.SwingUtilities; import net.miginfocom.swing.MigLayout; import org.jajuk.base.AlbumArtistManager; import org.jajuk.base.ArtistManager; import org.jajuk.base.Device; import org.jajuk.base.Directory; import org.jajuk.base.File; import org.jajuk.base.FileManager; import org.jajuk.base.GenreManager; import org.jajuk.base.Item; import org.jajuk.base.ItemManager; import org.jajuk.base.Playlist; import org.jajuk.base.PlaylistManager; import org.jajuk.base.PropertyMetaInformation; import org.jajuk.base.Track; import org.jajuk.base.TrackManager; import org.jajuk.events.JajukEvent; import org.jajuk.events.JajukEvents; import org.jajuk.events.ObservationManager; import org.jajuk.ui.widgets.CopyableLabel; import org.jajuk.ui.widgets.InformationJPanel; import org.jajuk.ui.widgets.JajukJDialog; import org.jajuk.ui.widgets.OKCancelPanel; import org.jajuk.ui.windows.JajukMainWindow; import org.jajuk.util.Const; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; import org.jajuk.util.UtilGUI; import org.jajuk.util.UtilString; import org.jajuk.util.error.CannotRenameException; import org.jajuk.util.error.JajukException; import org.jajuk.util.error.NoneAccessibleFileException; import org.jajuk.util.log.Log; import org.jdesktop.swingx.JXDatePicker; import org.jdesktop.swingx.VerticalLayout; /** * ItemManager properties dialog for any jajuk item. */ public class PropertiesDialog extends JajukJDialog implements ActionListener { /** The Constant PROPERTIES_WIZARD_6. DOCUMENT_ME */ private static final String PROPERTIES_WIZARD_6 = "PropertiesWizard.6"; /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /* Main panel */ /** DOCUMENT_ME. */ private JPanel jpMain; /** OK/Cancel panel. */ private OKCancelPanel okc; /** Items. */ private List alItems; /** Items2. */ private List alItems2; /** Files filter. */ private Set filter = null; /** number of editable items (all panels). */ private int iEditable = 0; /** First property panel. */ private PropertiesPanel panel1; /** Second property panel. */ private PropertiesPanel panel2; /** Did user chnaged something ?. */ private boolean changes = false; /** * Constructor for normal wizard with only one wizard panel and n items to * display. * * @param alItems items to display */ public PropertiesDialog(List alItems) { super(); // windows title: name of the element if there is // only one item, or "selection" word otherwise if (alItems.size() == 1) { setTitle(alItems.get(0).getDesc()); } else { setTitle(Messages.getString(PROPERTIES_WIZARD_6)); } this.alItems = alItems; boolean bMerged = false; if (alItems.size() > 1) { bMerged = true; } panel1 = new PropertiesPanel(alItems, alItems.size() == 1 ? UtilString.getLimitedString(alItems .get(0).getDesc(), 50) : Messages.getString(PROPERTIES_WIZARD_6) + " [" + alItems.size() + "]", bMerged); // OK/Cancel buttons okc = new OKCancelPanel(PropertiesDialog.this, Messages.getString("Apply"), Messages .getString("Close")); // Add items jpMain = new JPanel(new MigLayout("insets 5,gapx 5,gapy 5", "[grow]")); jpMain.add(panel1, "grow,wrap"); jpMain.add(okc, "span,right"); display(); } /** * Constructor for file wizard for ie with 2 wizard panels and n items to * display. * * @param alItems1 items to display in the first wizard panel (file for ie) * @param alItems2 items to display in the second panel (associated track for ie ) */ public PropertiesDialog(List alItems1, List alItems2) { super(); // windows title: name of the element of only one item, or "selection" // word otherwise setTitle(alItems1.size() == 1 ? alItems1.get(0).getDesc() : Messages .getString(PROPERTIES_WIZARD_6)); this.alItems = alItems1; this.alItems2 = alItems2; if (alItems1.size() > 0) { // computes filter refreshFileFilter(); if (alItems1.size() == 1) { panel1 = new PropertiesPanel(alItems1, UtilString.getLimitedString(alItems1.get(0) .getDesc(), 50), false); } else { panel1 = new PropertiesPanel(alItems1, UtilString.formatPropertyDesc(Messages .getString(PROPERTIES_WIZARD_6) + " [" + alItems.size() + "]"), true); } panel1.setBorder(BorderFactory.createEtchedBorder()); } if (alItems2.size() > 0) { if (alItems2.size() == 1) { panel2 = new PropertiesPanel(alItems2, UtilString.getLimitedString(alItems2.get(0) .getDesc(), 50), false); } else { panel2 = new PropertiesPanel(alItems2, UtilString.formatPropertyDesc(alItems2.size() + " " + Messages.getHumanPropertyName(Const.XML_TRACKS)), true); } panel2.setBorder(BorderFactory.createEtchedBorder()); } // OK/Cancel buttons okc = new OKCancelPanel(this, Messages.getString("Apply"), Messages.getString("Close")); // Add items jpMain = new JPanel(new MigLayout("insets 5,gapx 5,gapy 5", "[grow][grow]")); jpMain.add(panel1, "grow"); // panel2 can be null for a void directory for instance if (panel2 != null) { jpMain.add(panel2, "grow,wrap"); } // Use cell tag because the wrap is not done if panel2 is void jpMain.add(okc, "cell 0 1 1 1,span,right"); display(); } /** * Refresh the file filter used to update only selected files even * if the associated track is changed and can map several files. * Note that this method should be called after a file panel save * because files may have changed then (if user changed the file name). */ private void refreshFileFilter() { if (alItems.get(0) instanceof Directory) { filter = new HashSet(alItems.size() * 10); for (Item item : alItems) { Directory dir = (Directory) item; filter.addAll(dir.getFilesRecursively()); } } else if (alItems.get(0) instanceof File) { filter = new HashSet(alItems.size()); for (Item item : alItems) { filter.add((File) item); } } else { filter = null; } } /** * Display. DOCUMENT_ME */ private void display() { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { // If none editable item, save button is disabled if (iEditable == 0) { okc.getOKButton().setEnabled(false); } getRootPane().setDefaultButton(okc.getOKButton()); getContentPane().add(new JScrollPane(jpMain)); pack(); setLocationRelativeTo(JajukMainWindow.getInstance()); setVisible(true); } }); } /* * (non-Javadoc) * * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent) */ @Override public void actionPerformed(ActionEvent e) { if (e.getSource() == okc.getCancelButton()) { dispose(); } else if (e.getSource().equals(okc.getOKButton())) { dispose(); // close window, otherwise you will have some issues if // fields are not updated with changes Thread t = new Thread("Properties Wizard Action Thread") { @Override public void run() { try { panel1.save(); if (panel2 != null) { // refresh the file filter refreshFileFilter(); panel2.save(); } } catch (Exception ex) { Messages.showErrorMessage(104, ex.getMessage()); Log.error(104, ex.getMessage(), ex); } finally { // -UI refresh- if (changes) { ObservationManager.notify(new JajukEvent(JajukEvents.DEVICE_REFRESH)); } } } }; // Set min priority to allow EDT to be able to refresh UI between 2 tag // changes t.setPriority(Thread.MIN_PRIORITY); t.start(); } } /** * Tells whether a link button should be shown for a given property. * * @param meta DOCUMENT_ME * * @return true, if checks if is linkable */ public boolean isLinkable(PropertyMetaInformation meta) { String sKey = meta.getName(); return sKey.equals(Const.XML_DEVICE) || sKey.equals(Const.XML_TRACK) || sKey.equals(Const.XML_DEVICE) || sKey.equals(Const.XML_TRACK) || sKey.equals(Const.XML_ALBUM) || sKey.equals(Const.XML_ARTIST) || sKey.equals(Const.XML_YEAR) || sKey.equals(Const.XML_GENRE) || sKey.equals(Const.XML_DIRECTORY) || sKey.equals(Const.XML_FILE) || sKey.equals(Const.XML_PLAYLIST) || sKey.equals(Const.XML_PLAYLIST_FILE) || sKey.equals(Const.XML_FILES) || sKey.equals(Const.XML_PLAYLIST_FILES) // avoid confusing between music types and device types || (sKey.equals(Const.XML_TYPE) && !(alItems.get(0) instanceof Device)); } /** * A properties panel. */ class PropertiesPanel extends JPanel implements ActionListener { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** Properties panel. */ JPanel jpProperties; /** ItemManager description. */ JLabel jlDesc; /** All dynamic widgets. */ JComponent[][] widgets; /** Properties to display. */ List alToDisplay; /** Items. */ List alItems; /** Changed properties. */ Map hmPropertyToChange = new HashMap(); /** Merge flag. */ boolean bMerged = false; /** * Property panel for single types elements. * * @param alItems items to display * @param sDesc Description (title) * @param bMerged : whether this panel contains merged values */ PropertiesPanel(List alItems, String sDesc, boolean bMerged) { super(); this.alItems = alItems; this.bMerged = bMerged; Item pa = alItems.get(0); // first item Process properties to display alToDisplay = new ArrayList(10); for (PropertyMetaInformation meta : ItemManager.getItemManager(pa.getClass()).getProperties()) { // add only editable and non constructor properties if (meta.isVisible() && (bMerged ? meta.isMergeable() : true)) { // if more than one item to display, show only mergeable // properties alToDisplay.add(meta); } } // contains widgets for properties // Varname | value | link widgets = new JComponent[alToDisplay.size()][4]; int index = 0; for (final PropertyMetaInformation meta : alToDisplay) { // begin by checking if all items have the same value, otherwise // we show a void field boolean bAllEquals = true; Object oRef = pa.getValue(meta.getName()); for (Item item : alItems) { if (!item.getValue(meta.getName()).equals(oRef)) { bAllEquals = false; break; } } // -Set widgets- // Property name String sName = meta.getHumanName(); JLabel jlName = new JLabel(sName + " :"); // Check if property name is translated (for custom // properties)); if (meta.isCustom()) { jlName.setForeground(Color.BLUE); } // Property value computes editable state widgets[index][0] = jlName; // property editable ? boolean bEditable = meta.isEditable(); // Check meta-data is supported for the file type if (pa instanceof Track) { Track track = (Track) pa; // take any file mapping this track (note all files are of // the same type) File file = track.getFiles().get(0); if (file.getType().getTaggerClass() == null) { bEditable = false; } } if (!meta.isCustom()) { // (custom properties are always editable, even for offline // items) bEditable = bEditable && !(pa instanceof Directory && !((Directory) pa).getDevice().isMounted()) // item is not an unmounted dir && !(pa instanceof File // check item is not an unmounted file && !((File) pa).isReady()) // item is not an unmounted playlist && !(pa instanceof Playlist && !((Playlist) pa).isReady()); } if (bEditable) { iEditable++; if (meta.getType().equals(Date.class)) { final JXDatePicker jdp = new JXDatePicker(); jdp.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent arg0) { Object oValue = jdp.getDate(); hmPropertyToChange.put(meta, oValue); } }); if (bAllEquals) { // If several items, take first value found jdp.setDate(new Date(pa.getDateValue(meta.getName()).getTime())); } else { // Make sure to set default date to 1970, not today to allow user // to set date to today for multiple selection and to allow jajuk // to detect a change jdp.setDate(new Date(0)); } widgets[index][1] = jdp; } else if (meta.getType().equals(Boolean.class)) { // for a boolean, value is a checkbox final JCheckBox jcb = new JCheckBox(); jcb.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent arg0) { Object oValue = jcb.isSelected(); hmPropertyToChange.put(meta, oValue); } }); if (bAllEquals) { jcb.setSelected(pa.getBooleanValue(meta.getName())); } // if some elements are different, set opposite value of // first item to allow change else { jcb.setSelected(!pa.getBooleanValue(meta.getName())); } widgets[index][1] = jcb; } else if (meta.getType().equals(Double.class) || meta.getType().equals(Integer.class) || meta.getType().equals(Long.class)) { // Note : we manage field validation by ourself, and we // don't use formatted textfields because they display // numbers with comas (this is wrong to display // years for instance) final JTextField jtfValue; jtfValue = new JTextField(); jtfValue.addKeyListener(new KeyAdapter() { @Override public void keyReleased(KeyEvent arg0) { if (jtfValue.getText().length() == 0) { hmPropertyToChange.remove(meta); return; } Object oValue = null; try { if (meta.getType().equals(Long.class)) { oValue = Long.parseLong(jtfValue.getText()); } else if (meta.getType().equals(Double.class)) { oValue = Double.parseDouble(jtfValue.getText()); } else if (meta.getType().equals(Integer.class)) { oValue = Integer.parseInt(jtfValue.getText()); } } catch (Exception e) { Log.error(137, meta.getName(), null); jtfValue.setText(""); Messages.showErrorMessage(137, meta.getName()); hmPropertyToChange.remove(meta); return; } hmPropertyToChange.put(meta, oValue); } }); if (bAllEquals) { jtfValue.setText(pa.getHumanValue(meta.getName())); // If several items, take first value found } widgets[index][1] = jtfValue; } else if (meta.getType().equals(String.class) // for genres && meta.getName().equals(Const.XML_GENRE)) { Vector genres = GenreManager.getInstance().getGenresList(); final JComboBox jcb = new JComboBox(genres); jcb.setEditable(true); AutoCompleteDecorator.decorate(jcb); // set current genre to combo int i = -1; int comp = 0; String sCurrentGenre = pa.getHumanValue(Const.XML_GENRE); for (String s : genres) { if (s.equals(sCurrentGenre)) { i = comp; break; } comp++; } jcb.setSelectedIndex(i); // if different genre, don't show anything if (!bAllEquals) { jcb.setSelectedIndex(-1); } jcb.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent arg0) { Object oValue = jcb.getSelectedItem(); if (oValue == null || ((String) oValue).trim().length() == 0) { // can occur during ui interaction return; } // check that string length > 0 if (((String) oValue).length() < 1) { jcb.setSelectedIndex(-1); Log.error(137, meta.getName(), null); Messages.showErrorMessage(137, meta.getName()); return; } hmPropertyToChange.put(meta, oValue); } }); widgets[index][1] = jcb; } else if (meta.getType().equals(String.class) && (Const.XML_ARTIST.equals(meta.getName()) || Const.XML_ALBUM_ARTIST.equals(meta .getName()))) { // for artists or album-artists Vector artists = null; // This string is the artist or the album artist value, used to find combo box index to set String valueToCheck = null; if (Const.XML_ARTIST.equals(meta.getName())) { artists = ArtistManager.getArtistsList(); valueToCheck = pa.getHumanValue(Const.XML_ARTIST); } else if (Const.XML_ALBUM_ARTIST.equals(meta.getName())) { artists = AlbumArtistManager.getAlbumArtistsList(); valueToCheck = pa.getHumanValue(Const.XML_ALBUM_ARTIST); } final JComboBox jcb = new JComboBox(artists); jcb.setEditable(true); AutoCompleteDecorator.decorate(jcb); // set current genre to combo int i = -1; int comp = 0; for (String s : artists) { if (s.equals(valueToCheck)) { i = comp; break; } comp++; } jcb.setSelectedIndex(i); // if different artist, don't show anything if (!bAllEquals) { jcb.setSelectedIndex(-1); } jcb.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent arg0) { Object oValue = jcb.getSelectedItem(); if (oValue == null || ((String) oValue).trim().length() == 0) { // can occur during ui interaction return; } // check that string length > 0 if (((String) oValue).length() < 1) { jcb.setSelectedIndex(-1); Log.error(137, meta.getName(), null); Messages.showErrorMessage(137, meta.getName()); return; } hmPropertyToChange.put(meta, oValue); } }); widgets[index][1] = jcb; } else { // for all others formats (string, class) final JTextField jtfValue = new JTextField(); jtfValue.addKeyListener(new KeyAdapter() { @Override public void keyReleased(KeyEvent arg0) { if (jtfValue.getText().length() == 0) { hmPropertyToChange.remove(meta); return; } String value = jtfValue.getText(); hmPropertyToChange.put(meta, value); } }); if (bAllEquals) { // If several items, take first value found jtfValue.setText(pa.getHumanValue(meta.getName())); } widgets[index][1] = jtfValue; } } else { CopyableLabel jl = null; if (meta.getName().equals(Const.XML_ALBUM_DISC_ID)) { // Specific rendering : the album disc id should be translated from decimal to hex jl = new CopyableLabel((Long.toString(((Long) pa.getValue(meta.getName())), 16))); } else { // Regular un-editable item rendering jl = new CopyableLabel(pa.getHumanValue(meta.getName())); } // If several items, take first value found if (bAllEquals) { String s = pa.getHumanValue(meta.getName()); if (s.indexOf(',') != -1) { String[] sTab = s.split(","); StringBuilder sb = new StringBuilder(); sb.append(""); for (String element : sTab) { sb.append("

    ").append(element).append("

    "); } sb.append(""); jl.setToolTipText(sb.toString()); } else { jl.setToolTipText(s); } } widgets[index][1] = jl; } // Link if (isLinkable(meta)) { JButton jbLink = new JButton(IconLoader.getIcon(JajukIcons.PROPERTIES)); jbLink.addActionListener(this); jbLink.setActionCommand("link"); jbLink.setToolTipText(Messages.getString("PropertiesWizard.12")); widgets[index][2] = jbLink; } index++; } // Add title JLabel jlName = new JLabel("" + Messages.getString("PropertiesWizard.1") + ""); jlName.setToolTipText(Messages.getString("PropertiesWizard.1")); JLabel jlValue = new JLabel("" + Messages.getString("PropertiesWizard.2") + ""); jlValue.setToolTipText(Messages.getString("PropertiesWizard.2")); JLabel jlLink = new JLabel("" + Messages.getString("PropertiesWizard.4") + ""); jlLink.setToolTipText(Messages.getString("PropertiesWizard.4")); jpProperties = new JPanel(new MigLayout("insets 10,gapx 5,gapy 10", "[][grow][]")); jpProperties.add(jlName); jpProperties.add(jlValue, "grow"); jpProperties.add(jlLink, "wrap"); // Add widgets int i = 0; int j = 4; // for (PropertyMetaInformation meta : alToDisplay) { for (int k = 0; k < alToDisplay.size(); k++) { jpProperties.add(widgets[i][0]); if (widgets[i][2] == null) { // link widget can be null jpProperties.add(widgets[i][1], "grow,width 200:200, wrap"); } else { jpProperties.add(widgets[i][1], "grow,width 200:200"); jpProperties.add(widgets[i][2], "wrap"); } i++; j += 2; } setLayout(new VerticalLayout(10)); // desc jlDesc = new JLabel(UtilString.formatPropertyDesc(sDesc)); add(jlDesc); add(jpProperties); } /* * (non-Javadoc) * * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent) */ @Override public void actionPerformed(ActionEvent ae) { // Link if (ae.getActionCommand().equals("link")) { PropertyMetaInformation meta = alToDisplay.get(getWidgetIndex((JComponent) ae.getSource())); String sProperty = meta.getName(); if (Const.XML_FILES.equals(sProperty)) { Track track = (Track) alItems.get(0); List alFiles = new ArrayList(1); alFiles.addAll(track.getFiles()); // show properties window for this item new PropertiesDialog(alFiles); } else if (Const.XML_PLAYLIST_FILES.equals(sProperty)) { // can only be a set a files String sValue = alItems.get(0).getStringValue(sProperty); StringTokenizer st = new StringTokenizer(sValue, ","); List items = new ArrayList(3); while (st.hasMoreTokens()) { String sPlf = st.nextToken(); Item pa = PlaylistManager.getInstance().getPlaylistByID(sPlf); if (pa != null) { items.add(pa); } } new PropertiesDialog(items); // show properties window for this item } else { String sValue = alItems.get(0).getStringValue(sProperty); // can be only an ID Item pa = ItemManager.getItemManager(sProperty).getItemByID(sValue); if (pa != null) { List items = new ArrayList(1); items.add(pa); // show properties window for this item new PropertiesDialog(items); } } } } /** * Save changes in tags. */ protected void save() { try { UtilGUI.waiting(); // We remove autocommit state to group commit to tags for several tags // of a single file TrackManager.getInstance().setAutocommit(false); Object oValue = null; Item newItem = null; // list of actually changed tracks (used by out message) List alChanged = new ArrayList(2); // none change, leave if (hmPropertyToChange.size() == 0) { return; } // Computes all items to change // contains items to be changed List itemsToChange = new ArrayList(alItems); // Items in error List alInError = new ArrayList(itemsToChange.size()); // details for errors String sDetails = ""; // Check typed value format, display error message only once per // property for (PropertyMetaInformation meta : hmPropertyToChange.keySet()) { // New value oValue = hmPropertyToChange.get(meta); // Check it is not null for non custom properties. Note that // we also allow void values for comments if (oValue == null || (oValue.toString().trim().length() == 0) && !(meta.isCustom() || meta.getName().equals(Const.XML_TRACK_COMMENT))) { Log.error(137, '{' + meta.getName() + '}', null); Messages.showErrorMessage(137, '{' + meta.getName() + '}'); return; } } // Now we have all items to consider, write tags for each // property to change for (int i = 0; i < itemsToChange.size(); i++) { // Note that item object can be changed during the next for loop, so // do not declare it there Item item = null; for (PropertyMetaInformation meta : hmPropertyToChange.keySet()) { item = itemsToChange.get(i); // New value oValue = hmPropertyToChange.get(meta); // Old value String sOldValue = item.getHumanValue(meta.getName()); if (!UtilString.format(oValue, meta, true).equals(sOldValue)) { try { newItem = ItemManager.changeItem(item, meta.getName(), oValue, filter); changes = true; } // none accessible file for this track, for this error, // we display an error and leave completely catch (NoneAccessibleFileException none) { Log.error(none); Messages.showErrorMessage(none.getCode(), item.getHumanValue(Const.XML_NAME)); // close window to avoid reseting all properties to // old values dispose(); return; } // cannot rename file, for this error, we display an // error and leave completely catch (CannotRenameException cre) { Log.error(cre); Messages.showErrorMessage(cre.getCode()); dispose(); return; } // probably error writing a tag, store track reference // and continue catch (JajukException je) { Log.error(je); if (!alInError.contains(item)) { alInError.add(item); // create details label with 3 levels deep sDetails += buidlDetailsString(je); } continue; } // if this item was element of property panel elements, // update it if (alItems.contains(item)) { alItems.remove(item); alItems.add(newItem); } // Update itemsToChange to replace the item. Indeed, if we change // several properties to the same item, the item itself must // change itemsToChange.set(i, newItem); // if individual item, change title in case of // constructor element change if (!bMerged) { jlDesc.setText(UtilString.formatPropertyDesc(newItem.getDesc())); } // note this property have been changed if (!alChanged.contains(meta)) { alChanged.add(meta); } } } // Require full commit for all changed tags on the current file try { TrackManager.getInstance().commit(); } catch (Exception e) { Log.error(e); if (!alInError.contains(item)) { alInError.add(item); // create details label with 3 levels deep sDetails += buidlDetailsString(e); } } } // display a message for file write issues if (alInError.size() > 0) { String sInfo = ""; int index = 0; for (Item item : alInError) { // limit number of errors if (index == 15) { sInfo += "\n..."; break; } sInfo += "\n" + item.getHumanValue(Const.XML_NAME); index++; } Messages.showDetailedErrorMessage(104, sInfo, sDetails); } // display a message if user changed at least one property if (alChanged.size() > 0) { StringBuilder sbChanged = new StringBuilder(); sbChanged.append("{ "); for (PropertyMetaInformation meta : alChanged) { sbChanged.append(meta.getHumanName()).append(' '); } sbChanged.append('}'); InformationJPanel.getInstance().setMessage( alChanged.size() + " " + Messages.getString("PropertiesWizard.10") + ": " + sbChanged.toString(), InformationJPanel.MessageType.INFORMATIVE); } } finally { UtilGUI.stopWaiting(); // Reset auto-commit state TrackManager.getInstance().setAutocommit(true); // Force files resorting to ensure the sorting consistency, indeed, // files are sorted by name *and* track order and we need to force a // files resort after an order change (this is already done in case of // file name change) FileManager.getInstance().forceSorting(); } } /** * Build the errors details message. * * @param e the exception * * @return the errors details message */ private String buidlDetailsString(Exception e) { String sDetails = e.getMessage(); if (e.getCause() != null) { sDetails += "\nCaused by:" + e.getCause(); if (e.getCause().getCause() != null) { sDetails += "\nCaused by:" + e.getCause().getCause(); if (e.getCause().getCause().getCause() != null) { sDetails += "\nCaused by:" + e.getCause().getCause().getCause(); } } } sDetails += "\n\n"; return sDetails; } /** * Gets the widget index. * * @param widget DOCUMENT_ME * * @return index of a given widget in the widget table */ private int getWidgetIndex(JComponent widget) { int resu = -1; for (int row = 0; row < widgets.length; row++) { for (int col = 0; col < widgets[0].length; col++) { if (widget.equals(widgets[row][col])) { resu = row; break; } } } return resu; } } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/wizard/CustomPropertyWizard.java0000644000175000017500000001100411720500104026757 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.wizard; import java.awt.event.ActionListener; import java.awt.event.ItemListener; import javax.swing.BoxLayout; import javax.swing.JComboBox; import javax.swing.JLabel; import org.jajuk.base.AlbumManager; import org.jajuk.base.ArtistManager; import org.jajuk.base.DeviceManager; import org.jajuk.base.DirectoryManager; import org.jajuk.base.FileManager; import org.jajuk.base.GenreManager; import org.jajuk.base.ItemManager; import org.jajuk.base.PlaylistManager; import org.jajuk.base.TrackManager; import org.jajuk.base.YearManager; import org.jajuk.ui.perspectives.FilesPerspective; import org.jajuk.ui.perspectives.PerspectiveManager; import org.jajuk.ui.widgets.JajukJDialog; import org.jajuk.ui.widgets.OKCancelPanel; import org.jajuk.ui.windows.JajukMainWindow; import org.jajuk.util.Messages; import org.jajuk.util.UtilGUI; /** * DOCUMENT_ME. */ public abstract class CustomPropertyWizard extends JajukJDialog implements ActionListener, ItemListener { /** Generated serialVersionUID. */ private static final long serialVersionUID = -5148687837661745898L; /** DOCUMENT_ME. */ JLabel jlItemChoice; /** DOCUMENT_ME. */ JComboBox jcbItemChoice; /** DOCUMENT_ME. */ OKCancelPanel okp; /** DOCUMENT_ME. */ JLabel jlName; /** * Constuctor. * * @param sTitle DOCUMENT_ME */ CustomPropertyWizard(String sTitle) { setTitle(sTitle); setModal(true); setLocationRelativeTo(JajukMainWindow.getInstance()); } /** * Create common UI for property wizards. */ void populate() { getContentPane().setLayout(new BoxLayout(getContentPane(), BoxLayout.Y_AXIS)); UtilGUI.setShuffleLocation(this, 400, 400); jlItemChoice = new JLabel(Messages.getString("CustomPropertyWizard.0")); jlName = new JLabel(Messages.getString("CustomPropertyWizard.1")); jcbItemChoice = new JComboBox(); // Note : we don't provide the possibility to add custom properties to AlbumArtists // (we don't see the need for it) jcbItemChoice.addItem(Messages.getString("Item_Track")); jcbItemChoice.addItem(Messages.getString("Item_File")); jcbItemChoice.addItem(Messages.getString("Item_Genre")); jcbItemChoice.addItem(Messages.getString("Item_Artist")); jcbItemChoice.addItem(Messages.getString("Item_Album")); jcbItemChoice.addItem(Messages.getString("Item_Device")); jcbItemChoice.addItem(Messages.getString("Item_Directory")); jcbItemChoice.addItem(Messages.getString("Item_Playlist_File")); jcbItemChoice.addItem(Messages.getString("Item_Year")); okp = new OKCancelPanel(this); okp.getOKButton().setEnabled(false); // In physical perspective, default item is file, otherwise, it is track if (PerspectiveManager.getCurrentPerspective().getClass().equals(FilesPerspective.class)) { jcbItemChoice.setSelectedIndex(1); } else { jcbItemChoice.setSelectedIndex(0); } jcbItemChoice.addItemListener(this); } /** * Gets the item manager. * * @return ItemManager associated with selected element in combo box */ ItemManager getItemManager() { ItemManager im = null; switch (jcbItemChoice.getSelectedIndex()) { case 0: im = TrackManager.getInstance(); break; case 1: im = FileManager.getInstance(); break; case 2: im = GenreManager.getInstance(); break; case 3: im = ArtistManager.getInstance(); break; case 4: im = AlbumManager.getInstance(); break; case 5: im = DeviceManager.getInstance(); break; case 6: im = DirectoryManager.getInstance(); break; case 7: im = PlaylistManager.getInstance(); break; case 8: im = YearManager.getInstance(); break; } return im; } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/wizard/WebRadioWizard.java0000644000175000017500000003020011720500104025433 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.wizard; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.IOException; import java.util.ArrayList; import java.util.Collections; import java.util.List; import javax.swing.ButtonGroup; import javax.swing.JButton; import javax.swing.JComponent; import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JRadioButton; import javax.swing.JScrollPane; import javax.swing.JTextField; import javax.swing.event.CaretEvent; import javax.swing.event.CaretListener; import net.miginfocom.swing.MigLayout; import org.jajuk.events.JajukEvent; import org.jajuk.events.JajukEvents; import org.jajuk.events.ObservationManager; import org.jajuk.services.webradio.WebRadio; import org.jajuk.services.webradio.WebRadioManager; import org.jajuk.ui.helpers.FontManager; import org.jajuk.ui.helpers.FontManager.JajukFont; import org.jajuk.ui.windows.JajukMainWindow; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; import org.jajuk.util.LocaleManager; import org.jajuk.util.Messages; import org.jajuk.util.UtilGUI; import org.jajuk.util.log.Log; import org.qdwizard.Screen; import org.qdwizard.Wizard; /** * WebRadio management wizard. */ public class WebRadioWizard extends Wizard { /** web radios*. */ static List radios; /** * DOCUMENT_ME. */ public static class RadioPanel extends Screen implements ActionListener { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** All dynamic widgets. */ JComponent[][] widgets; /** DOCUMENT_ME. */ JButton jbNew; /** DOCUMENT_ME. */ JButton jbDelete; /** DOCUMENT_ME. */ JButton jbDefaults; /** DOCUMENT_ME. */ JPanel jpButtons; /** DOCUMENT_ME. */ JScrollPane jsp; /** Selected radio index. */ int radioIndex = 0; /* (non-Javadoc) * @see org.qdwizard.Screen#getDescription() */ @Override public String getDescription() { return Messages.getString("RadioWizard.0"); } /* (non-Javadoc) * @see org.qdwizard.Screen#getName() */ @Override public String getName() { return Messages.getString("RadioWizard.1"); } /** * Create panel UI. */ @Override public void initUI() { radios = new ArrayList(WebRadioManager.getInstance().getWebRadios()); setCanFinish(true); // button layout jpButtons = new JPanel(new MigLayout("insets 5,gapx 15,gapy 0")); jbNew = new JButton(Messages.getString("RadioWizard.2"), IconLoader.getIcon(JajukIcons.NEW)); jbNew.addActionListener(this); jbNew.setToolTipText(Messages.getString("RadioWizard.2")); jbDelete = new JButton(Messages.getString("RadioWizard.3"), IconLoader .getIcon(JajukIcons.DELETE)); jbDelete.addActionListener(this); jbDelete.setToolTipText(Messages.getString("RadioWizard.3")); jbDefaults = new JButton(Messages.getString("RadioWizard.4"), IconLoader .getIcon(JajukIcons.DEFAULTS)); jbDefaults.addActionListener(this); jbDefaults.setToolTipText(Messages.getString("RadioWizard.4")); jpButtons.add(jbNew); jpButtons.add(jbDelete); jpButtons.add(jbDefaults); // Add items setLayout(new MigLayout("insets 5,gapy 5", "[grow]")); add(getPanel(), "grow,wrap"); add(jpButtons, "span,right"); } /** * Gets the panel. * * @return a panel containing all items */ private JScrollPane getPanel() { widgets = new JComponent[radios.size()][3]; JPanel out = new JPanel(); // make sure to sort radios Collections.sort(radios); ButtonGroup group = new ButtonGroup(); // now add all web radios for (int index = 0; index < radios.size(); index++) { // Radio name final JTextField jtfName = new JTextField(); jtfName.setText(radios.get(index).getName()); jtfName.addCaretListener(new CaretListener() { @Override public void caretUpdate(CaretEvent arg0) { int index1 = getWidgetIndex(widgets, (JComponent) arg0.getSource()); String s = jtfName.getText(); // Check this name is not already token for (int i = 0; i < widgets.length; i++) { if (i == index1) { continue; } JTextField jtf = (JTextField) widgets[i][1]; if (jtf.getText().equals(s)) { setProblem(Messages.getString("RadioWizard.5")); return; } } // reset previous problems if (s.length() == 0 || ((JTextField) widgets[index1][2]).getText().length() == 0) { setProblem(Messages.getString("RadioWizard.11")); } else { setProblem(null); jtfName.setToolTipText(s); } radios.get(index1).setName(s); } }); jtfName.setToolTipText(jtfName.getText()); widgets[index][1] = jtfName; // radio button final JRadioButton jrbRadio = new JRadioButton(); group.add(jrbRadio); jrbRadio.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent ae) { ((JTextField) widgets[getWidgetIndex(widgets, jrbRadio)][1]).getText(); radioIndex = getWidgetIndex(widgets, jrbRadio); } }); widgets[index][0] = jrbRadio; if (index == radioIndex) { jrbRadio.setSelected(true); } WebRadio radio = radios.get(index); // URL final JTextField jtfURL = new JTextField(); if (radio.getUrl() != null) { jtfURL.setText(radio.getUrl()); jtfURL.setToolTipText(jtfURL.getText()); } jtfURL.addCaretListener(new CaretListener() { @Override public void caretUpdate(CaretEvent arg0) { int index1 = getWidgetIndex(widgets, (JComponent) arg0.getSource()); String s = jtfURL.getText(); // reset previous problems if (s.length() == 0 || ((JTextField) widgets[index1][1]).getText().length() == 0) { setProblem(Messages.getString("RadioWizard.11")); } else { setProblem(null); jtfURL.setToolTipText(s); } radios.get(index1).setUrl(s); } }); widgets[index][2] = jtfURL; } // Create layout out.setLayout(new MigLayout("insets 5,gapx 10,gapy 2", "[][][grow]")); // Create header JLabel jlHeader1 = new JLabel(Messages.getString("RadioWizard.9")); jlHeader1.setFont(FontManager.getInstance().getFont(JajukFont.BOLD)); JLabel jlHeader2 = new JLabel(Messages.getString("RadioWizard.8")); jlHeader2.setFont(FontManager.getInstance().getFont(JajukFont.BOLD)); out.add(jlHeader1, "center,span 2"); out.add(jlHeader2, "center,wrap"); // Add widgets for (int i = 0; i < widgets.length; i++) { out.add(widgets[i][0], "grow,left,width 25!"); out.add(widgets[i][1], "grow,left,width 200!"); out.add(widgets[i][2], "grow,left,wrap,width 250:250"); } jsp = new JScrollPane(out); // select first ambiance found if (radios.size() > 0) { JRadioButton jrb = (JRadioButton) widgets[0][0]; jrb.doClick(); } return jsp; } /** * Refresh panel. */ private void refreshScreen() { removeAll(); // refresh panel add(getPanel(), "grow,wrap"); add(jpButtons, "center,span"); revalidate(); repaint(); } /* * (non-Javadoc) * * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent) */ @Override public void actionPerformed(ActionEvent ae) { if (ae.getSource() == jbNew) { radios.add(new WebRadio("", null)); // refresh screen refreshScreen(); // select new row JRadioButton jrb = (JRadioButton) widgets[0][0]; jrb.setSelected(true); radioIndex = radios.size() - 1; setProblem(Messages.getString("RadioWizard.11")); jbDelete.setEnabled(true); JTextField jtf = (JTextField) widgets[0][1]; jtf.requestFocusInWindow(); } else if (ae.getSource() == jbDelete) { WebRadio radio = radios.get(radioIndex); radios.remove(radioIndex); WebRadioManager.getInstance().removeWebRadio(radio); if (WebRadioManager.getInstance().getWebRadios().size() == 0) { jbDelete.setEnabled(false); } if (radioIndex > 0) { radioIndex--; JRadioButton jrb = (JRadioButton) widgets[radioIndex][0]; jrb.setSelected(true); } // refresh screen refreshScreen(); } else if (ae.getSource() == jbDefaults) { // Ask for confirmation int choice = Messages.getChoice(Messages.getString("Confirmation_defaults_radios"), JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE); if (choice != JOptionPane.YES_OPTION) { return; } // OK ? Restore the list try { UtilGUI.waiting(); WebRadioManager.getInstance().restore(); // Refresh current list radios = new ArrayList(WebRadioManager.getInstance().getWebRadios()); } catch (Exception e) { // show an "operation failed' message to users Messages.showErrorMessage(169); Log.error(e); } finally { UtilGUI.stopWaiting(); } // refresh screen refreshScreen(); } } } /** * Gets the widget index. * * @param widgets DOCUMENT_ME * @param widget DOCUMENT_ME * @return index of a given widget row in the widget table */ private static int getWidgetIndex(JComponent[][] widgets, JComponent widget) { for (int row = 0; row < widgets.length; row++) { for (int col = 0; col < widgets[0].length; col++) { if (widget.equals(widgets[row][col])) { return row; } } } return -1; } /* * (non-Javadoc) * * @see org.jajuk.ui.wizard.Wizard#getPreviousScreen(java.lang.Class) */ @Override public Class getPreviousScreen( Class screen) { return null; } /* * (non-Javadoc) * * @see org.jajuk.ui.wizard.Wizard#getNextScreen(java.lang.Class) */ @Override public Class getNextScreen( Class screen) { return null; } /** * Instantiates a new web radio wizard. */ public WebRadioWizard() { super(Messages.getString("RadioWizard.7"), RadioPanel.class, null, JajukMainWindow .getInstance(), LocaleManager.getLocale(), 600, 500); setHeaderIcon(IconLoader.getIcon(JajukIcons.WEBRADIO)); } /* * (non-Javadoc) * * @see org.jajuk.ui.wizard.Wizard#finish() */ @Override public void finish() { for (WebRadio radio : radios) { WebRadioManager.getInstance().addWebRadio(radio); } // commit it to avoid it is lost before the app close try { WebRadioManager.getInstance().commit(); } catch (IOException e) { Log.error(e); } // Refresh UI ObservationManager.notify(new JajukEvent(JajukEvents.WEBRADIOS_CHANGE)); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/wizard/FirstTimeWizard.java0000644000175000017500000002627711720500104025670 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.wizard; import java.awt.Dimension; import java.awt.Toolkit; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.io.File; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JDialog; import javax.swing.JFileChooser; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JTextField; import javax.swing.WindowConstants; import javax.swing.border.BevelBorder; import javax.swing.border.EmptyBorder; import net.miginfocom.swing.MigLayout; import org.jajuk.base.Device; import org.jajuk.base.DeviceManager; import org.jajuk.services.core.SessionService; import org.jajuk.services.startup.StartupCollectionService; import org.jajuk.ui.actions.ActionManager; import org.jajuk.ui.actions.JajukActions; import org.jajuk.ui.widgets.JajukFileChooser; import org.jajuk.ui.widgets.OKCancelPanel; import org.jajuk.ui.widgets.PathSelector; import org.jajuk.ui.widgets.ToggleLink; import org.jajuk.util.Const; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukFileFilter; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; import org.jajuk.util.UtilGUI; import org.jajuk.util.filters.DirectoryFilter; import org.jajuk.util.log.Log; import org.jdesktop.swingx.JXCollapsiblePane; import org.jdesktop.swingx.VerticalLayout; /** * First time Wizard. */ public class FirstTimeWizard extends JDialog implements ActionListener, PropertyChangeListener { // Do not extend JajukJDialog because it requires main window to be instanciated and it comes with // many trouble (like Global keystrokes issues in file path selection) in this low-level dialog /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** DOCUMENT_ME. */ private JLabel jlLeftIcon; /** DOCUMENT_ME. */ private JPanel jpRightPanel; /** DOCUMENT_ME. */ private JButton jbFileSelection; /** DOCUMENT_ME. */ private JLabel jlSelectedFile; /** DOCUMENT_ME. */ private PathSelector workspacePath; /** DOCUMENT_ME. */ private JLabel jlRefreshTime; /** DOCUMENT_ME. */ private JTextField jtfRefreshTime; /** DOCUMENT_ME. */ private JCheckBox jcbHelp; /** DOCUMENT_ME. */ private JXCollapsiblePane advanced; /** DOCUMENT_ME. */ private JButton jbOk; /** DOCUMENT_ME. */ private JButton jbCancel; /** DOCUMENT_ME. */ private JPanel jpMain; /** Selected directory. */ private File fDir; /** Default workspace location. */ private String defaultWorkspacePath; /** User chosen workspace location. */ private String userWorkspacePath; /** * Gets the user workspace path. * * @return the user workspace path */ public String getUserWorkspacePath() { return this.userWorkspacePath; } /** * First time wizard. * * @param defaultWorkspacePath the default workspace path set in the textfield */ public FirstTimeWizard(String defaultWorkspacePath) { super(); this.defaultWorkspacePath = defaultWorkspacePath; } /* * (non-Javadoc) * * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent) */ @Override public void actionPerformed(final ActionEvent e) { if (e.getSource() == jbCancel) { dispose(); // close window // alert SessionService to continue startup SessionService.notifyFirstTimeWizardClosed(); } else if (e.getSource() == jbFileSelection) { final JajukFileChooser jfc = new JajukFileChooser(new JajukFileFilter(DirectoryFilter .getInstance())); jfc.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); jfc.setDialogTitle(Messages.getString("FirstTimeWizard.5")); jfc.setMultiSelectionEnabled(false); final int returnVal = jfc.showOpenDialog(this); if (returnVal == JFileChooser.APPROVE_OPTION) { fDir = jfc.getSelectedFile(); // First, check device availability int code = DeviceManager.getInstance().checkDeviceAvailablity(fDir.getName(), 0, fDir.getAbsolutePath(), true); if (code != 0) { Messages.showErrorMessage(code); jbOk.setEnabled(false); return; } jbOk.setEnabled(true); jbOk.grabFocus(); jlSelectedFile.setText(fDir.getAbsolutePath()); pack(); // repack as size of dialog can be exceeded now } } else if (e.getSource() == jbOk) { final boolean bShowHelp = jcbHelp.isSelected(); String sPATH = workspacePath.getUrl().trim(); // Check workspace directory if ((!sPATH.isEmpty()) && (!new File(sPATH).canRead())) { Messages.showErrorMessage(165); return; } // Close window dispose(); // update the user chosen workspace path (read afterward by the SessionService) userWorkspacePath = workspacePath.getUrl().trim(); // Notify Main to continue startup SessionService.notifyFirstTimeWizardClosed(); new Thread("First Time Wizard Action Thread") { @Override public void run() { // Wait for context loading (default configuration...) StartupCollectionService.waitForLaunchRefresh(); // Create a directory device final Device device = DeviceManager.getInstance().registerDevice(fDir.getName(), 0, fDir.getAbsolutePath()); device.setProperty(Const.XML_DEVICE_AUTO_MOUNT, true); // Set refresh time double dRefreshTime = 5d; try { dRefreshTime = Double.parseDouble(jtfRefreshTime.getText()); if (dRefreshTime < 0) { dRefreshTime = 0; } } catch (final NumberFormatException e1) { dRefreshTime = 0; } device.setProperty(Const.XML_DEVICE_AUTO_REFRESH, dRefreshTime); try { // Refresh device synchronously device.refresh(false, false, false, null); } catch (final Exception e2) { Log.error(112, device.getName(), e2); Messages.showErrorMessage(112, device.getName()); } // Show Help window if required if (bShowHelp) { // Display help window try { ActionManager.getAction(JajukActions.HELP_REQUIRED).perform(null); } catch (Exception e1) { Log.error(e1); } } } }.start(); } } /** * Inits the ui. */ public void initUI() { setIconImage(IconLoader.getIcon(JajukIcons.LOGO).getImage()); setTitle(Messages.getString("FirstTimeWizard.0")); jlLeftIcon = new JLabel(UtilGUI.getImage(Const.IMAGE_SEARCH)); jlLeftIcon.setBorder(new EmptyBorder(0, 20, 0, 0)); jpRightPanel = new JPanel(); JLabel jlWelcome = new JLabel(Messages.getString("FirstTimeWizard.1")); JLabel jlFileSelection = new JLabel(Messages.getString("FirstTimeWizard.2")); jbFileSelection = new JButton(IconLoader.getIcon(JajukIcons.OPEN_DIR)); jbFileSelection.addActionListener(this); JLabel jlSelectedFileText = new JLabel(Messages.getString("FirstTimeWizard.8")); jlSelectedFile = new JLabel(Messages.getString("FirstTimeWizard.9")); jlSelectedFile.setBorder(new BevelBorder(BevelBorder.LOWERED)); final JLabel jlWorkspace = new JLabel(Messages.getString("FirstTimeWizard.7")); jlWorkspace.setToolTipText(Messages.getString("FirstTimeWizard.7")); workspacePath = new PathSelector(defaultWorkspacePath); workspacePath.setToolTipText(Messages.getString("FirstTimeWizard.7")); // If user provided a forced workspace, he can't change it again here if (SessionService.isForcedWorkspace()) { jlWorkspace.setEnabled(false); workspacePath.setEnabled(false); } jcbHelp = new JCheckBox(Messages.getString("FirstTimeWizard.4")); // Refresh time jlRefreshTime = new JLabel(Messages.getString("DeviceWizard.53")); jtfRefreshTime = new JTextField("5");// 5 mins by default JLabel jlMins = new JLabel(Messages.getString("DeviceWizard.54")); // buttons OKCancelPanel okp = new OKCancelPanel(this); jbOk = okp.getOKButton(); jbCancel = okp.getCancelButton(); jbCancel.setText(Messages.getString("Later")); jbOk.setEnabled(false); advanced = new JXCollapsiblePane(); // we need to listen for the animation state property in order to allow to // resize the dialog after the advanced-panel is expanded/collapsed // see http://forums.java.net/jive/thread.jspa?threadID=67800&tstart=0 for some related // discussion // why we need to listen on "animationState" to know when the expanding/collapsing is finished advanced.addPropertyChangeListener("animationState", this); // Build the toggle link used to expand / collapse the panel final ToggleLink toggle = new ToggleLink(Messages.getString("FirstTimeWizard.6"), advanced); // Advanced collapsible panel advanced.setLayout(new VerticalLayout(10)); advanced.setCollapsed(true); advanced.add(jlWorkspace); advanced.add(workspacePath); advanced.add(jcbHelp); // Add items setLayout(new MigLayout("insets 10,gapx 10,gapy 15", "[][grow]", "[][][][][][]")); add(jlLeftIcon, "cell 0 0 1 6,top"); add(jlWelcome, "cell 1 0"); add(jlFileSelection, "split 2,cell 1 1"); add(jbFileSelection, "cell 1 1"); add(jlSelectedFileText, "split 2,cell 1 2"); add(jlSelectedFile, "cell 1 2, grow"); add(jlRefreshTime, "split 3,cell 1 3"); add(jtfRefreshTime, "cell 1 3, grow,width ::50"); add(jlMins, "cell 1 3"); add(toggle, "cell 1 4,grow"); add(advanced, "cell 1 5,grow"); add(okp, "right,span,cell 1 6"); getRootPane().setDefaultButton(jbOk); pack(); final Dimension dim = Toolkit.getDefaultToolkit().getScreenSize(); setLocation(((int) dim.getWidth() / 3), ((int) dim.getHeight() / 3)); setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE); setVisible(true); } /* * (non-Javadoc) * * @see java.beans.PropertyChangeListener#propertyChange(java.beans.PropertyChangeEvent ) */ @Override public void propertyChange(PropertyChangeEvent evt) { // if the property changes to "collapsed" or "expanded" the change of the panel is // finished and we should re-pack() the dialog in order to make space for the panel in the // dialog correctly if (evt.getNewValue().equals("collapsed") || evt.getNewValue().equals("expanded")) { pack(); // repack as size of dialog can be exceeded now } } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/wizard/PreparePartyConvertSettings.java0000644000175000017500000000615311720500104030270 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.wizard; import java.awt.Frame; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.JLabel; import javax.swing.JTextField; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import net.miginfocom.swing.MigLayout; import org.jajuk.ui.widgets.JajukJDialog; import org.jajuk.ui.widgets.OKCancelPanel; import org.jajuk.util.Messages; /** * Simple device creation wizard that creates a directory device given a * directory. */ public class PreparePartyConvertSettings extends JajukJDialog implements ActionListener { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** Listener which is informed about changes to the settings. */ ChangeListener listener; /** Text field for the input of the command. */ JTextField jtfPACPLCommand; /** OK/Cancel buttons. */ OKCancelPanel okp; /** * Instantiates a new prepare party convert settings. * * @param listener Listener for changes * @param command The current command * @param parent Parent frame */ public PreparePartyConvertSettings(ChangeListener listener, String command, Frame parent) { super(parent, true); setLocationRelativeTo(parent); this.listener = listener; setTitle(Messages.getString("PreparePartyWizard.38")); setAlwaysOnTop(true); okp = new OKCancelPanel(this); jtfPACPLCommand = new JTextField(command); // select all jtfPACPLCommand.setSelectionStart(0); jtfPACPLCommand.setSelectionEnd(command.length()); // Add items setLayout(new MigLayout("insets 10,gapx 10,gapy 15", "[]")); add(new JLabel(Messages.getString("PreparePartyWizard.39")), "wrap"); add(jtfPACPLCommand, "grow,wrap"); add(okp, "wrap"); getRootPane().setDefaultButton(okp.getOKButton()); pack(); setVisible(true); } /* (non-Javadoc) * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent) */ @Override public void actionPerformed(final ActionEvent e) { if (e.getSource() == okp.getCancelButton()) { dispose(); // close window } if (e.getSource() == okp.getOKButton()) { // inform the caller about the new value listener.stateChanged(new ChangeEvent(jtfPACPLCommand.getText())); // exit dispose(); } } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/wizard/AlarmClockDialog.java0000644000175000017500000003127611720500104025724 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.wizard; import java.awt.Dimension; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import java.util.Calendar; import javax.swing.ButtonGroup; import javax.swing.JCheckBox; import javax.swing.JComboBox; import javax.swing.JLabel; import javax.swing.JRadioButton; import javax.swing.JTextField; import javax.swing.event.ListSelectionEvent; import net.miginfocom.swing.MigLayout; import org.jajuk.base.File; import org.jajuk.base.FileManager; import org.jajuk.base.SearchResult; import org.jajuk.base.SearchResult.SearchResultType; import org.jajuk.events.JajukEvent; import org.jajuk.events.JajukEvents; import org.jajuk.events.ObservationManager; import org.jajuk.services.alarm.AlarmManager; import org.jajuk.services.webradio.WebRadio; import org.jajuk.services.webradio.WebRadioManager; import org.jajuk.ui.widgets.JajukJDialog; import org.jajuk.ui.widgets.OKCancelPanel; import org.jajuk.ui.widgets.SearchBox; import org.jajuk.ui.windows.JajukMainWindow; import org.jajuk.util.Conf; import org.jajuk.util.Const; import org.jajuk.util.Messages; import org.jajuk.util.log.Log; /** * Alarm Clock Dialog window. * * TODO : add validation on fields */ public class AlarmClockDialog extends JajukJDialog implements ActionListener, ItemListener, Const { /** Constant for MigLayout hint. */ private static final String LEFT_WRAP = "left,wrap"; /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** DOCUMENT_ME. */ private final JLabel jlChoice; /** DOCUMENT_ME. */ private final JCheckBox jcbTime; /** DOCUMENT_ME. */ private final JRadioButton jrbShuffle; /** DOCUMENT_ME. */ private final JRadioButton jrbBestof; /** DOCUMENT_ME. */ private final JRadioButton jrbNovelties; /** DOCUMENT_ME. */ private final JRadioButton jrbFile; /** DOCUMENT_ME. */ private final JTextField jtfHour; /** DOCUMENT_ME. */ private final JTextField jtfMinutes; /** DOCUMENT_ME. */ private final JTextField jtfSeconds; /** DOCUMENT_ME. */ private final JComboBox jcbAlarmAction; /** DOCUMENT_ME. */ private final SearchBox sbSearch; /** DOCUMENT_ME. */ private SearchResult sr; /** DOCUMENT_ME. */ private OKCancelPanel okCancelPanel; /** * Instantiates a new alarm clock dialog. */ public AlarmClockDialog() { super(); jcbTime = new JCheckBox(Messages.getString("AlarmDialog.0")); jcbTime.addActionListener(this); jtfHour = new JTextField(2); jtfHour.setToolTipText(Messages.getString("AlarmDialog.1")); jtfMinutes = new JTextField(2); jtfMinutes.setToolTipText(Messages.getString("AlarmDialog.2")); jtfSeconds = new JTextField(2); jtfSeconds.setToolTipText(Messages.getString("AlarmDialog.3")); final JLabel jlAlarmAction = new JLabel(Messages.getString("AlarmDialog.4")); jcbAlarmAction = new JComboBox(); jcbAlarmAction.addItem(Const.ALARM_START_ACTION); jcbAlarmAction.addItem(Const.ALARM_STOP_ACTION); jcbAlarmAction.setToolTipText(Messages.getString("AlarmDialog.5")); jcbAlarmAction.addActionListener(this); jlChoice = new JLabel(Messages.getString("ParameterView.9")); jrbShuffle = new JRadioButton(Messages.getString("ParameterView.14")); jrbShuffle.setToolTipText(Messages.getString("ParameterView.15")); jrbShuffle.addItemListener(this); jrbBestof = new JRadioButton(Messages.getString("ParameterView.131")); jrbBestof.setToolTipText(Messages.getString("ParameterView.132")); jrbBestof.addItemListener(this); jrbNovelties = new JRadioButton(Messages.getString("ParameterView.133")); jrbNovelties.setToolTipText(Messages.getString("ParameterView.134")); jrbNovelties.addItemListener(this); jrbFile = new JRadioButton(Messages.getString("ParameterView.16")); jrbFile.setToolTipText(Messages.getString("ParameterView.17")); jrbFile.addItemListener(this); sbSearch = new SearchBox() { private static final long serialVersionUID = 1L; @Override public void valueChanged(final ListSelectionEvent e) { if (!e.getValueIsAdjusting()) { sr = sbSearch.getResult(); if (sr.getType() == SearchResultType.FILE) { sbSearch.setText(sr.getFile().getTrack().getName()); } else if (sr.getType() == SearchResultType.WEBRADIO) { sbSearch.setText(sr.getWebradio().getName()); } sbSearch.hidePopup(); sr = sbSearch.getResult(); } } }; // disabled by default, is enabled only if jrbFile is enabled sbSearch.setEnabled(false); sbSearch.setToolTipText(Messages.getString("ParameterView.18")); final ButtonGroup bgChoices = new ButtonGroup(); bgChoices.add(jrbShuffle); bgChoices.add(jrbBestof); bgChoices.add(jrbNovelties); bgChoices.add(jrbFile); jrbShuffle.setSelected(true); okCancelPanel = new OKCancelPanel(this); setLayout(new MigLayout("insets 5,gapy 15", "[grow][grow]")); add(jcbTime, "right"); add(jtfHour, "left,split 5,width 30!"); add(new JLabel(":")); add(jtfMinutes, "width 30!"); add(new JLabel(":")); add(jtfSeconds, "width 30!,wrap"); add(jlAlarmAction, "center"); add(jcbAlarmAction, LEFT_WRAP); add(jlChoice, LEFT_WRAP); add(jrbShuffle, LEFT_WRAP); add(jrbBestof, LEFT_WRAP); add(jrbNovelties, LEFT_WRAP); add(jrbFile, "left"); add(sbSearch, "left,wrap,grow"); add(okCancelPanel, "right,span"); // Reload on GUI saved values loadValues(); setTitle(Messages.getString("AlarmClock.0")); setMinimumSize(new Dimension(250, 100)); pack(); setLocationRelativeTo(JajukMainWindow.getInstance()); setVisible(true); } /* (non-Javadoc) * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent) */ @Override public final void actionPerformed(final ActionEvent e) { boolean playAction = (jcbAlarmAction.getSelectedIndex() == 0); if (e.getSource() == jcbAlarmAction) { handleAction(playAction); } else if (e.getSource() == okCancelPanel.getOKButton()) { saveValues(); } else if (e.getSource() == okCancelPanel.getCancelButton()) { dispose(); } else if (e.getSource() == jcbTime) { handleTimeCheckbox(playAction); } } /** * Handle action. * * @param playAction DOCUMENT_ME */ private void handleAction(boolean playAction) { jlChoice.setEnabled(playAction); jrbShuffle.setEnabled(playAction); jrbBestof.setEnabled(playAction); jrbNovelties.setEnabled(playAction); jrbFile.setEnabled(playAction); sbSearch.setEnabled(playAction); } /** * Handle time checkbox. * * @param playAction DOCUMENT_ME */ private void handleTimeCheckbox(boolean playAction) { // Enable/ disable all widgets if user enables or disables the entire // alarm boolean enabled = jcbTime.isSelected(); jtfHour.setEnabled(enabled); jtfMinutes.setEnabled(enabled); jtfSeconds.setEnabled(enabled); jcbAlarmAction.setEnabled(enabled); jlChoice.setEnabled(enabled && playAction); jrbShuffle.setEnabled(enabled && playAction); jrbBestof.setEnabled(enabled && playAction); jrbNovelties.setEnabled(enabled && playAction); jrbFile.setEnabled(enabled && playAction); sbSearch.setEnabled(enabled && playAction); } /* (non-Javadoc) * @see java.awt.event.ItemListener#itemStateChanged(java.awt.event.ItemEvent) */ @Override public void itemStateChanged(final ItemEvent e) { if (e.getSource() == jrbFile) { sr = sbSearch.getResult(); sbSearch.setEnabled(jrbFile.isSelected()); } } /** * Store GUI values to persisted values. */ private void saveValues() { // Parse the final alarm value Calendar cal = Calendar.getInstance(); try { cal.set(Calendar.HOUR_OF_DAY, Integer.parseInt(jtfHour.getText())); cal.set(Calendar.MINUTE, Integer.parseInt(jtfMinutes.getText())); cal.set(Calendar.SECOND, Integer.parseInt(jtfSeconds.getText())); } catch (Exception e) { Log.error(e); Messages.showErrorMessage(177); return; } // Store values Conf.setProperty(Const.CONF_ALARM_ENABLED, ((Boolean) jcbTime.isSelected()).toString()); Conf.setProperty(Const.CONF_ALARM_ACTION, jcbAlarmAction.getSelectedItem().toString()); Conf.setProperty(CONF_ALARM_TIME_HOUR, jtfHour.getText()); Conf.setProperty(CONF_ALARM_TIME_MINUTES, jtfMinutes.getText()); Conf.setProperty(CONF_ALARM_TIME_SECONDS, jtfSeconds.getText()); if (jrbShuffle.isSelected()) { Conf.setProperty(Const.CONF_ALARM_MODE, Const.STARTUP_MODE_SHUFFLE); } else if (jrbFile.isSelected()) { Conf.setProperty(Const.CONF_ALARM_MODE, Const.STARTUP_MODE_ITEM); // sr = null means none search occurred in this session if (sr != null) { sr = sbSearch.getResult(); if (sr.getType() == SearchResultType.FILE) { Conf.setProperty(Const.CONF_ALARM_FILE, SearchResultType.FILE.name() + '/' + sr.getFile().getID()); } else if (sr.getType() == SearchResultType.WEBRADIO) { Conf.setProperty(Const.CONF_ALARM_FILE, SearchResultType.WEBRADIO.name() + '/' + sr.getWebradio().getName()); } } } else if (jrbBestof.isSelected()) { Conf.setProperty(Const.CONF_ALARM_MODE, Const.STARTUP_MODE_BESTOF); } else if (jrbNovelties.isSelected()) { Conf.setProperty(Const.CONF_ALARM_MODE, Const.STARTUP_MODE_NOVELTIES); } // Store properties in case of try { Conf.commit(); } catch (Exception e) { Log.error(e); } // Close the window dispose(); // Notify the Alarm manager ObservationManager.notify(new JajukEvent(JajukEvents.ALARMS_CHANGE)); // Display a message Messages.showInfoMessage(Messages.getString("Success")); // Start manager up AlarmManager.getInstance(); } /** * Load persisted values to GUI. */ private final void loadValues() { jcbTime.setSelected(Conf.getBoolean(CONF_ALARM_ENABLED)); jtfHour.setText(Conf.getString(CONF_ALARM_TIME_HOUR)); jtfMinutes.setText(Conf.getString(CONF_ALARM_TIME_MINUTES)); jtfSeconds.setText(Conf.getString(CONF_ALARM_TIME_SECONDS)); // Alarm mode (play/stop) if (ALARM_START_ACTION.equals(Conf.getString(CONF_ALARM_ACTION))) { jcbAlarmAction.setSelectedIndex(0); } else if (ALARM_STOP_ACTION.equals(Conf.getString(CONF_ALARM_ACTION))) { jcbAlarmAction.setSelectedIndex(1); } // Alarm action if (Const.STARTUP_MODE_BESTOF.equals(Conf.getString(CONF_ALARM_MODE))) { jrbBestof.setSelected(true); } else if (Const.STARTUP_MODE_NOVELTIES.equals(Conf.getString(CONF_ALARM_MODE))) { jrbNovelties.setSelected(true); } else if (Const.STARTUP_MODE_ITEM.equals(Conf.getString(CONF_ALARM_MODE))) { jrbFile.setSelected(true); String conf = Conf.getString(Const.CONF_ALARM_FILE); String item = conf.substring(conf.indexOf('/') + 1, conf.length()); if (conf.matches(SearchResultType.FILE.name() + ".*")) { File file = FileManager.getInstance().getFileByID(item); if (file != null) { sbSearch.setText(file.getTrack().getName()); } } else if (conf.matches(SearchResultType.WEBRADIO.name() + ".*")) { WebRadio radio = WebRadioManager.getInstance().getWebRadioByName(item); if (radio != null) { sbSearch.setText(radio.getName()); } } } else if (Const.STARTUP_MODE_SHUFFLE.equals(Conf.getString(CONF_ALARM_MODE))) { jrbShuffle.setSelected(true); } // Force an action event to update enable state of widgets actionPerformed(new ActionEvent(jcbTime, 0, null)); } /* (non-Javadoc) * @see java.awt.Window#dispose() */ @Override public void dispose() { // there are some resources to close in the Search-Box that I could not get rid of with any of the default dispose-methods in Swing... sbSearch.close(); super.dispose(); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/wizard/AboutWindow.java0000644000175000017500000000714311720500104025032 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.wizard; import java.awt.BorderLayout; import java.awt.Dimension; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTabbedPane; import javax.swing.JTextArea; import javax.swing.SwingUtilities; import net.miginfocom.swing.MigLayout; import org.jajuk.ui.widgets.JajukJDialog; import org.jajuk.util.Const; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; import org.jajuk.util.UtilGUI; import org.jfree.ui.about.Licences; import org.jfree.ui.about.SystemPropertiesPanel; /** * View used to show the Jajuk about and contributors. *

    * Help perspective * */ public class AboutWindow extends JajukJDialog { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** License panel. */ private JPanel jpLicence; /** JVM properties panel. */ private SystemPropertiesPanel spp; /** Tabbed pane with previous panels. */ private JTabbedPane jtp; /** Additional informations. */ private static final String INFOS = "http://jajuk.info"; /** * Constructor. */ public AboutWindow() { super(); SwingUtilities.invokeLater(new Runnable() { @Override public void run() { setTitle(Messages.getString("JajukJMenuBar.16")); initUI(); setSize(new Dimension(600, 300)); UtilGUI.centerWindow(AboutWindow.this); setVisible(true); } }); } /* * (non-Javadoc) * * @see org.jajuk.ui.IView#display() */ /** * Inits the ui. * DOCUMENT_ME */ public void initUI() { // license panel jpLicence = new JPanel(new BorderLayout()); JTextArea jta = new JTextArea(Licences.getInstance().getGPL()); jta.setLineWrap(true); jta.setWrapStyleWord(true); jta.setCaretPosition(0); jta.setEditable(false); jpLicence.add(new JScrollPane(jta)); jtp = new JTabbedPane(); JPanel jpAbout = new JPanel(new MigLayout("ins 5", "[grow]", "[grow][grow][grow]")); jpAbout.add(new JLabel(IconLoader.getIcon(JajukIcons.LOGO)), "left,split 2"); jpAbout.add(new JLabel("Jajuk " + Const.JAJUK_VERSION + " <" + Const.JAJUK_CODENAME + ">" + " " + Const.JAJUK_VERSION_DATE), "wrap"); jpAbout.add(new JLabel(Messages.getString("AboutView.11")), "center,wrap,grow"); jpAbout.add(new JLabel(INFOS), "center,grow,wrap"); spp = new SystemPropertiesPanel(); jtp.addTab(Messages.getString("AboutView.7"), jpAbout); jtp.addTab(Messages.getString("AboutView.8"), jpLicence); jtp.addTab(Messages.getString("AboutView.9"), spp); add(jtp); } /* * (non-Javadoc) * * @see org.jajuk.ui.IView#getDesc() */ /** * Gets the desc. * * @return the desc */ public String getDesc() { return Messages.getString("AboutView.10"); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/wizard/SimpleDeviceWizard.java0000644000175000017500000001450311720500104026320 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.wizard; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.File; import javax.swing.JButton; import javax.swing.JFileChooser; import javax.swing.JLabel; import javax.swing.JTextField; import javax.swing.border.BevelBorder; import net.miginfocom.swing.MigLayout; import org.jajuk.base.Device; import org.jajuk.base.DeviceManager; import org.jajuk.ui.widgets.JajukFileChooser; import org.jajuk.ui.widgets.JajukJDialog; import org.jajuk.ui.widgets.OKCancelPanel; import org.jajuk.util.Const; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukFileFilter; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; import org.jajuk.util.UtilGUI; import org.jajuk.util.filters.DirectoryFilter; import org.jajuk.util.log.Log; /** * Simple device creation wizard that creates a directory device given a * directory. */ public class SimpleDeviceWizard extends JajukJDialog implements ActionListener { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** DOCUMENT_ME. */ JButton jbFileSelection; /** DOCUMENT_ME. */ JLabel jlSelectedFile; /** DOCUMENT_ME. */ JTextField jtfRefreshTime; /** DOCUMENT_ME. */ OKCancelPanel okp; /** DOCUMENT_ME. */ String deviceName; /** Selected directory. */ private File fDir; /** * Instantiates a new simple device wizard. */ public SimpleDeviceWizard() { setTitle(Messages.getString("SimpleDeviceWizard.0")); setAlwaysOnTop(true); okp = new OKCancelPanel(this); jbFileSelection = new JButton(IconLoader.getIcon(JajukIcons.OPEN_DIR)); jbFileSelection.addActionListener(this); jlSelectedFile = new JLabel(Messages.getString("FirstTimeWizard.9")); jlSelectedFile.setBorder(new BevelBorder(BevelBorder.LOWERED)); jtfRefreshTime = new JTextField(Const.DEFAULT_REFRESH_INTERVAL); // Add items setLayout(new MigLayout("insets 10,gapx 10,gapy 15", "[][grow]")); add(new JLabel(UtilGUI.getImage(Const.IMAGE_SEARCH)), "cell 0 0 0 3"); add(new JLabel(Messages.getString("FirstTimeWizard.2")), "cell 1 0,split 2"); add(jbFileSelection, ""); // please add(new JLabel(Messages.getString("FirstTimeWizard.8")), "split 2,cell 1 1"); add(jlSelectedFile, "cell 1 1, grow"); // select // music // location add(new JLabel(Messages.getString("DeviceWizard.53")), "cell 1 2,split 3"); // Refresh // device // every add(jtfRefreshTime, "grow"); add(new JLabel(Messages.getString("DeviceWizard.54")), "wrap"); // mins add(okp, "right,cell 1 3"); getRootPane().setDefaultButton(okp.getOKButton()); } /* (non-Javadoc) * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent) */ @Override public void actionPerformed(final ActionEvent e) { if (e.getSource() == okp.getCancelButton()) { dispose(); // close window } else if (e.getSource() == jbFileSelection) { final JajukFileChooser jfc = new JajukFileChooser(new JajukFileFilter(DirectoryFilter .getInstance())); jfc.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); jfc.setDialogTitle(Messages.getString("FirstTimeWizard.5")); jfc.setMultiSelectionEnabled(false); final int returnVal = jfc.showOpenDialog(this); if (returnVal == JFileChooser.APPROVE_OPTION) { fDir = jfc.getSelectedFile(); deviceName = fDir.getName(); // First, check device *name* availability, otherwise, use a ~ // name int code = DeviceManager.getInstance().checkDeviceAvailablity(deviceName, 0, fDir.getAbsolutePath(), true); int prefix = 1; while (code == 19) { // code 19 means a device already exists with this // name deviceName = fDir.getName() + '~' + prefix; code = DeviceManager.getInstance().checkDeviceAvailablity(deviceName, 0, fDir.getAbsolutePath(), true); prefix++; } // Now, test again to detected others availability issues like wrong URL code = DeviceManager.getInstance().checkDeviceAvailablity(deviceName, 0, fDir.getAbsolutePath(), true); if (code != 0 && code != 19) { Messages.showErrorMessage(code); okp.getOKButton().setEnabled(false); return; } okp.getOKButton().setEnabled(true); okp.getOKButton().grabFocus(); jlSelectedFile.setText(fDir.getAbsolutePath()); pack(); // repack as size of dialog can be exceeded now } } else if (e.getSource() == okp.getOKButton()) { try { if(fDir == null) { Messages.showErrorMessage(143); return; } // Create a directory device final Device device = DeviceManager.getInstance().registerDevice(deviceName, 0, fDir.getAbsolutePath()); device.setProperty(Const.XML_DEVICE_AUTO_MOUNT, true); // Set refresh time double dRefreshTime; try { dRefreshTime = Double.parseDouble(jtfRefreshTime.getText()); if (dRefreshTime < 0) { dRefreshTime = 0; } } catch (final NumberFormatException e1) { dRefreshTime = 0; } device.setProperty(Const.XML_DEVICE_AUTO_REFRESH, dRefreshTime); try { device.refresh(true, false, false, null); } catch (final Exception e2) { Log.error(112, device.getName(), e2); Messages.showErrorMessage(112, device.getName()); } } finally { // exit dispose(); } } } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/wizard/RemovePropertyWizard.java0000644000175000017500000000737111720500104026756 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.wizard; import java.awt.event.ActionEvent; import java.awt.event.ItemEvent; import java.util.Iterator; import java.util.Properties; import javax.swing.JComboBox; import net.miginfocom.swing.MigLayout; import org.jajuk.base.ItemManager; import org.jajuk.base.PropertyMetaInformation; import org.jajuk.events.JajukEvent; import org.jajuk.events.JajukEvents; import org.jajuk.events.ObservationManager; import org.jajuk.util.Const; import org.jajuk.util.Messages; /** * Remove property wizard. */ public class RemovePropertyWizard extends CustomPropertyWizard { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** DOCUMENT_ME. */ JComboBox jcbName; /** * Constructor. */ public RemovePropertyWizard() { super(Messages.getString("RemovePropertyWizard.0")); jcbName = new JComboBox(); populate();// create default UI jcbName.addItemListener(this); populateProperties();// fill properties combo with properties for setLayout(new MigLayout("insets 10,gapx 10,gapy 15")); add(jlItemChoice, ""); add(jcbItemChoice, "width 200::,wrap"); add(jlName, ""); add(jcbName, "width 200::,wrap,grow"); add(okp, "span,right"); getRootPane().setDefaultButton(okp.getOKButton()); } /* * (non-Javadoc) * * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent) */ @Override public void actionPerformed(ActionEvent ae) { if (ae.getSource().equals(this.okp.getOKButton())) { ItemManager im = getItemManager(); String sProperty = jcbName.getSelectedItem().toString(); im.removeProperty(sProperty); Properties properties = new Properties(); properties.put(Const.DETAIL_CONTENT, sProperty); JajukEvent event = new JajukEvent(JajukEvents.CUSTOM_PROPERTIES_REMOVE, properties); ObservationManager.notify(event); dispose(); } else if (ae.getSource().equals(this.okp.getCancelButton())) { dispose(); } } /* * (non-Javadoc) * * @see java.awt.event.ItemListener#itemStateChanged(java.awt.event.ItemEvent) */ @Override public void itemStateChanged(ItemEvent e) { if (e.getSource() == jcbItemChoice) { populateProperties(); } // update OK button state if (jcbItemChoice.getSelectedIndex() != -1 && jcbName.getSelectedIndex() != -1) { okp.getOKButton().setEnabled(true); okp.getOKButton().requestFocusInWindow(); } else { okp.getOKButton().setEnabled(false); } } /** * Populate properties. * DOCUMENT_ME */ public final void populateProperties() { // clear combo jcbName.removeAllItems(); // refresh properties list for this item ItemManager im = getItemManager(); if (im != null) { Iterator it = im.getUserCustomProperties().iterator(); while (it.hasNext()) { PropertyMetaInformation meta = it.next(); jcbName.addItem(meta.getName()); } } } }jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/actions/0000755000175000017500000000000011720500104022060 5ustar drazzibdrazzibjajuk-1.9.6.orig/src/main/java/org/jajuk/ui/actions/UnBanSelectionAction.java0000644000175000017500000000514711720500104026741 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.actions; import java.awt.event.ActionEvent; import java.util.List; import org.jajuk.base.Track; import org.jajuk.base.TrackManager; import org.jajuk.events.JajukEvent; import org.jajuk.events.JajukEvents; import org.jajuk.events.ObservationManager; import org.jajuk.util.Const; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; import org.jajuk.util.log.Log; /** * DOCUMENT_ME. */ public class UnBanSelectionAction extends SelectionAction { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** * The UnBan action is used to un-ban a set of tracks *

    * Selection action *

    . */ UnBanSelectionAction() { super(Messages.getString("UnBanSelectionAction.0"), IconLoader.getIcon(JajukIcons.UNBAN), true); setShortDescription(Messages.getString("UnBanSelectionAction.1")); } /* (non-Javadoc) * @see org.jajuk.ui.actions.SelectionAction#perform(java.awt.event.ActionEvent) */ @Override public void perform(final ActionEvent e) throws Exception { new Thread("UnBanSelectionAction") { @Override public void run() { try { UnBanSelectionAction.super.perform(e); // Check selection is not void if (selection.size() == 0) { return; } // Extract tracks of each item List tracks = TrackManager.getInstance().getAssociatedTracks(selection, false); // Then ban them all ! for (Track track : tracks) { track.setProperty(Const.XML_TRACK_BANNED, false); } // Request a GUI refresh ObservationManager.notify(new JajukEvent(JajukEvents.RATE_CHANGED)); } catch (Exception e) { Log.error(e); } } }.start(); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/actions/SaveAsAction.java0000644000175000017500000000544011720500104025246 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.actions; import java.awt.event.ActionEvent; import java.util.List; import javax.swing.JComponent; import org.jajuk.base.Playlist; import org.jajuk.events.JajukEvent; import org.jajuk.events.JajukEvents; import org.jajuk.events.ObservationManager; import org.jajuk.ui.widgets.InformationJPanel; import org.jajuk.util.Const; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; import org.jajuk.util.error.JajukException; import org.jajuk.util.log.Log; /** * Action for saving as... an item */ public class SaveAsAction extends JajukAction { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** * Instantiates a new save as action. */ SaveAsAction() { super(Messages.getString("PhysicalPlaylistRepositoryView.2"), IconLoader .getIcon(JajukIcons.SAVE_AS), true); } /** * Invoked when an action occurs. * * @param e DOCUMENT_ME */ @Override @SuppressWarnings("unchecked") public void perform(final ActionEvent e) { new Thread("SaveAsAction") { @Override public void run() { JComponent source = (JComponent) e.getSource(); // TODO Do better here, accept a single playlist for ie Object o = source.getClientProperty(Const.DETAIL_SELECTION); Playlist playlist = null; try { if (o instanceof List) { playlist = ((List) o).get(0); } else { playlist = (Playlist) o; } playlist.saveAs(); InformationJPanel.getInstance().setMessage( Messages.getString("AbstractPlaylistEditorView.22"), InformationJPanel.MessageType.INFORMATIVE); ObservationManager.notify(new JajukEvent(JajukEvents.DEVICE_REFRESH)); } catch (JajukException je) { Log.error(je); Messages.showErrorMessage(je.getCode()); } catch (Exception ex) { Log.error(ex); } } }.start(); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/actions/NoveltiesAction.java0000644000175000017500000000524211720500104026034 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.actions; import java.awt.event.ActionEvent; import java.util.List; import org.jajuk.base.File; import org.jajuk.base.FileManager; import org.jajuk.services.dj.Ambience; import org.jajuk.services.dj.AmbienceManager; import org.jajuk.services.players.QueueModel; import org.jajuk.util.Conf; import org.jajuk.util.Const; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; import org.jajuk.util.UtilFeatures; import org.jajuk.util.error.JajukException; import org.jajuk.util.log.Log; /** * DOCUMENT_ME. */ public class NoveltiesAction extends JajukAction { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** * Instantiates a new novelties action. */ NoveltiesAction() { super(Messages.getString("JajukWindow.15"), IconLoader.getIcon(JajukIcons.NOVELTIES), true); setShortDescription(Messages.getString("JajukWindow.31")); } /* (non-Javadoc) * @see org.jajuk.ui.actions.JajukAction#perform(java.awt.event.ActionEvent) */ @Override public void perform(ActionEvent evt) throws JajukException { new Thread("NoveltiesAction") { @Override public void run() { try { Ambience ambience = AmbienceManager.getInstance().getSelectedAmbience(); List alToPlay = UtilFeatures.filterByAmbience(FileManager.getInstance() .getShuffleNoveltiesPlaylist(), ambience); if (alToPlay != null && alToPlay.size() > 0) { QueueModel.push(UtilFeatures.createStackItems(UtilFeatures.applyPlayOption(alToPlay), Conf.getBoolean(Const.CONF_STATE_REPEAT_ALL), false), false); } else { // none novelty found Messages.showWarningMessage(Messages.getString("Error.127")); } } catch (Exception e) { Log.error(e); } } }.start(); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/actions/RestoreViewsAction.java0000644000175000017500000000376011720500104026530 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.actions; import java.awt.event.ActionEvent; import javax.swing.SwingUtilities; import org.jajuk.ui.perspectives.IPerspective; import org.jajuk.ui.perspectives.PerspectiveManager; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; import org.jajuk.util.error.JajukException; /** * DOCUMENT_ME. */ public class RestoreViewsAction extends JajukAction { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** * Instantiates a new restore views action. */ RestoreViewsAction() { super(Messages.getString("JajukJMenuBar.17"), IconLoader.getIcon(JajukIcons.REFRESH), true); setShortDescription(Messages.getString("JajukJMenuBar.17")); } /* (non-Javadoc) * @see org.jajuk.ui.actions.JajukAction#perform(java.awt.event.ActionEvent) */ @Override public void perform(final ActionEvent e) throws JajukException { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { IPerspective perspective = PerspectiveManager.getCurrentPerspective(); // Restore local or global views perspective.restoreDefaults(); } }); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/actions/ActionManager.java0000644000175000017500000002661111720500104025441 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.actions; import java.util.ArrayList; import java.util.EnumMap; import java.util.List; import javax.swing.Action; import javax.swing.InputMap; import javax.swing.KeyStroke; import javax.swing.UIDefaults; import javax.swing.UIManager; import org.jajuk.util.UtilSystem; /** * Helper class used to create, store and lookup actions. *

    * Singleton *

    */ public final class ActionManager { /** The Constant MAP. DOCUMENT_ME */ private static final EnumMap MAP = new EnumMap( JajukActions.class); /** The Constant STROKE_LIST. DOCUMENT_ME */ private static final List STROKE_LIST = new ArrayList(); /** Self instance. */ private static ActionManager self = new ActionManager(); /** * Gets the instance. * * @return singleton */ public static ActionManager getInstance() { return self; } /** * Instantiates a new action manager. */ private ActionManager() { // Private constructor to disallow instantiation. // CommandJPanel: Mode Panel installAction(JajukActions.REPEAT_MODE, new RepeatModeAction(), true); installAction(JajukActions.REPEAT_ALL_MODE, new RepeatAllModeAction(), true); installAction(JajukActions.SHUFFLE_MODE, new ShuffleModeAction(), true); installAction(JajukActions.CONTINUE_MODE, new ContinueModeAction(), false); installAction(JajukActions.INTRO_MODE, new IntroModeAction(), false); installAction(JajukActions.KARAOKE_MODE, new KaraokeModeAction(), false); // CommandJPanel: Special Functions Panel installAction(JajukActions.SHUFFLE_GLOBAL, new GlobalRandomAction(), false); installAction(JajukActions.BEST_OF, new BestOfAction(), false); installAction(JajukActions.DJ, new DJAction(), false); installAction(JajukActions.NOVELTIES, new NoveltiesAction(), false); installAction(JajukActions.FINISH_ALBUM, new FinishAlbumAction(), false); installAction(JajukActions.WEB_RADIO, new WebRadioAction(), false); // CommandJPanel: Play Panel installAction(JajukActions.PREVIOUS_TRACK, new PreviousTrackAction(), true); installAction(JajukActions.REPLAY_ALBUM, new ReplayAlbumAction(), true); installAction(JajukActions.NEXT_TRACK, new NextTrackAction(), true); installAction(JajukActions.PREVIOUS_ALBUM, new PreviousAlbumAction(), true); installAction(JajukActions.NEXT_ALBUM, new NextAlbumAction(), true); installAction(JajukActions.REWIND_TRACK, new RewindTrackAction(), true); installAction(JajukActions.PAUSE_RESUME_TRACK, new PlayPauseAction(), true); installAction(JajukActions.STOP_TRACK, new StopTrackAction(), true); installAction(JajukActions.FORWARD_TRACK, new ForwardTrackAction(), true); installAction(JajukActions.INC_RATE, new ChangeTrackPreferenceAction(), true); // CommandJPanel: Volume control installAction(JajukActions.DECREASE_VOLUME, new DecreaseVolumeAction(), true); installAction(JajukActions.INCREASE_VOLUME, new IncreaseVolumeAction(), true); installAction(JajukActions.MUTE_STATE, new MuteAction(), true); // JajukJMenuBar: File Menu installAction(JajukActions.EXIT, new ExitAction(), false); // JajukJMenuBar: views installAction(JajukActions.VIEW_RESTORE_DEFAULTS, new RestoreViewsAction(), false); installAction(JajukActions.ALL_VIEW_RESTORE_DEFAULTS, new RestoreAllViewsAction(), false); // JajukJMenuBar: attributes installAction(JajukActions.CUSTOM_PROPERTIES_ADD, new NewPropertyAction(), false); installAction(JajukActions.CUSTOM_PROPERTIES_REMOVE, new RemovePropertyAction(), false); // JajukJMenuBar: configuration installAction(JajukActions.CONFIGURE_DJS, new DJConfigurationAction(), false); installAction(JajukActions.CONFIGURE_WEBRADIOS, new WebRadioConfigurationAction(), false); installAction(JajukActions.CONFIGURE_AMBIENCES, new AmbienceConfigurationAction(), false); installAction(JajukActions.SIMPLE_DEVICE_WIZARD, new SimpleDeviceWizardAction(), false); installAction(JajukActions.OPTIONS, new ConfigurationRequiredAction(), false); installAction(JajukActions.UNMOUNTED, new HideShowMountedDevicesAction(), false); // JajukJMenuBar: Help Menu installAction(JajukActions.HELP_REQUIRED, new HelpRequiredAction(), false); installAction(JajukActions.SHOW_DONATE, new ShowDonateAction(), false); installAction(JajukActions.SHOW_ABOUT, new ShowAboutAction(), false); installAction(JajukActions.EXTRA_TAGS_WIZARD, new ShowActivateTagsAction(), false); // Install this action only if Desktop class is supported, it is used to // open default mail client if (UtilSystem.isBrowserSupported()) { installAction(JajukActions.QUALITY, new QualityAction(), false); } installAction(JajukActions.SHOW_TRACES, new DebugLogAction(), false); installAction(JajukActions.TIP_OF_THE_DAY, new TipOfTheDayAction(), false); installAction(JajukActions.CHECK_FOR_UPDATES, new CheckForUpdateAction(), false); // Export installAction(JajukActions.CREATE_REPORT, new ReportAction(), false); // File Actions installAction(JajukActions.CUT, new CutAction(), false); installAction(JajukActions.COPY, new CopyAction(), false); installAction(JajukActions.DELETE, new DeleteSelectionAction(), false); installAction(JajukActions.PASTE, new PasteAction(), false); installAction(JajukActions.RENAME, new RenameAction(), false); installAction(JajukActions.NEW_FOLDER, new NewFolderAction(), false); // MISC installAction(JajukActions.FIND_DUPLICATE_FILES, new FindDuplicateTracksAction(), false); installAction(JajukActions.COPY_TO_CLIPBOARD, new CopyClipboardAction(), false); installAction(JajukActions.OPEN_EXPLORER, new OpenExplorerAction(), false); installAction(JajukActions.REFRESH, new RefreshAction(), false); installAction(JajukActions.ALARM_CLOCK, new AlarmClockAction(), false); installAction(JajukActions.SHOW_ALBUM_DETAILS, new ShowAlbumDetailsAction(), false); installAction(JajukActions.SLIM_JAJUK, new SlimbarAction(), false); installAction(JajukActions.COMMIT, new CommitAction(), false); installAction(JajukActions.GC, new GCAction(), false); installAction(JajukActions.QUEUE_TO_SLIM, new SlimBarQueueAction(), false); // Install full screen actions only if supported installAction(JajukActions.FULLSCREEN_JAJUK, new FullscreenAction(), false); installAction(JajukActions.PREPARE_PARTY, new PreparePartyAction(), false); // Selection actions installAction(JajukActions.SHOW_PROPERTIES, new ShowPropertiesAction(), true); installAction(JajukActions.PLAY_SELECTION, new PlaySelectionAction(), false); installAction(JajukActions.PLAY_SHUFFLE_SELECTION, new PlayShuffleSelectionAction(), false); installAction(JajukActions.PLAY_REPEAT_SELECTION, new PlayRepeatSelectionAction(), false); installAction(JajukActions.PUSH_FRONT_SELECTION, new PushFrontSelectionAction(), false); installAction(JajukActions.PUSH_SELECTION, new PushSelectionAction(), false); installAction(JajukActions.BOOKMARK_SELECTION, new BookmarkSelectionAction(), false); installAction(JajukActions.PLAY_ALBUM_SELECTION, new PlayAlbumSelectionAction(), false); installAction(JajukActions.PLAY_ARTIST_SELECTION, new PlayArtistSelectionAction(), false); installAction(JajukActions.PLAY_DIRECTORY_SELECTION, new PlayDirectorySelectionAction(), false); installAction(JajukActions.CDDB_SELECTION, new CDDBSelectionAction(), false); installAction(JajukActions.SAVE_AS, new SaveAsAction(), false); installAction(JajukActions.SYNC_TREE_TABLE, new SyncTreeTableAction(), false); // Preferences installAction(JajukActions.BAN, new BanCurrentAction(), false); installAction(JajukActions.BAN_SELECTION, new BanSelectionAction(), false); installAction(JajukActions.UN_BAN_SELECTION, new UnBanSelectionAction(), false); installAction(JajukActions.PREFERENCE_ADORE, new AdoreSelectionAction(), false); installAction(JajukActions.PREFERENCE_LOVE, new LoveSelectionAction(), false); installAction(JajukActions.PREFERENCE_LIKE, new LikeSelectionAction(), false); installAction(JajukActions.PREFERENCE_AVERAGE, new AverageSelectionAction(), false); installAction(JajukActions.PREFERENCE_POOR, new PoorSelectionAction(), false); installAction(JajukActions.PREFERENCE_HATE, new HateSelectionAction(), false); installAction(JajukActions.PREFERENCE_UNSET, new UnsetPreferenceSelectionAction(), false); // Install this action only if Desktop class is supported, it is used to // open default web browser if (UtilSystem.isBrowserSupported()) { installAction(JajukActions.LAUNCH_IN_BROWSER, new LaunchInBrowserAction(), false); } // Uninstall Look and feel keystrokes if required uninstallStrokes(); } /** * Gets the action. * * @param action The JajukActions to get. * * @return The JajukAction implementation linked to the * JajukActions. */ public static JajukAction getAction(JajukActions action) { JajukAction actionBase = MAP.get(action); if (actionBase == null) { throw new ExceptionInInitializerError("No action mapping found for " + action); } return actionBase; } /** * Installs a new action in the action manager. If removeFromLAF * is true, then the keystroke attached to the action will be * stored in list. To remove these keystrokes from the InputMaps * of the different components, call {@link #uninstallStrokes()}. * * @param name The name for the action. * @param action The action implementation. * @param removeFromLAF Remove default keystrokes from look and feel. */ private static void installAction(JajukActions name, JajukAction action, boolean removeFromLAF) { MAP.put(name, action); if (removeFromLAF) { KeyStroke stroke = (KeyStroke) action.getValue(Action.ACCELERATOR_KEY); if (stroke != null) { STROKE_LIST.add(stroke); } } } /** * Uninstall default keystrokes from different JComponents to allow more * globally configured JaJuk keystrokes. */ public static void uninstallStrokes() { UIDefaults defaults = UIManager.getDefaults(); for (Object uidefault : defaults.keySet()) { if (uidefault instanceof InputMap) { InputMap map = (InputMap) uidefault; for (KeyStroke stroke : STROKE_LIST) { map.remove(stroke); } } } } /** * Enable or disable the action. * * @param action DOCUMENT_ME * @param enable DOCUMENT_ME */ public void enable(JajukAction action, boolean enable) { action.enable(enable); } }jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/actions/RefactorAction.java0000644000175000017500000002130311720500104025625 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.actions; import java.io.IOException; import java.util.ArrayList; import java.util.List; import javax.swing.JOptionPane; import org.jajuk.base.Directory; import org.jajuk.base.DirectoryManager; import org.jajuk.base.File; import org.jajuk.base.Track; import org.jajuk.events.JajukEvent; import org.jajuk.events.JajukEvents; import org.jajuk.events.ObservationManager; import org.jajuk.ui.widgets.InformationJPanel; import org.jajuk.util.Conf; import org.jajuk.util.Const; import org.jajuk.util.JajukFileFilter; import org.jajuk.util.Messages; import org.jajuk.util.UtilGUI; import org.jajuk.util.UtilString; import org.jajuk.util.error.JajukException; import org.jajuk.util.filters.NotAudioFilter; import org.jajuk.util.log.Log; /** * DOCUMENT_ME. */ public class RefactorAction { /** DOCUMENT_ME. */ private static boolean bStopAll = false; /** DOCUMENT_ME. */ private static String sFS = java.io.File.separator; /** DOCUMENT_ME. */ private final List alFiles; /** [PERF] Stores directory to be refreshed to avoid rescanning them twice. */ private final List toBeRefreshed = new ArrayList(1); /** * The Constructor. * * @param pFiles files to be reorganized (can be from different directories) */ public RefactorAction(final List pFiles) { this.alFiles = pFiles; // check the directory user selected contains some files if (pFiles.size() == 0) { Messages.showErrorMessage(18); return; } StringBuilder sFiles = new StringBuilder(); for (final File f : alFiles) { sFiles.append(f.getName()).append('\n'); } if (Conf.getBoolean(Const.CONF_CONFIRMATIONS_REFACTOR_FILES)) { final int iResu = Messages.getChoice(Messages.getString("Confirmation_refactor_files") + " : \n" + sFiles, JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.INFORMATION_MESSAGE); if (iResu != JOptionPane.YES_OPTION) { // Cancel if (iResu == JOptionPane.CANCEL_OPTION) { RefactorAction.bStopAll = true; } UtilGUI.stopWaiting(); return; } } new Thread("Refactor Thread") { @Override public void run() { UtilGUI.waiting(); refactor(); ObservationManager.notify(new JajukEvent(JajukEvents.DEVICE_REFRESH)); } }.start(); UtilGUI.stopWaiting(); } /** * Refactoring itself. */ public void refactor() { boolean bOKToOverwrite = false; String sErrors = ""; String filename; for (final File fCurrent : alFiles) { final Track tCurrent = fCurrent.getTrack(); try { filename = UtilString.applyPattern(fCurrent, Conf.getString(Const.CONF_PATTERN_REFACTOR), true, true); } catch (final JajukException je) { sErrors += je.getMessage() + '\n'; continue; } filename += "." + tCurrent.getType().getExtension(); filename = filename.replace("/", RefactorAction.sFS); final java.io.File fOld = fCurrent.getFIO(); final String sPathname = fCurrent.getDevice().getFio().getPath() + RefactorAction.sFS + filename; java.io.File fNew = new java.io.File(sPathname); // Confirm if destination dir already exist if (fNew.getParentFile().exists() && !bOKToOverwrite) { final int resu = Messages.getChoice(Messages.getString("Warning.5"), JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE); if (resu == JOptionPane.NO_OPTION) { continue; } else if (resu == JOptionPane.CANCEL_OPTION) { return; } } // This flag is used to avoid displaying the confirmation at each // file bOKToOverwrite = true; fNew.getParentFile().mkdirs(); // Move file and related cover but save old Directory pathname // for future deletion try { final java.io.File fCover = tCurrent.getAlbum().findCover(); if (fCover != null) { java.io.File destFile = new java.io.File(fNew.getParent() + RefactorAction.sFS + fCover.getName()); if (!fCover.renameTo(destFile)) { throw new IOException("Cannot move item: " + fCover.getAbsolutePath() + " to " + destFile.getAbsolutePath()); } } } catch (Exception e) { // This exception can be thrown by instance if default cover is not // readable Log.error(e); } // Rename audio files boolean bRenameSuccess = false; // Test if source and target files are equals if (fNew.getAbsolutePath().equalsIgnoreCase(fOld.getAbsolutePath())) { sErrors += fCurrent.getAbsolutePath() + " (" + Messages.getString("Error.160") + ")\n"; } else { try { bRenameSuccess = fOld.renameTo(fNew); if (!bRenameSuccess) { sErrors += fCurrent.getAbsolutePath() + " (" + Messages.getString("Error.154") + ")\n"; } Log.debug("[Refactoring] {{" + fNew.getAbsolutePath() + "}} Success ? " + bRenameSuccess); } catch (Exception e) { Log.error(e); sErrors += fCurrent.getAbsolutePath() + " (" + Messages.getString("Error.161") + ")\n"; } } // Register and scans new directories String sFirstDir = null; final String sTest[] = sPathname.split(fCurrent.getDevice().getFio().getPath().replace("\\", "\\\\")); sFirstDir = sTest[1].split("\\" + RefactorAction.sFS)[1]; final Directory dir = DirectoryManager.getInstance().registerDirectory( sFirstDir, DirectoryManager.getInstance().getDirectoryForIO(fCurrent.getDevice().getFio(), fCurrent.getDevice()), fCurrent.getDevice()); // Ask to refresh this directory afterward if (!toBeRefreshed.contains(dir)) { toBeRefreshed.add(dir); } // See if old directory contain other files and move them final java.io.File dOld = fOld.getParentFile(); final java.io.File[] list = dOld.listFiles(new JajukFileFilter(NotAudioFilter.getInstance())); if (list == null) { DirectoryManager.getInstance().removeDirectory(fOld.getParent()); } else if (list.length != 0) { for (final java.io.File f : list) { fNew = new java.io.File(fNew.getParent() + RefactorAction.sFS + f.getName()); try { bRenameSuccess = f.renameTo(fNew); if (!bRenameSuccess) { sErrors += f.getAbsolutePath() + " (" + Messages.getString("Error.154") + ")\n"; } Log.debug("[Refactoring] {{" + fNew.getAbsolutePath() + "}} Success ? " + bRenameSuccess); } catch (Exception e) { Log.error(e); sErrors += f.getAbsolutePath() + " (" + Messages.getString("Error.161") + ")\n"; } } } // Only try to remove old directory, will work if actually empty, // do not force deletion here else if (list.length == 0 && dOld.delete()) { DirectoryManager.getInstance().removeDirectory(fOld.getParent()); } InformationJPanel.getInstance().setMessage( Messages.getString("RefactorWizard.0") + sPathname, InformationJPanel.MessageType.INFORMATIVE); } // Refresh and cleanup required directories for (final Directory dir : toBeRefreshed) { try { dir.refresh(false); } catch (Exception e) { Log.error(e); } dir.getDevice().cleanRemovedFiles(null); } if (!sErrors.isEmpty()) { Messages.showDetailedErrorMessage(147, "", sErrors); } else { InformationJPanel.getInstance().setMessage(Messages.getString("Success"), InformationJPanel.MessageType.INFORMATIVE); } } /** * Checks if is stop all. * * @return true, if is stop all */ public static boolean isStopAll() { return bStopAll; } /** * Reset stop all. * DOCUMENT_ME */ public static void resetStopAll() { bStopAll = false; } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/actions/ForwardTrackAction.java0000644000175000017500000000407311720500104026456 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.actions; import java.awt.event.ActionEvent; import org.jajuk.services.players.Player; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; import org.jajuk.util.log.Log; /** * Action class for fast forwarding the current track. Installed keystroke: * CTRL + ALT + RIGHT ARROW. */ public class ForwardTrackAction extends JajukAction { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** The Constant JUMP_SIZE. DOCUMENT_ME */ private static final float JUMP_SIZE = 0.1f; /** * Instantiates a new forward track action. */ ForwardTrackAction() { super(IconLoader.getIcon(JajukIcons.FWD), "altGraph F10", false, true); setShortDescription(Messages.getString("CommandJPanel.13")); } /* (non-Javadoc) * @see org.jajuk.ui.actions.JajukAction#perform(java.awt.event.ActionEvent) */ @Override public void perform(ActionEvent evt) { new Thread("ForwardTrackAction") { @Override public void run() { try { float fCurrentPosition = Player.getCurrentPosition(); Player.seek(fCurrentPosition + JUMP_SIZE); } catch (Exception e) { Log.error(e); } } }.start(); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/actions/CopyAction.java0000644000175000017500000000403511720500104024775 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.actions; import java.awt.event.ActionEvent; import java.util.List; import javax.swing.JComponent; import org.jajuk.base.Item; import org.jajuk.ui.helpers.ItemMoveManager; import org.jajuk.util.Const; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; /** * Action class for Copy. */ public class CopyAction extends JajukAction { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** * Instantiates a new copy action. */ CopyAction() { super(Messages.getString("FilesTreeView.3"), IconLoader.getIcon(JajukIcons.COPY), "ctrl C", true, false); setShortDescription(Messages.getString("FilesTreeView.3")); } /* (non-Javadoc) * @see org.jajuk.ui.actions.JajukAction#perform(java.awt.event.ActionEvent) */ @Override @SuppressWarnings("unchecked") public void perform(ActionEvent e) { JComponent source = (JComponent) e.getSource(); List alSelected = (List) source.getClientProperty(Const.DETAIL_SELECTION); ItemMoveManager.getInstance().removeAll(); ItemMoveManager.getInstance().addItems(alSelected); ItemMoveManager.getInstance().setAction(ItemMoveManager.MoveActions.COPY); } }jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/actions/ExitAction.java0000644000175000017500000000700111720500104024770 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.actions; import java.awt.event.ActionEvent; import javax.swing.JOptionPane; import javax.swing.SwingUtilities; import org.jajuk.services.core.ExitService; import org.jajuk.ui.perspectives.PerspectiveManager; import org.jajuk.ui.windows.JajukFullScreenWindow; import org.jajuk.ui.windows.JajukMainWindow; import org.jajuk.ui.windows.JajukSlimbar; import org.jajuk.ui.windows.JajukSystray; import org.jajuk.util.Conf; import org.jajuk.util.Const; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; import org.jajuk.util.UtilGUI; import org.jajuk.util.log.Log; /** * DOCUMENT_ME. */ public class ExitAction extends JajukAction { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** * Instantiates a new exit action. */ ExitAction() { super(Messages.getString("JajukWindow.4"), IconLoader.getIcon(JajukIcons.EXIT), "alt X", true, false); setShortDescription(Messages.getString("JajukWindow.21")); } /* * (non-Javadoc) * * @see org.jajuk.ui.actions.JajukAction#perform(java.awt.event.ActionEvent) */ @Override public void perform(ActionEvent evt) { // Ask if a confirmation is required if (Conf.getBoolean(Const.CONF_CONFIRMATIONS_EXIT)) { int iResu = Messages.getChoice(Messages.getString("Confirmation_exit"), JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.INFORMATION_MESSAGE); if (iResu != JOptionPane.YES_OPTION) { return; } } // IMPORTANT: all the following code must be done in EDT to avoid dead // locks. // Not not use SwingUtilities.invokeLater method in the ExitHook Thread, // this code may never be run if (SwingUtilities.isEventDispatchThread()) { // commit perspectives if no full restore // engaged. Perspective should be commited before the window // being closed to avoid a dead lock in VLDocking if (!RestoreAllViewsAction.isFullRestore() && JajukMainWindow.getInstance().getWindowStateDecorator().isDisplayed()) { try { PerspectiveManager.commit(); } catch (Exception e) { Log.error(e); } } // Store window/tray/slimbar configuration UtilGUI.storeWindowSate(); // hide windows ASAP JajukMainWindow.getInstance().getWindowStateDecorator().display(false); // hide systray JajukSystray.getInstance().getWindowStateDecorator().display(false); // Hide slimbar JajukSlimbar.getInstance().getWindowStateDecorator().display(false); // Hide full screen JajukFullScreenWindow.getInstance().getWindowStateDecorator().display(false); } // Exit Jajuk ExitService.exit(0); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/actions/CommitAction.java0000644000175000017500000000315211720500104025312 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.actions; import java.awt.event.ActionEvent; import org.jajuk.services.core.ExitService; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; /** * Action to run garbage collection. */ public class CommitAction extends JajukAction { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** * Instantiates a new action. */ CommitAction() { super(Messages.getString("JajukJMenuBar.33"), IconLoader.getIcon(JajukIcons.SAVE), true); setShortDescription(Messages.getString("JajukJMenuBar.33")); } /* (non-Javadoc) * @see org.jajuk.ui.actions.JajukAction#perform(java.awt.event.ActionEvent) */ @Override public void perform(ActionEvent evt) throws Exception { ExitService.commit(false); } }jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/actions/NewPropertyAction.java0000644000175000017500000000333411720500104026362 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.actions; import java.awt.event.ActionEvent; import org.jajuk.ui.wizard.NewPropertyWizard; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; import org.jajuk.util.error.JajukException; /** * DOCUMENT_ME. */ public class NewPropertyAction extends JajukAction { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** * Instantiates a new new property action. */ NewPropertyAction() { super(Messages.getString("JajukJMenuBar.6"), IconLoader.getIcon(JajukIcons.NEW), true); setShortDescription(Messages.getString("JajukJMenuBar.6")); } /* (non-Javadoc) * @see org.jajuk.ui.actions.JajukAction#perform(java.awt.event.ActionEvent) */ @Override public void perform(ActionEvent evt) throws JajukException { NewPropertyWizard npw = new NewPropertyWizard(); npw.pack(); npw.setVisible(true); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/actions/HideShowMountedDevicesAction.java0000644000175000017500000000421311720500104030432 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.actions; import java.awt.event.ActionEvent; import javax.swing.JCheckBoxMenuItem; import javax.swing.JComponent; import org.jajuk.events.JajukEvent; import org.jajuk.events.JajukEvents; import org.jajuk.events.ObservationManager; import org.jajuk.util.Conf; import org.jajuk.util.Const; import org.jajuk.util.Messages; /** * Fast access to hide/show unmounted devices option. */ public class HideShowMountedDevicesAction extends JajukAction { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** * Instantiates a new hide show mounted devices action. */ HideShowMountedDevicesAction() { super(Messages.getString("JajukJMenuBar.24"), true); } /* (non-Javadoc) * @see org.jajuk.ui.actions.JajukAction#perform(java.awt.event.ActionEvent) */ @Override public void perform(ActionEvent e) { JComponent source = (JComponent) e.getSource(); Object o = source.getClientProperty(Const.DETAIL_ORIGIN); JCheckBoxMenuItem jmiUnmounted = (JCheckBoxMenuItem) o; boolean bHideUnmountedStatus = Conf.getBoolean(Const.CONF_OPTIONS_HIDE_UNMOUNTED); Conf.setProperty(Const.CONF_OPTIONS_HIDE_UNMOUNTED, Boolean.toString(!bHideUnmountedStatus)); jmiUnmounted.setSelected(!bHideUnmountedStatus); ObservationManager.notify(new JajukEvent(JajukEvents.PARAMETERS_CHANGE)); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/actions/BestOfAction.java0000644000175000017500000000532511720500104025250 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.actions; import java.awt.event.ActionEvent; import java.util.List; import org.jajuk.base.File; import org.jajuk.base.FileManager; import org.jajuk.services.dj.Ambience; import org.jajuk.services.dj.AmbienceManager; import org.jajuk.services.players.QueueModel; import org.jajuk.util.Conf; import org.jajuk.util.Const; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; import org.jajuk.util.UtilFeatures; import org.jajuk.util.error.JajukException; import org.jajuk.util.log.Log; /** * DOCUMENT_ME. */ public class BestOfAction extends JajukAction { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** * Instantiates a new best of action. */ BestOfAction() { super(Messages.getString("JajukWindow.7"), IconLoader.getIcon(JajukIcons.BESTOF), true); setShortDescription(Messages.getString("JajukWindow.24")); } /* (non-Javadoc) * @see org.jajuk.ui.actions.JajukAction#perform(java.awt.event.ActionEvent) */ @Override public void perform(ActionEvent evt) throws JajukException { new Thread("BestOfAction") { @Override public void run() { try { Ambience ambience = AmbienceManager.getInstance().getSelectedAmbience(); List alToPlay = UtilFeatures.filterByAmbience(FileManager.getInstance() .getGlobalBestofPlaylist(), ambience); // For perfs (mainly playlist editor view refresh), we set a ceil for // tracks // number if (alToPlay.size() > 0 && alToPlay.size() > Const.NB_TRACKS_ON_ACTION) { alToPlay = alToPlay.subList(0, Const.NB_TRACKS_ON_ACTION); } QueueModel.push(UtilFeatures.createStackItems(alToPlay, Conf .getBoolean(Const.CONF_STATE_REPEAT_ALL), false), false); } catch (Exception e) { Log.error(e); } } }.start(); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/actions/BookmarkSelectionAction.java0000644000175000017500000000450611720500104027501 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.actions; import java.awt.event.ActionEvent; import java.util.List; import org.jajuk.base.File; import org.jajuk.services.bookmark.Bookmarks; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; import org.jajuk.util.UtilFeatures; import org.jajuk.util.log.Log; /** * Bookmark a selection *

    * Action emitter is responsible to ensure all items provided share the same * type *

    *

    * Selection data is provided using the swing properties DETAIL_SELECTION *

    . */ public class BookmarkSelectionAction extends SelectionAction { /** Generated serialVersionUID. */ private static final long serialVersionUID = -8078402652430413821L; /** * Instantiates a new bookmark selection action. */ BookmarkSelectionAction() { super(Messages.getString("TracksTableView.15"), IconLoader.getIcon(JajukIcons.BOOKMARK_FOLDERS), true); setShortDescription(Messages.getString("TracksTableView.15")); } /* * (non-Javadoc) * * @see org.jajuk.ui.actions.JajukAction#perform(java.awt.event.ActionEvent) */ @Override public void perform(final ActionEvent e) throws Exception { new Thread("BookmarkSelectionAction") { @Override public void run() { try { BookmarkSelectionAction.super.perform(e); List files = UtilFeatures.getPlayableFiles(selection); Bookmarks.getInstance().addFiles(files); } catch (Exception e) { Log.error(e); } } }.start(); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/actions/CutAction.java0000644000175000017500000000404711720500104024621 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.actions; import java.awt.event.ActionEvent; import java.util.ArrayList; import javax.swing.JComponent; import org.jajuk.base.Item; import org.jajuk.ui.helpers.ItemMoveManager; import org.jajuk.util.Const; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; /** * Action class for Cut. */ public class CutAction extends JajukAction { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** * Instantiates a new cut action. */ CutAction() { super(Messages.getString("FilesTreeView.4"), IconLoader.getIcon(JajukIcons.CUT), "ctrl X", true, false); setShortDescription(Messages.getString("FilesTreeView.4")); } /* (non-Javadoc) * @see org.jajuk.ui.actions.JajukAction#perform(java.awt.event.ActionEvent) */ @Override @SuppressWarnings("unchecked") public void perform(ActionEvent e) { JComponent source = (JComponent) e.getSource(); ArrayList alSelected = (ArrayList) source.getClientProperty(Const.DETAIL_SELECTION); ItemMoveManager.getInstance().removeAll(); ItemMoveManager.getInstance().addItems(alSelected); ItemMoveManager.getInstance().setAction(ItemMoveManager.MoveActions.CUT); } }jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/actions/package.html0000644000175000017500000000017111720500104024340 0ustar drazzibdrazzib DOCUMENT_ME jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/actions/PasteAction.java0000644000175000017500000003340111720500104025136 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.actions; import java.awt.event.ActionEvent; import java.util.ArrayList; import java.util.List; import javax.swing.JComponent; import javax.swing.JOptionPane; import org.jajuk.base.Album; import org.jajuk.base.Artist; import org.jajuk.base.Device; import org.jajuk.base.Directory; import org.jajuk.base.DirectoryManager; import org.jajuk.base.File; import org.jajuk.base.FileManager; import org.jajuk.base.Genre; import org.jajuk.base.Item; import org.jajuk.base.Playlist; import org.jajuk.base.Track; import org.jajuk.base.TrackManager; import org.jajuk.events.JajukEvent; import org.jajuk.events.JajukEvents; import org.jajuk.events.ObservationManager; import org.jajuk.ui.helpers.ItemMoveManager; import org.jajuk.ui.widgets.InformationJPanel; import org.jajuk.util.Const; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; import org.jajuk.util.UtilGUI; import org.jajuk.util.UtilSystem; import org.jajuk.util.log.Log; /** * DOCUMENT_ME. */ public class PasteAction extends JajukAction { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** * Instantiates a new paste action. */ PasteAction() { super(Messages.getString("ActionMove.0"), IconLoader.getIcon(JajukIcons.PASTE), "ctrl V", true, false); setShortDescription(Messages.getString("ActionMove.0")); } /* (non-Javadoc) * @see org.jajuk.ui.actions.JajukAction#perform(java.awt.event.ActionEvent) */ @Override @SuppressWarnings("unchecked") public void perform(ActionEvent e) { //TODO : rework this method into smaller units JComponent source = (JComponent) e.getSource(); final List alSelected = (List) source.getClientProperty(Const.DETAIL_SELECTION); final List itemsToMove = ItemMoveManager.getInstance().getAll(); final ItemMoveManager.MoveActions moveAction = ItemMoveManager.getInstance().getAction(); final List alFiles = new ArrayList(alSelected.size()); final List alPlaylists = new ArrayList(alSelected.size()); final List alDirs = new ArrayList(alSelected.size()); new Thread("Paste Thread") { @SuppressWarnings("cast") @Override public void run() { UtilGUI.waiting(); // Compute all files to move from various items list if (itemsToMove.size() == 0) { Log.debug("None item to move"); return; } Item first = itemsToMove.get(0); if (first instanceof Album || first instanceof Artist || first instanceof Genre) { List tracks = TrackManager.getInstance().getAssociatedTracks(itemsToMove, true); for (Track track : tracks) { alFiles.addAll(track.getFiles()); } } else { for (Item item : itemsToMove) { if (item instanceof File) { alFiles.add((File) item); } else if (item instanceof Track) { alFiles.addAll(((Track) item).getFiles()); } else if (item instanceof Directory) { alDirs.add((Directory) item); } else if (item instanceof Playlist) { alPlaylists.add((Playlist) item); } } } // Compute destination directory // alSelected can contain either a single Directory or a single Device Item item = alSelected.get(0); java.io.File dir; Directory destDir; if (item instanceof Directory) { dir = new java.io.File(((Directory) item).getAbsolutePath()); destDir = (Directory) item; } else if (item instanceof Device) { dir = new java.io.File(((Device) item).getRootDirectory().getAbsolutePath()); destDir = ((Device) item).getRootDirectory(); } else { dir = ((File) item).getDirectory().getFio(); destDir = ((File) item).getDirectory(); } // Compute source directories // We need to find the highest directory in order to refresh it along // with the destination file to avoid phantom references List srcDirs = new ArrayList(1); for (File file : alFiles) { boolean parentAlreadyPresent = false; // We have to iterate using items index because the collection can // grow for (int i = 0; i < srcDirs.size(); i++) { Directory directory = (Directory) srcDirs.get(i); if (file.getDirectory().isChildOf(directory)) { parentAlreadyPresent = true; break; } } if (!parentAlreadyPresent && !srcDirs.contains(file.getDirectory())) { srcDirs.add(file.getDirectory()); } } for (Playlist pl : alPlaylists) { boolean parentAlreadyPresent = false; // We have to iterate using items index because the collection can // grow for (int i = 0; i < srcDirs.size(); i++) { Directory directory = (Directory) srcDirs.get(i); if (pl.getDirectory().isChildOf(directory)) { parentAlreadyPresent = true; break; } } if (!parentAlreadyPresent && !srcDirs.contains(pl.getDirectory())) { srcDirs.add(pl.getDirectory()); } } boolean overwriteAll = false; boolean bErrorOccured = false; if (moveAction == ItemMoveManager.MoveActions.CUT) { for (File f : alFiles) { if (!overwriteAll) { java.io.File newFile = new java.io.File(dir.getAbsolutePath() + "/" + f.getName()); if (newFile.exists()) { int iResu = Messages.getChoice(Messages.getString("Confirmation_file_overwrite") + " : \n\n" + f.getName(), Messages.YES_NO_ALL_CANCEL_OPTION, JOptionPane.INFORMATION_MESSAGE); if (iResu == JOptionPane.NO_OPTION || iResu == JOptionPane.CANCEL_OPTION) { UtilGUI.stopWaiting(); return; } if (iResu == Messages.ALL_OPTION) { overwriteAll = true; } } } try { showMessage(f.getFIO()); FileManager.getInstance().changeFileDirectory(f, destDir); } catch (Exception ioe) { Log.error(131, ioe); Messages.showErrorMessage(131); bErrorOccured = true; } } for (Playlist pl : alPlaylists) { if (!overwriteAll) { java.io.File newFile = new java.io.File(dir.getAbsolutePath() + "/" + pl.getName()); if (newFile.exists()) { int iResu = Messages.getChoice(Messages.getString("Confirmation_file_overwrite") + " : \n\n" + pl.getName(), Messages.YES_NO_ALL_CANCEL_OPTION, JOptionPane.INFORMATION_MESSAGE); if (iResu == JOptionPane.NO_OPTION || iResu == JOptionPane.CANCEL_OPTION) { UtilGUI.stopWaiting(); return; } if (iResu == Messages.ALL_OPTION) { overwriteAll = true; } } } try { showMessage(pl.getFIO()); final java.io.File fileNew = new java.io.File( new StringBuilder(dir.getAbsolutePath()).append("/").append(pl.getName()) .toString()); if (!pl.getFIO().renameTo(fileNew)) { throw new Exception("Cannot move item: " + pl.getFIO().getAbsolutePath() + " to " + fileNew.getAbsolutePath()); } // Refresh source and destination destDir.refresh(false); // Refresh source directories as well for (Directory srcDir : srcDirs) { srcDir.cleanRemovedFiles(); srcDir.refresh(false); } } catch (Exception ioe) { Log.error(131, ioe); Messages.showErrorMessage(131); bErrorOccured = true; } } for (Directory d : alDirs) { try { java.io.File src = new java.io.File(d.getAbsolutePath()); java.io.File dst = new java.io.File(dir.getAbsolutePath() + "/" + d.getName()); showMessage(src); java.io.File newDir = new java.io.File( new StringBuilder(dst.getAbsolutePath()).toString()); if (!src.renameTo(newDir)) { throw new Exception("Cannot move item: " + src.getAbsolutePath() + " to " + dst.getAbsolutePath()); } DirectoryManager.getInstance().removeDirectory(d.getID()); } catch (Exception ioe) { Log.error(131, ioe); Messages.showErrorMessage(131); bErrorOccured = true; } } try { destDir.refresh(false); // Refresh source directories as well for (Directory srcDir : srcDirs) { srcDir.refresh(false); } } catch (Exception e1) { Log.error(e1); bErrorOccured = true; } } else if (moveAction == ItemMoveManager.MoveActions.COPY) { for (File f : alFiles) { if (!overwriteAll) { java.io.File newFile = new java.io.File(dir.getAbsolutePath() + "/" + f.getName()); if (newFile.exists()) { int iResu = Messages.getChoice(Messages.getString("Confirmation_file_overwrite") + " : \n\n" + f.getName(), Messages.YES_NO_ALL_CANCEL_OPTION, JOptionPane.INFORMATION_MESSAGE); if (iResu == JOptionPane.NO_OPTION || iResu == JOptionPane.CANCEL_OPTION) { UtilGUI.stopWaiting(); return; } if (iResu == Messages.ALL_OPTION) { overwriteAll = true; } } } try { showMessage(f.getFIO()); UtilSystem.copyToDir(f.getFIO(), dir); } catch (Exception ioe) { Log.error(131, ioe); Messages.showErrorMessage(131); bErrorOccured = true; } } for (Playlist pl : alPlaylists) { if (!overwriteAll) { java.io.File newFile = new java.io.File(dir.getAbsolutePath() + "/" + pl.getName()); if (newFile.exists()) { int iResu = Messages.getChoice(Messages.getString("Confirmation_file_overwrite") + " : \n\n" + pl.getName(), Messages.YES_NO_ALL_CANCEL_OPTION, JOptionPane.INFORMATION_MESSAGE); if (iResu == JOptionPane.NO_OPTION || iResu == JOptionPane.CANCEL_OPTION) { UtilGUI.stopWaiting(); return; } if (iResu == Messages.ALL_OPTION) { overwriteAll = true; } } } try { showMessage(pl.getFIO()); UtilSystem.copyToDir(pl.getFIO(), dir); // Refresh source and destination destDir.refresh(false); // Refresh source directories as well for (Directory srcDir : srcDirs) { srcDir.refresh(false); } } catch (Exception ioe) { Log.error(131, ioe); Messages.showErrorMessage(131); bErrorOccured = true; } } for (Directory d : alDirs) { try { java.io.File src = new java.io.File(d.getAbsolutePath()); java.io.File dst = new java.io.File(dir.getAbsolutePath() + "/" + d.getName()); showMessage(src); UtilSystem.copyRecursively(src, dst); } catch (Exception ioe) { Log.error(131, ioe); Messages.showErrorMessage(131); bErrorOccured = true; } } try { destDir.refresh(false); } catch (Exception e1) { Log.error(e1); bErrorOccured = true; } } ObservationManager.notify(new JajukEvent(JajukEvents.DEVICE_REFRESH)); UtilGUI.stopWaiting(); if (!bErrorOccured) { InformationJPanel.getInstance().setMessage(Messages.getString("Success"), InformationJPanel.MessageType.INFORMATIVE); } } }.start(); } /** * Display currently copied file to information panel. * * @param file DOCUMENT_ME */ private void showMessage(java.io.File file) { String message = Messages.getString("Device.45"); message += file.getAbsolutePath() + "]"; InformationJPanel.getInstance().setMessage(message, InformationJPanel.MessageType.INFORMATIVE); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/actions/RemovePropertyAction.java0000644000175000017500000000336611720500104027073 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.actions; import java.awt.event.ActionEvent; import org.jajuk.ui.wizard.RemovePropertyWizard; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; import org.jajuk.util.error.JajukException; /** * DOCUMENT_ME. */ public class RemovePropertyAction extends JajukAction { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** * Instantiates a new removes the property action. */ RemovePropertyAction() { super(Messages.getString("JajukJMenuBar.7"), IconLoader.getIcon(JajukIcons.DELETE), true); setShortDescription(Messages.getString("JajukJMenuBar.7")); } /* (non-Javadoc) * @see org.jajuk.ui.actions.JajukAction#perform(java.awt.event.ActionEvent) */ @Override public void perform(ActionEvent evt) throws JajukException { RemovePropertyWizard rpw = new RemovePropertyWizard(); rpw.pack(); rpw.setVisible(true); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/actions/PoorSelectionAction.java0000644000175000017500000000502311720500104026646 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.actions; import java.awt.event.ActionEvent; import java.util.List; import org.jajuk.base.Track; import org.jajuk.base.TrackManager; import org.jajuk.events.JajukEvent; import org.jajuk.events.JajukEvents; import org.jajuk.events.ObservationManager; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; import org.jajuk.util.log.Log; /** * DOCUMENT_ME. */ public class PoorSelectionAction extends SelectionAction { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** * Set poor preference to a selection *

    * Selection action *

    . */ PoorSelectionAction() { super(Messages.getString("Preference.2"), IconLoader.getIcon(JajukIcons.PREFERENCE_POOR), true); setShortDescription(Messages.getString("Preference.2")); } /* (non-Javadoc) * @see org.jajuk.ui.actions.SelectionAction#perform(java.awt.event.ActionEvent) */ @Override public void perform(final ActionEvent e) throws Exception { new Thread("PoorSelectionAction") { @Override public void run() { try { PoorSelectionAction.super.perform(e); // Check selection is not void if (selection.size() == 0) { return; } // Extract tracks of each item List tracks = TrackManager.getInstance().getAssociatedTracks(selection, false); // Set the preference for (Track track : tracks) { track.setPreference(-2l); } // Request a GUI refresh ObservationManager.notify(new JajukEvent(JajukEvents.RATE_CHANGED)); } catch (Exception e) { Log.error(e); } } }.start(); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/actions/KaraokeModeAction.java0000644000175000017500000000352511720500104026250 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.actions; import java.awt.event.ActionEvent; import org.jajuk.ui.widgets.JajukJMenuBar; import org.jajuk.util.Conf; import org.jajuk.util.Const; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; /** * Karaoke mode state change action. */ public class KaraokeModeAction extends JajukAction { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** * Instantiates a new karaoke mode action. */ KaraokeModeAction() { super(Messages.getString("JajukJMenuBar.31"), IconLoader.getIcon(JajukIcons.KARAOKE), true); setShortDescription(Messages.getString("CommandJPanel.27")); } /* (non-Javadoc) * @see org.jajuk.ui.actions.JajukAction#perform(java.awt.event.ActionEvent) */ @Override public void perform(ActionEvent evt) { boolean b = Boolean.valueOf(Conf.getString(Const.CONF_STATE_KARAOKE)); Conf.setProperty(Const.CONF_STATE_KARAOKE, Boolean.toString(!b)); JajukJMenuBar.getInstance().setKaraokeSelected(!b); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/actions/DecreaseVolumeAction.java0000644000175000017500000000364611720500104026775 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.actions; import java.awt.event.ActionEvent; import org.jajuk.services.players.Player; import org.jajuk.util.log.Log; /** * Action class for decreasing the volume. Installed keystroke: * CTRL + DOWN ARROW. */ public class DecreaseVolumeAction extends JajukAction { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** * Instantiates a new decrease volume action. */ DecreaseVolumeAction() { super("decrease volume", "ctrl DOWN", true, true); } /* (non-Javadoc) * @see org.jajuk.ui.actions.JajukAction#perform(java.awt.event.ActionEvent) */ @Override public void perform(ActionEvent evt) { new Thread("DecreaseVolumeAction") { @Override public void run() { try { float old = Player.getCurrentVolume(); float newVolume = old - 0.05f; // if user move the volume slider, unmute if (Player.isMuted()) { Player.mute(false); } Player.setVolume(newVolume); } catch (Exception e) { Log.error(e); } } }.start(); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/actions/PlayArtistSelectionAction.java0000644000175000017500000000554511720500104030034 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.actions; import java.awt.event.ActionEvent; import java.util.List; import org.jajuk.base.Artist; import org.jajuk.base.File; import org.jajuk.base.Track; import org.jajuk.services.players.QueueModel; import org.jajuk.util.Conf; import org.jajuk.util.Const; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; import org.jajuk.util.UtilFeatures; import org.jajuk.util.log.Log; /** * Play artists a selection. We expect the selection to be tracks and we play * only the first found artist *

    * Action launcher is responsible to ensure all items provided share the same * type *

    *

    * Selection data is provided using the swing properties DETAIL_SELECTION *

    */ public class PlayArtistSelectionAction extends SelectionAction { /** Generated serialVersionUID. */ private static final long serialVersionUID = -8078402652430413821L; /** * Instantiates a new play artist selection action. */ PlayArtistSelectionAction() { super(Messages.getString("TracksTableView.12"), IconLoader.getIcon(JajukIcons.ARTIST), true); setShortDescription(Messages.getString("TracksTableView.12")); } /* * (non-Javadoc) * * @see org.jajuk.ui.actions.JajukAction#perform(java.awt.event.ActionEvent) */ @Override public void perform(final ActionEvent e) throws Exception { new Thread("PlayArtistSelectionAction") { @Override public void run() { try { PlayArtistSelectionAction.super.perform(e); if (selection.size() == 0 || !(selection.get(0) instanceof Track)) { return; } // Select all files from the first found album Artist artist = ((Track) selection.get(0)).getArtist(); List files = UtilFeatures.getPlayableFiles(artist); QueueModel.push(UtilFeatures.createStackItems(UtilFeatures.applyPlayOption(files), Conf .getBoolean(Const.CONF_STATE_REPEAT_ALL), true), false); } catch (Exception e) { Log.error(e); } } }.start(); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/actions/QualityAction.java0000644000175000017500000000547011720500104025517 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.actions; import java.awt.Desktop; import java.awt.Toolkit; import java.awt.datatransfer.Clipboard; import java.awt.datatransfer.StringSelection; import java.awt.event.ActionEvent; import java.net.URI; import org.jajuk.util.Const; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; import org.jajuk.util.UtilString; import org.jajuk.util.log.Log; /** * Action for collecting some system information and opening a browser-window * with the URL to report a new ticket. The user can then simply paste the * information into the ticket. */ public class QualityAction extends JajukAction { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** * Instantiates a new quality action. */ QualityAction() { super(Messages.getString("JajukJMenuBar.19"), IconLoader.getIcon(JajukIcons.EDIT), true); } /** * Invoked when the user chooses to report a ticket. * * @param evt The event, not used currently. */ @Override public void perform(ActionEvent evt) { StringBuilder sBody = new StringBuilder(); sBody.append("Version: ").append(Const.JAJUK_VERSION).append('\n'); sBody.append(UtilString.getAnonymizedSystemProperties().toString()).append('\n'); sBody.append(UtilString.getAnonymizedJajukProperties().toString()).append('\n'); for (String line : Log.getSpool()) { sBody.append(line).append('\n'); } // if it is a bug, copy logs into the clipboard StringSelection data = new StringSelection(sBody.toString()); Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); clipboard.setContents(data, data); try { // Show Trac ticket creation page in an external browser Desktop.getDesktop().browse(new URI("http://trac.jajuk.info/newticket")); // Display a message Messages.showInfoMessage(Messages.getString("QualityFeedbackWizard.20")); } catch (Exception e) { Messages.showErrorMessage(136); Log.error(e); } } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/actions/ShowAboutAction.java0000644000175000017500000000311311720500104025772 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.actions; import java.awt.event.ActionEvent; import org.jajuk.ui.wizard.AboutWindow; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; /** * Action for displaying the tip of the day. */ public class ShowAboutAction extends JajukAction { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** * Instantiates a new show about action. */ ShowAboutAction() { super(Messages.getString("JajukWindow.5"), IconLoader.getIcon(JajukIcons.INFO), true); setShortDescription(Messages.getString("JajukWindow.22")); } /** * Invoked when an action occurs. * * @param evt DOCUMENT_ME */ @Override public void perform(ActionEvent evt) { new AboutWindow(); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/actions/CheckForUpdateAction.java0000644000175000017500000000432111720500104026710 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.actions; import java.awt.event.ActionEvent; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; import org.jajuk.util.UpgradeManager; import org.jajuk.util.error.JajukException; import org.jajuk.util.log.Log; /** * DOCUMENT_ME. */ public class CheckForUpdateAction extends JajukAction { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** * Instantiates a new check for update action. */ CheckForUpdateAction() { super(Messages.getString("JajukJMenuBar.27"), IconLoader.getIcon(JajukIcons.UPDATE_MANAGER), true); setShortDescription(Messages.getString("JajukJMenuBar.27")); } /* (non-Javadoc) * @see org.jajuk.ui.actions.JajukAction#perform(java.awt.event.ActionEvent) */ @Override public void perform(ActionEvent evt) throws JajukException { new Thread("CheckForUpdateAction") { @Override public void run() { try { String newRelease = UpgradeManager.getNewVersionName(); if (newRelease != null) { Messages.showInfoMessage(Messages.getString("UpdateManager.0") + newRelease + Messages.getString("UpdateManager.1")); } else { Messages.showInfoMessage(Messages.getString("UpdateManager.2")); } } catch (Exception e) { Log.error(e); } } }.start(); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/actions/RestoreAllViewsAction.java0000644000175000017500000000631111720500104027154 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.actions; import java.awt.event.ActionEvent; import java.io.File; import javax.swing.JOptionPane; import org.jajuk.services.core.ExitService; import org.jajuk.services.core.SessionService; import org.jajuk.ui.perspectives.IPerspective; import org.jajuk.ui.perspectives.PerspectiveManager; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; import org.jajuk.util.error.JajukException; /** * DOCUMENT_ME. */ public class RestoreAllViewsAction extends JajukAction { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** DOCUMENT_ME. */ private static boolean fullRestore = false; /** * Instantiates a new restore all views action. */ RestoreAllViewsAction() { super(Messages.getString("JajukJMenuBar.26"), IconLoader.getIcon(JajukIcons.RESTORE_ALL_VIEWS), true); setShortDescription(Messages.getString("JajukJMenuBar.26")); } /* * (non-Javadoc) * * @see org.jajuk.ui.actions.JajukAction#perform(java.awt.event.ActionEvent) */ @Override public void perform(final ActionEvent e) throws JajukException { new Thread("Restore All Views Thread") { @Override public void run() { // display a confirmation message int i = Messages.getChoice(Messages.getString("Confirmation_restore_all"), JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.INFORMATION_MESSAGE); if (i != JOptionPane.YES_OPTION) { return; } // Drop all perspectives conf for (IPerspective perspective : PerspectiveManager.getPerspectives()) { File loadFile = SessionService.getConfFileByPath(perspective.getClass().getSimpleName() + ".xml"); // Lazy deletion, this file have already been removed by a previous reset loadFile.delete(); } // Indicates to not commiting current configuration fullRestore = true; // Exit Jajuk new Thread("Restore All Views - Exit Thread") { @Override public void run() { ExitService.exit(0); } }.start(); } }.start(); } /** * Checks if is full restore. * * @return true, if is full restore */ public static boolean isFullRestore() { return fullRestore; } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/actions/FindDuplicateTracksAction.java0000644000175000017500000001700411720500104027746 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.actions; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Set; import java.util.TreeMap; import java.util.TreeSet; import javax.swing.JButton; import javax.swing.JComponent; import javax.swing.JDialog; import javax.swing.JOptionPane; import javax.swing.SwingWorker; import org.jajuk.base.File; import org.jajuk.base.Track; import org.jajuk.base.TrackComparator; import org.jajuk.base.TrackComparator.TrackComparatorType; import org.jajuk.base.TrackManager; import org.jajuk.ui.windows.JajukMainWindow; import org.jajuk.ui.wizard.DuplicateTracksDialog; import org.jajuk.util.Conf; import org.jajuk.util.Const; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; import org.jajuk.util.UtilGUI; /** * DOCUMENT_ME. */ public class FindDuplicateTracksAction extends JajukAction { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** Result : a list of dups files for a given track. */ List> duplicateTracksList; /** Temporary storage during dups detection. */ private Map> mapTrackDups; /** Track comparator. */ TrackComparator comparator = new TrackComparator(TrackComparatorType.ALMOST_IDENTICAL); /** * Instantiates a new find duplicate tracks action. */ FindDuplicateTracksAction() { super(Messages.getString("FindDuplicateTracksAction.2"), IconLoader.getIcon(JajukIcons.SEARCH), true); setShortDescription(Messages.getString("FindDuplicateTracksAction.2")); } /** * Add a dup for a given track. * * @param track DOCUMENT_ME * @param files list of files */ private void addDup(Track track, List files) { // Ignore case where thy are none ready files if (files.size() > 0) { String key = comparator.buildIdenticalTestFootprint(track).toLowerCase(); Set dups = mapTrackDups.get(key); if (dups == null) { // We sort files by path because we don't want to allow user to drop files from different directories dups = new TreeSet(); mapTrackDups.put(key, dups); } dups.addAll(files); } } /* * Return the next track relative to current position or null if it is the last track * @return the next track relative to current position or null if it is the last track */ /** * Gets the next track. * * @param tracks DOCUMENT_ME * @param index DOCUMENT_ME * * @return the next track */ private Track getNextTrack(List tracks, int index) { Track next = null; if (index < tracks.size() - 1) { next = tracks.get(index + 1); } return next; } /** * Return either all or only mounted files for given track * according to OPTIONS_HIDE_UNMOUNTED option. * * @param track DOCUMENT_ME * * @return either all or only mounted files for given track */ private List getFiles(Track track) { if (Conf.getBoolean(Const.CONF_OPTIONS_HIDE_UNMOUNTED)) { return track.getReadyFiles(); } else { return track.getFiles(); } } /** * Create the dups list. */ void populateDups() { duplicateTracksList = new ArrayList>(); // Use a tree map so footprints are sorted mapTrackDups = new TreeMap>(); List tracks = TrackManager.getInstance().getTracks(); // For finding duplicate files, we don't just rely on the number of files associated with // a track (>1), we also find almost-identical tracks, ie based on album name, not its ID // because then, we can't detect identical files located in several directories with a // different set of files (because track uses album id in its hashcode and album id uses CDDB discid // computed by jajuk based on the duration of all files in a given directory) // Sort using the ALMOST-IDENTICAL Collections.sort(tracks, comparator); int index = 0; while (index <= tracks.size() - 1) { Track track = tracks.get(index); Track next = getNextTrack(tracks, index); // 1- Find dups files for the same track if (getFiles(track).size() > 1) { addDup(track, getFiles(track)); } // 2- Compare each track to find adjacent duplicates (different tracks) if (next != null && comparator.compare(track, next) == 0) { addDup(track, getFiles(track)); addDup(next, getFiles(next)); } index++; } // Build final list (note that it is already sorted by track, mapTrackDups is a TreeMap) for (String footprint : mapTrackDups.keySet()) { Set dups = mapTrackDups.get(footprint); // dups can be 1 in fuzzy search if track1 ~= track2 and track1 files are mounted and not the tracks2's ones if (dups.size() > 1) { duplicateTracksList.add(new ArrayList(dups)); } } } /* * (non-Javadoc) * * @see org.jajuk.ui.actions.JajukAction#perform(java.awt.event.ActionEvent) */ @Override public void perform(final ActionEvent evt) throws Exception { UtilGUI.waiting(); SwingWorker sw = new SwingWorker() { @Override protected Void doInBackground() throws Exception { populateDups(); return null; } @Override public void done() { try { if (duplicateTracksList.size() == 0) { Messages.showInfoMessage(Messages.getString("FindDuplicateTracksAction.0")); } else { final JOptionPane optionPane = UtilGUI.getNarrowOptionPane(100); final JDialog duplicateFiles = optionPane.createDialog(null, Messages .getString("FindDuplicateTracksAction.3")); duplicateFiles.setResizable(true); JButton jbClose = new JButton(Messages.getString("Close")); jbClose.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { duplicateFiles.dispose(); } }); // Create and set up the content pane. JComponent newContentPane = new DuplicateTracksDialog(duplicateTracksList, jbClose); newContentPane.setOpaque(true); UtilGUI.setEscapeKeyboardAction(duplicateFiles, newContentPane); duplicateFiles.setContentPane(newContentPane); // Display the window. duplicateFiles.setSize(800, 600); duplicateFiles.setLocationRelativeTo(JajukMainWindow.getInstance()); duplicateFiles.setVisible(true); } } finally { UtilGUI.stopWaiting(); } } }; sw.execute(); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/actions/MuteAction.java0000644000175000017500000000542511720500104025001 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.actions; import static org.jajuk.ui.actions.JajukActions.MUTE_STATE; import java.awt.event.ActionEvent; import javax.swing.SwingUtilities; import org.jajuk.services.players.Player; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; /** * Action of clicking on the mute button. */ public class MuteAction extends JajukAction { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** * Instantiates a new mute action. */ MuteAction() { super(Messages.getString("JajukWindow.2"), IconLoader.getIcon(JajukIcons.VOLUME_LEVEL1), "F8", true, true); setShortDescription(Messages.getString("JajukWindow.19")); } /* (non-Javadoc) * @see org.jajuk.ui.actions.JajukAction#perform(java.awt.event.ActionEvent) */ @Override public void perform(ActionEvent evt) { Player.mute(); SwingUtilities.invokeLater(new Runnable() { @Override public void run() { if (Player.isMuted()) { setName(Messages.getString("JajukWindow.1")); } else { setName(Messages.getString("JajukWindow.2")); } setVolumeIcon(100 * Player.getCurrentVolume()); } }); } /** * Set Volume Icon. * * @param fVolume DOCUMENT_ME */ public static void setVolumeIcon(final float fVolume) { if (fVolume <= 0 || Player.isMuted()) { // We need to check if player is mute to handle cases when volume > 0 // and user muted jajuk in stopped state. ActionManager.getAction(MUTE_STATE).setIcon(IconLoader.getIcon(JajukIcons.MUTED)); } else if (fVolume <= 33) { ActionManager.getAction(MUTE_STATE).setIcon(IconLoader.getIcon(JajukIcons.VOLUME_LEVEL1)); } else if (fVolume <= 66) { ActionManager.getAction(MUTE_STATE).setIcon(IconLoader.getIcon(JajukIcons.VOLUME_LEVEL2)); } else { ActionManager.getAction(MUTE_STATE).setIcon(IconLoader.getIcon(JajukIcons.VOLUME_LEVEL3)); } } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/actions/SlimBarQueueAction.java0000644000175000017500000000340211720500104026416 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.actions; import java.awt.event.ActionEvent; import org.jajuk.ui.windows.JajukSlimbar; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; /** * DOCUMENT_ME. */ public class SlimBarQueueAction extends JajukAction { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1223773056757729079L; /** * Instantiates a new slim bar queue action. */ SlimBarQueueAction() { super(Messages.getString("PhysicalPlaylistRepositoryView.9"), IconLoader .getIcon(JajukIcons.PLAYLIST_FILE), true); setShortDescription(Messages.getString("PhysicalPlaylistRepositoryView.9")); } /* (non-Javadoc) * @see org.jajuk.ui.actions.JajukAction#perform(java.awt.event.ActionEvent) */ @Override public void perform(ActionEvent evt) throws Exception { JajukSlimbar slimBar = JajukSlimbar.getInstance(); slimBar.setDisplayQueue(!slimBar.isDisplayQueue()); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/actions/PushSelectionAction.java0000644000175000017500000000471011720500104026650 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.actions; import java.awt.event.ActionEvent; import java.util.List; import org.jajuk.base.File; import org.jajuk.services.players.QueueModel; import org.jajuk.util.Conf; import org.jajuk.util.Const; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; import org.jajuk.util.UtilFeatures; import org.jajuk.util.log.Log; /** * Push a selection *

    * Action emitter is responsible to ensure all items provided share the same * type *

    *

    * Selection data is provided using the swing properties DETAIL_SELECTION *

    . */ public class PushSelectionAction extends SelectionAction { /** Generated serialVersionUID. */ private static final long serialVersionUID = -8078402652430413821L; /** * Instantiates a new push selection action. */ PushSelectionAction() { super(Messages.getString("TracksTableView.8"), IconLoader.getIcon(JajukIcons.PUSH), true); setShortDescription(Messages.getString("TracksTableView.8")); } /* * (non-Javadoc) * * @see org.jajuk.ui.actions.JajukAction#perform(java.awt.event.ActionEvent) */ @Override public void perform(final ActionEvent e) throws Exception { new Thread("PushSelectionAction") { @Override public void run() { try { PushSelectionAction.super.perform(e); List files = UtilFeatures.getPlayableFiles(selection); QueueModel.push(UtilFeatures.createStackItems(UtilFeatures.applyPlayOption(files), Conf .getBoolean(Const.CONF_STATE_REPEAT_ALL), true), true); } catch (Exception e1) { Log.error(e1); } } }.start(); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/actions/AlarmClockAction.java0000644000175000017500000000323111720500104026070 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.actions; import java.awt.event.ActionEvent; import org.jajuk.ui.wizard.AlarmClockDialog; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; import org.jajuk.util.error.JajukException; /** * Alarm wizard action. */ public class AlarmClockAction extends JajukAction { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** * Instantiates a new alarm clock action. */ AlarmClockAction() { super(Messages.getString("AlarmClock.0"), IconLoader.getIcon(JajukIcons.ALARM), true); setShortDescription(Messages.getString("AlarmClock.0")); } /* (non-Javadoc) * @see org.jajuk.ui.actions.JajukAction#perform(java.awt.event.ActionEvent) */ @Override public void perform(ActionEvent evt) throws JajukException { new AlarmClockDialog(); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/actions/RefreshAction.java0000644000175000017500000000562111720500104025463 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.actions; import java.awt.event.ActionEvent; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import org.jajuk.base.Device; import org.jajuk.base.Directory; import org.jajuk.base.Item; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; import org.jajuk.util.log.Log; /** * DOCUMENT_ME. */ public class RefreshAction extends SelectionAction { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** * Instantiates a new refresh action. */ RefreshAction() { super(Messages.getString("ActionRefresh.0"), IconLoader.getIcon(JajukIcons.REFRESH), true); setShortDescription(Messages.getString("ActionRefresh.0")); } /* (non-Javadoc) * @see org.jajuk.ui.actions.JajukAction#perform(java.awt.event.ActionEvent) */ @Override public void perform(ActionEvent e) { try { RefreshAction.super.perform(e); } catch (Exception ex) { Log.error(ex); } // Note that we already tested void or mixed-up selection in // FilesTreeView.isRefreshSelectionValid() method. // The GUI allows only single device selection. if (selection.get(0) instanceof Device) { // ask user if he wants to make deep or fast scan Device device = (Device) selection.get(0); device.refresh(true, true, false, null); } else { // Directory selection, we have to group directories of the same device HashMap> devicesDirectories = new HashMap>( selection.size()); for (Item item : selection) { Directory dir = (Directory) item; Device device = dir.getDevice(); List dirs = devicesDirectories.get(device); if (dirs == null) { dirs = new ArrayList(); devicesDirectories.put(device, dirs); } dirs.add(dir); } for (Device device : devicesDirectories.keySet()) { List dirs = devicesDirectories.get(device); device.refresh(true, true, false, dirs); } } } }jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/actions/IncreaseVolumeAction.java0000644000175000017500000000364211720500104027007 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.actions; import java.awt.event.ActionEvent; import org.jajuk.services.players.Player; import org.jajuk.util.log.Log; /** * Action class for increasing the volume. Installed keystroke: * CTRL + UP ARROW. */ public class IncreaseVolumeAction extends JajukAction { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** * Instantiates a new increase volume action. */ IncreaseVolumeAction() { super("increase volume", "ctrl UP", true, true); } /* (non-Javadoc) * @see org.jajuk.ui.actions.JajukAction#perform(java.awt.event.ActionEvent) */ @Override public void perform(ActionEvent evt) { new Thread("IncreaseVolumeAction") { @Override public void run() { try { float old = Player.getCurrentVolume(); float newVolume = old + 0.05f; // if user move the volume slider, unmute if (Player.isMuted()) { Player.mute(false); } Player.setVolume(newVolume); } catch (Exception e) { Log.error(e); } } }.start(); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/actions/CDDBSelectionAction.java0000644000175000017500000000536211720500104026431 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.actions; import java.awt.event.ActionEvent; import java.util.List; import org.apache.commons.collections.CollectionUtils; import org.jajuk.base.Track; import org.jajuk.base.TrackManager; import org.jajuk.ui.wizard.CDDBWizard; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; import org.jajuk.util.filters.JajukPredicates; import org.jajuk.util.log.Log; /** * Find tags from CDDB on selection *

    * Action emitter is responsible to ensure all items provided share the same * type *

    *

    * Selection data is provided using the swing properties DETAIL_SELECTION *

    . */ public class CDDBSelectionAction extends SelectionAction { /** Generated serialVersionUID. */ private static final long serialVersionUID = -8078402652430413821L; /** * Instantiates a new cDDB selection action. */ CDDBSelectionAction() { super(Messages.getString("TracksTreeView.34"), IconLoader.getIcon(JajukIcons.CDDB), true); setShortDescription(Messages.getString("TracksTreeView.34")); } /* * (non-Javadoc) * * @see org.jajuk.ui.actions.JajukAction#perform(java.awt.event.ActionEvent) */ @Override public void perform(final ActionEvent e) throws Exception { try { CDDBSelectionAction.super.perform(e); // Check selection is not void if (selection.size() == 0) { return; } // - We perform here fast computation, no need to use a SwingWorker here. // Actual network call to freedb is done in the CDDBWizard class that uses // a SwingWorker. // Build a list of tracks from various items List tracks = TrackManager.getInstance().getAssociatedTracks(selection, true); // Remove video tracks found (clips) CollectionUtils.filter(tracks, new JajukPredicates.NotVideoPredicate()); // Display the wizard new CDDBWizard(tracks); } catch (Exception ex) { Log.error(ex); } } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/actions/RepeatAllModeAction.java0000644000175000017500000000420411720500104026537 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.actions; import java.awt.event.ActionEvent; import org.jajuk.events.JajukEvent; import org.jajuk.events.JajukEvents; import org.jajuk.events.ObservationManager; import org.jajuk.services.players.QueueModel; import org.jajuk.util.Conf; import org.jajuk.util.Const; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; import org.jajuk.util.UtilGUI; /** * DOCUMENT_ME. */ public class RepeatAllModeAction extends JajukAction { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** * Instantiates a new repeat all mode action. */ RepeatAllModeAction() { super(Messages.getString("JajukJMenuBar.30"), IconLoader.getIcon(JajukIcons.REPEAT_ALL), true); setShortDescription(Messages.getString("CommandJPanel.26")); } /** * Invoked when an action occurs. * * @param evt DOCUMENT_ME */ @Override public void perform(ActionEvent evt) { boolean b = Conf.getBoolean(Const.CONF_STATE_REPEAT_ALL); UtilGUI.setRepeatAllGui(!b); QueueModel.setRepeatModeToAll(!b); // computes planned tracks QueueModel.computesPlanned(false); // Refresh Queue View ObservationManager.notify(new JajukEvent(JajukEvents.QUEUE_NEED_REFRESH)); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/actions/LikeSelectionAction.java0000644000175000017500000000502211720500104026612 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.actions; import java.awt.event.ActionEvent; import java.util.List; import org.jajuk.base.Track; import org.jajuk.base.TrackManager; import org.jajuk.events.JajukEvent; import org.jajuk.events.JajukEvents; import org.jajuk.events.ObservationManager; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; import org.jajuk.util.log.Log; /** * DOCUMENT_ME. */ public class LikeSelectionAction extends SelectionAction { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** * Set like preference to a selection *

    * Selection action *

    . */ LikeSelectionAction() { super(Messages.getString("Preference.4"), IconLoader.getIcon(JajukIcons.PREFERENCE_LIKE), true); setShortDescription(Messages.getString("Preference.4")); } /* (non-Javadoc) * @see org.jajuk.ui.actions.SelectionAction#perform(java.awt.event.ActionEvent) */ @Override public void perform(final ActionEvent e) throws Exception { new Thread("LikeSelectionAction") { @Override public void run() { try { LikeSelectionAction.super.perform(e); // Check selection is not void if (selection.size() == 0) { return; } // Extract tracks of each item List tracks = TrackManager.getInstance().getAssociatedTracks(selection, false); // Set the preference for (Track track : tracks) { track.setPreference(1l); } // Request a GUI refresh ObservationManager.notify(new JajukEvent(JajukEvents.RATE_CHANGED)); } catch (Exception e) { Log.error(e); } } }.start(); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/actions/WebRadioAction.java0000644000175000017500000000405511720500104025561 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.actions; import java.awt.event.ActionEvent; import org.jajuk.services.players.QueueModel; import org.jajuk.services.webradio.WebRadio; import org.jajuk.services.webradio.WebRadioManager; import org.jajuk.util.Conf; import org.jajuk.util.Const; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; import org.jajuk.util.error.JajukException; /** * DOCUMENT_ME. */ public class WebRadioAction extends JajukAction { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** * Instantiates a new web radio action. */ WebRadioAction() { super(Messages.getString("CommandJPanel.25"), IconLoader.getIcon(JajukIcons.WEBRADIO), true); setShortDescription(WebRadioManager.getCurrentWebRadioTooltip()); } /* (non-Javadoc) * @see org.jajuk.ui.actions.JajukAction#perform(java.awt.event.ActionEvent) */ @Override public void perform(ActionEvent evt) throws JajukException { new Thread("WebRadio Thread") { @Override public void run() { WebRadio radio = WebRadioManager.getInstance().getWebRadioByName( Conf.getString(Const.CONF_DEFAULT_WEB_RADIO)); QueueModel.launchRadio(radio); } }.start(); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/actions/JajukAction.java0000644000175000017500000003213511720500104025131 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.actions; import java.awt.event.ActionEvent; import java.lang.reflect.InvocationTargetException; import javax.swing.AbstractAction; import javax.swing.Icon; import javax.swing.KeyStroke; import org.jajuk.util.Conf; import org.jajuk.util.Const; import org.jajuk.util.UtilSystem; import org.jajuk.util.log.Log; /** * Common super class for Swing actions. This class provides useful construction * options to create actions, just leaving open the necessity of implementing * the {@link #actionPerformed(java.awt.event.ActionEvent)} method. */ public abstract class JajukAction extends AbstractAction { /** Generated serialVersionUID. */ private static final long serialVersionUID = -2535230785022978297L; /** Is this action an hotkey ?. */ private boolean bHotkey = false; /** enable state. */ private boolean bEnable = true; // Instantiate a static JIntellitype object if under Windows // BEWARE ! don't use direct call to JIntellitype like // JIntellitype.isJIntellitypeSupported()) because we don't want to create a linkage // dependency for non Windows OS. The JIntellitype jar is not available under Debian for ie static { if (UtilSystem.isUnderWindows()) { try { Class.forName("org.jajuk.ui.actions.WindowsHotKeyManager") .getMethod("registerJIntellitype").invoke(null, (Object[]) null); } catch (Exception e) { Log.error(e); } } } /** * Construct an action with the given name, icon and accelerator keystroke. * * @param pName DOCUMENT_ME * @param icon The icon to use for visualization of the action. * @param stroke The keystroke to use. * @param enabled By default enable or disable the action. * @param bHotkey DOCUMENT_ME */ protected JajukAction(String pName, Icon icon, KeyStroke stroke, boolean enabled, boolean bHotkey) { // check hotkeys are enabled (false by default) this.bHotkey = UtilSystem.isUnderWindows() && bHotkey && Conf.getBoolean(Const.CONF_OPTIONS_HOTKEYS); String name = pName; if (name != null) { int mnemonic = ActionUtil.getMnemonic(name); name = ActionUtil.strip(name); if (mnemonic >= 0) { setMnemonic(mnemonic); } setName(name); } if (icon != null) { setIcon(icon); } if (stroke != null) { if (this.bHotkey) { try { Class.forName("org.jajuk.ui.actions.WindowsHotKeyManager").getMethod("registerHotKey", new Class[] { KeyStroke.class, JajukAction.class }).invoke(null, new Object[] { stroke, this }); } catch (ClassNotFoundException e) { Log.error(e); } catch (IllegalArgumentException e) { Log.error(e); } catch (SecurityException e) { Log.error(e); } catch (IllegalAccessException e) { Log.error(e); } catch (InvocationTargetException e) { Log.error(e); } catch (NoSuchMethodException e) { Log.error(e); } } // else use standard swing keystroke feature setAcceleratorKey(stroke); } setEnabled(enabled); } /** * Construct an action with the given name, icon and accelerator keystroke. * * @param name The unique name for the action. This name is used in the labels * for visualization. If the name contains a '_' (underscore) * character. The character following this underscore is used as * mnemonic key for the action. * @param icon The icon to use for visualization of the action. * @param stroke The keystroke to use. If the keystroke given is not a valid * keystroke using the rules describe in * @param enabled By default enable or disable the action. * @param bHotkey is it a hotkey (available even when window has not the focus) ? * {@link javax.swing.KeyStroke#getKeyStroke(String)}, null is used * instead. */ protected JajukAction(String name, Icon icon, String stroke, boolean enabled, boolean bHotkey) { this(name, icon, KeyStroke.getKeyStroke(stroke), enabled, bHotkey); } /** * Construct an action with the given name and accelerator keystroke, no icon. * * @param name The unique name for the action. This name is used in the labels * for visualization. If the name contains a '_' (underscore) * character. The character following this underscore is used as * mnemonic key for the action. * @param stroke The keystroke to use. * @param enabled By default enable or disable the action. * @param bHotkey is it a hotkey (available even when window has not the focus) ? */ protected JajukAction(String name, KeyStroke stroke, boolean enabled, boolean bHotkey) { this(name, null, stroke, enabled, bHotkey); } /** * Construct an action with the given name and accelerator keystroke, no icon. * * @param name The unique name for the action. This name is used in the labels * for visualization. If the name contains a '_' (underscore) * character. The character following this underscore is used as * mnemonic key for the action. * @param stroke The keystroke to use. If the keystroke given is not a valid * keystroke using the rules describe in * @param enabled By default enable or disable the action. * @param bHotkey is it a hotkey (available even when window has not the focus) ? * {@link javax.swing.KeyStroke#getKeyStroke(String)}, null is used * instead. */ protected JajukAction(String name, String stroke, boolean enabled, boolean bHotkey) { this(name, null, stroke, enabled, bHotkey); } /** * Construct an action with the given icon and accelerator keystroke, no name. * * @param icon The icon to use for visualization of the action. * @param stroke The keystroke to use. * @param enabled By default enable or disable the action. * @param bHotkey is it a hotkey (available even when window has not the focus) ? * * @see javax.swing.KeyStroke#getKeyStroke(String) */ protected JajukAction(Icon icon, KeyStroke stroke, boolean enabled, boolean bHotkey) { this(null, icon, stroke, enabled, bHotkey); } /** * Construct an action with the given icon and accelerator keystroke, no name. * * @param icon The icon to use for visualization of the action. * @param stroke The keystroke to use. If the keystroke given is not a valid * keystroke using the rules describe in * @param enabled By default enable or disable the action. * @param bHotkey is it a hotkey (available even when window has not the focus) ? * {@link javax.swing.KeyStroke#getKeyStroke(String)}, null is used * instead. * @see javax.swing.KeyStroke#getKeyStroke(String) */ protected JajukAction(Icon icon, String stroke, boolean enabled, boolean bHotkey) { this(null, icon, stroke, enabled, bHotkey); } /** * Construct an action with the given name and icon, no accelerator keystroke. * * @param name The unique name for the action. This name is used in the labels * for visualization. If the name contains a '_' (underscore) * character. The character following this underscore is used as * mnemonic key for the action. * @param icon The icon to use for visualization of the action. * @param enabled By default enable or disable the action. */ protected JajukAction(String name, Icon icon, boolean enabled) { this(name, icon, (KeyStroke) null, enabled, false); } /** * Construct an action with the given icon, no name, no accelerator keystroke. * * @param icon The icon to use for visualization of the action. * @param enabled By default enable or disable the action. */ protected JajukAction(Icon icon, boolean enabled) { this(null, icon, (KeyStroke) null, enabled, false); } /** * Construct an action with the given name, no icon, no accelerator keystroke. * * @param name The unique name for the action. This name is used in the labels * for visualization. If the name contains a '_' (underscore) * character. The character following this underscore is used as * mnemonic key for the action. * @param enabled By default enable or disable the action. */ protected JajukAction(String name, boolean enabled) { this(name, null, (KeyStroke) null, enabled, false); } /** * Sets the name. * * @param name The name for the action. This name is used for a menu or a button. */ public final void setName(String name) { putValue(NAME, name); } /** * Sets the short description. * * @param description The short description for the action. This is used for tooltip * text. */ public void setShortDescription(String description) { putValue(SHORT_DESCRIPTION, description); } /** * Sets the long description. * * @param description The long description for the action. This can be used for * context-sensitive help. */ public void setLongDescription(String description) { putValue(LONG_DESCRIPTION, description); } /** * Sets the icon. * * @param icon The small icon for the action. Use for toolbar buttons. */ public final void setIcon(Icon icon) { putValue(SMALL_ICON, icon); } /** * Sets the action command. * * @param actionCommand The action command for this action. This is used for creating the * ActionEvent. */ public void setActionCommand(String actionCommand) { putValue(ACCELERATOR_KEY, actionCommand); } /** * Sets the accelerator key. * * @param stroke The keystroke for the action. This is used as a shortcut key. */ public final void setAcceleratorKey(KeyStroke stroke) { putValue(ACCELERATOR_KEY, stroke); } /** * Sets the accelerator key. * * @param stroke The keystroke for the action. If the keystroke given is not a * valid keystroke using the rules described in * {@link javax.swing.KeyStroke#getKeyStroke(String)}, * null is used instead. This is used as a shortcut * key. */ public final void setAcceleratorKey(String stroke) { putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke(stroke)); } /** * Sets the keyboard mnemonic on the current action.

    A mnemonic must * correspond to a single key on the keyboard and should be specified using * one of the VK_XXX keycodes defined in * java.awt.event.KeyEvent. Mnemonics are case-insensitive, * therefore a key event with the corresponding keycode would cause the button * to be activated whether or not the Shift modifier was pressed.

    If the * character defined by the mnemonic is found within the button's label * string, the first occurrence of it will be underlined to indicate the * mnemonic to the user. * * @param mnemonic The key code which represents the mnemonic. The mnemonic is the * key which when combined with the look and feel's mouseless * modifier (usually Alt) will activate this button if focus * is contained somewhere within this action's ancestor window. * * @see java.awt.event.KeyEvent */ public final void setMnemonic(int mnemonic) { putValue(MNEMONIC_KEY, mnemonic); } /** * Invoked when an action occurs. This implementation calls * * @param evt The event. * {@link #perform(java.awt.event.ActionEvent)} to add error handling and * logging to the action system. */ @Override public final void actionPerformed(ActionEvent evt) { try { perform(evt); } catch (Throwable e2) { Log.error(e2); } } /** * Perform the action. * * @param evt DOCUMENT_ME * * @throws Exception When anything goes wrong when performing the action. */ public abstract void perform(ActionEvent evt) throws Exception; /** * Free intellipad resources. * * @throws Exception the exception */ public static void cleanup() throws Exception { if (UtilSystem.isUnderWindows()) { Class.forName("org.jajuk.ui.actions.WindowsHotKeyManager").getMethod("cleanup").invoke(null, (Object[]) null); } } /** * Checks if is hotkey. * * @return whether it is an hotkey */ public boolean isHotkey() { return this.bHotkey; } /** * Enable or disable the action. * * @param enable DOCUMENT_ME */ protected void enable(boolean enable) { this.bEnable = enable; } /** * Checks if is enable. * * @return enable state for the action */ protected boolean isEnable() { return this.bEnable; } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/actions/NextTrackAction.java0000644000175000017500000000621011720500104025763 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.actions; import java.awt.event.ActionEvent; import java.util.ArrayList; import java.util.List; import org.jajuk.services.players.QueueModel; import org.jajuk.services.webradio.WebRadio; import org.jajuk.services.webradio.WebRadioManager; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; import org.jajuk.util.log.Log; /** * Action class for jumping to the next track. Installed keystroke: * CTRL + RIGHT ARROW. */ public class NextTrackAction extends JajukAction { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** * Instantiates a new next track action. */ NextTrackAction() { super(Messages.getString("JajukWindow.14"), IconLoader.getIcon(JajukIcons.PLAYER_NEXT_SMALL), "F10", false, true); setShortDescription(Messages.getString("CommandJPanel.9")); } /* (non-Javadoc) * @see org.jajuk.ui.actions.JajukAction#perform(java.awt.event.ActionEvent) */ @Override public void perform(ActionEvent evt) { // check modifiers to see if it is a movement inside track, between // tracks or between albums if (evt != null // evt == null when using hotkeys && (evt.getModifiers() & ActionEvent.SHIFT_MASK) == ActionEvent.SHIFT_MASK) { ActionManager.getAction(JajukActions.NEXT_ALBUM).actionPerformed(evt); } else { // if playing a radio, launch next radio station if (QueueModel.isPlayingRadio()) { final List radios = new ArrayList(WebRadioManager.getInstance() .getWebRadios()); int index = radios.indexOf(QueueModel.getCurrentRadio()); if (index == radios.size() - 1) { index = 0; } else { index++; } final int i = index; new Thread("Next Track Thread") { @Override public void run() { QueueModel.launchRadio(radios.get(i)); } }.start(); } else { // Playing a track new Thread("Next Track Thread") { @Override public void run() { synchronized (QueueModel.class) { try { QueueModel.playNext(); } catch (Exception e) { Log.error(e); } } } }.start(); } } } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/actions/ShowDonateAction.java0000644000175000017500000000320711720500104026136 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.actions; import java.awt.event.ActionEvent; import org.jajuk.ui.wizard.DonateWindow; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; /** * Action for displaying the tip of the day. */ public class ShowDonateAction extends JajukAction { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** * Instantiates a new show about action. */ ShowDonateAction() { super(Messages.getString("JajukDonate.1"), IconLoader.getIcon(JajukIcons.DONATE), true); setShortDescription(Messages.getString("JajukDonate.4")); } /** * Invoked when an action occurs. * * @param evt DOCUMENT_ME */ @Override public void perform(ActionEvent evt) { new DonateWindow(); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/actions/DJAction.java0000644000175000017500000000607411720500104024365 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.actions; import java.awt.event.ActionEvent; import java.util.List; import org.jajuk.base.File; import org.jajuk.base.GenreManager; import org.jajuk.services.dj.DigitalDJ; import org.jajuk.services.dj.DigitalDJManager; import org.jajuk.services.players.QueueModel; import org.jajuk.util.Conf; import org.jajuk.util.Const; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; import org.jajuk.util.UtilFeatures; import org.jajuk.util.UtilGUI; import org.jajuk.util.error.JajukException; import org.jajuk.util.log.Log; /** * DOCUMENT_ME. */ public class DJAction extends JajukAction { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** * Instantiates a new dJ action. */ DJAction() { super(Messages.getString("CommandJPanel.16"), IconLoader.getIcon(JajukIcons.DIGITAL_DJ), true); } /* (non-Javadoc) * @see org.jajuk.ui.actions.JajukAction#perform(java.awt.event.ActionEvent) */ @Override public void perform(ActionEvent evt) throws JajukException { if (GenreManager.getInstance().getElementCount() == 0) { Messages.showErrorMessage(156); // void collection error } else { new Thread("DJ Thread") { @Override public void run() { DigitalDJ dj = DigitalDJManager.getInstance().getDJByID( Conf.getString(Const.CONF_DEFAULT_DJ)); try { if (dj != null) { Conf.setProperty(Const.CONF_FADE_DURATION, Integer.toString(dj.getFadingDuration())); UtilGUI.waiting(); List al = dj.generatePlaylist(); if (al != null && al.size() == 0) { // DJ constraints cannot be // respected Messages.showErrorMessage(158); return; } QueueModel.push(UtilFeatures.createStackItems(UtilFeatures.applyPlayOption(al), Conf .getBoolean(Const.CONF_STATE_REPEAT_ALL), false), false); } else { Messages.showErrorMessage(157); } } catch (Exception e) { Log.debug(e); Messages.showErrorMessage(176); } finally { UtilGUI.stopWaiting(); } } }.start(); } } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/actions/AmbienceConfigurationAction.java0000644000175000017500000000361311720500104030317 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.actions; import java.awt.event.ActionEvent; import javax.swing.SwingUtilities; import org.jajuk.ui.wizard.AmbienceWizard; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; /** * Action for configure ambiences. */ public class AmbienceConfigurationAction extends JajukAction { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** * Instantiates a new ambience configuration action. */ AmbienceConfigurationAction() { super(Messages.getString("CommandJPanel.19"), IconLoader.getIcon(JajukIcons.GENRE), true); } /* (non-Javadoc) * @see org.jajuk.ui.actions.JajukAction#perform(java.awt.event.ActionEvent) */ @Override public void perform(ActionEvent evt) { /* * Display the ambience wizard in an invokeLater to allow a combo that show * it to close its popup */ SwingUtilities.invokeLater(new Runnable() { @Override public void run() { AmbienceWizard ambience = new AmbienceWizard(); ambience.show(); } }); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/actions/FullscreenAction.java0000644000175000017500000000475111720500104026172 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.actions; import java.awt.event.ActionEvent; import org.jajuk.ui.windows.JajukFullScreenWindow; import org.jajuk.ui.windows.JajukMainWindow; import org.jajuk.ui.windows.WindowStateDecorator; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; /** * DOCUMENT_ME. */ public class FullscreenAction extends JajukAction { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1223773056757729079L; /** * Instantiates a new fullscreen action. */ FullscreenAction() { super(Messages.getString("JajukFullscreen.0"), IconLoader.getIcon(JajukIcons.FULL_SCREEN), true); setShortDescription(Messages.getString("JajukFullscreen.0")); } /* (non-Javadoc) * @see org.jajuk.ui.actions.JajukAction#perform(java.awt.event.ActionEvent) */ @Override public void perform(ActionEvent evt) throws Exception { /* * If full screen window is visible, hide it and show the main window. Note * that both main window and fsw can"t be displayed at the same time: */ WindowStateDecorator sdFullscreen = JajukFullScreenWindow.getInstance() .getWindowStateDecorator(); WindowStateDecorator sdMainWindow = JajukMainWindow.getInstance().getWindowStateDecorator(); if (sdFullscreen.isDisplayed()) { // close the previous window before displaying the other sdFullscreen.display(false); sdMainWindow.display(true); // Update the icon according to status setIcon(IconLoader.getIcon(JajukIcons.FULL_SCREEN)); } else { sdFullscreen.display(true); sdMainWindow.display(false); setIcon(IconLoader.getIcon(JajukIcons.SLIM_WINDOW)); } } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/actions/ShowAlbumDetailsAction.java0000644000175000017500000000463511720500104027300 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.actions; import java.awt.event.ActionEvent; import java.util.List; import javax.swing.JComponent; import org.jajuk.base.Album; import org.jajuk.ui.thumbnails.LocalAlbumThumbnail; import org.jajuk.ui.thumbnails.ThumbnailPopup; import org.jajuk.util.Const; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; /** * Show a thumb popup on an album. *

    * This action is expecting a single album as selection *

    *

    * Selection data is provided using the swing properties DETAIL_SELECTION *

    */ public class ShowAlbumDetailsAction extends JajukAction { /** Generated serialVersionUID. */ private static final long serialVersionUID = -8078402652430413821L; /** * Instantiates a new show album details action. */ ShowAlbumDetailsAction() { super(Messages.getString("CatalogView.20"), IconLoader.getIcon(JajukIcons.POPUP), true); setShortDescription(Messages.getString("CatalogView.20")); } /* * (non-Javadoc) * * @see org.jajuk.ui.actions.JajukAction#perform(java.awt.event.ActionEvent) */ @SuppressWarnings("unchecked") @Override public void perform(ActionEvent e) { JComponent source = (JComponent) e.getSource(); Object o = source.getClientProperty(Const.DETAIL_SELECTION); Album album = null; if (o instanceof Album) { album = (Album) o; } else if (o instanceof List) { album = (Album) (((List) o).get(0)); } else { return; } LocalAlbumThumbnail thumb = new LocalAlbumThumbnail(album, 200, true); new ThumbnailPopup(thumb.getDescription(), null, false); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/actions/PreparePartyAction.java0000644000175000017500000000572311720500104026506 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.actions; import java.awt.event.ActionEvent; import java.util.List; import javax.swing.JComponent; import org.jajuk.base.Item; import org.jajuk.base.Playlist; import org.jajuk.ui.wizard.PreparePartyWizard; import org.jajuk.util.Const; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; import org.jajuk.util.error.JajukException; /** * DOCUMENT_ME. */ public class PreparePartyAction extends JajukAction { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** * Instantiates a new prepare party action. */ PreparePartyAction() { super(Messages.getString("AbstractPlaylistEditorView.27"), IconLoader .getIcon(JajukIcons.PREPARE_PARTY), true); setShortDescription(Messages.getString("AbstractPlaylistEditorView.27")); } /* (non-Javadoc) * @see org.jajuk.ui.actions.JajukAction#perform(java.awt.event.ActionEvent) */ @SuppressWarnings("unchecked") @Override public void perform(ActionEvent e) throws JajukException { JComponent source = (JComponent) e.getSource(); // if we get a playlist, pass it on so that the Wizard does not provide a // choice of where to take the tracks anymore Object o = source.getClientProperty(Const.DETAIL_SELECTION); if (o != null) { // If action call comes from a tree, the selection is returned as a list final Playlist playlist; if (o instanceof List) { playlist = (Playlist) ((List) o).get(0); } else { playlist = ((Playlist) o); } // indicate to the Wizard that it should use the pre-built Playlist and // not provide the first selection screen. We need to do this in a static // method before creation because the Wizard needs to use this during // construction already PreparePartyWizard.setPlaylist(playlist); PreparePartyWizard wizard = new PreparePartyWizard(true); wizard.show(); } else { // without playlist, just display the general wizard that allows all kinds // of sources for the tracks PreparePartyWizard wizard = new PreparePartyWizard(false); wizard.show(); } } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/actions/LoveSelectionAction.java0000644000175000017500000000502211720500104026633 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.actions; import java.awt.event.ActionEvent; import java.util.List; import org.jajuk.base.Track; import org.jajuk.base.TrackManager; import org.jajuk.events.JajukEvent; import org.jajuk.events.JajukEvents; import org.jajuk.events.ObservationManager; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; import org.jajuk.util.log.Log; /** * DOCUMENT_ME. */ public class LoveSelectionAction extends SelectionAction { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** * Set love preference to a selection *

    * Selection action *

    . */ LoveSelectionAction() { super(Messages.getString("Preference.5"), IconLoader.getIcon(JajukIcons.PREFERENCE_LOVE), true); setShortDescription(Messages.getString("Preference.5")); } /* (non-Javadoc) * @see org.jajuk.ui.actions.SelectionAction#perform(java.awt.event.ActionEvent) */ @Override public void perform(final ActionEvent e) throws Exception { new Thread("LoveSelectionAction") { @Override public void run() { try { LoveSelectionAction.super.perform(e); // Check selection is not void if (selection.size() == 0) { return; } // Extract tracks of each item List tracks = TrackManager.getInstance().getAssociatedTracks(selection, false); // Set the preference for (Track track : tracks) { track.setPreference(2l); } // Request a GUI refresh ObservationManager.notify(new JajukEvent(JajukEvents.RATE_CHANGED)); } catch (Exception e) { Log.error(e); } } }.start(); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/actions/DeleteSelectionAction.java0000644000175000017500000002645711720500104027147 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.actions; import java.awt.event.ActionEvent; import java.util.ArrayList; import java.util.List; import javax.swing.JOptionPane; import javax.swing.KeyStroke; import org.jajuk.base.Album; import org.jajuk.base.Artist; import org.jajuk.base.Directory; import org.jajuk.base.DirectoryManager; import org.jajuk.base.File; import org.jajuk.base.FileManager; import org.jajuk.base.Genre; import org.jajuk.base.Item; import org.jajuk.base.Playlist; import org.jajuk.base.PlaylistManager; import org.jajuk.base.Track; import org.jajuk.base.TrackManager; import org.jajuk.events.JajukEvent; import org.jajuk.events.JajukEvents; import org.jajuk.events.ObservationManager; import org.jajuk.services.players.QueueModel; import org.jajuk.ui.widgets.InformationJPanel; import org.jajuk.util.Conf; import org.jajuk.util.Const; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; import org.jajuk.util.UtilGUI; import org.jajuk.util.UtilSystem; import org.jajuk.util.log.Log; /** * DOCUMENT_ME. */ public class DeleteSelectionAction extends SelectionAction { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** DOCUMENT_ME. */ private List alFiles; /** DOCUMENT_ME. */ private List rejFiles; /** DOCUMENT_ME. */ private List alDirs; /** DOCUMENT_ME. */ private List rejDirs; /** DOCUMENT_ME. */ private List emptyDirs; /** * Instantiates a new delete selection action. */ DeleteSelectionAction() { super(Messages.getString("FilesTreeView.7"), IconLoader.getIcon(JajukIcons.DELETE), true); setAcceleratorKey(KeyStroke.getKeyStroke("DELETE")); setShortDescription(Messages.getString("FilesTreeView.7")); } /** * Called on files deletion (long task). */ class FilesDeletionThread extends Thread { /** * Instantiates a new files deletion thread. */ FilesDeletionThread() { super("Files Deletion Thread"); } /* (non-Javadoc) * @see java.lang.Thread#run() */ @Override public void run() { UtilGUI.waiting(); for (File f : alFiles) { try { Directory d = f.getDirectory(); UtilSystem.deleteFile(f.getFIO()); FileManager.getInstance().removeFile(f); if (d.getFiles().size() == 0) { emptyDirs.add(f.getDirectory()); } } catch (Exception ioe) { Log.error(131, ioe); rejFiles.add(f); } } UtilGUI.stopWaiting(); InformationJPanel.getInstance().setMessage(Messages.getString("ActionDelete.0"), InformationJPanel.MessageType.INFORMATIVE); if (rejFiles.size() > 0) { String rejString = ""; for (File f : rejFiles) { rejString += f.getName() + "\n"; } // Operation failed... display list of files in error Messages.showWarningMessage(Messages.getErrorMessage(136) + "\n" + rejString); } // requires device refresh ObservationManager.notify(new JajukEvent(JajukEvents.DEVICE_REFRESH)); } } /** * Called on directories deletion (long task). */ class DirectoriesDeletionThread extends Thread { /** * Instantiates a new directories deletion thread. */ DirectoriesDeletionThread() { super("Directories Deletion Thread"); } /* (non-Javadoc) * @see java.lang.Thread#run() */ @Override public void run() { UtilGUI.waiting(); for (Directory d : alDirs) { try { for (File f : d.getFiles()) { if (QueueModel.getPlayingFile() != null && f.equals(QueueModel.getPlayingFile())) { throw new Exception("File currently in use"); } } UtilSystem.deleteDir(new java.io.File(d.getAbsolutePath())); DirectoryManager.getInstance().removeDirectory(d.getID()); } catch (Exception ioe) { Log.error(131, ioe); rejDirs.add(d); } } UtilGUI.stopWaiting(); InformationJPanel.getInstance().setMessage(Messages.getString("ActionDelete.1"), InformationJPanel.MessageType.INFORMATIVE); if (rejDirs.size() > 0) { String rejString = ""; for (Directory d : rejDirs) { rejString += d.getName() + "\n"; } // Operation failed... display list of files in error Messages.showWarningMessage(Messages.getErrorMessage(136) + "\n\n" + rejString); } // requires device refresh ObservationManager.notify(new JajukEvent(JajukEvents.DEVICE_REFRESH)); } } /* * (non-Javadoc) * * @see org.jajuk.ui.actions.SelectionAction#perform(java.awt.event.ActionEvent) */ @Override public void perform(ActionEvent e) throws Exception { // Make sure to consider selection as a raw playlist, not its content expandPlaylists = false; super.perform(e); // Get required data from the tree (selected node and node type) alFiles = new ArrayList(selection.size()); rejFiles = new ArrayList(selection.size()); alDirs = new ArrayList(selection.size()); rejDirs = new ArrayList(selection.size()); emptyDirs = new ArrayList(selection.size()); // Compute all files to move from various items list if (selection.size() == 0) { Log.debug("None item to move"); return; } Item first = selection.get(0); if (first instanceof Album || first instanceof Artist || first instanceof Genre) { List tracks = TrackManager.getInstance().getAssociatedTracks(selection, true); for (Track track : tracks) { alFiles.addAll(track.getFiles()); } } else { for (Item item : selection) { if (item instanceof File) { alFiles.add((File) item); } else if (item instanceof Track) { alFiles.addAll(((Track) item).getFiles()); } else if (item instanceof Directory) { alDirs.add((Directory) item); } else if ((item instanceof Playlist) && (Conf.getBoolean(Const.CONF_CONFIRMATIONS_DELETE_FILE))) { // file delete confirmation Playlist plf = (Playlist) item; String sFileToDelete = plf.getAbsolutePath(); String sMessage = Messages.getString("Confirmation_delete") + "\n" + sFileToDelete; int i = Messages.getChoice(sMessage, JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE); if (i == JOptionPane.YES_OPTION) { try { PlaylistManager.getInstance().deletePlaylistFile(plf); // requires device refresh ObservationManager.notify(new JajukEvent(JajukEvents.DEVICE_REFRESH)); } catch (Exception e2) { Log.error(e2); Messages.showErrorMessage(131); } } } } } // Consider files (selection can contain both files and directories) if (alFiles.size() > 0) { handleFiles(); } // Now consider directories (selection can contain both files and directories) if (alDirs.size() > 0) { handleDirectories(); } } /** * Handle directories. */ private void handleDirectories() { // Ask if a confirmation is required if (Conf.getBoolean(Const.CONF_CONFIRMATIONS_DELETE_FILE)) { String sFiles = ""; int count = 0; for (Directory d : alDirs) { sFiles += d.getAbsolutePath() + "\n"; count += d.getFilesRecursively().size(); for (File f : d.getFilesRecursively()) { sFiles += " + " + f.getName() + "\n"; } } int iResu = Messages.getChoice(Messages.getString("Confirmation_delete_dirs") + " : \n" + sFiles + "\n" + count + " " + Messages.getString("Confirmation_file_number"), JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.INFORMATION_MESSAGE); if (iResu != JOptionPane.YES_OPTION) { return; } // Check if selection doesn't contain playing file's directory for (Directory dir : alDirs) { if (QueueModel.getPlayingFile() != null && QueueModel.getPlayingFile().hasAncestor(dir)) { Messages .showWarningMessage(Messages.getErrorMessage(172) + " : " + dir.getAbsolutePath()); return; } } } //Actual deletion new DirectoriesDeletionThread().start(); } /** * Handle files. */ private void handleFiles() { // Ask if a confirmation is required if (Conf.getBoolean(Const.CONF_CONFIRMATIONS_DELETE_FILE)) { String sFiles = ""; for (File f : alFiles) { sFiles += f.getName() + "\n"; } int iResu = Messages.getChoice(Messages.getString("Confirmation_delete_files") + " : \n\n" + sFiles + "\n" + alFiles.size() + " " + Messages.getString("Confirmation_file_number"), JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.INFORMATION_MESSAGE); if (iResu != JOptionPane.YES_OPTION) { return; } } // Check if selection doesn't contain playing file for (File f : alFiles) { if (QueueModel.getPlayingFile() != null && f.equals(QueueModel.getPlayingFile())) { Messages.showWarningMessage(Messages.getErrorMessage(172) + " : " + f.getAbsolutePath()); return; } } //Actual deletion new FilesDeletionThread().start(); // Cleanup empty directories if (emptyDirs.size() > 0) { String emptyDirsString = ""; for (Directory d : emptyDirs) { emptyDirsString += d.getName() + "\n"; } int iResu = Messages.getChoice(Messages.getString("Confirmation_delete_empty_dirs") + " : \n\n" + emptyDirsString, JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.INFORMATION_MESSAGE); if (iResu != JOptionPane.YES_OPTION) { return; } else { for (Directory d : emptyDirs) { try { UtilSystem.deleteDir(new java.io.File(d.getAbsolutePath())); DirectoryManager.getInstance().removeDirectory(d.getID()); } catch (Exception ioe) { Log.error(131, ioe); rejDirs.add(d); } } if (rejDirs.size() > 0) { String rejString = ""; for (Directory d : rejDirs) { rejString += d.getName() + "\n"; } // Operation failed... display list of files in error Messages.showWarningMessage(Messages.getErrorMessage(136) + "\n" + rejString); } // requires device refresh ObservationManager.notify(new JajukEvent(JajukEvents.DEVICE_REFRESH)); } } } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/actions/DebugLogAction.java0000644000175000017500000001050411720500104025551 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.actions; import java.awt.Color; import java.awt.Dimension; import java.awt.Insets; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.JButton; import javax.swing.JDialog; import javax.swing.JEditorPane; import javax.swing.JScrollPane; import net.miginfocom.swing.MigLayout; import org.jajuk.ui.helpers.FontManager; import org.jajuk.ui.helpers.FontManager.JajukFont; import org.jajuk.ui.windows.JajukMainWindow; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; import org.jajuk.util.UtilGUI; import org.jajuk.util.UtilString; import org.jajuk.util.log.Log; /** * DOCUMENT_ME. */ public class DebugLogAction extends JajukAction { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** * Instantiates a new debug log action. */ DebugLogAction() { super(Messages.getString("JajukJMenuBar.23"), IconLoader.getIcon(JajukIcons.TRACES), true); setShortDescription(Messages.getString("JajukJMenuBar.23")); } /* (non-Javadoc) * @see org.jajuk.ui.actions.JajukAction#perform(java.awt.event.ActionEvent) */ @Override public void perform(ActionEvent evt) { final JEditorPane text = new JEditorPane("text/html", getTraces()); text.setEditable(false); text.setMargin(new Insets(10, 10, 10, 10)); text.setOpaque(true); text.setBackground(Color.WHITE); text.setForeground(Color.DARK_GRAY); text.setFont(FontManager.getInstance().getFont(JajukFont.BOLD)); final JDialog dialog = new JDialog(JajukMainWindow.getInstance(), Messages .getString("DebugLogAction.0"), false); JButton jbRefresh = new JButton(Messages.getString("DebugLogAction.1"), IconLoader .getIcon(JajukIcons.REFRESH)); jbRefresh.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { // Refresh traces text.setText(getTraces()); } }); JButton jbClose = new JButton(Messages.getString("Close"), IconLoader.getIcon(JajukIcons.CLOSE)); jbClose.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { dialog.dispose(); } }); dialog.setLayout(new MigLayout("insets 10", "[grow]")); JScrollPane panel = new JScrollPane(text); UtilGUI.setEscapeKeyboardAction(dialog, panel); dialog.add(panel, "grow,wrap"); dialog.add(jbRefresh, "split 2,right,sg button"); dialog.add(jbClose, "right,sg button"); dialog.setPreferredSize(new Dimension(800, 600)); dialog.pack(); dialog.setLocationRelativeTo(JajukMainWindow.getInstance()); dialog.setVisible(true); } /** * Gets the traces. * * @return Current traces */ private String getTraces() { // Store system properties StringBuilder traces = new StringBuilder("").append( cleanHTML(UtilString.getAnonymizedSystemProperties().toString())).append("
    ").append( cleanHTML(UtilString.getAnonymizedJajukProperties().toString())).append("

    "); // Store last traces for (String line : Log.getSpool()) { traces.append(line).append("
    "); } traces.append(""); return traces.toString(); } /** * Replace some HTML in the properties to make them suitable for printing. * * @param str DOCUMENT_ME * * @return the string */ private static String cleanHTML(String str) { // don't allow HTML-formatting return str.replace("<", "<"); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/actions/SelectionAction.java0000644000175000017500000000644711720500104026021 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.actions; import java.awt.event.ActionEvent; import java.util.ArrayList; import java.util.List; import java.util.Set; import javax.swing.ImageIcon; import javax.swing.JComponent; import org.jajuk.base.Item; import org.jajuk.base.Playlist; import org.jajuk.util.Const; /** * Convenient abstract class to factorize operations on selection. */ public abstract class SelectionAction extends JajukAction { /** Generated serialVersionUID. */ private static final long serialVersionUID = -6072746800882488360L; /** DOCUMENT_ME. */ List selection = null; /** Whether the selection should contain the playlist itself (false) or mapped files (true). */ boolean expandPlaylists = true; /** * Instantiates a new selection action. * * @param msg DOCUMENT_ME * @param icon DOCUMENT_ME * @param enabled DOCUMENT_ME */ protected SelectionAction(String msg, ImageIcon icon, boolean enabled) { super(msg, icon, enabled); } /* * This method transforms various entries to a list of items * * @see org.jajuk.ui.actions.JajukAction#perform(java.awt.event.ActionEvent) */ /* (non-Javadoc) * @see org.jajuk.ui.actions.JajukAction#perform(java.awt.event.ActionEvent) */ @SuppressWarnings("unchecked") @Override public void perform(ActionEvent e) throws Exception { JComponent source = (JComponent) e.getSource(); Object o = source.getClientProperty(Const.DETAIL_SELECTION); if (o instanceof Item) { selection = new ArrayList(1); selection.add((Item) o); } else if (o instanceof List) { List list = (List) o; // List of playlists, replace playlist by playlist files if (list.size() > 0 && list.get(0) instanceof Playlist) { selection = new ArrayList(10); for (Item item : list) { Playlist pl = (Playlist) item; if (expandPlaylists) { selection.addAll(pl.getFiles()); } else { selection.add(pl); } } } else { // List of albums, artists ... files or tracks : just perform a cast selection = (List) source.getClientProperty(Const.DETAIL_SELECTION); } } else if (o instanceof Set) { selection = new ArrayList((Set) o); } else if (o instanceof Playlist) { selection = new ArrayList(1); Playlist pl = (Playlist) o; if (expandPlaylists) { selection.addAll(pl.getFiles()); } else { selection.add(pl); } } } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/actions/DJConfigurationAction.java0000644000175000017500000000320511720500104027106 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.actions; import java.awt.event.ActionEvent; import org.jajuk.ui.wizard.DigitalDJWizard; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; /** * Action for configure DJs. */ public class DJConfigurationAction extends JajukAction { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** * Instantiates a new dJ configuration action. */ DJConfigurationAction() { super(Messages.getString("CommandJPanel.17"), IconLoader.getIcon(JajukIcons.CONFIGURATION), true); } /* (non-Javadoc) * @see org.jajuk.ui.actions.JajukAction#perform(java.awt.event.ActionEvent) */ @Override public void perform(ActionEvent evt) { DigitalDJWizard wizard = new DigitalDJWizard(); // display the DJ wizard wizard.show(); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/actions/ChangeTrackPreferenceAction.java0000644000175000017500000000477211720500104030244 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.actions; import java.awt.event.ActionEvent; import org.jajuk.base.File; import org.jajuk.base.Track; import org.jajuk.events.JajukEvent; import org.jajuk.events.JajukEvents; import org.jajuk.events.ObservationManager; import org.jajuk.services.players.QueueModel; import org.jajuk.util.Conf; import org.jajuk.util.Const; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; import org.jajuk.util.error.JajukException; import org.jajuk.util.log.Log; /** * Manual preference change of current played track. */ public class ChangeTrackPreferenceAction extends JajukAction { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** * Instantiates a new change track preference action. */ ChangeTrackPreferenceAction() { super(Messages.getString("IncRateAction.0"), IconLoader.getIcon(JajukIcons.INC_RATING), true); setShortDescription(Messages.getString("IncRateAction.0")); } /* (non-Javadoc) * @see org.jajuk.ui.actions.JajukAction#perform(java.awt.event.ActionEvent) */ @Override public void perform(ActionEvent evt) throws JajukException { new Thread("ChangeTrackPreferenceAction") { @Override public void run() { try { File file = QueueModel.getPlayingFile(); if (file != null) { Track track = file.getTrack(); track.setPreference(Conf.getInt(Const.CONF_INC_RATING)); } // Force immediate rating refresh (without using the rating manager) ObservationManager.notify(new JajukEvent(JajukEvents.RATE_CHANGED)); } catch (Exception e) { Log.error(e); } } }.start(); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/actions/SlimbarAction.java0000644000175000017500000000604111720500104025453 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.actions; import java.awt.event.ActionEvent; import org.jajuk.events.JajukEvent; import org.jajuk.events.JajukEvents; import org.jajuk.events.ObservationManager; import org.jajuk.ui.windows.JajukMainWindow; import org.jajuk.ui.windows.JajukSlimbar; import org.jajuk.ui.windows.WindowStateDecorator; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; import org.jajuk.util.UtilGUI; /** * Action to hide slim bar. */ public class SlimbarAction extends JajukAction { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** * Instantiates a new slimbar action. */ SlimbarAction() { super(Messages.getString("JajukSlimWindow.0"), IconLoader.getIcon(JajukIcons.SLIM_WINDOW), true); setShortDescription(Messages.getString("JajukSlimWindow.0")); } /* * (non-Javadoc) * * @see org.jajuk.ui.actions.JajukAction#perform(java.awt.event.ActionEvent) */ @Override public void perform(ActionEvent evt) throws Exception { /* * If slimbar is visible, hide it and show the main window. Note that both main window and * slimbar can be displayed at the same time: If the slimbar is visible and user display main * window by right clicking on the tray, the main window is displayed, this is a normal behavior */ WindowStateDecorator sdSlimbar = JajukSlimbar.getInstance().getWindowStateDecorator(); WindowStateDecorator sdMainWindow = JajukMainWindow.getInstance().getWindowStateDecorator(); if (sdSlimbar.isDisplayed()) { // close the previous window before displaying the other sdSlimbar.display(false); sdMainWindow.display(true); // Update the icon according to status setIcon(IconLoader.getIcon(JajukIcons.SLIM_WINDOW)); } else { sdMainWindow.display(false); sdSlimbar.display(true); // Update the icon according to status setIcon(IconLoader.getIcon(JajukIcons.FULL_SCREEN)); } // Store window-type displayed (useful for tray display/hide feature for ie.) UtilGUI.storeWindowSate(); // Notify that slimbar visibility change (menu bar is interested in it) ObservationManager.notify(new JajukEvent(JajukEvents.SLIMBAR_VISIBILTY_CHANGED)); } }jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/actions/SimpleDeviceWizardAction.java0000644000175000017500000000340411720500104027614 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.actions; import java.awt.event.ActionEvent; import org.jajuk.ui.windows.JajukMainWindow; import org.jajuk.ui.wizard.SimpleDeviceWizard; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; /** * Action for displaying the simple device creation wizard. */ public class SimpleDeviceWizardAction extends JajukAction { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** * Instantiates a new simple device wizard action. */ SimpleDeviceWizardAction() { super(Messages.getString("JajukJMenuBar.18"), IconLoader.getIcon(JajukIcons.WIZARD), true); } /** * Invoked when an action occurs. * * @param evt DOCUMENT_ME */ @Override public void perform(ActionEvent evt) { SimpleDeviceWizard wizard = new SimpleDeviceWizard(); wizard.pack(); wizard.setLocationRelativeTo(JajukMainWindow.getInstance()); wizard.setVisible(true); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/actions/HelpRequiredAction.java0000644000175000017500000000342111720500104026452 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.actions; import java.awt.Desktop; import java.awt.event.ActionEvent; import java.net.URI; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; import org.jajuk.util.log.Log; /** * Action for displaying the online help. */ public class HelpRequiredAction extends JajukAction { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** * Instantiates a new help required action. */ HelpRequiredAction() { super(Messages.getString("JajukJMenuBar.15"), IconLoader.getIcon(JajukIcons.INFO), "F1", true, false); } /* (non-Javadoc) * @see org.jajuk.ui.actions.JajukAction#perform(java.awt.event.ActionEvent) */ @Override public void perform(ActionEvent evt) { try { Desktop.getDesktop().browse(new URI("http://jajuk.info/index.php/Table_of_contents")); } catch (Exception e) { Messages.showErrorMessage(136); Log.error(e); } } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/actions/BanSelectionAction.java0000644000175000017500000000522511720500104026433 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.actions; import java.awt.event.ActionEvent; import java.util.List; import org.jajuk.base.Track; import org.jajuk.base.TrackManager; import org.jajuk.events.JajukEvent; import org.jajuk.events.JajukEvents; import org.jajuk.events.ObservationManager; import org.jajuk.util.Const; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; import org.jajuk.util.log.Log; /** * DOCUMENT_ME. */ public class BanSelectionAction extends SelectionAction { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** * The Ban action is used to ban a set of tracks so they will never be * proposed by jajuk automatic selections *

    * Selection action *

    . */ BanSelectionAction() { super(Messages.getString("BanSelectionAction.0"), IconLoader.getIcon(JajukIcons.BAN), true); setShortDescription(Messages.getString("BanSelectionAction.1")); } /* (non-Javadoc) * @see org.jajuk.ui.actions.SelectionAction#perform(java.awt.event.ActionEvent) */ @Override public void perform(final ActionEvent e) throws Exception { new Thread("BanSelectionAction") { @Override public void run() { try { BanSelectionAction.super.perform(e); // Check selection is not void if (selection.size() == 0) { return; } // Extract tracks of each item List tracks = TrackManager.getInstance().getAssociatedTracks(selection, false); // Then ban them all ! for (Track track : tracks) { track.setProperty(Const.XML_TRACK_BANNED, true); } // Request a GUI refresh ObservationManager.notify(new JajukEvent(JajukEvents.RATE_CHANGED)); } catch (Exception e) { Log.error(e); } } }.start(); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/actions/PlayDirectorySelectionAction.java0000644000175000017500000000555011720500104030526 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.actions; import java.awt.event.ActionEvent; import java.util.List; import org.jajuk.base.Directory; import org.jajuk.base.File; import org.jajuk.services.players.QueueModel; import org.jajuk.util.Conf; import org.jajuk.util.Const; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; import org.jajuk.util.UtilFeatures; import org.jajuk.util.log.Log; /** * Play directories for a selection of files. For now, jajuk only play the first * found full directory *

    * Action emitter is responsible to ensure all items provided share the same * type *

    *

    * Selection data is provided using the swing properties DETAIL_SELECTION *

    */ public class PlayDirectorySelectionAction extends SelectionAction { /** Generated serialVersionUID. */ private static final long serialVersionUID = -8078402652430413821L; /** * Instantiates a new play directory selection action. */ PlayDirectorySelectionAction() { super(Messages.getString("FilesTableView.15"), IconLoader.getIcon(JajukIcons.DIRECTORY_SYNCHRO), true); setShortDescription(Messages.getString("FilesTableView.15")); } /* * (non-Javadoc) * * @see org.jajuk.ui.actions.JajukAction#perform(java.awt.event.ActionEvent) */ @Override public void perform(final ActionEvent e) throws Exception { new Thread("PlayDirectorySelectionAction") { @Override public void run() { try { PlayDirectorySelectionAction.super.perform(e); if (selection.size() == 0 || !(selection.get(0) instanceof File)) { return; } // Select all files from the first found directory Directory dir = ((File) selection.get(0)).getDirectory(); List files = UtilFeatures.getPlayableFiles(dir); QueueModel.push(UtilFeatures.createStackItems(UtilFeatures.applyPlayOption(files), Conf .getBoolean(Const.CONF_STATE_REPEAT_ALL), true), false); } catch (Exception e) { Log.error(e); } } }.start(); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/actions/CopyClipboardAction.java0000644000175000017500000000603611720500104026620 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.actions; import java.awt.Toolkit; import java.awt.datatransfer.Clipboard; import java.awt.datatransfer.StringSelection; import java.awt.event.ActionEvent; import java.util.List; import javax.swing.JComponent; import org.jajuk.base.Directory; import org.jajuk.base.File; import org.jajuk.base.Item; import org.jajuk.base.Playlist; import org.jajuk.base.Track; import org.jajuk.util.Const; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; /** * Copy to clipboard the item absolute address. */ public class CopyClipboardAction extends JajukAction { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** * Instantiates a new copy clipboard action. */ CopyClipboardAction() { super(Messages.getString("CopyClipboardAction.0"), IconLoader .getIcon(JajukIcons.COPY_TO_CLIPBOARD), true); setShortDescription(Messages.getString("CopyClipboardAction.0")); } /* (non-Javadoc) * @see org.jajuk.ui.actions.JajukAction#perform(java.awt.event.ActionEvent) */ @Override public void perform(ActionEvent e) throws Exception { // This action expect either an item or a simple String from DETAIL_CONTENT // Swing client property JComponent source = (JComponent) e.getSource(); Object o = source.getClientProperty(Const.DETAIL_CONTENT); String sData = ""; if (o instanceof List) { @SuppressWarnings("unchecked") List list = (List) o; if (list.size() > 0) { o = list.get(0); } } if (o instanceof Item) { Item item = (Item) o; if (item instanceof File) { sData = ((File) item).getAbsolutePath(); } else if (item instanceof Directory) { sData = ((Directory) item).getAbsolutePath(); } else if (item instanceof Playlist) { sData = ((Playlist) item).getAbsolutePath(); } else if (item instanceof Track) { sData = ((Track) item).getFiles().get(0).getAbsolutePath(); } } else if (o instanceof String) { sData = (String) o; } StringSelection data = new StringSelection(sData); Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); clipboard.setContents(data, data); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/actions/AverageSelectionAction.java0000644000175000017500000000505511720500104027306 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.actions; import java.awt.event.ActionEvent; import java.util.List; import org.jajuk.base.Track; import org.jajuk.base.TrackManager; import org.jajuk.events.JajukEvent; import org.jajuk.events.JajukEvents; import org.jajuk.events.ObservationManager; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; import org.jajuk.util.log.Log; /** * DOCUMENT_ME. */ public class AverageSelectionAction extends SelectionAction { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** * Set average preference to a selection *

    * Selection action *

    . */ AverageSelectionAction() { super(Messages.getString("Preference.3"), IconLoader.getIcon(JajukIcons.PREFERENCE_AVERAGE), true); setShortDescription(Messages.getString("Preference.3")); } /* (non-Javadoc) * @see org.jajuk.ui.actions.SelectionAction#perform(java.awt.event.ActionEvent) */ @Override public void perform(final ActionEvent e) throws Exception { new Thread("AverageSelectionAction") { @Override public void run() { try { AverageSelectionAction.super.perform(e); // Check selection is not void if (selection.size() == 0) { return; } // Extract tracks of each item List tracks = TrackManager.getInstance().getAssociatedTracks(selection, false); // Set the preference for (Track track : tracks) { track.setPreference(-1l); } // Request a GUI refresh ObservationManager.notify(new JajukEvent(JajukEvents.RATE_CHANGED)); } catch (Exception e) { Log.error(e); } } }.start(); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/actions/GCAction.java0000644000175000017500000000306011720500104024351 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.actions; import java.awt.event.ActionEvent; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; /** * Action to run garbage collection. */ public class GCAction extends JajukAction { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** * Instantiates a new action. */ GCAction() { super(Messages.getString("JajukJMenuBar.32"), IconLoader.getIcon(JajukIcons.CLEAR_FILTER), true); setShortDescription(Messages.getString("JajukJMenuBar.32")); } /* (non-Javadoc) * @see org.jajuk.ui.actions.JajukAction#perform(java.awt.event.ActionEvent) */ @Override public void perform(ActionEvent evt) throws Exception { System.gc(); } }jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/actions/PlayAlbumSelectionAction.java0000644000175000017500000000553311720500104027623 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.actions; import java.awt.event.ActionEvent; import java.util.List; import org.jajuk.base.Album; import org.jajuk.base.File; import org.jajuk.base.Track; import org.jajuk.services.players.QueueModel; import org.jajuk.util.Conf; import org.jajuk.util.Const; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; import org.jajuk.util.UtilFeatures; import org.jajuk.util.log.Log; /** * Play albums for a selection. We expect the selection to be tracks and we play * only the first found album *

    * Action emitter is responsible to ensure all items provided share the same * type *

    *

    * Selection data is provided using the swing properties DETAIL_SELECTION *

    */ public class PlayAlbumSelectionAction extends SelectionAction { /** Generated serialVersionUID. */ private static final long serialVersionUID = -8078402652430413821L; /** * Instantiates a new play album selection action. */ PlayAlbumSelectionAction() { super(Messages.getString("TracksTableView.11"), IconLoader.getIcon(JajukIcons.ALBUM), true); setShortDescription(Messages.getString("TracksTableView.11")); } /* * (non-Javadoc) * * @see org.jajuk.ui.actions.JajukAction#perform(java.awt.event.ActionEvent) */ @Override public void perform(final ActionEvent e) throws Exception { new Thread("PlayAlbumSelectionAction") { @Override public void run() { try { PlayAlbumSelectionAction.super.perform(e); if (selection.size() == 0 || !(selection.get(0) instanceof Track)) { return; } // Select all files from the first found album Album album = ((Track) selection.get(0)).getAlbum(); List files = UtilFeatures.getPlayableFiles(album); QueueModel.push(UtilFeatures.createStackItems(UtilFeatures.applyPlayOption(files), Conf .getBoolean(Const.CONF_STATE_REPEAT_ALL), true), false); } catch (Exception e) { Log.error(e); } } }.start(); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/actions/ReportAction.java0000644000175000017500000001257711720500104025350 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.actions; import java.awt.event.ActionEvent; import java.util.List; import javax.swing.JComponent; import javax.swing.JFileChooser; import org.jajuk.base.Item; import org.jajuk.services.reporting.Exporter; import org.jajuk.services.reporting.ExporterFactory; import org.jajuk.ui.widgets.JajukFileChooser; import org.jajuk.util.Const; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukFileFilter; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; import org.jajuk.util.UtilGUI; import org.jajuk.util.error.JajukException; import org.jajuk.util.filters.HTMLFilter; import org.jajuk.util.filters.XMLFilter; import org.jajuk.util.log.Log; /** * Report collection as a file. */ public class ReportAction extends JajukAction { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** * Instantiates a new report action. */ ReportAction() { super(Messages.getString("TracksTreeView.33"), IconLoader.getIcon(JajukIcons.REPORT), true); setShortDescription(Messages.getString("TracksTreeView.33")); } /* (non-Javadoc) * @see org.jajuk.ui.actions.JajukAction#perform(java.awt.event.ActionEvent) */ @Override @SuppressWarnings("unchecked") public void perform(final ActionEvent e) throws JajukException { final JComponent source = (JComponent) e.getSource(); // First item final String type = (String) source.getClientProperty(Const.DETAIL_ORIGIN); // Get required data from the tree (selected node and node type) final List alSelected = (List) source.getClientProperty(Const.DETAIL_SELECTION); // Display a save as dialog final JajukFileFilter filter = new JajukFileFilter(XMLFilter.getInstance(), HTMLFilter .getInstance()); final JajukFileChooser chooser = new JajukFileChooser(filter); // Allow to navigate between directories chooser.setAcceptDirectories(true); chooser.setDialogTitle(Messages.getString("TracksTreeView.33")); // set a default file name if (Const.COLLECTION_LOGICAL.equals(type) || Const.COLLECTION_PHYSICAL.equals(type)) { // collection node selected, use file name 'collection" chooser.setSelectedFile(new java.io.File(Messages.getString("ReportAction.17"))); } else { // use the first node name final Item item = alSelected.get(0); // Use html format as a default chooser.setSelectedFile(new java.io.File(item.getName())); } chooser.setDialogType(JFileChooser.SAVE_DIALOG); // display the dialog final int returnVal = chooser.showSaveDialog(null); // Wait for user selection if (returnVal == JFileChooser.APPROVE_OPTION) { // Make sure user didn't select a directory (we have to accept // them to allow user to navigate) if (chooser.getSelectedFile().isDirectory()) { return; } // make it in a separated thread to avoid freezing // screen for big collections new Thread("Report Thread") { @Override public void run() { try { UtilGUI.waiting(); final String filepath = chooser.getSelectedFile().getAbsolutePath(); final String filetypename = chooser.getFileFilter().getDescription(); // Create an exporter according to file extension final Exporter exporter = ExporterFactory.createExporter(filetypename); // Full logical collection report if (Const.COLLECTION_LOGICAL.equals(type)) { exporter.processCollection(Exporter.LOGICAL_COLLECTION); } // Full physical collection report else if (Const.COLLECTION_PHYSICAL.equals(type)) { exporter.processCollection(Exporter.PHYSICAL_COLLECTION); } // Normal report on an item or a set of items else { exporter.process(alSelected); } // Save the results String filename = filepath; // Append extension only if needed. // (if user selected an existing item, the extension // musn't be appended twice) if (!filepath.endsWith(filetypename)) { filename = filepath + '.' + filetypename; } // Save created report exporter.saveToFile(filename); // Success Messages.showInfoMessage(Messages.getString("ReportAction.0")); } catch (final Exception e) { Log.error(e); Messages.showErrorMessage(167, e.getMessage()); } finally { UtilGUI.stopWaiting(); } } }.start(); } } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/actions/NewFolderAction.java0000644000175000017500000000704111720500104025750 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.actions; import java.awt.event.ActionEvent; import java.util.ArrayList; import java.util.List; import javax.swing.JComponent; import javax.swing.JOptionPane; import org.jajuk.base.Device; import org.jajuk.base.Directory; import org.jajuk.base.DirectoryManager; import org.jajuk.base.Item; import org.jajuk.events.JajukEvent; import org.jajuk.events.JajukEvents; import org.jajuk.events.ObservationManager; import org.jajuk.util.Const; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; import org.jajuk.util.log.Log; /** * DOCUMENT_ME. */ public class NewFolderAction extends JajukAction { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** * Instantiates a new new folder action. */ NewFolderAction() { super(Messages.getString("NewFolderAction.0"), IconLoader.getIcon(JajukIcons.DIRECTORY_SYNCHRO), true); setShortDescription(Messages.getString("NewFolderAction.0")); } /* * (non-Javadoc) * * @see org.jajuk.ui.actions.JajukAction#perform(java.awt.event.ActionEvent) */ @Override @SuppressWarnings("unchecked") public void perform(final ActionEvent e) { JComponent source = (JComponent) e.getSource(); // Get required data from the tree (selected node and node type) final List alSelected = (ArrayList) source .getClientProperty(Const.DETAIL_SELECTION); final Item currentItem = alSelected.get(0); final String folderName = JOptionPane.showInputDialog(null, Messages .getString("NewFolderAction.1") + "\n\n"); if ((folderName != null) && (folderName.length() > 0)) { // If selected item is a directory, extract the associated root // directory // from the device and use it final Directory dir; if (currentItem instanceof Device) { dir = ((Device) currentItem).getRootDirectory(); } else if (currentItem instanceof Directory) { dir = (Directory) currentItem; } else { Log.debug("Wrong item type"); return; } try { java.io.File newFolder = new java.io.File(dir.getAbsolutePath() + "/" + folderName); if (!newFolder.exists()) { if (newFolder.mkdir()) { DirectoryManager.getInstance().registerDirectory(folderName, dir, dir.getDevice()); ObservationManager.notify(new JajukEvent(JajukEvents.DEVICE_REFRESH)); } else { Messages.showErrorMessage(136); return; } } else { Messages.showWarningMessage(Messages.getString("NewFolderAction.2")); return; } } catch (Exception er) { Log.error(er); Messages.showErrorMessage(136); } } } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/actions/PreviousAlbumAction.java0000644000175000017500000000343411720500104026662 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.actions; import java.awt.event.ActionEvent; import org.jajuk.services.players.QueueModel; import org.jajuk.util.log.Log; /** * Action class for jumping to the previous album. Installed keystroke: * CTRL + SHIFT + LEFT ARROW. */ public class PreviousAlbumAction extends JajukAction { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** * Instantiates a new previous album action. */ PreviousAlbumAction() { super("previous album", "shift F9", false, true); } /* (non-Javadoc) * @see org.jajuk.ui.actions.JajukAction#perform(java.awt.event.ActionEvent) */ @Override public void perform(ActionEvent evt) { new Thread("Previous Album Thread") { @Override public void run() { synchronized (QueueModel.class) { try { QueueModel.playPreviousAlbum(); } catch (Exception e) { Log.error(e); } } } }.start(); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/actions/PlaySelectionAction.java0000644000175000017500000000471511720500104026643 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.actions; import java.awt.event.ActionEvent; import java.util.List; import org.jajuk.base.File; import org.jajuk.services.players.QueueModel; import org.jajuk.util.Conf; import org.jajuk.util.Const; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; import org.jajuk.util.UtilFeatures; import org.jajuk.util.log.Log; /** * Play a selection *

    * Action emitter is responsible to ensure all items provided share the same * type *

    *

    * Selection data is provided using the swing properties DETAIL_SELECTION *

    . */ public class PlaySelectionAction extends SelectionAction { /** Generated serialVersionUID. */ private static final long serialVersionUID = -8078402652430413821L; /** * Instantiates a new play selection action. */ PlaySelectionAction() { super(Messages.getString("TracksTableView.7"), IconLoader.getIcon(JajukIcons.PLAY_16X16), true); setShortDescription(Messages.getString("TracksTableView.7")); } /* * (non-Javadoc) * * @see org.jajuk.ui.actions.JajukAction#perform(java.awt.event.ActionEvent) */ @Override public void perform(final ActionEvent e) throws Exception { new Thread("PlaySelectionAction") { @Override public void run() { try { PlaySelectionAction.super.perform(e); List files = UtilFeatures.getPlayableFiles(selection); QueueModel.push(UtilFeatures.createStackItems(UtilFeatures.applyPlayOption(files), Conf .getBoolean(Const.CONF_STATE_REPEAT_ALL), true), false); } catch (Exception e) { Log.error(e); } } }.start(); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/actions/ShuffleModeAction.java0000644000175000017500000000450611720500104026267 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.actions; import java.awt.event.ActionEvent; import org.jajuk.events.JajukEvent; import org.jajuk.events.JajukEvents; import org.jajuk.events.ObservationManager; import org.jajuk.services.players.QueueModel; import org.jajuk.ui.widgets.CommandJPanel; import org.jajuk.ui.widgets.JajukJMenuBar; import org.jajuk.util.Conf; import org.jajuk.util.Const; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; /** * DOCUMENT_ME. */ public class ShuffleModeAction extends JajukAction { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** * Instantiates a new shuffle mode action. */ ShuffleModeAction() { super(Messages.getString("JajukJMenuBar.11"), IconLoader.getIcon(JajukIcons.SHUFFLE), "ctrl H", true, false); setShortDescription(Messages.getString("CommandJPanel.2")); } /** * Invoked when an action occurs. * * @param evt DOCUMENT_ME */ @Override public void perform(ActionEvent evt) { boolean b = Conf.getBoolean(Const.CONF_STATE_SHUFFLE); Conf.setProperty(Const.CONF_STATE_SHUFFLE, Boolean.toString(!b)); JajukJMenuBar.getInstance().setShuffleSelected(!b); CommandJPanel.getInstance().setRandomSelected(!b); if (!b) { // enabled button QueueModel.shuffle(); // shuffle current selection } // computes planned tracks QueueModel.computesPlanned(true); // Refresh Queue View ObservationManager.notify(new JajukEvent(JajukEvents.QUEUE_NEED_REFRESH)); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/actions/HateSelectionAction.java0000644000175000017500000000502311720500104026610 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.actions; import java.awt.event.ActionEvent; import java.util.List; import org.jajuk.base.Track; import org.jajuk.base.TrackManager; import org.jajuk.events.JajukEvent; import org.jajuk.events.JajukEvents; import org.jajuk.events.ObservationManager; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; import org.jajuk.util.log.Log; /** * DOCUMENT_ME. */ public class HateSelectionAction extends SelectionAction { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** * Set hate preference to a selection *

    * Selection action *

    . */ HateSelectionAction() { super(Messages.getString("Preference.1"), IconLoader.getIcon(JajukIcons.PREFERENCE_HATE), true); setShortDescription(Messages.getString("Preference.1")); } /* (non-Javadoc) * @see org.jajuk.ui.actions.SelectionAction#perform(java.awt.event.ActionEvent) */ @Override public void perform(final ActionEvent e) throws Exception { new Thread("HateSelectionAction") { @Override public void run() { try { HateSelectionAction.super.perform(e); // Check selection is not void if (selection.size() == 0) { return; } // Extract tracks of each item List tracks = TrackManager.getInstance().getAssociatedTracks(selection, false); // Set the preference for (Track track : tracks) { track.setPreference(-3l); } // Request a GUI refresh ObservationManager.notify(new JajukEvent(JajukEvents.RATE_CHANGED)); } catch (Exception e) { Log.error(e); } } }.start(); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/actions/SyncTreeTableAction.java0000644000175000017500000000651011720500104026567 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.actions; import java.awt.event.ActionEvent; import java.util.Properties; import org.jajuk.events.JajukEvent; import org.jajuk.events.JajukEvents; import org.jajuk.events.ObservationManager; import org.jajuk.ui.widgets.JajukToggleButton; import org.jajuk.util.Conf; import org.jajuk.util.Const; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; /** * Action of requiring table and tree synchronization. *
    When called against a tree view, selecting an item in a table view will expand and scroll the item in tree. *
    When called against a table view, selecting an item in a tree view will filter the table accordingly. */ public class SyncTreeTableAction extends JajukAction { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** * The Constructor. */ protected SyncTreeTableAction() { super(Messages.getString("SyncTreeTableAction.0"), IconLoader .getIcon(JajukIcons.TREE_TABLE_SYNC), true); setShortDescription(Messages.getString("SyncTreeTableAction.1")); } /* * (non-Javadoc) * * @see org.jajuk.ui.actions.JajukAction#perform(java.awt.event.ActionEvent) */ @Override public void perform(ActionEvent evt) throws Exception { JajukToggleButton source = (JajukToggleButton) evt.getSource(); String currentViewID = (String) (source.getClientProperty(Const.DETAIL_VIEW)); // Store the new sync state into the view-level property Conf.setProperty(Const.CONF_SYNC_TABLE_TREE + "." + currentViewID, Boolean.toString(source .isSelected())); // If the sync button is deselected, we force the tables to refresh to un-filtered state // We use the RATE_CHANGED event because this event force table views // refreshing but not the tree view's one. if (!source.isSelected()) { ObservationManager.notify(new JajukEvent(JajukEvents.RATE_CHANGED)); } // Re-apply last interesting events so effect is token live Properties detailsTableEvent = ObservationManager .getDetailsLastOccurence(JajukEvents.TABLE_SELECTION_CHANGED); if (detailsTableEvent != null) { ObservationManager.notify(new JajukEvent(JajukEvents.TABLE_SELECTION_CHANGED, detailsTableEvent)); } Properties detailsTreeEvent = ObservationManager .getDetailsLastOccurence(JajukEvents.TREE_SELECTION_CHANGED); if (detailsTreeEvent != null) { ObservationManager .notify(new JajukEvent(JajukEvents.TREE_SELECTION_CHANGED, detailsTreeEvent)); } } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/actions/ReplayAlbumAction.java0000644000175000017500000000516111720500104026301 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.actions; import java.awt.event.ActionEvent; import java.util.ArrayList; import java.util.List; import org.jajuk.base.File; import org.jajuk.base.Track; import org.jajuk.services.players.QueueModel; import org.jajuk.util.Conf; import org.jajuk.util.Const; import org.jajuk.util.UtilFeatures; import org.jajuk.util.log.Log; /** * Action class for jumping to the begining of current album. */ public class ReplayAlbumAction extends JajukAction { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** * Instantiates a new replay album action. */ ReplayAlbumAction() { super("replay album", "alt F9", false, true); } /* (non-Javadoc) * @see org.jajuk.ui.actions.JajukAction#perform(java.awt.event.ActionEvent) */ @Override public void perform(ActionEvent evt) { new Thread("Replay Album Thread") { @Override public void run() { synchronized (QueueModel.class) { try { File current = QueueModel.getPlayingFile(); if (current != null) { // Create a new cache list to avoid synchronization of the album cache List tracks = new ArrayList(current.getTrack().getAlbum() .getTracksCache()); List files = null; files = new ArrayList(tracks.size()); for (Track track : tracks) { files.add(track.getBestFile(true)); } QueueModel.resetAround(QueueModel.getIndex(), current.getTrack().getAlbum()); QueueModel.push(UtilFeatures.createStackItems(files, Conf .getBoolean(Const.CONF_STATE_REPEAT_ALL), true), false); } } catch (Exception e) { Log.error(e); } } } }.start(); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/actions/OpenExplorerAction.java0000644000175000017500000000435511720500104026512 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.actions; import java.awt.event.ActionEvent; import java.util.List; import javax.swing.JComponent; import org.jajuk.base.Directory; import org.jajuk.base.Item; import org.jajuk.util.Const; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; import org.jajuk.util.UtilSystem; import org.jajuk.util.log.Log; /** * Open directory in default explorer program. */ public class OpenExplorerAction extends JajukAction { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** * Instantiates a new open explorer action. */ OpenExplorerAction() { super(Messages.getString("OpenExplorerAction.0"), IconLoader.getIcon(JajukIcons.OPEN_EXPLORER), true); setShortDescription(Messages.getString("OpenExplorerAction.1")); } /* (non-Javadoc) * @see org.jajuk.ui.actions.JajukAction#perform(java.awt.event.ActionEvent) */ @SuppressWarnings("unchecked") @Override public void perform(ActionEvent e) throws Exception { // This action expect either an item or a simple String from DETAIL_CONTENT // Swing client property JComponent source = (JComponent) e.getSource(); try { List selection = (List) source.getClientProperty(Const.DETAIL_CONTENT); Directory dir = (Directory) selection.get(0); UtilSystem.openInExplorer(dir.getFio()); } catch (Exception ex) { Log.error(ex); } } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/actions/RewindTrackAction.java0000644000175000017500000000471411720500104026304 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.actions; import java.awt.event.ActionEvent; import org.jajuk.services.players.Player; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; import org.jajuk.util.log.Log; /** * Action class for rewinding the current track. Installed keystroke: * CTRL + ALT + LEFT ARROW. */ public class RewindTrackAction extends JajukAction { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** The Constant JUMP_SIZE. DOCUMENT_ME */ private static final float JUMP_SIZE = 0.1f; /** * Instantiates a new rewind track action. */ RewindTrackAction() { super(IconLoader.getIcon(JajukIcons.REW), "altGraph F9", false, true); setShortDescription(Messages.getString("CommandJPanel.10")); } /* (non-Javadoc) * @see org.jajuk.ui.actions.JajukAction#perform(java.awt.event.ActionEvent) */ @Override public void perform(final ActionEvent evt) { new Thread("RewindTrackAction") { @Override public void run() { try { /* * check modifiers to see if it is a movement inside track, between * tracks or between albums */ if (evt != null // evt == null when using hotkeys && (evt.getModifiers() & ActionEvent.SHIFT_MASK) == ActionEvent.SHIFT_MASK) { // replay the entire file Player.seek(0); } else { float fCurrentPosition = Player.getCurrentPosition(); Player.seek(fCurrentPosition - JUMP_SIZE); } } catch (Exception e) { Log.error(e); } } }.start(); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/actions/GlobalRandomAction.java0000644000175000017500000000570511720500104026431 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.actions; import java.awt.event.ActionEvent; import java.util.List; import org.jajuk.base.File; import org.jajuk.base.FileManager; import org.jajuk.services.dj.Ambience; import org.jajuk.services.dj.AmbienceManager; import org.jajuk.services.players.QueueModel; import org.jajuk.util.Conf; import org.jajuk.util.Const; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; import org.jajuk.util.UtilFeatures; import org.jajuk.util.error.JajukException; /** * DOCUMENT_ME. */ public class GlobalRandomAction extends JajukAction { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** * Instantiates a new global random action. */ GlobalRandomAction() { super(Messages.getString("JajukWindow.6"), IconLoader.getIcon(JajukIcons.SHUFFLE_GLOBAL), true); String sTooltip = Messages.getString("JajukWindow.23"); Ambience ambience = AmbienceManager.getInstance().getAmbience( Conf.getString(Const.CONF_DEFAULT_AMBIENCE)); if (ambience != null) { String sAmbience = ambience.getName(); sTooltip = "" + Messages.getString("JajukWindow.23") + "

    " + sAmbience + "

    "; } setShortDescription(sTooltip); } /* (non-Javadoc) * @see org.jajuk.ui.actions.JajukAction#perform(java.awt.event.ActionEvent) */ @Override public void perform(ActionEvent evt) throws JajukException { new Thread("Global Random Thread") { @Override public void run() { Ambience ambience = AmbienceManager.getInstance().getSelectedAmbience(); List alToPlay = UtilFeatures.filterByAmbience(FileManager.getInstance() .getGlobalShufflePlaylist(), ambience); // For perfs (mainly playlist editor view refresh), we set a ceil for // tracks number if (alToPlay.size() > Const.NB_TRACKS_ON_ACTION) { alToPlay = alToPlay.subList(0, Const.NB_TRACKS_ON_ACTION); } // Push them QueueModel.push(UtilFeatures.createStackItems(alToPlay, Conf .getBoolean(Const.CONF_STATE_REPEAT_ALL), false), false); } }.start(); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/actions/IntroModeAction.java0000644000175000017500000000346111720500104025765 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.actions; import java.awt.event.ActionEvent; import org.jajuk.ui.widgets.JajukJMenuBar; import org.jajuk.util.Conf; import org.jajuk.util.Const; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; /** * DOCUMENT_ME. */ public class IntroModeAction extends JajukAction { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** * Instantiates a new intro mode action. */ IntroModeAction() { super(Messages.getString("JajukJMenuBar.13"), IconLoader.getIcon(JajukIcons.INTRO), true); setShortDescription(Messages.getString("CommandJPanel.4")); } /* (non-Javadoc) * @see org.jajuk.ui.actions.JajukAction#perform(java.awt.event.ActionEvent) */ @Override public void perform(ActionEvent evt) { boolean b = Boolean.valueOf(Conf.getString(Const.CONF_STATE_INTRO)); Conf.setProperty(Const.CONF_STATE_INTRO, Boolean.toString(!b)); JajukJMenuBar.getInstance().setIntroSelected(!b); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/actions/AdoreSelectionAction.java0000644000175000017500000000503011720500104026757 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.actions; import java.awt.event.ActionEvent; import java.util.List; import org.jajuk.base.Track; import org.jajuk.base.TrackManager; import org.jajuk.events.JajukEvent; import org.jajuk.events.JajukEvents; import org.jajuk.events.ObservationManager; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; import org.jajuk.util.log.Log; /** * DOCUMENT_ME. */ public class AdoreSelectionAction extends SelectionAction { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** * Set adore preference to a selection *

    * Selection action *

    . */ AdoreSelectionAction() { super(Messages.getString("Preference.6"), IconLoader.getIcon(JajukIcons.PREFERENCE_ADORE), true); setShortDescription(Messages.getString("Preference.6")); } /* (non-Javadoc) * @see org.jajuk.ui.actions.SelectionAction#perform(java.awt.event.ActionEvent) */ @Override public void perform(final ActionEvent e) throws Exception { new Thread("AdoreSelectionAction") { @Override public void run() { try { AdoreSelectionAction.super.perform(e); // Check selection is not void if (selection.size() == 0) { return; } // Extract tracks of each item List tracks = TrackManager.getInstance().getAssociatedTracks(selection, false); // Set the preference for (Track track : tracks) { track.setPreference(3l); } // Request a GUI refresh ObservationManager.notify(new JajukEvent(JajukEvents.RATE_CHANGED)); } catch (Exception e) { Log.error(e); } } }.start(); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/actions/PlayShuffleSelectionAction.java0000644000175000017500000000516411720500104030157 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.actions; import java.awt.event.ActionEvent; import java.util.Collections; import java.util.List; import org.jajuk.base.File; import org.jajuk.services.players.QueueModel; import org.jajuk.util.Conf; import org.jajuk.util.Const; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; import org.jajuk.util.UtilFeatures; import org.jajuk.util.UtilSystem; import org.jajuk.util.log.Log; /** * Play shuffle a selection *

    * Action emitter is responsible to ensure all items provided share the same * type *

    *

    * Selection data is provided using the swing properties DETAIL_SELECTION *

    . */ public class PlayShuffleSelectionAction extends SelectionAction { /** Generated serialVersionUID. */ private static final long serialVersionUID = -8078402652430413821L; /** * Instantiates a new play shuffle selection action. */ PlayShuffleSelectionAction() { super(Messages.getString("TracksTableView.9"), IconLoader.getIcon(JajukIcons.SHUFFLE), true); setShortDescription(Messages.getString("TracksTableView.9")); } /* * (non-Javadoc) * * @see org.jajuk.ui.actions.JajukAction#perform(java.awt.event.ActionEvent) */ @Override public void perform(final ActionEvent e) throws Exception { new Thread("PlayShuffleSelectionAction") { @Override public void run() { try { PlayShuffleSelectionAction.super.perform(e); List files = UtilFeatures.getPlayableFiles(selection); Collections.shuffle(files, UtilSystem.getRandom()); QueueModel.push(UtilFeatures.createStackItems(UtilFeatures.applyPlayOption(files), Conf .getBoolean(Const.CONF_STATE_REPEAT_ALL), true), false); } catch (Exception e) { Log.error(e); } } }.start(); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/actions/JajukActions.java0000644000175000017500000002034311720500104025312 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.actions; /** * This enum contains a constant for all actions present in Jajuk. *

    */ public enum JajukActions { /** Used for application exit. */ EXIT, /** Used when the repeat status was changed. */ REPEAT_MODE, /** Used when the repeat all status was changed. */ REPEAT_ALL_MODE, /** Used when the shuffle mode was changed. */ SHUFFLE_MODE, /** Used when the continue mode was changed. */ CONTINUE_MODE, /** Used when the intro mode was changed. */ INTRO_MODE, /** Used when the karaoke mode was changed. */ KARAOKE_MODE, /** Used when a new device is requested. */ DEVICE_NEW, /** Used when a device is removed. */ DEVICE_DELETE, /** Used when device properties are requested. */ DEVICE_PROPERTIES, /** Used when a device mount is requested. */ DEVICE_MOUNT, /** Used when a device unmount is requested. */ DEVICE_UNMOUNT, /** Used when a device test is requested. */ DEVICE_TEST, /** Used when a device refresh is requested. */ DEVICE_REFRESH, /** Used when a device synchronization is requested. */ DEVICE_SYNCHRO, /** Used when a view refresh is requested. This is used in device view. */ VIEW_REFRESH_REQUEST, /** Used when a view needs to be closed. */ VIEW_CLOSE_REQUEST, /** Used when view needs to be shown. */ VIEW_SHOW_REQUEST, /** Used when the display status of a view needs to be changed. */ VIEW_SHOW_STATUS_CHANGED_REQUEST, /** Used when defaults settings need to be restored. */ VIEW_RESTORE_DEFAULTS, /** Used when defaults settings for all perspectives. */ ALL_VIEW_RESTORE_DEFAULTS, /** Used when a command from the history is selected. */ VIEW_COMMAND_SELECT_HISTORY_ITEM, /** Used when the help should be displayed. */ HELP_REQUIRED, /** Used to see debug traces. */ SHOW_TRACES, /** Used when the cover should be refreshed. */ COVER_REFRESH, /** Used when a request for a cover change is made. */ COVER_CHANGE, /** Used when a playlist refresh is requested. */ PLAYLIST_REFRESH, /** Used when a playlist change is requested. */ PLAYLIST_CHANGED, /** Used when a file has been launched by the fifo. */ FILE_LAUNCHED, /** Used as heart beat for general use to refresh subscribers every n secs. */ HEART_BEAT, /** Used when a reinit has is required. */ ZERO, /** Used when a new element has been added in the history. */ ADD_HISTORY_ITEM, /** Used when a special mode (global shuffle, novelties, bestof...) changed. */ SPECIAL_MODE, /** Used when the global shuffle button is pressed. */ SHUFFLE_GLOBAL, /** Used when the best of button is pressed. */ BEST_OF, /** Used when the DJ button is pressed. */ DJ, /** Used when the novelties button is pressed. */ NOVELTIES, /** Used when the finish album button is pressed. Indicates the current album will play until the end. */ FINISH_ALBUM, /** Used when an error occurred during a play. */ PLAY_ERROR, /** Used when the mute state changed. */ MUTE_STATE, /** Used when table and tree views need to be synchronized. */ SYNC_TREE_TABLE, /** Used when history should be cleared. */ CLEAR_HISTORY, /** Used when the first time wizard needs to be launched. */ SIMPLE_DEVICE_WIZARD, /** Used to launch the quality feedback agent. */ QUALITY, /** Used to change the volume. */ VOLUME_CHANGED, /** Used when a new property is created. */ CREATE_PROPERTY, /** Used when a property is deleted. */ DELETE_PROPERTY, /** Used when a new custom property is added. */ CUSTOM_PROPERTIES_ADD, /** Used when a custom property is removed. */ CUSTOM_PROPERTIES_REMOVE, /** Used when a file name changes. */ FILE_NAME_CHANGED, /** Used when file rate changes. */ RATE_CHANGED, /** Used to display a tip of the day window. */ TIP_OF_THE_DAY, /** Used to check for jajuk updates. */ CHECK_FOR_UPDATES, /** Used to display an about dialog. */ SHOW_ABOUT, /** Used to display an tag configure dialog. */ EXTRA_TAGS_WIZARD, /** Used to jump to the previous track. */ PREVIOUS_TRACK, /** Used to display the current queue in slim bar. */ QUEUE_TO_SLIM, /** Replay current album. */ REPLAY_ALBUM, /** Used to jump to the next track. */ NEXT_TRACK, /** Used to rewind the current track. */ REWIND_TRACK, /** Used to fast-forward the current track. */ FORWARD_TRACK, /** Used to increase current track rate. */ INC_RATE, /** Used to stop playing. */ STOP_TRACK, /** Used to pause/resume playing. */ PAUSE_RESUME_TRACK, /** Used to jump to the previous album. */ PREVIOUS_ALBUM, /** Used to jump to the next album. */ NEXT_ALBUM, /** Used to increase the volume. */ INCREASE_VOLUME, /** Used to decrease the volume. */ DECREASE_VOLUME, /** Used to configure djs. */ CONFIGURE_DJS, /** Used to configure ambiences. */ CONFIGURE_AMBIENCES, /** Used to configure webradios. */ CONFIGURE_WEBRADIOS, /** Used to configure the application. */ OPTIONS, /** Used to show or hide unmounted devices. */ UNMOUNTED, /** Create a report. */ CREATE_REPORT, /** Copy to clipboard data from UtilFeatures.copyData */ COPY_TO_CLIPBOARD, /** Open directory in default explorer program. */ OPEN_EXPLORER, /** Launch in an external browser the url given in UtilFeatures.url */ LAUNCH_IN_BROWSER, /** Launch a web radio. */ WEB_RADIO, /** Used to delete selected files/directories from disk. */ DELETE, /** Used to move selected files and directories. */ PASTE, /** Used to refresh a directory. */ REFRESH, /** Used to find duplicate files. */ FIND_DUPLICATE_FILES, /** Used to set alarm clock. */ ALARM_CLOCK, /** Show properties on a single or a selection of items. */ SHOW_PROPERTIES, /** Play a selection. */ PLAY_SELECTION, /** Play randomly a selection. */ PLAY_SHUFFLE_SELECTION, /** Play a selection in a loop. */ PLAY_REPEAT_SELECTION, /** Push a selection. */ PUSH_SELECTION, /** Push a selection to the front. */ PUSH_FRONT_SELECTION, /** Bookmark selection. */ BOOKMARK_SELECTION, /** Play album for selection. */ PLAY_ALBUM_SELECTION, /** Play artist for selection. */ PLAY_ARTIST_SELECTION, /** Play full directory for selection. */ PLAY_DIRECTORY_SELECTION, /** Search online tags. */ CDDB_SELECTION, /** Show album details. */ SHOW_ALBUM_DETAILS, /** Used to cut and move Selected Items. */ CUT, /** Used to copy and move Selected Items. */ COPY, /** Used to rename files/directories. */ RENAME, /** Used to create New Folder. */ NEW_FOLDER, /** Used to create a slim interface for Jajuk. */ SLIM_JAJUK, /** Used to perform GC. */ GC, /** Used to manually save settings and collection. */ COMMIT, /** Save as. */ SAVE_AS, /** Ban current item. */ BAN, /** Ban selection. */ BAN_SELECTION, /** Un-Ban selection. */ UN_BAN_SELECTION, /** Set adore preference to selection. */ PREFERENCE_ADORE, /** Set love preference to selection. */ PREFERENCE_LOVE, /** Set like preference to selection. */ PREFERENCE_LIKE, /** Set average preference to selection. */ PREFERENCE_AVERAGE, /** Set poor preference to selection. */ PREFERENCE_POOR, /** Set hate preference to selection. */ PREFERENCE_HATE, /** Set unset preference to selection. */ PREFERENCE_UNSET, /** Prepare party. */ PREPARE_PARTY, /** fullscreen. */ FULLSCREEN_JAJUK, /** display donate dialog. */ SHOW_DONATE } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/actions/LaunchInBrowserAction.java0000644000175000017500000000511411720500104027127 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.actions; import java.awt.Desktop; import java.awt.event.ActionEvent; import java.io.File; import java.net.URI; import javax.swing.JComponent; import org.jajuk.util.Const; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; import org.jajuk.util.UtilSystem; import org.jajuk.util.error.JajukException; import org.jajuk.util.log.Log; /** * Launch the URL from UtilFeatures.url in the default browser */ public class LaunchInBrowserAction extends JajukAction { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** * Instantiates a new launch in browser action. */ LaunchInBrowserAction() { // this action is available only under GNU/Linux and windows for now super(Messages.getString("LaunchInBrowserAction.0"), IconLoader.getIcon(JajukIcons.LAUNCH), UtilSystem.isBrowserSupported()); setShortDescription(Messages.getString("LaunchInBrowserAction.0")); } /* (non-Javadoc) * @see org.jajuk.ui.actions.JajukAction#perform(java.awt.event.ActionEvent) */ @Override public void perform(final ActionEvent evt) throws JajukException { new Thread("LaunchInBrowserAction") { @Override public void run() { try { JComponent source = (JComponent) evt.getSource(); String url = (String) source.getClientProperty(Const.DETAIL_CONTENT); // If URL is a file, open the file with default editor File file = new File(url); if (file.exists()) { Desktop.getDesktop().open(file); } else { // Open a browser for HTTP URLs Desktop.getDesktop().browse(new URI(url)); } } catch (Exception e) { Log.error(e); } } }.start(); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/actions/WebRadioConfigurationAction.java0000644000175000017500000000323411720500104030307 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.actions; import java.awt.event.ActionEvent; import org.jajuk.ui.wizard.WebRadioWizard; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; /** * Action for configure WebRadios. */ public class WebRadioConfigurationAction extends JajukAction { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** * Instantiates a new web radio configuration action. */ WebRadioConfigurationAction() { super(Messages.getString("CommandJPanel.24"), IconLoader.getIcon(JajukIcons.CONFIGURATION), true); } /* (non-Javadoc) * @see org.jajuk.ui.actions.JajukAction#perform(java.awt.event.ActionEvent) */ @Override public void perform(ActionEvent evt) { // display the wizard WebRadioWizard wizard = new WebRadioWizard(); wizard.show(); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/actions/FinishAlbumAction.java0000644000175000017500000000606111720500104026265 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.actions; import java.awt.event.ActionEvent; import java.util.List; import java.util.Properties; import org.jajuk.base.Directory; import org.jajuk.events.JajukEvent; import org.jajuk.events.JajukEvents; import org.jajuk.events.ObservationManager; import org.jajuk.services.players.QueueModel; import org.jajuk.services.players.StackItem; import org.jajuk.util.Const; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; import org.jajuk.util.UtilFeatures; import org.jajuk.util.error.JajukException; import org.jajuk.util.log.Log; /** * DOCUMENT_ME. */ public class FinishAlbumAction extends JajukAction { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** * Instantiates a new finish album action. */ FinishAlbumAction() { super(Messages.getString("JajukWindow.16"), IconLoader.getIcon(JajukIcons.FINISH_ALBUM), !QueueModel.isStopped()); setShortDescription(Messages.getString("JajukWindow.32")); } /* * (non-Javadoc) * * @see org.jajuk.ui.actions.JajukAction#perform(java.awt.event.ActionEvent) */ @Override public void perform(ActionEvent evt) throws JajukException { new Thread("FinishAlbumAction") { @Override public void run() { try { StackItem item = QueueModel.getCurrentItem();// stores // current item Directory dir = item.getFile().getDirectory(); List stack = UtilFeatures.createStackItems(dir .getFilesFromFile(item.getFile()), item.isRepeat(), item.isUserLaunch()); // Then re-add current item only if some more tracks are to be ran. Otherwise, just ignore // this command, better than displaying a bozing error message. if (stack != null && stack.size() > 0) { QueueModel.push(stack, true, true); QueueModel.computesPlanned(true); // update planned list Properties properties = new Properties(); properties.put(Const.DETAIL_ORIGIN, Const.DETAIL_SPECIAL_MODE_NORMAL); ObservationManager.notify(new JajukEvent(JajukEvents.SPECIAL_MODE, properties)); } } catch (Exception e) { Log.error(e); } } }.start(); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/actions/PlayPauseAction.java0000644000175000017500000000510011720500104025760 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.actions; import java.awt.event.ActionEvent; import org.jajuk.services.players.Player; import org.jajuk.services.players.QueueModel; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; /** * DOCUMENT_ME. */ public class PlayPauseAction extends JajukAction { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** DOCUMENT_ME. */ private static boolean bAlreadyLaunching = false; /** * Instantiates a new play pause action. */ PlayPauseAction() { super(Messages.getString("JajukWindow.10"), IconLoader.getIcon(JajukIcons.PLAYER_PAUSE), "ctrl P", false, true); setShortDescription(Messages.getString("JajukWindow.26")); } /* (non-Javadoc) * @see org.jajuk.ui.actions.JajukAction#perform(java.awt.event.ActionEvent) */ @Override public void perform(ActionEvent evt) { // Note that we don't change here the label and icon, already done in // PlayerstateMediator if (QueueModel.isStopped()) { // We use here a flag to avoid launching the goTo() thread twice. In case // of playing error, this would create several looping threads trying to // play in concurrently and would broke the wait after an error contract if (bAlreadyLaunching) { return; } new Thread("PlayPause Thread") { @Override public void run() { try { bAlreadyLaunching = true; QueueModel.goTo(QueueModel.getIndex()); } finally { bAlreadyLaunching = false; } } }.start(); } else if (Player.isPaused()) { // player was paused, resume it Player.resume(); } else { // player is not paused, pause it Player.pause(); } } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/actions/PreviousTrackAction.java0000644000175000017500000000740111720500104026664 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.actions; import java.awt.event.ActionEvent; import java.util.ArrayList; import java.util.List; import org.jajuk.services.players.Player; import org.jajuk.services.players.QueueModel; import org.jajuk.services.webradio.WebRadio; import org.jajuk.services.webradio.WebRadioManager; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; import org.jajuk.util.log.Log; /** * Action class for jumping to the previous track. Installed keystroke: * CTRL + LEFT ARROW. */ public class PreviousTrackAction extends JajukAction { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** * Instantiates a new previous track action. */ PreviousTrackAction() { super(Messages.getString("JajukWindow.13"), IconLoader .getIcon(JajukIcons.PLAYER_PREVIOUS_SMALL), "F9", false, true); setShortDescription(Messages.getString("CommandJPanel.8")); } /* * (non-Javadoc) * * @see org.jajuk.ui.actions.JajukAction#perform(java.awt.event.ActionEvent) */ @Override public void perform(final ActionEvent evt) { // check modifiers to see if it is a movement inside track, between // tracks or between albums if (evt != null && // evt == null when using hotkeys (evt.getModifiers() & ActionEvent.CTRL_MASK) == ActionEvent.CTRL_MASK) { // CTRL + previous = replay album ActionManager.getAction(JajukActions.REPLAY_ALBUM).actionPerformed(evt); } else if (evt != null && (evt.getModifiers() & ActionEvent.SHIFT_MASK) == ActionEvent.SHIFT_MASK) { // SHIFT + previous = replay album ActionManager.getAction(JajukActions.PREVIOUS_ALBUM).actionPerformed(evt); } else { // if playing a radio, launch next radio station if (QueueModel.isPlayingRadio()) { final List radios = new ArrayList(WebRadioManager.getInstance() .getWebRadios()); int index = radios.indexOf(QueueModel.getCurrentRadio()); if (index == 0) { index = radios.size() - 1; } else { index--; } final int i = index; new Thread("Previous Track Thread") { @Override public void run() { QueueModel.launchRadio(radios.get(i)); } }.start(); } else { new Thread("Previous Track Thread") { @Override public void run() { synchronized (QueueModel.class) { // ALT + previous = replay track if (evt != null && (evt.getModifiers() == 4332424)) { // replay the entire file Player.seek(0); } else { // No key modifier : play previous track try { QueueModel.playPrevious(); } catch (Exception e) { Log.error(e); } } } } }.start(); } } } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/actions/ShowActivateTagsAction.java0000644000175000017500000000326211720500104027304 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.actions; import java.awt.event.ActionEvent; import org.jajuk.ui.wizard.ExtraTagsConfigurationWizard; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; /** * Action for displaying the tip of the day. */ public class ShowActivateTagsAction extends JajukAction { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** * Instantiates a new show about action. */ ShowActivateTagsAction() { super(Messages.getString("JajukWindow.40"), IconLoader.getIcon(JajukIcons.ADD), true); setShortDescription(Messages.getString("JajukWindow.41")); } /** * Invoked when an action occurs. * * @param evt DOCUMENT_ME */ @Override public void perform(ActionEvent evt) { new ExtraTagsConfigurationWizard(); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/actions/RepeatModeAction.java0000644000175000017500000000474511720500104026120 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.actions; import java.awt.event.ActionEvent; import org.jajuk.events.JajukEvent; import org.jajuk.events.JajukEvents; import org.jajuk.events.ObservationManager; import org.jajuk.services.players.QueueModel; import org.jajuk.services.players.StackItem; import org.jajuk.util.Conf; import org.jajuk.util.Const; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; import org.jajuk.util.UtilGUI; /** * DOCUMENT_ME. */ public class RepeatModeAction extends JajukAction { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** * Instantiates a new repeat mode action. */ RepeatModeAction() { super(Messages.getString("JajukJMenuBar.10"), IconLoader.getIcon(JajukIcons.REPEAT), "ctrl T", true, false); setShortDescription(Messages.getString("CommandJPanel.1")); } /** * Invoked when an action occurs. * * @param evt DOCUMENT_ME */ @Override public void perform(ActionEvent evt) { boolean b = Conf.getBoolean(Const.CONF_STATE_REPEAT); UtilGUI.setRepeatSingleGui(!b); // disabling repeat for an item forced unset for all items and enabling single repeat unset // repeat for all items and then set it only for current track QueueModel.setRepeatModeToAll(false); if (!b) { // enabled button // if FIFO is not void, repeat over current item StackItem item = QueueModel.getCurrentItem(); if (item != null) { item.setRepeat(true); } } // computes planned tracks QueueModel.computesPlanned(false); // Refresh Queue View ObservationManager.notify(new JajukEvent(JajukEvents.QUEUE_NEED_REFRESH)); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/actions/ConfigurationRequiredAction.java0000644000175000017500000000334111720500104030372 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.actions; import java.awt.event.ActionEvent; import org.jajuk.ui.perspectives.ConfigurationPerspective; import org.jajuk.ui.perspectives.PerspectiveManager; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; /** * Action for configurate the application. */ public class ConfigurationRequiredAction extends JajukAction { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** * Instantiates a new configuration required action. */ ConfigurationRequiredAction() { super(Messages.getString("JajukJMenuBar.22"), IconLoader.getIcon(JajukIcons.CONFIGURATION), true); } /* (non-Javadoc) * @see org.jajuk.ui.actions.JajukAction#perform(java.awt.event.ActionEvent) */ @Override public void perform(ActionEvent evt) { PerspectiveManager.setCurrentPerspective(ConfigurationPerspective.class.getName()); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/actions/ContinueModeAction.java0000644000175000017500000000517211720500104026457 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.actions; import java.awt.event.ActionEvent; import org.jajuk.base.FileManager; import org.jajuk.events.JajukEvent; import org.jajuk.events.JajukEvents; import org.jajuk.events.ObservationManager; import org.jajuk.services.players.QueueModel; import org.jajuk.services.players.StackItem; import org.jajuk.ui.widgets.JajukJMenuBar; import org.jajuk.util.Conf; import org.jajuk.util.Const; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; import org.jajuk.util.error.JajukException; /** * DOCUMENT_ME. */ public class ContinueModeAction extends JajukAction { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** * Instantiates a new continue mode action. */ ContinueModeAction() { super(Messages.getString("JajukJMenuBar.12"), IconLoader.getIcon(JajukIcons.CONTINUE), true); setShortDescription(Messages.getString("CommandJPanel.3")); } /* (non-Javadoc) * @see org.jajuk.ui.actions.JajukAction#perform(java.awt.event.ActionEvent) */ @Override public void perform(ActionEvent evt) throws JajukException { boolean b = Conf.getBoolean(Const.CONF_STATE_CONTINUE); Conf.setProperty(Const.CONF_STATE_CONTINUE, Boolean.toString(!b)); JajukJMenuBar.getInstance().setContinueSelected(!b); if (!b) { // enabled button if (QueueModel.isStopped()) { // if nothing playing, play next track if possible StackItem item = QueueModel.getLastPlayed(); if (item != null) { QueueModel.push(new StackItem(FileManager.getInstance().getNextFile(item.getFile())), false); } } } // computes planned tracks QueueModel.computesPlanned(false); // Refresh Queue View ObservationManager.notify(new JajukEvent(JajukEvents.QUEUE_NEED_REFRESH)); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/actions/UnsetPreferenceSelectionAction.java0000644000175000017500000000510211720500104031022 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.actions; import java.awt.event.ActionEvent; import java.util.List; import org.jajuk.base.Track; import org.jajuk.base.TrackManager; import org.jajuk.events.JajukEvent; import org.jajuk.events.JajukEvents; import org.jajuk.events.ObservationManager; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; import org.jajuk.util.log.Log; /** * DOCUMENT_ME. */ public class UnsetPreferenceSelectionAction extends SelectionAction { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** * Set default preference to a selection *

    * Selection action *

    . */ UnsetPreferenceSelectionAction() { super(Messages.getString("Preference.8"), IconLoader.getIcon(JajukIcons.PREFERENCE_UNSET), true); setShortDescription(Messages.getString("Preference.8")); } /* (non-Javadoc) * @see org.jajuk.ui.actions.SelectionAction#perform(java.awt.event.ActionEvent) */ @Override public void perform(final ActionEvent e) throws Exception { new Thread("UnsetPreferenceSelectionAction") { @Override public void run() { try { UnsetPreferenceSelectionAction.super.perform(e); // Check selection is not void if (selection.size() == 0) { return; } // Extract tracks of each item List tracks = TrackManager.getInstance().getAssociatedTracks(selection, false); // Set the preference for (Track track : tracks) { track.setPreference(0l); } // Request a GUI refresh ObservationManager.notify(new JajukEvent(JajukEvents.RATE_CHANGED)); } catch (Exception e) { Log.error(e); } } }.start(); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/actions/NextAlbumAction.java0000644000175000017500000000343411720500104025764 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.actions; import java.awt.event.ActionEvent; import org.jajuk.services.players.QueueModel; import org.jajuk.util.log.Log; /** * Action class for jumping to the next album. Installed keystroke: * CTRL + SHIFT + RIGHT ARROW. */ public class NextAlbumAction extends JajukAction { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** * Instantiates a new next album action. */ NextAlbumAction() { super("next album", "shift F10", false, true); } /* (non-Javadoc) * @see org.jajuk.ui.actions.JajukAction#perform(java.awt.event.ActionEvent) */ @Override public void perform(ActionEvent evt) { new Thread("Next Album Thread") { @Override public void run() { // Take FIFO lock synchronized (QueueModel.class) { try { QueueModel.playNextAlbum(); } catch (Exception e) { Log.error(e); } } } }.start(); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/actions/BanCurrentAction.java0000644000175000017500000000513011720500104026123 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.actions; import java.awt.event.ActionEvent; import org.jajuk.base.File; import org.jajuk.base.Track; import org.jajuk.events.JajukEvent; import org.jajuk.events.JajukEvents; import org.jajuk.events.ObservationManager; import org.jajuk.services.players.QueueModel; import org.jajuk.util.Const; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; /** * DOCUMENT_ME. */ public class BanCurrentAction extends SelectionAction { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** * Ban / Unban current track. The Ban action is used to ban a track so it is * never selected */ BanCurrentAction() { super(Messages.getString("BanSelectionAction.0"), IconLoader.getIcon(JajukIcons.BAN), true); setShortDescription(Messages.getString("BanSelectionAction.1")); } /* (non-Javadoc) * @see org.jajuk.ui.actions.SelectionAction#perform(java.awt.event.ActionEvent) */ @Override public void perform(ActionEvent e) throws Exception { File current = QueueModel.getPlayingFile(); if (current != null) { Track track = current.getTrack(); boolean alreadyBanned = track.getBooleanValue(Const.XML_TRACK_BANNED); track.setProperty(Const.XML_TRACK_BANNED, !alreadyBanned); // Request a GUI refresh ObservationManager.notify(new JajukEvent(JajukEvents.RATE_CHANGED)); // Alert GUI so we can switch buttons from ban icon to unban one ObservationManager.notify(new JajukEvent(JajukEvents.BANNED)); // Go to next track if it is banned if (ActionManager.getAction(JajukActions.NEXT_TRACK).isEnabled() && track.getBooleanValue(Const.XML_TRACK_BANNED)) { ActionManager.getAction(JajukActions.NEXT_TRACK).perform(null); } } } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/actions/ActionUtil.java0000644000175000017500000000670111720500104025002 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.actions; import java.awt.event.KeyEvent; import javax.swing.Action; import javax.swing.ActionMap; import javax.swing.InputMap; import javax.swing.JComponent; import javax.swing.KeyStroke; /** * Utility class for swing actions. */ public final class ActionUtil { /** The character to use as mnemonic indicator. */ public static final char INDICATOR = '_'; /** * Instantiates a new action util. */ private ActionUtil() { // Private access to disallow construction. } /** * Strips a mnemonic character out of a given text. A text's mnemonic is the * first character following a '_' character. * * @param text The text to strip the mnemonic character from. * * @return An int defining the mnemonic character for the given * text. If there was no mnemonic indicator found, -1 * will be returned. */ public static int getMnemonic(String text) { for (int i = 0; i < text.length() - 1; i++) { if (text.charAt(i) == INDICATOR) { return text.charAt(i + 1); } } return -1; } /** * Strips the text from mnemonic indicators. * * @param text The text to work on. * * @return The text with all mnemonic indicators stripped. If there are no * indicators in the given text, the original text will be returned. * * @see #INDICATOR */ public static String strip(String text) { return text.replace(String.valueOf(INDICATOR), ""); } /** * Install the keystrokes for several actions on a single button. The * keystrokes are added with {@link JComponent#WHEN_IN_FOCUSED_WINDOW} * condition. * * @param component The component to which the key stroke will be added. * @param actions The actions to add to the keystrokes. */ public static void installKeystrokes(JComponent component, Action... actions) { for (Action action : actions) { KeyStroke stroke = (KeyStroke) action.getValue(Action.ACCELERATOR_KEY); if (stroke != null) { InputMap keyMap = component.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW); keyMap.put(stroke, action); ActionMap actionMap = component.getActionMap(); actionMap.put(action, action); } } } /** * Return whether a key event matches the mnemonic of a provided action. * * @param action DOCUMENT_ME * @param ke DOCUMENT_ME * * @return whether a key event matches the mnemonic of a provided action */ public static boolean matches(Action action, KeyEvent ke) { KeyStroke key = (KeyStroke) action.getValue(Action.ACCELERATOR_KEY); return KeyStroke.getKeyStrokeForEvent(ke).equals(key); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/actions/StopTrackAction.java0000644000175000017500000000420111720500104025770 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.actions; import java.awt.event.ActionEvent; import org.jajuk.services.players.QueueModel; import org.jajuk.util.Conf; import org.jajuk.util.Const; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; import org.jajuk.util.log.Log; /** * DOCUMENT_ME. */ public class StopTrackAction extends JajukAction { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** * Instantiates a new stop track action. */ StopTrackAction() { super(Messages.getString("JajukWindow.27"), IconLoader.getIcon(JajukIcons.STOP_16X16), "ctrl S", false, false); setShortDescription(Messages.getString("JajukWindow.27")); } /* (non-Javadoc) * @see org.jajuk.ui.actions.JajukAction#perform(java.awt.event.ActionEvent) */ @Override public void perform(ActionEvent evt) { new Thread("StopTrackAction") { @Override public void run() { try { QueueModel.stopRequest(); // Save the stopped state (do not do it in the QueueModel.stopRequest() // method because it must be set only on a human request, not at jajuk engine shutdown Conf.setProperty(Const.CONF_STARTUP_STOPPED, "true"); } catch (Exception e) { Log.error(e); } } }.start(); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/actions/RenameAction.java0000644000175000017500000001210111720500104025263 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.actions; import java.awt.event.ActionEvent; import java.io.IOException; import java.util.List; import javax.swing.JComponent; import javax.swing.JOptionPane; import org.jajuk.base.Directory; import org.jajuk.base.DirectoryManager; import org.jajuk.base.File; import org.jajuk.base.FileManager; import org.jajuk.base.Item; import org.jajuk.events.JajukEvent; import org.jajuk.events.JajukEvents; import org.jajuk.events.ObservationManager; import org.jajuk.services.players.QueueModel; import org.jajuk.util.Const; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; import org.jajuk.util.UtilGUI; import org.jajuk.util.log.Log; /** * DOCUMENT_ME. */ public class RenameAction extends JajukAction { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** * Instantiates a new rename action. */ RenameAction() { super(Messages.getString("RenameAction.0"), IconLoader.getIcon(JajukIcons.EDIT), "F2", true, false); setShortDescription(Messages.getString("RenameAction.0")); } /* * (non-Javadoc) * * @see org.jajuk.ui.actions.JajukAction#perform(java.awt.event.ActionEvent) */ @Override @SuppressWarnings("unchecked") public void perform(ActionEvent e) { JComponent source = (JComponent) e.getSource(); // Get required data from the tree (selected node and node type) final List alSelected = (List) source.getClientProperty(Const.DETAIL_SELECTION); final Item currentItem = alSelected.get(0); // Check if file is currently played if (QueueModel.getPlayingFile() != null && QueueModel.getPlayingFile().equals(currentItem)) { Messages.showErrorMessage(134); return; } if (currentItem instanceof File) { String newName = JOptionPane.showInputDialog(null, Messages.getString("RenameAction.1") + "\n\n", ((File) currentItem).getName()); if ((newName != null) && (newName.length() > 0)) { try { UtilGUI.waiting(); FileManager.getInstance().changeFileName((File) currentItem, newName); ObservationManager.notify(new JajukEvent(JajukEvents.DEVICE_REFRESH)); } catch (Exception er) { Messages.showErrorMessage(134); Log.error(er); } finally { UtilGUI.stopWaiting(); } } } else if (currentItem instanceof Directory) { /* * Renaming of a directory * * @TODO Note that this implementation is trivial and looses all custom properties applied on * files (hopefully not the tracks ones) because we simply remove the directory and force its * scan again. A better implementation would clone all files recursively */ // check that the directory is not an ancestor of the currently played file if (QueueModel.getPlayingFile() != null && QueueModel.getPlayingFile().hasAncestor((Directory) currentItem)) { Messages.showWarningMessage(Messages.getErrorMessage(172)); return; } String newName = JOptionPane.showInputDialog(null, Messages.getString("RenameAction.2") + "\n\n", ((Directory) currentItem).getName()); if ((newName != null) && (newName.length() > 0)) { try { UtilGUI.waiting(); java.io.File newFile = new java.io.File(((Directory) currentItem).getParentDirectory() .getAbsolutePath() + "/" + newName); java.io.File dir = ((Directory) currentItem).getFio(); // For directories, we don't copy / delete, we just rename for performance reasons // and because the Utilsystem.move() code only works for files. // We check that the directory has actually been renamed. if (!dir.renameTo(newFile)) { throw new IOException("Cannot rename directory : " + dir.getAbsolutePath()); } DirectoryManager.getInstance().removeDirectory(((Directory) currentItem).getID()); (((Directory) currentItem).getParentDirectory()).refresh(false); ObservationManager.notify(new JajukEvent(JajukEvents.DEVICE_REFRESH)); } catch (Exception er) { Log.error(er); Messages.showErrorMessage(134); } finally { UtilGUI.stopWaiting(); } } } } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/actions/ShowPropertiesAction.java0000644000175000017500000000653211720500104027064 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.actions; import java.awt.event.ActionEvent; import java.util.ArrayList; import java.util.List; import org.jajuk.base.Directory; import org.jajuk.base.File; import org.jajuk.base.Item; import org.jajuk.base.LogicalItem; import org.jajuk.base.Track; import org.jajuk.base.TrackManager; import org.jajuk.ui.wizard.PropertiesDialog; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; /** * Display properties action. Allows displaying properties on single or multiple * items of the same type. *

    * Action emitter is responsible to ensure all items provided share the same * type *

    *

    * Selection data is provided using the swing properties DETAIL_SELECTION *

    */ public class ShowPropertiesAction extends SelectionAction { /** Generated serialVersionUID. */ private static final long serialVersionUID = -8078402652430413821L; /** * Instantiates a new show properties action. */ ShowPropertiesAction() { super(Messages.getString("TracksTableView.14"), IconLoader.getIcon(JajukIcons.PROPERTIES), true); setShortDescription(Messages.getString("ShowPropertiesAction.0")); setAcceleratorKey("alt ENTER"); } /* * (non-Javadoc) * * @see org.jajuk.ui.actions.JajukAction#perform(java.awt.event.ActionEvent) */ @Override public void perform(ActionEvent e) throws Exception { super.perform(e); // If selection contains files, we have to show the tracks along with files if (selection.size() == 0) { Messages.showErrorMessage(142); return; } Item first = selection.get(0); if (first instanceof File) { List tracks = new ArrayList(selection.size()); for (Item file : selection) { // Ignore playlists that can be embedded for a device properties request if (file instanceof File) { tracks.add(((File) file).getTrack()); } } new PropertiesDialog(selection, tracks); } else if (first instanceof Track) { new PropertiesDialog(selection); } else if (first instanceof LogicalItem || first instanceof Directory) { // Artist, Album, Genre... : display the dual properties panel: one for // the item itself, the other with all tracks List tracks = TrackManager.getInstance().getAssociatedTracks(selection, false); List items = new ArrayList(tracks); new PropertiesDialog(selection, items); } else { // All others types: just display the properties window new PropertiesDialog(selection); } } }jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/actions/PushFrontSelectionAction.java0000644000175000017500000000432511720500104027663 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.actions; import java.awt.event.ActionEvent; import java.util.List; import org.jajuk.base.File; import org.jajuk.services.players.QueueModel; import org.jajuk.util.Conf; import org.jajuk.util.Const; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; import org.jajuk.util.UtilFeatures; /** * Push a selection *

    * Action emitter is responsible to ensure all items provided share the same * type *

    *

    * Selection data is provided using the swing properties DETAIL_SELECTION *

    . */ public class PushFrontSelectionAction extends SelectionAction { /** Generated serialVersionUID. */ private static final long serialVersionUID = -8078402652430413821L; /** * Instantiates a new push front selection action. */ PushFrontSelectionAction() { super(Messages.getString("TracksTableView.16"), IconLoader.getIcon(JajukIcons.PUSH), true); setShortDescription(Messages.getString("TracksTableView.16")); } /* * (non-Javadoc) * * @see org.jajuk.ui.actions.JajukAction#perform(java.awt.event.ActionEvent) */ @Override public void perform(ActionEvent e) throws Exception { super.perform(e); List files = UtilFeatures.getPlayableFiles(selection); QueueModel.push(UtilFeatures.createStackItems(UtilFeatures.applyPlayOption(files), Conf .getBoolean(Const.CONF_STATE_REPEAT_ALL), true), true, true); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/actions/PlayRepeatSelectionAction.java0000644000175000017500000000511111720500104027773 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.actions; import java.awt.event.ActionEvent; import java.util.List; import org.jajuk.base.File; import org.jajuk.services.players.QueueModel; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; import org.jajuk.util.UtilFeatures; import org.jajuk.util.UtilGUI; import org.jajuk.util.log.Log; /** * Play repeat a selection *

    * Action emitter is responsible to ensure all items provided share the same * type *

    *

    * Selection data is provided using the swing properties DETAIL_SELECTION *

    . */ public class PlayRepeatSelectionAction extends SelectionAction { /** Generated serialVersionUID. */ private static final long serialVersionUID = -8078402652430413821L; /** * Instantiates a new play repeat selection action. */ PlayRepeatSelectionAction() { super(Messages.getString("TracksTableView.10"), IconLoader.getIcon(JajukIcons.REPEAT), true); setShortDescription(Messages.getString("TracksTableView.10")); } /* * (non-Javadoc) * * @see org.jajuk.ui.actions.JajukAction#perform(java.awt.event.ActionEvent) */ @Override public void perform(final ActionEvent e) throws Exception { new Thread("PlayRepeatSelectionAction") { @Override public void run() { try { PlayRepeatSelectionAction.super.perform(e); List files = UtilFeatures.getPlayableFiles(selection); QueueModel.push(UtilFeatures.createStackItems(UtilFeatures.applyPlayOption(files), true, true), false); if (files.size() == 1) { UtilGUI.setRepeatSingleGui(true); } else { UtilGUI.setRepeatAllGui(true); } } catch (Exception e) { Log.error(e); } } }.start(); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/actions/TipOfTheDayAction.java0000644000175000017500000000321611720500104026203 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.actions; import java.awt.event.ActionEvent; import org.jajuk.ui.wizard.TipOfTheDayWizard; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; /** * Action for displaying the tip of the day. */ public class TipOfTheDayAction extends JajukAction { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** * Instantiates a new tip of the day action. */ TipOfTheDayAction() { super(Messages.getString("JajukJMenuBar.20"), IconLoader.getIcon(JajukIcons.TIP_SMALL), true); } /** * Invoked when an action occurs. * * @param evt DOCUMENT_ME */ @Override public void perform(ActionEvent evt) { TipOfTheDayWizard tipsView = new TipOfTheDayWizard(); tipsView.setLocationByPlatform(true); tipsView.setVisible(true); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/views/0000755000175000017500000000000011720500104021555 5ustar drazzibdrazzibjajuk-1.9.6.orig/src/main/java/org/jajuk/ui/views/FilesTableView.java0000644000175000017500000000666111720500104025276 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.views; import javax.swing.JMenuItem; import org.jajuk.ui.actions.ActionManager; import org.jajuk.ui.actions.JajukActions; import org.jajuk.ui.helpers.FilesTableModel; import org.jajuk.ui.helpers.JajukTableModel; import org.jajuk.ui.helpers.TwoStepsDisplayable; import org.jajuk.ui.widgets.JajukTable; import org.jajuk.util.Conf; import org.jajuk.util.Const; import org.jajuk.util.Messages; import org.jajuk.util.UtilGUI; /** * Logical table view. */ public class FilesTableView extends AbstractTableView implements TwoStepsDisplayable { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** DOCUMENT_ME. */ private JMenuItem jmiFilePlayDirectory; /** * Instantiates a new files table view. */ public FilesTableView() { super(); columnsConf = CONF_FILES_TABLE_COLUMNS; editableConf = CONF_FILES_TABLE_EDITION; } /* * (non-Javadoc) * * @see org.jajuk.ui.IView#getDesc() */ @Override public String getDesc() { return Messages.getString("FilesTableView.0"); } /* * (non-Javadoc) * * @see org.jajuk.ui.views.IView#initUI() */ @Override public void initUI() { UtilGUI.populate(this); } /* * (non-Javadoc) * * @see org.jajuk.ui.helpers.TwoStepsDisplayable#shortCall(java.lang.Object) */ @Override public void shortCall(Object in) { jtable = new JajukTable(model, true, columnsConf); super.shortCall(null); // File menu jmiFilePlayDirectory = new JMenuItem(ActionManager .getAction(JajukActions.PLAY_DIRECTORY_SELECTION)); jmiFilePlayDirectory.putClientProperty(Const.DETAIL_SELECTION, jtable.getSelection()); jtable.getMenu().add(jmiFilePlayDirectory, 4); // Add this generic menu item manually to ensure it's the last one in // the list for GUI reasons jtable.getMenu().addSeparator(); jtable.getMenu().add(pjmTracks); jtable.getMenu().add(jmiBookmark); jtable.getMenu().addSeparator(); jtable.getMenu().add(jmiProperties); } /* * (non-Javadoc) * * @see org.jajuk.ui.helpers.TwoStepsDisplayable#longCall() */ @Override public Object longCall() { super.longCall(); return null; } /** * populate the table. * * @return the jajuk table model */ @Override public synchronized JajukTableModel populateTable() { // model creation return new FilesTableModel(getID()); } /* * (non-Javadoc) * * @see org.jajuk.ui.views.AbstractTableView#initTable() */ @Override void initTable() { boolean bEditable = Conf.getBoolean(Const.CONF_FILES_TABLE_EDITION); jtbEditable.setSelected(bEditable); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/views/package.html0000644000175000017500000000013411720500104024034 0ustar drazzibdrazzib

    Interfaces and implementations of standard Jajuk views

    jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/views/CoverView.java0000644000175000017500000015123511720500104024340 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.views; import java.awt.Component; import java.awt.Dimension; import java.awt.Image; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.ComponentEvent; import java.awt.event.ComponentListener; import java.awt.event.MouseEvent; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.net.URL; import java.net.UnknownHostException; import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Properties; import java.util.Set; import javax.swing.BorderFactory; import javax.swing.ImageIcon; import javax.swing.JComboBox; import javax.swing.JFileChooser; import javax.swing.JLabel; import javax.swing.JList; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JToolBar; import javax.swing.SwingConstants; import javax.swing.SwingUtilities; import javax.swing.SwingWorker; import javax.swing.border.EmptyBorder; import javax.swing.plaf.basic.BasicComboBoxRenderer; import net.miginfocom.swing.MigLayout; import org.apache.commons.lang.StringUtils; import org.jajuk.base.Album; import org.jajuk.base.Artist; import org.jajuk.base.Directory; import org.jajuk.base.Track; import org.jajuk.events.JajukEvent; import org.jajuk.events.JajukEvents; import org.jajuk.events.ObservationManager; import org.jajuk.services.covers.Cover; import org.jajuk.services.covers.Cover.CoverType; import org.jajuk.services.players.QueueModel; import org.jajuk.services.players.StackItem; import org.jajuk.services.tags.Tag; import org.jajuk.ui.helpers.JajukMouseAdapter; import org.jajuk.ui.thumbnails.ThumbnailManager; import org.jajuk.ui.widgets.InformationJPanel; import org.jajuk.ui.widgets.JajukButton; import org.jajuk.ui.widgets.JajukFileChooser; import org.jajuk.ui.widgets.JajukJToolbar; import org.jajuk.ui.windows.JajukMainWindow; import org.jajuk.util.Conf; import org.jajuk.util.Const; import org.jajuk.util.DownloadManager; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukFileFilter; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; import org.jajuk.util.UtilFeatures; import org.jajuk.util.UtilGUI; import org.jajuk.util.UtilSystem; import org.jajuk.util.error.JajukException; import org.jajuk.util.filters.GIFFilter; import org.jajuk.util.filters.ImageFilter; import org.jajuk.util.filters.JPGFilter; import org.jajuk.util.filters.PNGFilter; import org.jajuk.util.log.Log; /** * Cover view. Displays an image for the current album * * All methods dealing with covers content must be synchronized. */ public class CoverView extends ViewAdapter implements ComponentListener, ActionListener { /** The Constant PLUS_QUOTE. DOCUMENT_ME */ private static final String PLUS_QUOTE = "+\""; /** The Constant QUOTE_BLANK. DOCUMENT_ME */ private static final String QUOTE_BLANK = "\" "; /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** No cover cover. */ private static Cover nocover; /** Error counter to check connection availability. */ private static int iErrorCounter = 0; /** Connected one flag : true if jajuk managed once to connect to the web to bring covers. */ private static boolean bOnceConnected = false; /** Reference File for cover. */ private org.jajuk.base.File fileReference; /** File directory used as a cache for perfs. */ private Directory dirReference; /** List of available covers for the current file. */ private final LinkedList alCovers = new LinkedList(); // NOPMD // control panel /** DOCUMENT_ME. */ private JPanel jpControl; /** DOCUMENT_ME. */ private JajukButton jbPrevious; /** DOCUMENT_ME. */ private JajukButton jbNext; /** DOCUMENT_ME. */ private JajukButton jbDelete; /** DOCUMENT_ME. */ private JajukButton jbSave; /** DOCUMENT_ME. */ private JajukButton jbDefault; /** DOCUMENT_ME. */ private JLabel jlSize; /** DOCUMENT_ME. */ private JLabel jlFound; /** DOCUMENT_ME. */ private JLabel jlSearching; /** Cover search accuracy combo. */ private JComboBox jcbAccuracy; /** Date last resize (used for adjustment management). */ private long lDateLastResize; /** URL and size of the image. */ private JLabel jl; /** Used Cover index. */ private int index = 0; /** Event ID. */ private volatile int iEventID; /** Flag telling that user wants to display a better cover. */ private boolean bGotoBetter = false; /** Final image to display. */ private ImageIcon ii; /** Force next track cover reload flag*. */ private boolean bForceCoverReload = true; /** DOCUMENT_ME. */ private boolean includeControls; /** Whether the view has not yet been displayed for its first time */ private boolean initEvent = true; /** Thread launch at view init to reset its state */ private class CoverResetThread extends Thread { @Override public void run() { if (fileReference == null) { // regular cover view if (QueueModel.isStopped()) { update(new JajukEvent(JajukEvents.ZERO)); } // check if a track has already been launched else if (QueueModel.isPlayingRadio()) { update(new JajukEvent(JajukEvents.WEBRADIO_LAUNCHED, ObservationManager.getDetailsLastOccurence(JajukEvents.WEBRADIO_LAUNCHED))); // If the view is displayed for the first time, a ComponentResized event is launched at its first display but // we want to perform the full process : update past launches files (FILE_LAUNCHED). // But if it is no more the initial resize event, we only want to refresh the cover, not the full story. } else if (!initEvent) { displayCurrentCover(); } else { update(new JajukEvent(JajukEvents.FILE_LAUNCHED)); } } else { // cover view used as dialog update(new JajukEvent(JajukEvents.COVER_NEED_REFRESH)); } // It will never more be the first time ... CoverView.this.initEvent = false; } } /** * Constructor. */ public CoverView() { super(); } /** * Constructor. * * @param file Reference file. Used to display cover for a particular file, null if the cover view is used in the "reular" way as a view, not * as a dialog from catalog view for ie. */ public CoverView(final org.jajuk.base.File file) { super(); fileReference = file; } /* * (non-Javadoc) * * @see org.jajuk.ui.views.IView#initUI() */ @Override public void initUI() { initUI(true); } /* * (non-Javadoc) * * @see org.jajuk.ui.IView#display() */ /** * Inits the ui. * * @param includeControls DOCUMENT_ME */ public void initUI(boolean includeControls) { this.includeControls = includeControls; // Control panel jlSearching = new JLabel("", IconLoader.getIcon(JajukIcons.NET_SEARCH), SwingConstants.CENTER); jpControl = new JPanel(); if (includeControls) { jpControl.setBorder(BorderFactory.createEtchedBorder()); } final JToolBar jtb = new JajukJToolbar(); jbPrevious = new JajukButton(IconLoader.getIcon(JajukIcons.PLAYER_PREVIOUS_SMALL)); jbPrevious.addActionListener(this); jbPrevious.setToolTipText(Messages.getString("CoverView.4")); jbNext = new JajukButton(IconLoader.getIcon(JajukIcons.PLAYER_NEXT_SMALL)); jbNext.addActionListener(this); jbNext.setToolTipText(Messages.getString("CoverView.5")); jbDelete = new JajukButton(IconLoader.getIcon(JajukIcons.DELETE)); jbDelete.addActionListener(this); jbDelete.setToolTipText(Messages.getString("CoverView.2")); jbSave = new JajukButton(IconLoader.getIcon(JajukIcons.SAVE)); jbSave.addActionListener(this); jbSave.setToolTipText(Messages.getString("CoverView.6")); jbDefault = new JajukButton(IconLoader.getIcon(JajukIcons.DEFAULT_COVER)); jbDefault.addActionListener(this); jbDefault.setToolTipText(Messages.getString("CoverView.8")); jlSize = new JLabel(""); jlFound = new JLabel(""); jcbAccuracy = new JComboBox(); // Add tooltips on combo items jcbAccuracy.setRenderer(new BasicComboBoxRenderer() { private static final long serialVersionUID = -6943363556191659895L; @Override public Component getListCellRendererComponent(final JList list, final Object value, final int index, final boolean isSelected, final boolean cellHasFocus) { super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); switch (index) { case 0: setToolTipText(Messages.getString("ParameterView.156")); break; case 1: setToolTipText(Messages.getString("ParameterView.157")); break; case 2: setToolTipText(Messages.getString("ParameterView.158")); break; case 3: setToolTipText(Messages.getString("ParameterView.216")); break; case 4: setToolTipText(Messages.getString("ParameterView.217")); break; case 5: setToolTipText(Messages.getString("ParameterView.218")); break; } setBorder(new EmptyBorder(0, 3, 0, 3)); return this; } }); jcbAccuracy.setToolTipText(Messages.getString("ParameterView.155")); jcbAccuracy.addItem(IconLoader.getIcon(JajukIcons.ACCURACY_LOW)); jcbAccuracy.addItem(IconLoader.getIcon(JajukIcons.ACCURACY_MEDIUM)); jcbAccuracy.addItem(IconLoader.getIcon(JajukIcons.ACCURACY_HIGH)); jcbAccuracy.addItem(IconLoader.getIcon(JajukIcons.ARTIST)); jcbAccuracy.addItem(IconLoader.getIcon(JajukIcons.ALBUM)); jcbAccuracy.addItem(IconLoader.getIcon(JajukIcons.TRACK)); int i = 1; // medium accuracy try { i = Conf.getInt(Const.CONF_COVERS_ACCURACY + "_" + ((getPerspective() == null) ? "popup" : getPerspective().getID())); } catch (final NumberFormatException e) { // Will reach this point at first launch } jcbAccuracy.setSelectedIndex(i); jcbAccuracy.addActionListener(this); jtb.add(jbPrevious); jtb.add(jbNext); jtb.addSeparator(); jtb.add(jbDelete); jtb.add(jbSave); jtb.add(jbDefault); if (includeControls) { jpControl.setLayout(new MigLayout("insets 5 2 5 2", "[][grow][grow][][25]")); jpControl.add(jtb); jpControl.add(jlSize, "center,gapright 5::"); jpControl.add(jlFound, "center,gapright 5::"); jpControl.add(jcbAccuracy, "grow,width 47!,gapright 5"); jpControl.add(jlSearching); } // Cover view used in catalog view should not listen events if (fileReference == null) { ObservationManager.register(this); } try { // instantiate default cover if (CoverView.nocover == null) { CoverView.nocover = new Cover(Const.IMAGES_SPLASHSCREEN, CoverType.NO_COVER); } } catch (final Exception e) { Log.error(e); } // global layout MigLayout globalLayout = null; if (includeControls) { globalLayout = new MigLayout("ins 0,gapy 10", "[grow]", "[30!][grow]"); } else { globalLayout = new MigLayout("ins 0,gapy 10", "[grow]", "[grow]"); } setLayout(globalLayout); add(jpControl, "grow,wrap"); // We have to start using the componentListener AFTER the view is fully displayed // to avoid blank covers due to wrong (negative) cover dimensions. new Thread() { public void run() { try { Thread.sleep(1000); } catch (InterruptedException e) { Log.error(e); } // Force a init event as the ComponentListener was not yet attached to the view. componentResized(null); // Attach the listener for further manual actions against the view. addComponentListener(CoverView.this); } }.start(); } /* * (non-Javadoc) * * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent) */ @Override public void actionPerformed(final ActionEvent e) { if (e.getSource() == jcbAccuracy) { handleAccuracy(); } else if (e.getSource() == jbPrevious) { // previous : show a handlePrevious(); } else if (e.getSource() == jbNext) { // next : show a worse cover handleNext(); } else if (e.getSource() == jbDelete) { // delete a local cover handleDelete(); } else if (e.getSource() == jbDefault) { handleDefault(); } else if ((e.getSource() == jbSave) && ((e.getModifiers() & ActionEvent.CTRL_MASK) == ActionEvent.CTRL_MASK)) { // save a file as... (can be local now) handleSaveAs(); } else if (e.getSource() == jbSave) { handleSave(); } } /** * Stores accuracy. */ private void handleAccuracy() { // Note that we have to store/retrieve accuracy using an id. When // this view is used from a popup, we can't use perspective id Conf.setProperty(Const.CONF_COVERS_ACCURACY + "_" + ((getPerspective() == null) ? "popup" : getPerspective().getID()), Integer.toString(jcbAccuracy.getSelectedIndex())); new Thread("Cover Accuracy Thread") { @Override public void run() { // force refresh if (getPerspective() == null) { dirReference = null; } update(new JajukEvent(JajukEvents.COVER_NEED_REFRESH)); } }.start(); } /** * Called on the previous cover button event. */ private synchronized void handlePrevious() { // better cover bGotoBetter = true; index++; if (index > alCovers.size() - 1) { index = 0; } displayCurrentCover(); bGotoBetter = false; // make sure default behavior is to go // to worse covers } /** * Called on the next cover button event. */ private synchronized void handleNext() { bGotoBetter = false; index--; if (index < 0) { index = alCovers.size() - 1; } displayCurrentCover(); } /** * Called on the delete cover button event. */ private synchronized void handleDelete() { // sanity check if (index >= alCovers.size()) { Log.warn("Cannot delete cover that is not available."); return; } if (index < 0) { Log.warn("Cannot delete cover with invalid index."); return; } // get the cover at the specified position final Cover cover = alCovers.get(index); // don't delete the splashscreen-jpg!! if (cover.getType().equals(CoverType.NO_COVER)) { Log.warn("Cannot delete default Jajuk cover."); return; } // show confirmation message if required if (Conf.getBoolean(Const.CONF_CONFIRMATIONS_DELETE_COVER)) { final int iResu = Messages.getChoice(Messages.getString("Confirmation_delete_cover") + " : " + cover.getFile(), JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE); if (iResu != JOptionPane.YES_OPTION) { return; } } // yet there? ok, delete the cover try { final File file = cover.getFile(); if (file.isFile() && file.exists()) { UtilSystem.deleteFile(file); } else { // not a file, must have a problem throw new Exception("Encountered file which either is not a file or does not exist: " + file); } } catch (final Exception ioe) { Log.error(131, ioe); Messages.showErrorMessage(131); return; } // If this was the absolute cover, remove the reference in the // collection if (cover.getType() == CoverType.SELECTED_COVER) { dirReference.removeProperty("default_cover"); } // reorganize covers alCovers.remove(index); index--; if (index < 0) { index = alCovers.size() - 1; } ObservationManager.notify(new JajukEvent(JajukEvents.COVER_NEED_REFRESH)); if (fileReference != null) { update(new JajukEvent(JajukEvents.COVER_NEED_REFRESH)); } } /** * Called when saving a cover. */ private synchronized void handleSave() { // sanity check if (index >= alCovers.size()) { Log.warn("Cannot save cover that is not available."); return; } if (index < 0) { Log.warn("Cannot save cover with invalid index."); return; } // save a file with its original name new Thread("Cover Save Thread") { @Override public void run() { synchronized (CoverView.this) { final Cover cover = alCovers.get(index); // should not happen, only remote covers here if (cover.getType() != CoverType.REMOTE_COVER) { Log.debug("Try to save a local cover"); return; } String sFilePath = null; sFilePath = dirReference.getFio().getPath() + "/" + UtilSystem.getOnlyFile(cover.getURL().toString()); sFilePath = convertCoverPath(sFilePath); try { // copy file from cache final File fSource = DownloadManager.downloadToCache(cover.getURL()); final File file = new File(sFilePath); UtilSystem.copy(fSource, file); InformationJPanel.getInstance().setMessage(Messages.getString("CoverView.11"), InformationJPanel.MessageType.INFORMATIVE); final Cover cover2 = new Cover(file, CoverType.SELECTED_COVER); if (!alCovers.contains(cover2)) { alCovers.add(cover2); setFoundText(); } // Reset cached cover in associated albums to make sure that new covers // will be discovered in various views like Catalog View. resetCachedCover(); // Notify cover change ObservationManager.notify(new JajukEvent(JajukEvents.COVER_NEED_REFRESH)); // add new cover in others cover views } catch (final Exception ex) { Log.error(24, ex); Messages.showErrorMessage(24); } } } }.start(); } /** * Reset cached cover in associated albums to make sure that new covers * will be discovered in various views like Catalog View. */ private synchronized void resetCachedCover() { org.jajuk.base.File fCurrent = fileReference; if (fCurrent == null) { fCurrent = QueueModel.getPlayingFile(); } Set albums = fCurrent.getDirectory().getAlbums(); // If we cached NO_COVER for this album, make sure to reset this value for (Album album : albums) { String cachedCoverPath = album.getStringValue(XML_ALBUM_DISCOVERED_COVER); if (COVER_NONE.equals(cachedCoverPath)) { album.setProperty(XML_ALBUM_DISCOVERED_COVER, ""); } ObservationManager.notify(new JajukEvent(JajukEvents.COVER_DEFAULT_CHANGED)); } } /** * Converts a cover path according to options and jajuk conventions * * @param sFilePath current cover path * * @return the converted cover file path */ private String convertCoverPath(String sFilePath) { int pos = sFilePath.lastIndexOf('.'); if (Conf.getBoolean(Const.CONF_COVERS_SAVE_EXPLORER_FRIENDLY)) { // Covers should be stored as folder.xxx for windows explorer String ext = sFilePath.substring(pos, sFilePath.length()); String parent = new File(sFilePath).getParent(); return parent + System.getProperty("file.separator") + "Folder" + ext; } else { // Add a jajuk suffix to know this cover has been downloaded by jajuk return new StringBuilder(sFilePath).insert(pos, Const.FILE_JAJUK_DOWNLOADED_FILES_SUFFIX) .toString(); } } /** * Called when saving as a cover. */ private synchronized void handleSaveAs() { // sanity check if (index >= alCovers.size()) { Log.warn("Cannot save cover that is not available."); return; } if (index < 0) { Log.warn("Cannot save cover with invalid index."); return; } new Thread("Cover SaveAs Thread") { @Override public void run() { synchronized (CoverView.this) { final Cover cover = alCovers.get(index); final JajukFileChooser jfchooser = new JajukFileChooser(new JajukFileFilter( GIFFilter.getInstance(), PNGFilter.getInstance(), JPGFilter.getInstance())); jfchooser.setAcceptDirectories(true); jfchooser.setCurrentDirectory(dirReference.getFio()); jfchooser.setDialogTitle(Messages.getString("CoverView.10")); final File finalFile = new File(dirReference.getFio().getPath() + "/" + UtilSystem.getOnlyFile(cover.getURL().toString())); jfchooser.setSelectedFile(finalFile); final int returnVal = jfchooser.showSaveDialog(JajukMainWindow.getInstance()); File fNew = null; if (returnVal == JFileChooser.APPROVE_OPTION) { fNew = jfchooser.getSelectedFile(); // if user try to save as without changing file name if (fNew.getAbsolutePath().equals(cover.getFile().getAbsolutePath())) { return; } try { UtilSystem.copy(cover.getFile(), fNew); InformationJPanel.getInstance().setMessage(Messages.getString("CoverView.11"), InformationJPanel.MessageType.INFORMATIVE); // Reset cached cover in associated albums to make sure that new covers // will be discovered in various views like Catalog View. resetCachedCover(); // Notify cover change ObservationManager.notify(new JajukEvent(JajukEvents.COVER_NEED_REFRESH)); } catch (final Exception ex) { Log.error(24, ex); Messages.showErrorMessage(24); } } } } }.start(); } /** * Called when making a cover default. */ private synchronized void handleDefault() { // sanity check if (index >= alCovers.size()) { Log.warn("Cannot default cover which is not available."); return; } if (index < 0) { Log.warn("Cannot default cover with invalid index."); return; } new Thread("Default cover thread") { public void run() { synchronized (CoverView.this) { Cover cover = alCovers.get(index); org.jajuk.base.File fCurrent = fileReference; // Path of the default cover, it is simply the URL of the current cover for local covers // but it is another path to a newly created image for tag or remote covers String destPath = cover.getFile().getAbsolutePath(); if (fCurrent == null) { fCurrent = QueueModel.getPlayingFile(); } if (cover.getType() == CoverType.TAG_COVER) { destPath = dirReference.getFio().getPath() + "/" + cover.getFile().getName(); destPath = convertCoverPath(destPath); File destFile = new File(destPath); try { // Copy cached file to music directory // Note that the refreshCover() methods automatically // extract any track cover tag to an image file in the cache UtilSystem.copy(cover.getFile(), destFile); Cover cover2 = new Cover(destFile, CoverType.SELECTED_COVER); alCovers.add(cover2); } catch (Exception ex) { Log.error(24, ex); Messages.showErrorMessage(24); return; } } else if (cover.getType() == CoverType.REMOTE_COVER) { String sFilename = UtilSystem.getOnlyFile(cover.getURL().toString()); destPath = dirReference.getFio().getPath() + "/" + sFilename; destPath = convertCoverPath(destPath); try { // Download cover and copy file from cache to music directory File fSource = DownloadManager.downloadToCache(cover.getURL()); File fileDest = new File(destPath); UtilSystem.copy(fSource, new File(destPath)); Cover cover2 = new Cover(fileDest, CoverType.SELECTED_COVER); if (!alCovers.contains(cover2)) { alCovers.add(cover2); setFoundText(); } } catch (Exception ex) { Log.error(24, ex); Messages.showErrorMessage(24); return; } } // Remove previous thumbs to avoid using outdated images // Reset cached cover ThumbnailManager.cleanThumbs(fCurrent.getTrack().getAlbum()); refreshThumbs(cover); InformationJPanel.getInstance().setMessage(Messages.getString("Success"), InformationJPanel.MessageType.INFORMATIVE); // For every kind of cover types : ObservationManager.notify(new JajukEvent(JajukEvents.COVER_DEFAULT_CHANGED)); ObservationManager.notify(new JajukEvent(JajukEvents.COVER_NEED_REFRESH)); // then make it the default cover for this album if (fCurrent != null && fCurrent.getTrack() != null && fCurrent.getTrack().getAlbum() != null && cover.getFile() != null) { Album album = fCurrent.getTrack().getAlbum(); album.setProperty(XML_ALBUM_SELECTED_COVER, destPath); album.setProperty(XML_ALBUM_DISCOVERED_COVER, destPath); } } } }.start(); } /* * (non-Javadoc) * * @see java.awt.event.ComponentListener#componentResized(java.awt.event.ComponentEvent ) */ @Override public void componentResized(final ComponentEvent e) { final long lCurrentDate = System.currentTimeMillis(); // adjusting code if (lCurrentDate - lDateLastResize < 500) { // Do consider only one event every // 500 ms to avoid race conditions and lead to unexpected states (verified) lDateLastResize = lCurrentDate; return; } lDateLastResize = lCurrentDate; Log.debug("Cover resized"); // Force initial cover refresh. We do this inside this method and not initUI() // because we make sure that the window is fully displayed then (otherwise, we get // a black cover when switching from slimbar to main window for ie) CoverResetThread refresh = new CoverResetThread(); refresh.start(); } /** * Creates the query. * * @param file DOCUMENT_ME * * @return an accurate google search query for a file */ public String createQuery(final org.jajuk.base.File file) { String sQuery = ""; int iAccuracy = 0; try { iAccuracy = Conf.getInt(Const.CONF_COVERS_ACCURACY + "_" + ((getPerspective() == null) ? "popup" : getPerspective().getID())); } catch (final NumberFormatException e) { // can append if accuracy never set Log.debug("Unknown accuracy"); } final Track track = file.getTrack(); final Artist artist = track.getArtist(); final Album album = track.getAlbum(); switch (iAccuracy) { case 0: // low, default if (!artist.seemsUnknown()) { sQuery += artist.getName() + " "; } if (!album.seemsUnknown()) { sQuery += album.getName() + " "; } break; case 1: // medium if (!artist.seemsUnknown()) { sQuery += '\"' + artist.getName() + QUOTE_BLANK; // put quotes around it } if (!album.seemsUnknown()) { sQuery += '\"' + album.getName() + QUOTE_BLANK; } break; case 2: // high if (!artist.seemsUnknown()) { sQuery += PLUS_QUOTE + artist.getName() + QUOTE_BLANK; // put "" around it } if (!album.seemsUnknown()) { sQuery += PLUS_QUOTE + album.getName() + QUOTE_BLANK; } break; case 3: // by artist if (!artist.seemsUnknown()) { sQuery += artist.getName() + " "; } break; case 4: // by album if (!album.seemsUnknown()) { sQuery += album.getName() + " "; } break; case 5: // by track name sQuery += track.getName(); break; default: break; } return sQuery; } /** * Display given cover. * * @param index index of the cover to display */ private synchronized void displayCover(final int index) { if ((alCovers.size() == 0) || (index >= alCovers.size()) || (index < 0)) { // just a check alCovers.add(CoverView.nocover); // display nocover by default displayCover(0); return; } final Cover cover = alCovers.get(index); // take image at the given index final URL url = cover.getURL(); // enable delete button only for local covers jbDelete.setEnabled(cover.getType() == CoverType.LOCAL_COVER || cover.getType() == CoverType.SELECTED_COVER || cover.getType() == CoverType.STANDARD_COVER); //Disable default command for "none" cover jbDefault.setEnabled(cover.getType() != CoverType.NO_COVER); if (url != null) { jbSave.setEnabled(false); String sType = " (L)"; // local cover if (cover.getType() == CoverType.REMOTE_COVER) { sType = "(@)"; // Web cover jbSave.setEnabled(true); } else if (cover.getType() == CoverType.TAG_COVER) { sType = "(T)"; // Tag cover } final String size = cover.getSize(); jl = new JLabel(ii); jl.setMinimumSize(new Dimension(0, 0)); // required for info // node resizing if (cover.getType() == CoverType.TAG_COVER) { jl.setToolTipText("Tag
    " + size + "K"); } else { jl.setToolTipText("" + url.toString() + "
    " + size + "K"); } setSizeText(size + "K" + sType); setFoundText(); } // set tooltip for previous and next track try { int indexPrevious = index + 1; if (indexPrevious > alCovers.size() - 1) { indexPrevious = 0; } final URL urlPrevious = alCovers.get(indexPrevious).getURL(); if (urlPrevious != null) { jbPrevious.setToolTipText("" + Messages.getString("CoverView.4") + "
    " + urlPrevious.toString() + ""); } int indexNext = index - 1; if (indexNext < 0) { indexNext = alCovers.size() - 1; } final URL urlNext = alCovers.get(indexNext).getURL(); if (urlNext != null) { jbNext.setToolTipText("" + Messages.getString("CoverView.5") + "
    " + urlNext.toString() + ""); } } catch (final Exception e) { // the url code can throw out of bounds // exception for unknown reasons so check it Log.debug("jl=" + jl + " url={{" + url + "}}"); Log.error(e); } if (getComponentCount() > 0) { removeAll(); } if (includeControls) { add(jpControl, "grow,wrap"); } // Invert the mirrow option when clicking on the cover jl.addMouseListener(new JajukMouseAdapter() { @Override public void mousePressed(MouseEvent e) { boolean isMirrowed = Conf.getBoolean(Const.CONF_COVERS_MIRROW_COVER); Conf.setProperty(Const.CONF_COVERS_MIRROW_COVER, !isMirrowed + ""); ObservationManager.notify(new JajukEvent(JajukEvents.COVER_NEED_REFRESH)); } }); add(jl, "center,wrap"); // make sure the image is repainted to avoid overlapping covers CoverView.this.revalidate(); CoverView.this.repaint(); searching(false); } /** * Display current cover (at this.index), try all covers in case of error */ private void displayCurrentCover() { SwingWorker sw = new SwingWorker() { @Override public Void doInBackground() { synchronized (CoverView.this) { // Avoid looping if (alCovers.size() == 0) { // should not append alCovers.add(CoverView.nocover); // Add at last the default cover if all remote cover has // been discarded try { prepareDisplay(0); } catch (JajukException e) { Log.error(e); } return null; } if ((alCovers.size() == 1) && ((alCovers.get(0)).getType() == CoverType.NO_COVER)) { // only a default cover try { prepareDisplay(0); } catch (JajukException e) { Log.error(e); } return null; } // else, there is at least one local cover and no // default cover while (alCovers.size() > 0) { try { prepareDisplay(index); return null; // OK, leave } catch (Exception e) { Log.debug("Removed cover: {{" + alCovers.get(index) + "}}"); alCovers.remove(index); // refresh number of found covers if (!bGotoBetter) { // we go to worse covers. If we go to better // covers, we just // keep the same index try a worse cover... if (index - 1 >= 0) { index--; } else { // no more worse cover index = alCovers.size() - 1; // come back to best cover } } } } // if this code is executed, it means than no available // cover was found, then display default cover alCovers.add(CoverView.nocover); // Add at last the default cover // if all remote cover has been discarded try { index = 0; prepareDisplay(index); } catch (JajukException e) { Log.error(e); } } return null; } @Override public void done() { displayCover(index); } }; sw.execute(); } /** * Gets the cover number. * * @return number of real covers (not default) covers found */ private synchronized int getCoverNumber() { return alCovers.size(); } /* * (non-Javadoc) * * @see org.jajuk.ui.IView#getDesc() */ @Override public String getDesc() { return Messages.getString("CoverView.3"); } /* * (non-Javadoc) * * @see org.jajuk.events.Observer#getRegistrationKeys() */ @Override public Set getRegistrationKeys() { final Set eventSubjectSet = new HashSet(); eventSubjectSet.add(JajukEvents.FILE_LAUNCHED); eventSubjectSet.add(JajukEvents.WEBRADIO_LAUNCHED); eventSubjectSet.add(JajukEvents.ZERO); eventSubjectSet.add(JajukEvents.PLAYER_STOP); eventSubjectSet.add(JajukEvents.COVER_NEED_REFRESH); return eventSubjectSet; } /** * Long action to compute image to display (download, resizing...) * * @param index DOCUMENT_ME * * @return null (just used by the SwingWorker) * * @throws JajukException the jajuk exception */ private Object prepareDisplay(final int index) throws JajukException { final int iLocalEventID = iEventID; Log.debug("display index: " + index); searching(true); // lookup icon // find next correct cover ImageIcon icon = null; Cover cover = null; try { if (iEventID == iLocalEventID) { cover = alCovers.get(index); // take image at the given index Image img = cover.getImage(); if (!Conf.getBoolean(Const.CONF_COVERS_MIRROW_COVER) || cover.getType().equals(CoverType.NO_COVER)) { icon = new ImageIcon(img); } else { icon = new ImageIcon(UtilGUI.get3dImage(img)); } if (icon.getIconHeight() == 0 || icon.getIconWidth() == 0) { throw new JajukException(0, "Wrong picture, size is null"); } } else { Log.debug("Download stopped - 2"); return null; } } catch (final FileNotFoundException e) { setCursor(UtilGUI.DEFAULT_CURSOR); searching(false); // do not display a stacktrace for FileNotfound as we expect this in cases // where the picture is gone on the net Log.warn("Cover image not found at URL: " + (cover == null ? "" : cover.getURL().toString())); return null; } catch (final UnknownHostException e) { setCursor(UtilGUI.DEFAULT_CURSOR); searching(false); // do not display a stacktrace for HostNotFound as we expect this in cases // where the whole server is gone on the net Log.warn("Cover image not found at URL: " + (cover == null ? "" : cover.getURL().toString())); return null; } catch (final IOException e) { // this cover cannot be loaded setCursor(UtilGUI.DEFAULT_CURSOR); searching(false); Log.error(e); throw new JajukException(0, e); } catch (final InterruptedException e) { // this cover cannot be loaded setCursor(UtilGUI.DEFAULT_CURSOR); searching(false); Log.error(e); throw new JajukException(0, e); } // We apply a 90% of space availability to avoid image cut-offs (see #1283) final int iDisplayAreaHeight = (int) (0.9f * CoverView.this.getHeight() - 30); final int iDisplayAreaWidth = (int) (0.9f * CoverView.this.getWidth() - 10); // check minimum sizes if ((iDisplayAreaHeight < 1) || (iDisplayAreaWidth < 1)) { return null; } int iNewWidth; int iNewHeight; if (iDisplayAreaHeight > iDisplayAreaWidth) { // Width is smaller than height : try to optimize height iNewHeight = iDisplayAreaHeight; // take all possible height // we check now if width will be visible entirely with optimized // height final float fHeightRatio = (float) iNewHeight / icon.getIconHeight(); if (icon.getIconWidth() * fHeightRatio <= iDisplayAreaWidth) { iNewWidth = (int) (icon.getIconWidth() * fHeightRatio); } else { // no? so we optimize width iNewWidth = iDisplayAreaWidth; iNewHeight = (int) (icon.getIconHeight() * ((float) iNewWidth / icon.getIconWidth())); } } else { // Height is smaller or equal than width : try to optimize width iNewWidth = iDisplayAreaWidth; // take all possible width // we check now if height will be visible entirely with // optimized width final float fWidthRatio = (float) iNewWidth / icon.getIconWidth(); if (icon.getIconHeight() * fWidthRatio <= iDisplayAreaHeight) { iNewHeight = (int) (icon.getIconHeight() * fWidthRatio); } else { // no? so we optimize width iNewHeight = iDisplayAreaHeight; iNewWidth = (int) (icon.getIconWidth() * ((float) iNewHeight / icon.getIconHeight())); } } if (iEventID == iLocalEventID) { // Note that at this point, the image is fully loaded (done in the ImageIcon constructor) ii = UtilGUI.getResizedImage(icon, iNewWidth, iNewHeight); // Free source and destination image buffer, see // http://forums.sun.com/thread.jspa?threadID=5424304&tstart=60 icon.getImage().flush(); ii.getImage().flush(); } else { Log.debug("Download stopped - 2"); return null; } return null; } /** * Refresh default cover thumb (used in catalog view). * * @param cover DOCUMENT_ME */ private void refreshThumbs(final Cover cover) { if (dirReference == null) { Log.warn("Cannot refresh thumbnails without reference directory"); return; } // refresh thumbs try { for (int size = 50; size <= 300; size += 50) { final Album album = dirReference.getFiles().iterator().next().getTrack().getAlbum(); final File fThumb = ThumbnailManager.getThumbBySize(album, size); ThumbnailManager.createThumbnail(cover.getFile(), fThumb, size); } } catch (final InterruptedException ex) { Log.error(24, ex); } catch (final IOException ex) { Log.error(24, ex); } catch (final RuntimeException ex) { Log.error(24, ex); } } /** * Display or hide search icon. * * @param bSearching DOCUMENT_ME */ public void searching(final boolean bSearching) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { if (bSearching) { jlSearching.setIcon(IconLoader.getIcon(JajukIcons.NET_SEARCH)); } else { jlSearching.setIcon(null); } } }); } /** * Set the cover Found text. */ private void setFoundText() { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { // make sure not to display negative indexes int i = getCoverNumber() - index; if (i < 0) { Log.debug("Negative cover index: " + i); i = 0; } jlFound.setText(i + "/" + getCoverNumber()); } }); } /** * Set the cover Found text. * * @param sFound specified text */ private void setFoundText(final String sFound) { if (sFound != null) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { jlFound.setText(sFound); } }); } } /** * Set the cover size text. * * @param sSize DOCUMENT_ME */ private void setSizeText(final String sSize) { if (sSize != null) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { jlSize.setText(sSize); } }); } } /** * Gets the current image. * * @return the current image * * @throws IOException Signals that an I/O exception has occurred. * @throws InterruptedException the interrupted exception * @throws JajukException the jajuk exception */ public Image getCurrentImage() throws IOException, InterruptedException, JajukException { if (alCovers.size() > 0) { return alCovers.get(0).getImage(); } return CoverView.nocover.getImage(); } /* * (non-Javadoc) * * @see org.jajuk.ui.Observer#update(java.lang.String) */ @Override public void update(final JajukEvent event) { final JajukEvents subject = event.getSubject(); iEventID = (int) (Integer.MAX_VALUE * Math.random()); final int iLocalEventID = iEventID; try { searching(true); // When receiving this event, check if we should change the cover or // not // (we don't change cover if playing another track of the same album // except if option shuffle cover is set) if (JajukEvents.FILE_LAUNCHED.equals(subject)) { updateFileLaunched(event, iLocalEventID); } else if (JajukEvents.ZERO.equals(subject) || JajukEvents.WEBRADIO_LAUNCHED.equals(subject) || JajukEvents.PLAYER_STOP.equals(subject)) { updateStopOrWebRadioLaunched(); } else if (JajukEvents.COVER_NEED_REFRESH.equals(subject)) { refreshCovers(iLocalEventID, true); } } catch (final IOException e) { Log.error(e); } finally { searching(false); // hide searching icon } } /** * Update stop or web radio launched. * DOCUMENT_ME */ private synchronized void updateStopOrWebRadioLaunched() { // Ignore this event if a reference file has been set if (fileReference != null) { return; } setFoundText(""); setSizeText(""); alCovers.clear(); alCovers.add(CoverView.nocover); // add the default cover index = 0; displayCurrentCover(); dirReference = null; // Force cover to reload at next track bForceCoverReload = true; // disable commands enableCommands(false); } /** * Update file launched. * * @param event DOCUMENT_ME * @param iLocalEventID DOCUMENT_ME * * @throws IOException Signals that an I/O exception has occurred. */ private synchronized void updateFileLaunched(final JajukEvent event, final int iLocalEventID) throws IOException { org.jajuk.base.File last = null; Properties details = event.getDetails(); if (details != null) { StackItem item = (StackItem) details.get(Const.DETAIL_OLD); if (item != null) { last = item.getFile(); } } // Ignore this event if a reference file has been set and if // this event has already been handled if ((fileReference != null) && (dirReference != null)) { return; } // if we are always in the same directory, just leave to // save cpu boolean dirChanged = last == null ? true : !last.getDirectory().equals( QueueModel.getPlayingFile().getDirectory()); if (bForceCoverReload) { dirChanged = true; } refreshCovers(iLocalEventID, dirChanged); if (Conf.getBoolean(Const.CONF_COVERS_SHUFFLE)) { // Ignore this event if a reference file has been set if (fileReference != null) { return; } // choose a random cover index = (int) (Math.random() * alCovers.size() - 1); displayCurrentCover(); } enableCommands(true); } /** * Convenient method to massively enable/disable this view buttons. * * @param enable DOCUMENT_ME */ private void enableCommands(final boolean enable) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { jcbAccuracy.setEnabled(enable); jbDefault.setEnabled(enable); jbDelete.setEnabled(enable); jbNext.setEnabled(enable); jbPrevious.setEnabled(enable); jbSave.setEnabled(enable); jlFound.setVisible(enable); jlSize.setVisible(enable); } }); } /** * Covers refreshing effective code *

    * Must be called outside the EDT, contains network access *

    . * * @param iLocalEventID DOCUMENT_ME * @param dirChanged DOCUMENT_ME * * @throws IOException Signals that an I/O exception has occurred. */ private synchronized void refreshCovers(int iLocalEventID, boolean dirChanged) throws IOException { // Reset this flag bForceCoverReload = false; org.jajuk.base.File fCurrent = fileReference; // check if a file has been given for this cover view // if not, take current cover if (fCurrent == null) { fCurrent = QueueModel.getPlayingFile(); } // no current cover if (fCurrent == null) { dirReference = null; } else { // store this dir dirReference = fCurrent.getDirectory(); } if (dirReference == null) { alCovers.clear(); alCovers.add(CoverView.nocover); index = 0; displayCurrentCover(); return; } if (fCurrent == null) { throw new IllegalArgumentException("Internal Error: Unexpected value, " + "variable fCurrent should not be empty. dirReference: " + dirReference); } // We only need to refresh the other covers if the directory changed // but we still clear tag-based covers even if directory didn't change // so the song-specific tag is token into account. Iterator it = alCovers.iterator(); while (it.hasNext()) { Cover cover = it.next(); if (cover.getType() == CoverType.TAG_COVER) { it.remove(); } } if (dirChanged) { // remove all existing covers alCovers.clear(); // Search for local covers in all directories mapping // the current track to reach other devices covers and // display them together final Track trackCurrent = fCurrent.getTrack(); final List alFiles = trackCurrent.getFiles(); // Add any selected default cover String defaultCoverPath = trackCurrent.getAlbum().getStringValue(XML_ALBUM_SELECTED_COVER); if (StringUtils.isNotBlank(defaultCoverPath)) { File coverFile = new File(defaultCoverPath); if (coverFile.exists()) { final Cover cover = new Cover(coverFile, CoverType.SELECTED_COVER); // Avoid dups if (!alCovers.contains(cover)) { alCovers.add(cover); } } } // list of files mapping the track for (final org.jajuk.base.File file : alFiles) { final Directory dirScanned = file.getDirectory(); if (!dirScanned.getDevice().isMounted()) { // if the device is not ready, just ignore it continue; } // Now search for regular or standard local covers // null if none file found final java.io.File[] files = dirScanned.getFio().listFiles(); for (int i = 0; (files != null) && (i < files.length); i++) { // check size to avoid out of memory errors if (files[i].length() > Const.MAX_COVER_SIZE * 1024) { continue; } final JajukFileFilter filter = ImageFilter.getInstance(); if (filter.accept(files[i])) { Cover cover = null; if (UtilFeatures.isStandardCover(files[i])) { cover = new Cover(files[i], CoverType.STANDARD_COVER); } else { cover = new Cover(files[i], CoverType.LOCAL_COVER); } if (!alCovers.contains(cover)) { alCovers.add(cover); } } } } // Then we search for web covers online if max // connection errors number is not reached or if user // already managed to connect. // We also drop the query if user required none internet access if (Conf.getBoolean(Const.CONF_COVERS_AUTO_COVER) && !Conf.getBoolean(Const.CONF_NETWORK_NONE_INTERNET_ACCESS) && (CoverView.bOnceConnected || (CoverView.iErrorCounter < Const.STOP_TO_SEARCH))) { try { final String sQuery = createQuery(fCurrent); Log.debug("Query={{" + sQuery + "}}"); if (!sQuery.isEmpty()) { // there is not enough information in tags // for a web search List alUrls; alUrls = DownloadManager.getRemoteCoversList(sQuery); CoverView.bOnceConnected = true; // user managed once to connect to the web if (alUrls.size() > Const.MAX_REMOTE_COVERS) { // limit number of remote covers alUrls = new ArrayList(alUrls.subList(0, Const.MAX_REMOTE_COVERS)); } Collections.reverse(alUrls); // set best results to be displayed first final Iterator it2 = alUrls.iterator(); // add found covers while (it2.hasNext() && (iEventID == iLocalEventID)) { // load each cover (pre-load or post-load) // and stop if a signal has been emitted final URL url = it2.next(); final Cover cover = new Cover(url, CoverType.REMOTE_COVER); // Create a cover with given url ( image // will be really downloaded when // required if no preload) if (!alCovers.contains(cover)) { Log.debug("Found Cover: {{" + url.toString() + "}}"); alCovers.add(cover); } } if (iEventID != iLocalEventID) { // a stop signal has been emitted // from a concurrent thread Log.debug("Download stopped - 1"); return; } } } catch (final IOException e) { Log.warn(e.getMessage()); // can occur in case of timeout or error during // covers list download CoverView.iErrorCounter++; if (CoverView.iErrorCounter == Const.STOP_TO_SEARCH) { Log.warn("Too many connection fails," + " stop to search for covers online"); InformationJPanel.getInstance().setMessage(Messages.getString("Error.030"), InformationJPanel.MessageType.WARNING); } } catch (final Exception e) { Log.error(e); } } } // Check for tag covers try { Tag tag = new Tag(fCurrent.getFIO(), false); List tagCovers = tag.getCovers(); // Reverse order of the found tag covers because we want best last // in alCovers and we want to keep tag order. Collections.reverse(tagCovers); for (Cover cover : tagCovers) { // Avoid dups if (!alCovers.contains(cover)) { alCovers.add(cover); } } } catch (JajukException e1) { Log.error(e1); } if (alCovers.size() == 0) {// add the default cover if none // other cover has been found alCovers.add(CoverView.nocover); } Collections.sort(alCovers); Log.debug("Local cover list: {{" + alCovers + "}}"); if (Conf.getBoolean(Const.CONF_COVERS_SHUFFLE)) { // choose a random cover index = (int) (Math.random() * alCovers.size()); } else { index = alCovers.size() - 1; // current index points to the best available cover } displayCurrentCover(); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/views/LyricsView.java0000644000175000017500000003764611720500104024540 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.views; import java.awt.Insets; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import java.awt.event.MouseEvent; import java.util.HashSet; import java.util.Set; import javax.swing.BoxLayout; import javax.swing.JLabel; import javax.swing.JMenuItem; import javax.swing.JPanel; import javax.swing.JPopupMenu; import javax.swing.JScrollPane; import javax.swing.JTextArea; import javax.swing.JToolBar; import javax.swing.SwingUtilities; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; import net.miginfocom.swing.MigLayout; import org.jajuk.base.File; import org.jajuk.events.JajukEvent; import org.jajuk.events.JajukEvents; import org.jajuk.events.ObservationManager; import org.jajuk.services.lyrics.LyricsService; import org.jajuk.services.lyrics.providers.GenericWebLyricsProvider; import org.jajuk.services.lyrics.providers.ILyricsProvider; import org.jajuk.services.lyrics.providers.JajukLyricsProvider; import org.jajuk.services.lyrics.providers.TxtLyricsProvider; import org.jajuk.services.players.QueueModel; import org.jajuk.services.webradio.WebRadio; import org.jajuk.ui.actions.ActionManager; import org.jajuk.ui.actions.JajukActions; import org.jajuk.ui.helpers.FontManager; import org.jajuk.ui.helpers.FontManager.JajukFont; import org.jajuk.ui.helpers.JajukMouseAdapter; import org.jajuk.ui.widgets.JajukButton; import org.jajuk.ui.widgets.JajukJToolbar; import org.jajuk.ui.widgets.JajukToggleButton; import org.jajuk.util.Conf; import org.jajuk.util.Const; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; import org.jajuk.util.UtilFeatures; import org.jajuk.util.UtilGUI; import org.jajuk.util.UtilSystem; import org.jajuk.util.error.LyricsPersistenceException; import org.jajuk.util.log.Log; import org.jdesktop.swingx.JXBusyLabel; /** * Lyrics view *

    * Data comes from the Tag of the file or a txt file if present; otherwise from * www.lyrc.com.ar, lyrics.wikia.com or lyricsfly.com *

    */ public class LyricsView extends ViewAdapter implements DocumentListener { /** Generated serialVersionUID. */ private static final long serialVersionUID = 2229941034734574056L; /** DOCUMENT_ME. */ private JTextArea jtaLyrics; /** DOCUMENT_ME. */ private JScrollPane jspLyrics; /** DOCUMENT_ME. */ private JLabel jlTitle; /** DOCUMENT_ME. */ private String sURL; /** Currently analyzed file. */ private File file; /** DOCUMENT_ME. */ private String lyrics; /** DOCUMENT_ME. */ private JMenuItem jmiCopyToClipboard; /** DOCUMENT_ME. */ private JMenuItem jmiLaunchInBrowser; /** DOCUMENT_ME. */ private JPanel jpMain; /** DOCUMENT_ME. */ private JajukButton jbSave; /** DOCUMENT_ME. */ private JajukButton jbDelete; /** DOCUMENT_ME. */ private JajukToggleButton jtbEdit; /** Edition toolbar. */ private JToolBar toolbarEdit; /** DOCUMENT_ME. */ private boolean changeDetected = false; /** * DOCUMENT_ME. */ class LyricsUpdateThread extends Thread { /** * Instantiates a new lyrics update thread. */ LyricsUpdateThread() { super("Lyrics Update Thread-" + file.getTrack().getArtist().getName2() + "-" + file.getTrack().getName()); } /* (non-Javadoc) * @see java.lang.Thread#run() */ @Override public void run() { // Launch lyrics service asynchronously and out of the // AWT dispatcher thread lyrics = LyricsService.getLyrics(file); if (lyrics != null) { ILyricsProvider provider = LyricsService.getCurrentProvider(); sURL = provider.getSourceAddress(); } else { sURL = ""; } // Notify to make UI changes ObservationManager.notify(new JajukEvent(JajukEvents.LYRICS_DOWNLOADED)); } } /** * Instantiates a new lyrics view. */ public LyricsView() { super(); } /* * (non-Javadoc) * * @see org.jajuk.ui.IView#initUI() */ @Override public void initUI() { final FontManager fmgr = FontManager.getInstance(); jtaLyrics = new JTextArea(); jtaLyrics.setFont(fmgr.getFont(JajukFont.PLAIN)); jlTitle = new JLabel(); jlTitle.setFont(fmgr.getFont(JajukFont.PLAIN_L)); jspLyrics = new JScrollPane(jtaLyrics); jtaLyrics.setLineWrap(true); jtaLyrics.setWrapStyleWord(true); jtaLyrics.setEditable(false); jtaLyrics.setMargin(new Insets(10, 10, 10, 10)); jtaLyrics.setFont(fmgr.getFont(JajukFont.BOLD)); jtaLyrics.addMouseListener(new JajukMouseAdapter() { @Override public void handlePopup(final MouseEvent e) { final JPopupMenu menu = new JPopupMenu(); menu.add(jmiCopyToClipboard); if (UtilSystem.isBrowserSupported()) { jmiLaunchInBrowser.putClientProperty(Const.DETAIL_CONTENT, sURL); jmiCopyToClipboard.putClientProperty(Const.DETAIL_CONTENT, sURL); menu.add(jmiLaunchInBrowser); } menu.show(jtaLyrics, e.getX(), e.getY()); } }); // Detect text area content change to enable save button on changes jtaLyrics.getDocument().addDocumentListener(this); initEditUI(); //Create a toolbar to group edition commands toolbarEdit = new JajukJToolbar(); toolbarEdit.add(jtbEdit); toolbarEdit.add(jbSave); toolbarEdit.add(jbDelete); // Menu items jmiCopyToClipboard = new JMenuItem(ActionManager.getAction(JajukActions.COPY_TO_CLIPBOARD)); if (UtilSystem.isBrowserSupported()) { jmiLaunchInBrowser = new JMenuItem(ActionManager.getAction(JajukActions.LAUNCH_IN_BROWSER)); } // Add items jpMain = new JPanel(new MigLayout("insets 5,gapx 3, gapy 5,filly", "[95][grow]", "[][grow]")); jpMain.add(jtbEdit, "left,split 3"); jpMain.add(jbSave, "left"); jpMain.add(jbDelete, "left"); jpMain.add(jlTitle, "left,wrap"); jpMain.add(jspLyrics, "span,grow"); setLayout(new BoxLayout(this, BoxLayout.X_AXIS)); add(jpMain); ObservationManager.register(this); // force initial buttons states updateButtonsState(); // Force initial message refresh UtilFeatures.updateStatus(this); } /** * Initializes the UI of edit lyrics mode. */ public void initEditUI() { jtbEdit = new JajukToggleButton(IconLoader.getIcon(JajukIcons.EDIT)); jtbEdit.setToolTipText(Messages.getString("LyricsView.2")); jtbEdit.addItemListener(new ItemListener() { @Override public void itemStateChanged(ItemEvent ev) { if (jtbEdit.isSelected()) { jtaLyrics.setEditable(true); // Don't keep "No result found" text if (jtaLyrics.getText().equals(Messages.getString("WikipediaView.3"))) { jtaLyrics.getDocument().removeDocumentListener(LyricsView.this); jtaLyrics.setText(""); jtaLyrics.getDocument().addDocumentListener(LyricsView.this); } jtaLyrics.requestFocus(); jtbEdit.setToolTipText(Messages.getString("LyricsView.3")); } else { exitEditLyrics(true); jtbEdit.setToolTipText(Messages.getString("LyricsView.2")); } } }); jbSave = new JajukButton(IconLoader.getIcon(JajukIcons.SAVE)); jbSave.setToolTipText(Messages.getString("LyricsView.4")); jbSave.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { try { JajukLyricsProvider provider = getJajukProvider(); LyricsService.commitLyrics(provider); } catch (LyricsPersistenceException lpe) { Log.error(lpe); // Always the same i18n message : "Operation failed" Messages.showErrorMessage(136, lpe.getMessage()); } exitEditLyrics(false); } }); jbDelete = new JajukButton(IconLoader.getIcon(JajukIcons.DELETE)); jbDelete.setToolTipText(Messages.getString("LyricsView.5")); jbDelete.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent ae) { try { JajukLyricsProvider provider = getJajukProvider(); LyricsService.deleteLyrics(provider); } catch (LyricsPersistenceException lpe) { Log.error(lpe); Messages.showErrorMessage(136, lpe.getMessage()); } exitEditLyrics(true); } }); } /** * Get the GUI provider. * * @return the jajuk provider */ public JajukLyricsProvider getJajukProvider() { JajukLyricsProvider jajukLyricsProvider = new JajukLyricsProvider(); jajukLyricsProvider.setAudioFile(file); jajukLyricsProvider.setLyrics(jtaLyrics.getText()); return jajukLyricsProvider; } /** * Switch from lyrics edit to view mode. * * @param callUpdate Whether to call an update after switching */ public void exitEditLyrics(boolean callUpdate) { changeDetected = false; jtaLyrics.setEditable(false); jtbEdit.setSelected(false); updateButtonsState(); if (callUpdate) { update(new JajukEvent(JajukEvents.FILE_LAUNCHED)); } } /* * (non-Javadoc) * * @see org.jajuk.base.Observer#getRegistrationKeys() */ @Override public Set getRegistrationKeys() { final Set eventSubjectSet = new HashSet(); eventSubjectSet.add(JajukEvents.FILE_LAUNCHED); eventSubjectSet.add(JajukEvents.ZERO); eventSubjectSet.add(JajukEvents.PLAYER_STOP); eventSubjectSet.add(JajukEvents.WEBRADIO_LAUNCHED); eventSubjectSet.add(JajukEvents.LYRICS_DOWNLOADED); return eventSubjectSet; } /* * (non-Javadoc) * * @see org.jajuk.base.Observer#update(org.jajuk.base.Event) */ @Override public void update(final JajukEvent event) { // Ignore any event while we are editing if (jtbEdit.isSelected()) { return; } final JajukEvents subject = event.getSubject(); if (subject.equals(JajukEvents.FILE_LAUNCHED)) { file = QueueModel.getPlayingFile(); // file is null is view started with no playing track (the event is // simulated in initUI()) if (file == null) { return; } // If Internet access is allowed, download lyrics if (Conf.getBoolean(CONF_NETWORK_NONE_INTERNET_ACCESS)) { resetNoInternet(); } else { showBuzyLabel(); // Launch lyrics search asynchronously new LyricsUpdateThread().start(); } } else if (JajukEvents.ZERO.equals(subject) || JajukEvents.PLAYER_STOP.equals(subject)) { reset(); file = null; } else if (subject.equals(JajukEvents.WEBRADIO_LAUNCHED)) { resetWebradio((WebRadio) event.getDetails().get(Const.DETAIL_CONTENT)); file = null; } else if (subject.equals(JajukEvents.LYRICS_DOWNLOADED)) { refreshLyrics(); } } /** * Reset GUI in case of Internet disabled. */ private void resetNoInternet() { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { removeAll(); add(jpMain); jlTitle.setText(file.getTrack().getName()); jlTitle.setToolTipText(file.getTrack().getName()); updateButtonsState(); jtaLyrics.setText(Messages.getString("LyricsView.1")); jspLyrics.setEnabled(true); sURL = ""; revalidate(); repaint(); } }); } /** * Show buzy label when searching lyrics. */ private void showBuzyLabel() { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { removeAll(); final JXBusyLabel busy = new JXBusyLabel(); busy.setBusy(true); add(UtilGUI.getCentredPanel(busy, BoxLayout.X_AXIS)); revalidate(); repaint(); } }); } /** * Reset webradio. * * @param radio DOCUMENT_ME */ private void resetWebradio(final WebRadio radio) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { if (radio != null) { jlTitle.setText(radio.getName()); updateButtonsState(); jspLyrics.setEnabled(false); jtaLyrics.setText(radio.getName()); updateButtonsState(); revalidate(); repaint(); } } }); } /** * Compute buttons states. */ private void updateButtonsState() { ILyricsProvider provider = LyricsService.getCurrentProvider(); // Delete button jbDelete.setEnabled(file != null && provider != null && !(provider instanceof GenericWebLyricsProvider)); // Save button : enabled only for changes in the text area or // if we just got lyrics from the web or form a txt file // (so user can try to commit it to the tag) jbSave.setEnabled((jtbEdit.isSelected() && changeDetected) || provider instanceof GenericWebLyricsProvider || provider instanceof TxtLyricsProvider); } /** * Refresh lyrics once downloaded. */ private void refreshLyrics() { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { removeAll(); add(jpMain); jtaLyrics.setToolTipText(sURL); if ((lyrics != null) && (lyrics.length() > 0)) { jtaLyrics.setText(lyrics); } else { jtaLyrics.setText(Messages.getString("WikipediaView.3")); } // Make sure to display the begin of the text (must be // done in a thread to be executed when textarea display // is actually finished) SwingUtilities.invokeLater(new Runnable() { @Override public void run() { jspLyrics.getVerticalScrollBar().setValue(0); } }); jlTitle.setText(file.getTrack().getName()); jspLyrics.setEnabled(true); updateButtonsState(); revalidate(); repaint(); } }); } /** * Hide lyrics scrollable text and display a "Ready to play" message. */ private void reset() { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { jspLyrics.setEnabled(false); updateButtonsState(); jlTitle.setText(Messages.getString("JajukWindow.18")); jtaLyrics.getDocument().removeDocumentListener(LyricsView.this); jtaLyrics.setText(""); jtaLyrics.getDocument().addDocumentListener(LyricsView.this); jtaLyrics.setToolTipText(Messages.getString("JajukWindow.18")); } }); } /* * (non-Javadoc) * * @see org.jajuk.ui.IView#getDesc() */ @Override public String getDesc() { return Messages.getString("LyricsView.0"); } /* (non-Javadoc) * @see javax.swing.event.DocumentListener#removeUpdate(javax.swing.event.DocumentEvent) */ @Override public void removeUpdate(DocumentEvent e) { changeDetected = true; updateButtonsState(); } /* (non-Javadoc) * @see javax.swing.event.DocumentListener#insertUpdate(javax.swing.event.DocumentEvent) */ @Override public void insertUpdate(DocumentEvent e) { changeDetected = true; updateButtonsState(); } /* (non-Javadoc) * @see javax.swing.event.DocumentListener#changedUpdate(javax.swing.event.DocumentEvent) */ @Override public void changedUpdate(DocumentEvent e) { changeDetected = true; updateButtonsState(); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/views/FilesTreeView.java0000644000175000017500000012572411720500104025150 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.views; import java.awt.Component; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.ComponentAdapter; import java.awt.event.ComponentEvent; import java.awt.event.MouseEvent; import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; import java.util.Enumeration; import java.util.HashSet; import java.util.List; import java.util.Properties; import java.util.Set; import javax.swing.Action; import javax.swing.BorderFactory; import javax.swing.ImageIcon; import javax.swing.JLayeredPane; import javax.swing.JMenuItem; import javax.swing.JPopupMenu; import javax.swing.JScrollPane; import javax.swing.JTree; import javax.swing.event.TreeExpansionEvent; import javax.swing.event.TreeExpansionListener; import javax.swing.event.TreeSelectionEvent; import javax.swing.event.TreeSelectionListener; import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.DefaultTreeModel; import javax.swing.tree.MutableTreeNode; import javax.swing.tree.TreePath; import net.miginfocom.swing.MigLayout; import org.jajuk.base.Device; import org.jajuk.base.DeviceManager; import org.jajuk.base.Directory; import org.jajuk.base.DirectoryManager; import org.jajuk.base.File; import org.jajuk.base.FileManager; import org.jajuk.base.Item; import org.jajuk.base.Playlist; import org.jajuk.base.Type; import org.jajuk.base.TypeManager; import org.jajuk.events.JajukEvent; import org.jajuk.events.JajukEvents; import org.jajuk.events.ObservationManager; import org.jajuk.services.players.QueueModel; import org.jajuk.services.players.StackItem; import org.jajuk.ui.actions.ActionManager; import org.jajuk.ui.actions.JajukActions; import org.jajuk.ui.actions.RefactorAction; import org.jajuk.ui.helpers.FontManager; import org.jajuk.ui.helpers.FontManager.JajukFont; import org.jajuk.ui.helpers.ItemMoveManager; import org.jajuk.ui.helpers.ItemMoveManager.MoveActions; import org.jajuk.ui.helpers.JajukMouseAdapter; import org.jajuk.ui.helpers.LazyLoadingTreeNode; import org.jajuk.ui.helpers.TreeRootElement; import org.jajuk.ui.helpers.TreeTransferHandler; import org.jajuk.ui.perspectives.PerspectiveManager; import org.jajuk.ui.widgets.InformationJPanel; import org.jajuk.ui.wizard.DeviceWizard; import org.jajuk.util.Conf; import org.jajuk.util.Const; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; import org.jajuk.util.UtilFeatures; import org.jajuk.util.UtilGUI; import org.jajuk.util.UtilSystem; import org.jajuk.util.error.JajukException; import org.jajuk.util.log.Log; import org.jvnet.substance.api.renderers.SubstanceDefaultTreeCellRenderer; /** * Physical tree view. */ public class FilesTreeView extends AbstractTreeView implements ActionListener, org.jajuk.events.Observer { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** Directories selection. */ List alDirs = new ArrayList(10); /** DOCUMENT_ME. */ JMenuItem jmiDirRefresh; /** DOCUMENT_ME. */ JMenuItem jmiDirDesynchro; /** DOCUMENT_ME. */ JMenuItem jmiDirResynchro; /** DOCUMENT_ME. */ JMenuItem jmiDirCreatePlaylist; /** DOCUMENT_ME. */ JMenuItem jmiDirRefactor; /** DOCUMENT_ME. */ JMenuItem jmiDirCopyURL; /** DOCUMENT_ME. */ JMenuItem jmiDirOpenExplorer; /** DOCUMENT_ME. */ JMenuItem jmiDevMount; /** DOCUMENT_ME. */ JMenuItem jmiDevUnmount; /** DOCUMENT_ME. */ JMenuItem jmiDevRefresh; /** DOCUMENT_ME. */ JMenuItem jmiDevSynchronize; /** DOCUMENT_ME. */ JMenuItem jmiDevTest; /** DOCUMENT_ME. */ JMenuItem jmiDevOrganize; /** DOCUMENT_ME. */ JMenuItem jmiDevConfiguration; /** DOCUMENT_ME. */ JMenuItem jmiDevDelete; /** DOCUMENT_ME. */ JMenuItem jmiPlaylistFileCopy; /** DOCUMENT_ME. */ JMenuItem jmiPlaylistFileCut; /** DOCUMENT_ME. */ JMenuItem jmiPlaylistFilePaste; /** DOCUMENT_ME. */ JMenuItem jmiPlaylistCopyURL; /** DOCUMENT_ME. */ JMenuItem jmiPlaylistPrepareParty; /* * (non-Javadoc) * * @see org.jajuk.ui.IView#getDesc() */ @Override public String getDesc() { return Messages.getString("FilesTreeView.0"); } /** * Constructor. */ public FilesTreeView() { } /* * (non-Javadoc) * * @see org.jajuk.ui.IView#display() */ @Override public void initUI() { super.initUI(); // Directory menu Action actionRefreshDir = ActionManager.getAction(JajukActions.REFRESH); jmiDirRefresh = new JMenuItem(actionRefreshDir); jmiDirRefresh.putClientProperty(Const.DETAIL_SELECTION, alSelected); jmiDirRefresh.addActionListener(this); jmiDirDesynchro = new JMenuItem(Messages.getString("FilesTreeView.14"), IconLoader.getIcon(JajukIcons.DIRECTORY_DESYNCHRO)); jmiDirDesynchro.addActionListener(this); jmiDirResynchro = new JMenuItem(Messages.getString("FilesTreeView.15"), IconLoader.getIcon(JajukIcons.DIRECTORY_SYNCHRO)); jmiDirResynchro.addActionListener(this); jmiDirCreatePlaylist = new JMenuItem(Messages.getString("FilesTreeView.16")); jmiDirCreatePlaylist.setEnabled(false); jmiDirCreatePlaylist.addActionListener(this); jmiDirRefactor = new JMenuItem(Messages.getString(("FilesTreeView.62")), IconLoader.getIcon(JajukIcons.REORGANIZE)); jmiDirRefactor.addActionListener(this); jmiDirCopyURL = new JMenuItem(ActionManager.getAction(JajukActions.COPY_TO_CLIPBOARD)); jmiDirCopyURL.putClientProperty(Const.DETAIL_CONTENT, alSelected); jmiDirOpenExplorer = new JMenuItem(ActionManager.getAction(JajukActions.OPEN_EXPLORER)); jmiDirOpenExplorer.putClientProperty(Const.DETAIL_CONTENT, alSelected); // Device menu jmiDevMount = new JMenuItem(Messages.getString("FilesTreeView.28"), IconLoader.getIcon(JajukIcons.UNMOUNT)); jmiDevMount.addActionListener(this); jmiDevUnmount = new JMenuItem(Messages.getString("FilesTreeView.29"), IconLoader.getIcon(JajukIcons.UNMOUNT)); jmiDevUnmount.addActionListener(this); jmiDevRefresh = new JMenuItem(Messages.getString("FilesTreeView.30"), IconLoader.getIcon(JajukIcons.REFRESH)); jmiDevRefresh.addActionListener(this); jmiDevSynchronize = new JMenuItem(Messages.getString("FilesTreeView.31"), IconLoader.getIcon(JajukIcons.SYNCHRO)); jmiDevSynchronize.addActionListener(this); jmiDevTest = new JMenuItem(Messages.getString("FilesTreeView.32"), IconLoader.getIcon(JajukIcons.TEST)); jmiDevTest.addActionListener(this); jmiDevConfiguration = new JMenuItem(Messages.getString("FilesTreeView.55"), IconLoader.getIcon(JajukIcons.CONFIGURATION)); jmiDevConfiguration.addActionListener(this); jmiDevDelete = new JMenuItem(Messages.getString("DeviceView.13"), IconLoader.getIcon(JajukIcons.DELETE)); jmiDevDelete.addActionListener(this); jmiDevOrganize = new JMenuItem(Messages.getString(("FilesTreeView.62")), IconLoader.getIcon(JajukIcons.REORGANIZE)); jmiDevOrganize.addActionListener(this); // playlist menu jmiPlaylistFileCopy = new JMenuItem(Messages.getString("FilesTreeView.40")); jmiPlaylistFileCopy.setEnabled(false); jmiPlaylistFileCopy.addActionListener(this); jmiPlaylistFileCut = new JMenuItem(Messages.getString("FilesTreeView.41")); jmiPlaylistFileCut.setEnabled(false); jmiPlaylistFileCut.addActionListener(this); jmiPlaylistFilePaste = new JMenuItem(Messages.getString("FilesTreeView.42")); jmiPlaylistFilePaste.setEnabled(false); jmiPlaylistFilePaste.addActionListener(this); jmiPlaylistCopyURL = new JMenuItem(ActionManager.getAction(JajukActions.COPY_TO_CLIPBOARD)); jmiPlaylistCopyURL.putClientProperty(Const.DETAIL_CONTENT, alSelected); jmiPlaylistPrepareParty = new JMenuItem(ActionManager.getAction(JajukActions.PREPARE_PARTY)); jmiPlaylistPrepareParty.putClientProperty(Const.DETAIL_SELECTION, alSelected); // Add Action Listener jmiCopy.addActionListener(this); jmiCut.addActionListener(this); jmiPaste.addActionListener(this); // By default disable paste jmiPaste.setEnabled(false); top = new TreeRootElement(Messages.getString("FilesTreeView.47")); // Register on the list for subject we are interested in ObservationManager.register(this); // fill the tree model populateTree(); // create tree createTree(true); /** * CAUTION ! we register several listeners against this tree Swing can't * ensure the order where listeners will treat them so don't count in the * mouse listener to get correct selection from selection listener */ jtree.setCellRenderer(new FilesTreeCellRenderer()); // Tree selection listener to detect a selection (single click // , manages simple or multiple selections) jtree.addTreeSelectionListener(new FilesTreeSelectionListener()); // Listen for single / double click jtree.addMouseListener(new FilesMouseAdapter()); // Expansion analyzed to keep expended state jtree.addTreeExpansionListener(new FilesTreeExpansionListener()); jtree.setAutoscrolls(true); jspTree = new JScrollPane(jtree); jspTree.setBorder(BorderFactory.createEmptyBorder(0, 1, 0, 0)); // DND support jtree.setDragEnabled(true); jtree.setTransferHandler(new TreeTransferHandler(jtree)); // layout : the tree takes all the available height and we display the // command buttons on a different layer (because we don't want to use a // dedicated row like in the Tracks tree table : it's too ugly and // space-consuming) setLayout(new MigLayout("ins 3", "[grow]", "[grow]")); final JLayeredPane lp = new JLayeredPane(); addComponentListener(new ComponentAdapter() { @Override public void componentResized(ComponentEvent e) { // At first display and afterwards at each view resize, we cleanup and // re-add tree and command buttons adapted to the new view size. lp.removeAll(); jspTree.setBounds(0, 0, getWidth() - 5, getHeight() - 5); lp.add(jspTree, JLayeredPane.DEFAULT_LAYER); jtbSync.setBounds(getWidth() - 80, 0, 25, 22); lp.add(jtbSync, JLayeredPane.POPUP_LAYER); jbCollapseAll.setBounds(getWidth() - 50, 0, 23, 22); lp.add(jbCollapseAll, JLayeredPane.POPUP_LAYER); lp.revalidate(); lp.repaint(); } }); add(lp, "grow"); // expand all expand(); } /** * Fill the tree. */ @Override public void populateTree() { // Use a refreshing flag, not a 'synchronized' here (see deadlock, bug #1756 (Deadlock in AbstractTreeView and PerspectiveManager) if (refreshing) { Log.debug("Tree view already refreshing. Leaving."); return; } try { refreshing = true; top.removeAllChildren(); // see http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6472844 for a // small memory leak that is caused here... if (jtree != null && jtree.getModel() != null) { ((DefaultTreeModel) (jtree.getModel())).reload(); } // add all devices as "LazyLoading" nodes so all subsequent elements are // only populated if necessary List devices = DeviceManager.getInstance().getDevices(); for (Device device : devices) { DefaultMutableTreeNode nodeDevice = new DeviceNode(device); top.add(nodeDevice); } } finally { refreshing = false; } } /* * (non-Javadoc) * * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent) */ @Override public void actionPerformed(final ActionEvent e) { // multiple selection on properties(note we handle files and dirs // properties later) if ((e.getSource() == jmiDirRefactor || e.getSource() == jmiDevOrganize)) { UtilGUI.waiting(); for (Item item : alSelected) { // Check if user made a global cancel if (RefactorAction.isStopAll()) { RefactorAction.resetStopAll(); return; } // If user selected a device, take associated directory if (item instanceof Device) { item = ((Device) item).getRootDirectory(); } final Directory dir = (Directory) item; UtilGUI.waiting(); new RefactorAction(dir.getFilesRecursively()); } } else if (e.getSource() == jmiDevMount) { for (TreePath element : paths) { DeviceNode node = (DeviceNode) (element.getLastPathComponent()); Device device = node.getDevice(); try { device.mount(true); jtree.expandPath(new TreePath(node.getPath())); } catch (JajukException je) { Messages.showErrorMessage(je.getCode()); } catch (Exception ex) { Messages.showErrorMessage(11); } } } else if (e.getSource() == jmiDevUnmount) { for (TreePath element : paths) { DeviceNode node = (DeviceNode) (element.getLastPathComponent()); Device device = node.getDevice(); try { device.unmount(); jtree.collapsePath(new TreePath(node.getPath())); } catch (Exception ex) { Messages.showErrorMessage(12); } } } else if (e.getSource() == jmiDevRefresh) { Device device = ((DeviceNode) (paths[0].getLastPathComponent())).getDevice(); // ask user if he wants to make deep // or fast scan device.refresh(true, true, false, null); } else if (e.getSource() == jmiDevSynchronize) { Device device = ((DeviceNode) (paths[0].getLastPathComponent())).getDevice(); device.synchronize(true); } else if (e.getSource() == jmiDevTest) { new Thread("Files Tree Action Thread") { // test asynchronously in case of delay (samba // pbm for ie) @Override public void run() { Device device = ((DeviceNode) (paths[0].getLastPathComponent())).getDevice(); if (device.test()) { Messages.showInfoMessage(Messages.getString("DeviceView.21"), IconLoader.getIcon(JajukIcons.OK)); } else { Messages.showInfoMessage(Messages.getString("DeviceView.22"), IconLoader.getIcon(JajukIcons.KO)); } } }.start(); } else if (e.getSource() == jmiDirDesynchro) { setSynchonizationStateRecursively(false); jtree.revalidate(); jtree.repaint(); } else if (e.getSource() == jmiDirResynchro) { setSynchonizationStateRecursively(true); jtree.revalidate(); jtree.repaint(); } else if (e.getSource() == jmiCopy || e.getSource() == jmiCut) { jmiPaste.setEnabled(true); jmenu.repaint(); } else if (e.getSource() == jmiPaste) { if (MoveActions.CUT.equals(ItemMoveManager.getInstance().getAction())) { jmiPaste.setEnabled(false); jmenu.repaint(); } } else if (e.getSource() == jmiDevConfiguration) { Device device = ((DeviceNode) paths[0].getLastPathComponent()).getDevice(); DeviceWizard dw = new DeviceWizard(); dw.updateWidgets(device); dw.pack(); dw.setVisible(true); } else if (e.getSource() == jmiDevDelete) { Device device = ((DeviceNode) paths[0].getLastPathComponent()).getDevice(); DeviceManager.getInstance().removeDevice(device); // refresh views ObservationManager.notify(new JajukEvent(JajukEvents.DEVICE_REFRESH)); } } /** * Sets the synchronization state recursively for all files selected. * * @param sync whether the directories should be synchronized */ private void setSynchonizationStateRecursively(boolean sync) { Set directories = new HashSet(); for (Item item : alSelected) { Directory dir = (Directory) item; directories.add(dir); directories.addAll(dir.getDirectoriesRecursively()); } for (Directory dir : directories) { dir.setProperty(Const.XML_DIRECTORY_SYNCHRONIZED, sync); } } /** * Manages auto-expand Expand behavior is: *

    * At startup, tree expand state is the same that the one kept at last session * (we use XML_EXPANDED stored properties to restore it) *

    *

    * When mounting a device from the tree, the device node is expanded *

    *

    * When unmounting a device from the tree, the device node is collapsed *

    * . */ @Override void expand() { // make sure the main element is expanded jtree.expandRow(0); // begin by expanding all needed devices and directory, only after, // collapse unmounted devices if required for (int i = 0; i < jtree.getRowCount(); i++) { Object o = jtree.getPathForRow(i).getLastPathComponent(); if (o instanceof DeviceNode) { Device device = ((DeviceNode) o).getDevice(); if (device.getBooleanValue(Const.XML_EXPANDED)) { jtree.expandRow(i); } // Collapse node (useful to hide an live-unmounted device for ie) else { jtree.collapseRow(i); } } else if (o instanceof DirectoryNode) { Directory dir = ((DirectoryNode) o).getDirectory(); if (dir.getBooleanValue(Const.XML_EXPANDED)) { jtree.expandRow(i); } } } } /* * (non-Javadoc) * * @see org.jajuk.ui.views.AbstractTreeView#scrollTo(org.jajuk.base.Item) */ @Override void scrollTo(Item item) { // Set manual change because we force here tree selection and // we don't want to force table views to synchronize bInternalAction = true; try { // Clear selection so we only select new synchronized item jtree.getSelectionModel().clearSelection(); // Expand recursively item's directory because of the lazy loading stuff expandRecursively(item); // Now scroll to the item and select it for (int i = 0; i < jtree.getRowCount(); i++) { Object o = jtree.getPathForRow(i).getLastPathComponent(); if (o instanceof FileNode) { o = ((FileNode) o).getFile(); } else if (o instanceof PlaylistFileNode) { o = ((PlaylistFileNode) o).getPlaylistFile(); } else { continue; } if (item.equals(o)) { jtree.scrollRowToVisible(i); jtree.getSelectionModel().addSelectionPath(jtree.getPathForRow(i)); } } } finally { bInternalAction = false; } } /** * Expand recursively all directory nodes of given item. * * @param item : file or playlist */ private void expandRecursively(Item item) { jtree.expandRow(0); boolean stopLoop = false; // Keep tree path list here, do not put this call in the loop as // it would change at each node expand List paths = new ArrayList(); for (int i = 0; i < jtree.getRowCount(); i++) { TreePath path = jtree.getPathForRow(i); paths.add(path); } // item is either a file or a playlist for (int i = 0; i < paths.size(); i++) { Object o = paths.get(i).getLastPathComponent(); if (o instanceof DirectoryNode || o instanceof DeviceNode) { Directory testedDirectory = null; // If the node is a device, search its root directory and check it if (o instanceof DeviceNode) { Device testedDevice = ((DeviceNode) o).getDevice(); testedDirectory = testedDevice.getRootDirectory(); } else { testedDirectory = ((DirectoryNode) o).getDirectory(); } if (item instanceof File) { File file = (File) item; if (file.hasAncestor(testedDirectory)) { jtree.expandRow(i); } if (testedDirectory.equals(file.getDirectory())) { stopLoop = true; } } else if (item instanceof Playlist) { Playlist playlist = (Playlist) item; if (playlist.hasAncestor(testedDirectory)) { jtree.expandRow(i); } if (testedDirectory.equals(playlist.getDirectory())) { stopLoop = true; } } } } if (!stopLoop) { expandRecursively(item); } } /** * DOCUMENT_ME. */ class FilesMouseAdapter extends JajukMouseAdapter { /* * (non-Javadoc) * * @see * org.jajuk.ui.helpers.JajukMouseAdapter#handleActionSeveralClicks(java.awt.event.MouseEvent) */ @Override public void handleActionSeveralClicks(final MouseEvent e) { TreePath path = jtree.getPathForLocation(e.getX(), e.getY()); if (path == null) { return; } Object o = path.getLastPathComponent(); if (o instanceof FileNode) { File file = ((FileNode) o).getFile(); try { QueueModel.push(new StackItem(file, Conf.getBoolean(Const.CONF_STATE_REPEAT_ALL), true), Conf.getBoolean(Const.CONF_OPTIONS_PUSH_ON_CLICK)); } catch (JajukException je) { Log.error(je); } } // double click on a playlist else if (o instanceof PlaylistFileNode) { Playlist plf = ((PlaylistFileNode) o).getPlaylistFile(); List alToPlay = null; try { alToPlay = plf.getFiles(); } catch (JajukException je) { Log.error(je.getCode(), "{{" + plf.getName() + "}}", null); Messages.showErrorMessage(je.getCode(), plf.getName()); return; } // check playlist contains accessible // tracks if (alToPlay == null || alToPlay.size() == 0) { Messages.showErrorMessage(18); return; } else { QueueModel.push( UtilFeatures.createStackItems(UtilFeatures.applyPlayOption(alToPlay), Conf.getBoolean(Const.CONF_STATE_REPEAT), true), false); } } } /* * (non-Javadoc) * * @see org.jajuk.ui.helpers.JajukMouseAdapter#handlePopup(java.awt.event.MouseEvent) */ @Override @SuppressWarnings("unchecked") public void handlePopup(final MouseEvent e) { TreePath path = jtree.getPathForLocation(e.getX(), e.getY()); if (path == null) { return; } // right click on a selected node set Right click // behavior identical to konqueror tree: // if none or 1 node is selected, a right click on // another node select it if more than 1, we keep selection and // display a popup for them if (jtree.getSelectionCount() < 2) { jtree.getSelectionModel().setSelectionPath(path); } paths = jtree.getSelectionModel().getSelectionPaths(); alDirs.clear(); // test mix between types ( not allowed ) Class c = paths[0].getLastPathComponent().getClass(); for (int i = 0; i < paths.length; i++) { if (!paths[i].getLastPathComponent().getClass().equals(c)) { return; } } // Test that all items are mounted or hide menu item // device:mono selection for the moment if (c.equals(DeviceNode.class)) { Device device = ((DeviceNode) (paths[0].getLastPathComponent())).getDevice(); if (device.isMounted()) { jmiDevMount.setEnabled(false); jmiDevUnmount.setEnabled(true); } else { jmiDevMount.setEnabled(true); jmiDevUnmount.setEnabled(false); } final Directory dir = DirectoryManager.getInstance().registerDirectory(device); boolean bShowCDDB = false; if (dir.getFiles().size() > 0) { bShowCDDB = true; } jmiCDDBWizard.setEnabled(bShowCDDB); } if (c.equals(DirectoryNode.class)) { for (TreePath element : paths) { Directory dir = ((DirectoryNode) (element.getLastPathComponent())).getDirectory(); if (!dir.getDevice().isMounted()) { continue; } } } if (c.equals(FileNode.class)) { for (TreePath element : paths) { File file = ((FileNode) (element.getLastPathComponent())).getFile(); if (!file.isReady()) { continue; } } } jmiDelete.setEnabled(true); if (c.equals(PlaylistFileNode.class)) { for (TreePath element : paths) { Playlist plf = ((PlaylistFileNode) (element.getLastPathComponent())).getPlaylistFile(); if (!plf.isReady()) { jmiDelete.setEnabled(false); continue; } } } // get all components recursively for (TreePath element : paths) { Object o = element.getLastPathComponent(); // return all childs nodes recursively Enumeration e2 = ((DefaultMutableTreeNode) o) .depthFirstEnumeration(); while (e2.hasMoreElements()) { DefaultMutableTreeNode node = e2.nextElement(); if (node instanceof DirectoryNode) { Directory dir = ((DirectoryNode) node).getDirectory(); alDirs.add(dir); } } } // display menus according node type if (paths[0].getLastPathComponent() instanceof FileNode) { jmenu = new JPopupMenu(); jmenu.add(jmiPlay); jmenu.add(jmiFrontPush); jmenu.add(jmiPush); jmenu.addSeparator(); jmenu.add(jmiCut); jmenu.add(jmiCopy); jmenu.add(jmiRename); jmenu.add(jmiDelete); jmenu.add(jmiCopyURL); jmenu.addSeparator(); jmenu.add(pjmTracks); jmenu.add(jmiAddFavorite); jmenu.addSeparator(); jmenu.add(jmiProperties); jmenu.show(jtree, e.getX(), e.getY()); } else if (paths[0].getLastPathComponent() instanceof DirectoryNode) { jmenu = new JPopupMenu(); jmenu.add(jmiPlay); jmenu.add(jmiFrontPush); jmenu.add(jmiPush); jmenu.add(jmiPlayShuffle); jmenu.add(jmiPlayRepeat); jmenu.addSeparator(); jmenu.add(jmiCut); jmenu.add(jmiCopy); jmenu.add(jmiPaste); jmenu.add(jmiNewFolder); jmenu.add(jmiDelete); jmenu.add(jmiDirCopyURL); jmenu.add(jmiDirOpenExplorer); jmenu.addSeparator(); jmenu.add(jmiDirRefresh); jmenu.add(jmiRename); jmenu.add(jmiDirDesynchro); jmenu.add(jmiDirResynchro); jmenu.addSeparator(); jmenu.add(jmiCDDBWizard); jmenu.add(jmiReport); jmenu.add(jmiDirRefactor); jmenu.addSeparator(); jmenu.add(pjmTracks); jmenu.addSeparator(); jmenu.add(jmiProperties); jmenu.show(jtree, e.getX(), e.getY()); } else if (paths[0].getLastPathComponent() instanceof PlaylistFileNode) { jmenu = new JPopupMenu(); jmenu.add(jmiPlay); jmenu.add(jmiFrontPush); jmenu.add(jmiPush); jmenu.add(jmiPlayShuffle); jmenu.add(jmiPlayRepeat); jmenu.addSeparator(); jmenu.add(jmiPlaylistCopyURL); jmenu.add(jmiPlaylistPrepareParty); jmenu.add(jmiDelete); jmenu.addSeparator(); jmenu.add(jmiProperties); jmenu.show(jtree, e.getX(), e.getY()); } else if (paths[0].getLastPathComponent() instanceof DeviceNode) { jmenu = new JPopupMenu(); jmenu.add(jmiPlay); jmenu.add(jmiFrontPush); jmenu.add(jmiPush); jmenu.add(jmiPaste); jmenu.add(jmiPlayShuffle); jmenu.add(jmiPlayRepeat); jmenu.addSeparator(); jmenu.add(jmiNewFolder); jmenu.add(jmiDevMount); jmenu.add(jmiDevUnmount); jmenu.add(jmiDevRefresh); jmenu.add(jmiDevSynchronize); jmenu.addSeparator(); jmenu.add(jmiDevTest); jmenu.add(jmiCDDBWizard); jmenu.add(jmiDevOrganize); jmenu.add(jmiReport); jmenu.addSeparator(); jmenu.add(jmiDevDelete); jmenu.add(jmiDevConfiguration); jmenu.addSeparator(); jmenu.add(jmiProperties); Device device = ((DeviceNode) paths[0].getLastPathComponent()).getDevice(); // if the device is not synchronized if (device.getValue(Const.XML_DEVICE_SYNCHRO_SOURCE).equals("")) { jmiDevSynchronize.setEnabled(false); } else { jmiDevSynchronize.setEnabled(true); } // operations on devices are mono-target expect for // reporting if (paths.length > 1) { // Disable all menu items except reporting for (int i = 0; i < jmenu.getSubElements().length; i++) { ((JMenuItem) jmenu.getSubElements()[i]).setEnabled(false); } jmiReport.setEnabled(true); } else { // Enable all menu items for (int i = 0; i < jmenu.getSubElements().length; i++) { ((JMenuItem) jmenu.getSubElements()[i]).setEnabled(true); } } jmenu.show(jtree, e.getX(), e.getY()); } else if (paths[0].getLastPathComponent() instanceof DefaultMutableTreeNode) { // Collection menu JPopupMenu jmenuCollection = new JPopupMenu(); // Export Action actionReportCollection = ActionManager.getAction(JajukActions.CREATE_REPORT); JMenuItem jmiCollectionReport = new JMenuItem(actionReportCollection); // Add custom data to this component in order to allow the ReportAction // to be able to get it jmiCollectionReport.putClientProperty(Const.DETAIL_ORIGIN, COLLECTION_PHYSICAL); jmenuCollection.add(jmiCollectionReport); Action actionDuplicateFiles = ActionManager.getAction(JajukActions.FIND_DUPLICATE_FILES); JMenuItem jmiCollectionDuplicateFiles = new JMenuItem(actionDuplicateFiles); jmenuCollection.add(jmiCollectionDuplicateFiles); // collection jmenuCollection.show(jtree, e.getX(), e.getY()); } } } /** * DOCUMENT_ME. */ class FilesTreeSelectionListener implements TreeSelectionListener { /* * (non-Javadoc) * * @see javax.swing.event.TreeSelectionListener#valueChanged(javax.swing.event * .TreeSelectionEvent) */ @Override public void valueChanged(TreeSelectionEvent e) { paths = jtree.getSelectionModel().getSelectionPaths(); // nothing selected, can be called during dnd if (paths == null) { return; } int items = 0; long lSize = 0; // get all components recursively selectedRecursively.clear(); alSelected.clear(); // Treat case when use selected the tree's root Object firstPath = paths[0].getLastPathComponent(); if (firstPath instanceof TreeRootElement) { selectedRecursively.addAll(FileManager.getInstance().getFiles()); } else { // Regular selection, one or more nodes for (TreePath element : paths) { // return all child nodes recursively, do not count on the tree's // model as it is lazy loaded Object o = element.getLastPathComponent(); Item item = (Item) ((DefaultMutableTreeNode) o).getUserObject(); alSelected.add(item); Directory directory = null; if (o instanceof DeviceNode) { directory = ((DeviceNode) o).getDevice().getRootDirectory(); } else if (o instanceof DirectoryNode) { directory = ((DirectoryNode) o).getDirectory(); } if (directory != null) { selectedRecursively.addAll(directory.getFilesRecursively()); selectedRecursively.addAll(directory.getPlaylistFiles()); } else if (o instanceof FileNode) { selectedRecursively.add(((FileNode) o).getFile()); } else if (o instanceof PlaylistFileNode) { selectedRecursively.add(((PlaylistFileNode) o).getPlaylistFile()); } } } // Compute recursive selection size, nb of items... for (Item item : selectedRecursively) { if (item instanceof File) { lSize += ((File) item).getSize(); } } items = selectedRecursively.size(); lSize /= 1048576; // set size in MB StringBuilder sbOut = new StringBuilder().append(items).append( Messages.getString("FilesTreeView.52")); if (lSize > 1024) { // more than 1024 MB -> in GB sbOut.append(lSize / 1024).append('.').append(lSize % 1024) .append(Messages.getString("FilesTreeView.53")); } else { sbOut.append(lSize).append(Messages.getString("FilesTreeView.54")); } InformationJPanel.getInstance().setSelection(sbOut.toString()); // Notify the tree selection change (used by tree/table sync) if (!bInternalAction) { Properties properties = new Properties(); properties.put(Const.DETAIL_SELECTION, selectedRecursively); properties .put(Const.DETAIL_PERSPECTIVE, PerspectiveManager.getCurrentPerspective().getID()); properties.put(Const.DETAIL_VIEW, getID()); ObservationManager.notify(new JajukEvent(JajukEvents.TREE_SELECTION_CHANGED, properties)); } // Enable CDDB retagging only for a single directory selection jmiCDDBWizard.setEnabled(alSelected.size() == 1 && alSelected.get(0) instanceof Directory); // Enable device refresh for a single item jmiDevRefresh.setEnabled(alSelected.size() == 1 && alSelected.get(0) instanceof Device); // Enable Copy url for a single item only jmiCopyURL.setEnabled(alSelected.size() == 1 && alSelected.get(0) instanceof File); jmiDirCopyURL.setEnabled(alSelected.size() == 1 && alSelected.get(0) instanceof Directory); jmiDirOpenExplorer.setEnabled(alSelected.size() == 1 && alSelected.get(0) instanceof Directory); jmiPlaylistCopyURL .setEnabled(alSelected.size() == 1 && alSelected.get(0) instanceof Playlist); jmiPlaylistPrepareParty.setEnabled(alSelected.size() == 1 && alSelected.get(0) instanceof Playlist); // Update preference menu pjmTracks.resetUI(alSelected); } } /** * DOCUMENT_ME. */ class FilesTreeExpansionListener implements TreeExpansionListener { /* * (non-Javadoc) * * @see javax.swing.event.TreeExpansionListener#treeCollapsed(javax.swing.event * .TreeExpansionEvent) */ @Override public void treeCollapsed(TreeExpansionEvent event) { Object o = event.getPath().getLastPathComponent(); if (o instanceof DirectoryNode && bManualAction) { Directory dir = ((DirectoryNode) o).getDirectory(); dir.removeProperty(Const.XML_EXPANDED); } else if (o instanceof DeviceNode && bManualAction) { Device device = ((DeviceNode) o).getDevice(); device.removeProperty(Const.XML_EXPANDED); } } /* * (non-Javadoc) * * @see javax.swing.event.TreeExpansionListener#treeExpanded(javax.swing.event * .TreeExpansionEvent) */ @Override public void treeExpanded(TreeExpansionEvent event) { Object o = event.getPath().getLastPathComponent(); if (o instanceof DirectoryNode && bManualAction) { Directory dir = ((DirectoryNode) o).getDirectory(); dir.setProperty(Const.XML_EXPANDED, true); } else if (o instanceof DeviceNode && bManualAction) { Device device = ((DeviceNode) o).getDevice(); device.setProperty(Const.XML_EXPANDED, true); } } } /** * Fill the provided list with sub-elements for that directory, i.e. * sub-directories, files and playlists. * * @param parent The parent-directory to start from. * @param list The list to add elements to. This list can contain elements before * which will not be touched. */ static void populateFromDirectory(Directory parent, List list) { // now we get all directories in this device for (Directory directory : parent.getDirectories()) { if (directory.shouldBeHidden()) { continue; } list.add(new DirectoryNode(directory)); } // then files for (File file : parent.getFiles()) { if (file.shouldBeHidden()) { continue; } list.add(new FileNode(file)); } // and playlists for (Playlist pl : parent.getPlaylistFiles()) { if (pl.shouldBeHidden()) { continue; } list.add(new PlaylistFileNode(pl)); } } } /** * File node */ class FileNode extends DefaultMutableTreeNode { private static final long serialVersionUID = 1L; /** * Constructor * * @param file */ public FileNode(File file) { super(file); } /** * return a string representation of this file node */ @Override public String toString() { return getFile().getName(); } /** * @return Returns the file. */ public File getFile() { return (File) super.getUserObject(); } } /** * Device node */ class DeviceNode extends LazyLoadingTreeNode { private static final long serialVersionUID = 1L; /** * Constructor * * @param device */ public DeviceNode(Device device) { super(device); } /** * return a string representation of this device node */ @Override public String toString() { return getDevice().getName(); } /** * @return Returns the device. */ public Device getDevice() { return (Device) super.getUserObject(); } /* * (non-Javadoc) * * @see org.jajuk.ui.widgets.LazyLoadingTreeNode#loadChildren(javax.swing.tree. DefaultTreeModel) */ @Override public MutableTreeNode[] loadChildren(DefaultTreeModel model) { List list = new ArrayList(); // first level is the directory of the device itself, usually only one for (Directory parent : getDevice().getDirectories()) { // so for each directory that is listed for that Device we build up the // list of sub-elements FilesTreeView.populateFromDirectory(parent, list); } return list.toArray(new MutableTreeNode[list.size()]); } } /** * Directory node */ class DirectoryNode extends LazyLoadingTreeNode { private static final long serialVersionUID = 1L; /** * Constructor * * @param Directory */ public DirectoryNode(Directory directory) { super(directory); } /** * return a string representation of this directory node */ @Override public String toString() { return getDirectory().getName(); } /** * @return Returns the directory. */ public Directory getDirectory() { return (Directory) getUserObject(); } /* * (non-Javadoc) * * @see org.jajuk.ui.helpers.LazyLoadingTreeNode#loadChildren(javax.swing.tree .DefaultTreeModel) */ @Override public MutableTreeNode[] loadChildren(DefaultTreeModel model) { List list = new ArrayList(); // simply collect all items one level below that directory FilesTreeView.populateFromDirectory(getDirectory(), list); return list.toArray(new MutableTreeNode[list.size()]); } } /** * Playlist node */ class PlaylistFileNode extends DefaultMutableTreeNode { private static final long serialVersionUID = 1L; /** * Constructor * * @param Playlist */ public PlaylistFileNode(Playlist playlistFile) { super(playlistFile); } /** * return a string representation of this playlistFile node */ @Override public String toString() { return getPlaylistFile().getName(); } /** * @return Returns the playlist node. */ public Playlist getPlaylistFile() { return (Playlist) getUserObject(); } } class FilesTreeCellRenderer extends SubstanceDefaultTreeCellRenderer { private static final long serialVersionUID = 1L; @Override public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean expanded, boolean leaf, int row, boolean hasFocus) { super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus); setFont(FontManager.getInstance().getFont(JajukFont.PLAIN)); if (value instanceof FileNode) { setBorder(null); File file = ((FileNode) value).getFile(); // Note: file.getName() is better here as it will do less and not // create java.io.File in File String ext = UtilSystem.getExtension(file.getName()); Type type = TypeManager.getInstance().getTypeByExtension(ext); // Find associated icon with this type URL icon = null; String sIcon; if (type != null) { sIcon = (String) type.getProperties().get(Const.XML_TYPE_ICON); try { icon = new URL(sIcon); } catch (MalformedURLException e) { Log.error(e); } } if (icon == null) { setIcon(IconLoader.getIcon(JajukIcons.TYPE_WAV)); } else { setIcon(new ImageIcon(icon)); } } else if (value instanceof PlaylistFileNode) { setBorder(null); setIcon(IconLoader.getIcon(JajukIcons.PLAYLIST_FILE)); } else if (value instanceof DeviceNode) { setBorder(BorderFactory.createEmptyBorder(2, 0, 3, 0)); Device device = ((DeviceNode) value).getDevice(); switch ((int) device.getType()) { case 0: if (device.isMounted()) { setIcon(IconLoader.getIcon(JajukIcons.DEVICE_DIRECTORY_MOUNTED_SMALL)); } else { setIcon(IconLoader.getIcon(JajukIcons.DEVICE_DIRECTORY_UNMOUNTED_SMALL)); } break; case 1: if (device.isMounted()) { setIcon(IconLoader.getIcon(JajukIcons.DEVICE_CD_MOUNTED_SMALL)); } else { setIcon(IconLoader.getIcon(JajukIcons.DEVICE_CD_UNMOUNTED_SMALL)); } break; case 2: if (device.isMounted()) { setIcon(IconLoader.getIcon(JajukIcons.DEVICE_NETWORK_DRIVE_MOUNTED_SMALL)); } else { setIcon(IconLoader.getIcon(JajukIcons.DEVICE_NETWORK_DRIVE_UNMOUNTED_SMALL)); } break; case 3: if (device.isMounted()) { setIcon(IconLoader.getIcon(JajukIcons.DEVICE_EXT_DD_MOUNTED_SMALL)); } else { setIcon(IconLoader.getIcon(JajukIcons.DEVICE_EXT_DD_UNMOUNTED_SMALL)); } break; case 4: if (device.isMounted()) { setIcon(IconLoader.getIcon(JajukIcons.DEVICE_PLAYER_MOUNTED_SMALL)); } else { setIcon(IconLoader.getIcon(JajukIcons.DEVICE_PLAYER_UNMOUNTED_SMALL)); } break; } } else if (value instanceof DirectoryNode) { setBorder(null); Directory dir = ((DirectoryNode) value).getDirectory(); boolean bSynchro = dir.getBooleanValue(Const.XML_DIRECTORY_SYNCHRONIZED); if (bSynchro) { // means this device is not synchronized setIcon(IconLoader.getIcon(JajukIcons.DIRECTORY_SYNCHRO)); } else { setIcon(IconLoader.getIcon(JajukIcons.DIRECTORY_DESYNCHRO)); } // collection node } else { setIcon(IconLoader.getIcon(JajukIcons.LIST)); } return this; } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/views/CatalogView.java0000644000175000017500000006336711720500104024644 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.views; import ext.FlowScrollPanel; import java.awt.Color; import java.awt.Dimension; import java.awt.FlowLayout; import java.awt.Insets; import java.awt.KeyboardFocusManager; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.ComponentListener; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.MouseWheelEvent; import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; import javax.swing.BorderFactory; import javax.swing.FocusManager; import javax.swing.JButton; import javax.swing.JComboBox; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JSlider; import javax.swing.JTextField; import javax.swing.JToolBar; import javax.swing.ScrollPaneConstants; import javax.swing.SwingUtilities; import javax.swing.Timer; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import net.miginfocom.swing.MigLayout; import org.jajuk.base.Album; import org.jajuk.base.AlbumComparator; import org.jajuk.base.AlbumManager; import org.jajuk.base.Directory; import org.jajuk.base.Item; import org.jajuk.base.PropertyMetaInformation; import org.jajuk.base.Track; import org.jajuk.base.TrackManager; import org.jajuk.events.JajukEvent; import org.jajuk.events.JajukEvents; import org.jajuk.events.ObservationManager; import org.jajuk.ui.helpers.DefaultMouseWheelListener; import org.jajuk.ui.helpers.FontManager; import org.jajuk.ui.helpers.FontManager.JajukFont; import org.jajuk.ui.helpers.TwoStepsDisplayable; import org.jajuk.ui.thumbnails.LocalAlbumThumbnail; import org.jajuk.ui.thumbnails.ThumbnailManager; import org.jajuk.ui.widgets.InformationJPanel; import org.jajuk.ui.widgets.JajukJToolbar; import org.jajuk.ui.widgets.SteppedComboBox; import org.jajuk.util.Conf; import org.jajuk.util.Const; import org.jajuk.util.Filter; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; import org.jajuk.util.UtilGUI; import org.jajuk.util.log.Log; import org.jdesktop.swingx.JXBusyLabel; /** * Catalog view. Displays all default covers by album *

    * Catalog perspectives */ public class CatalogView extends ViewAdapter implements ComponentListener, ActionListener, TwoStepsDisplayable { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; // Top control panel /** DOCUMENT_ME. */ JPanel jpControlTop; /** DOCUMENT_ME. */ JLabel jlSorter; /** DOCUMENT_ME. */ SteppedComboBox jcbSorter; /** DOCUMENT_ME. */ JLabel jlFilter; /** DOCUMENT_ME. */ SteppedComboBox jcbFilter; /** DOCUMENT_ME. */ JLabel jlContains; /** DOCUMENT_ME. */ JTextField jtfValue; /** DOCUMENT_ME. */ JButton jbPrev; /** DOCUMENT_ME. */ JButton jbNext; /** DOCUMENT_ME. */ SteppedComboBox jcbPage; // Bottom control panel /** DOCUMENT_ME. */ JPanel jpControlBottom; /** DOCUMENT_ME. */ JComboBox jcbShowCover; /** DOCUMENT_ME. */ JSlider jsSize; /** DOCUMENT_ME. */ FlowScrollPanel jpItems; /** DOCUMENT_ME. */ JScrollPane jsp; /** Filter properties. */ List alFilters; /** Sorter properties. */ List alSorters; /** Do search panel need a search. */ private boolean bNeedSearch = false; /** Populating flag. */ private boolean bPopulating = false; /** Default time in ms before launching a search automatically. */ private static final int WAIT_TIME = 600; /** Date last key pressed. */ private long lDateTyped; /** Last selected item. */ private LocalAlbumThumbnail item; /** Page index. */ private int page = 0; /** Number of page in current selection. */ int iNbPages = 0; /** Utility list used by size selector. */ private final List sizes = new ArrayList(10); /** Thumbs list *. */ private List thumbs; /** Last scrollbar position *. */ private int scrollPosition; /** Swing Timer to refresh the component. */ private final Timer timerSearch = new Timer(WAIT_TIME, new ActionListener() { @Override public void actionPerformed(ActionEvent e) { if (bNeedSearch && !bPopulating && (System.currentTimeMillis() - lDateTyped >= WAIT_TIME)) { // reset paging page = 0; populateCatalog(); bNeedSearch = false; } } }); /** * Gets the selected item. * * @return the selected item */ public LocalAlbumThumbnail getSelectedItem() { return item; } /* * (non-Javadoc) * * @see org.jajuk.ui.IView#display() */ @Override public void initUI() { initMetaInformation(); sizes.add(THUMBNAIL_SIZE_50X50); sizes.add(THUMBNAIL_SIZE_100X100); sizes.add(THUMBNAIL_SIZE_150X150); sizes.add(THUMBNAIL_SIZE_200X200); sizes.add(THUMBNAIL_SIZE_250X250); sizes.add(THUMBNAIL_SIZE_300X300); // --Top (most used) control items jpControlTop = new JPanel(); jlSorter = new JLabel(Messages.getString("Sort") + " "); jcbSorter = new SteppedComboBox(); jcbSorter.setEditable(false); // note that a single album can contains tracks with different artists // or genres, we will show it only one for (PropertyMetaInformation meta : alSorters) { jcbSorter.addItem(meta.getHumanName()); } jcbSorter.setSelectedIndex(Conf.getInt(Const.CONF_THUMBS_SORTER)); jcbSorter.addActionListener(this); jlFilter = new JLabel(Messages.getString("AbstractTableView.0") + " "); jlContains = new JLabel(" " + Messages.getString("AbstractTableView.7") + " "); jcbFilter = new SteppedComboBox(); jcbFilter.setEditable(false); // note that a single album can contains tracks with different artists // or genres, we will show it only one for (PropertyMetaInformation meta : alFilters) { if (meta == null) { // "any" filter jcbFilter.addItem(Messages.getString("AbstractTableView.8")); } else { jcbFilter.addItem(meta.getHumanName()); } } jcbFilter.setSelectedIndex(Conf.getInt(Const.CONF_THUMBS_FILTER)); jcbFilter.addActionListener(this); jtfValue = new JTextField(); jtfValue.setForeground(new Color(172, 172, 172)); jtfValue.setMargin(new Insets(0, 3, 0, 0)); jtfValue.setFont(FontManager.getInstance().getFont(JajukFont.SEARCHBOX)); jtfValue.addKeyListener(new CatalogViewKeyAdaptor()); JToolBar jtbPage = new JajukJToolbar(); jtbPage.setFloatable(false); jtbPage.setRollover(true); jbPrev = new JButton(IconLoader.getIcon(JajukIcons.PLAYER_PREVIOUS_SMALL)); jbPrev.setToolTipText(Messages.getString("CatalogView.12")); jbPrev.addActionListener(this); jbNext = new JButton(IconLoader.getIcon(JajukIcons.PLAYER_NEXT_SMALL)); jbNext.setToolTipText(Messages.getString("CatalogView.13")); jbNext.addActionListener(this); jcbPage = new SteppedComboBox(); jcbPage.setToolTipText(Messages.getString("CatalogView.14")); jcbPage.addActionListener(this); jtbPage.add(jbPrev); jtbPage.add(jcbPage); jtbPage.add(jbNext); jpControlTop.setLayout(new MigLayout("ins 3", "[grow][grow][grow][grow]")); jpControlTop.add(jlFilter, "split 2"); jpControlTop.add(jcbFilter, "grow"); jpControlTop.add(jlContains, "split 2"); jpControlTop.add(jtfValue, "gapright 40,grow,width 100::"); jpControlTop.add(jlSorter, "split 2"); jpControlTop.add(jcbSorter, "gapright 40,grow"); jpControlTop.add(jtbPage, "gapright 5,grow"); // --Bottom (less used) items jcbShowCover = new JComboBox(); jcbShowCover.addItem(Messages.getString("CatalogView.21")); jcbShowCover.addItem(Messages.getString("CatalogView.22")); jcbShowCover.addItem(Messages.getString("CatalogView.2")); jcbShowCover.setSelectedIndex(Conf.getInt(Const.CONF_THUMBS_SHOW_COVER)); jcbShowCover.addActionListener(this); JLabel jlSize = new JLabel(Messages.getString("CatalogView.15")); jsSize = new JSlider(0, 5); jsSize.setMajorTickSpacing(1); jsSize.setMinorTickSpacing(1); jsSize.setSnapToTicks(true); jsSize.setPaintTicks(true); jsSize.addMouseWheelListener(new CatalogViewMouseWheelListener(jsSize)); int index = sizes.indexOf(Conf.getString(Const.CONF_THUMBS_SIZE)); if (index < 0) { index = 2; // 150x150 if a problem occurs } jsSize.setValue(index); // compute size string for slider tooltip String sizeToDisplay = "" + (50 + 50 * index) + "x" + "" + (50 + 50 * index); jsSize.setToolTipText(Messages.getString("CatalogView.4") + " " + sizeToDisplay); jsSize.addChangeListener(new ChangeListener() { @Override public void stateChanged(ChangeEvent arg0) { sliderValueChanged(); } }); jpControlBottom = new JPanel(new MigLayout("gapx 20")); jpControlBottom.add(jcbShowCover); jpControlBottom.add(jlSize, "split 2"); jpControlBottom.add(jsSize); // Set layout initLayout(); populateCatalog(); // subscriptions to events ObservationManager.register(this); // Show facts showFacts(); // Start the timers timerSearch.start(); } /** * Inits the meta information. * DOCUMENT_ME */ private void initMetaInformation() { alFilters = new ArrayList(10); alFilters.add(null); // All alFilters.add(TrackManager.getInstance().getMetaInformation(Const.XML_TRACK_GENRE)); alFilters.add(TrackManager.getInstance().getMetaInformation(Const.XML_TRACK_ARTIST)); alFilters.add(TrackManager.getInstance().getMetaInformation(Const.XML_TRACK_ALBUM)); alFilters.add(TrackManager.getInstance().getMetaInformation(Const.XML_YEAR)); // please note: this needs to be kept in-sync with what we do in // AlbumComparator! alSorters = new ArrayList(10); alSorters.add(TrackManager.getInstance().getMetaInformation(Const.XML_TRACK_GENRE)); alSorters.add(TrackManager.getInstance().getMetaInformation(Const.XML_TRACK_ARTIST)); alSorters.add(TrackManager.getInstance().getMetaInformation(Const.XML_TRACK_ALBUM)); alSorters.add(TrackManager.getInstance().getMetaInformation(Const.XML_YEAR)); alSorters.add(TrackManager.getInstance().getMetaInformation(Const.XML_TRACK_DISCOVERY_DATE)); alSorters.add(TrackManager.getInstance().getMetaInformation(Const.XML_TRACK_RATE)); alSorters.add(TrackManager.getInstance().getMetaInformation(Const.XML_TRACK_HITS)); } /** * Initialize final layout and add main panels. */ private void initLayout() { // Remove any busy label if (getComponentCount() > 0) { removeAll(); } jpItems = new FlowScrollPanel(); jsp = new JScrollPane(jpItems, ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED); jsp.setBorder(BorderFactory.createEmptyBorder(0, 1, 0, 0)); jpItems.setScroller(jsp); jpItems.setLayout(new FlowLayout(FlowLayout.LEFT)); // global layout setLayout(new MigLayout("", "[grow]", "[][grow][]")); add(jpControlTop, "grow,wrap"); add(jsp, "wrap,grow"); add(jpControlBottom, "grow"); revalidate(); repaint(); } /** * Reset the catalog view and show a busy label Must be called from the EDT. */ private void showBusyLabel() { if (getComponentCount() > 0) { removeAll(); } JXBusyLabel busy = new JXBusyLabel(new Dimension(100, 100)); busy.setBusy(true); setLayout(new MigLayout("", "[grow]", "[grow]")); add(busy, "center"); revalidate(); repaint(); } /** * Show various information in the information panel. */ private void showFacts() { // display facts in the information panel // n albums String sMessage = AlbumManager.getInstance().getElementCount() + " " + Messages.getString("CatalogView.16"); int albumsPerPage = Conf.getInt(Const.CONF_CATALOG_PAGE_SIZE); // n albums / page if (albumsPerPage > 0) { sMessage += " - " + albumsPerPage + Messages.getString("CatalogView.17"); } InformationJPanel.getInstance().setSelection(sMessage); } /* * (non-Javadoc) * * @see org.jajuk.events.Observer#getRegistrationKeys() */ @Override public Set getRegistrationKeys() { Set eventSubjectSet = new HashSet(); eventSubjectSet.add(JajukEvents.DEVICE_REFRESH); eventSubjectSet.add(JajukEvents.DEVICE_MOUNT); eventSubjectSet.add(JajukEvents.DEVICE_UNMOUNT); eventSubjectSet.add(JajukEvents.COVER_DEFAULT_CHANGED); eventSubjectSet.add(JajukEvents.PARAMETERS_CHANGE); return eventSubjectSet; } /** * Populate the catalog *

    * Must be called from the EDT. */ private void populateCatalog() { // Prevent unwanted view population requests, do not try to synchronize // 'this' : too many threads if (bPopulating) { Log.debug("Already populating the catalog view"); return; } bPopulating = true; // Store current state scrollPosition = jsp.getVerticalScrollBar().getValue(); thumbs = new ArrayList(100); // Clear all the view and show a busy label instead showBusyLabel(); // Show the page UtilGUI.populate(this); } /** * Compute the catalog page to be displayed. *

    * Do *not* call this from the EDT, can take a while to run * * @return the object */ @Override public Object longCall() { // Every albums List albums = null; // The final album list we will display List pageAlbums = new ArrayList(Conf.getInt(Const.CONF_CATALOG_PAGE_SIZE)); try { Filter filter = null; if (jtfValue.getText().length() > 0) { PropertyMetaInformation meta = alFilters.get(jcbFilter.getSelectedIndex()); filter = new Filter((meta == null) ? null : meta.getName(), jtfValue.getText(), true, false); } // filter albums matching tracks List alAllTracks = TrackManager.getInstance().getTracks(); Filter.filterItems(alAllTracks, filter); // keep matching albums HashSet hsAlbums = new HashSet(alAllTracks.size() / 10); for (Item item : alAllTracks) { Track track = (Track) item; Album album = track.getAlbum(); hsAlbums.add(album); } // Remove albums with no cover if required Iterator itAlbums = hsAlbums.iterator(); while (itAlbums.hasNext()) { Album album = itAlbums.next(); if (jcbShowCover.getSelectedIndex() == Const.CATALOG_VIEW_COVER_MODE_WITH && !album.containsCover()) { itAlbums.remove(); } else if (jcbShowCover.getSelectedIndex() == Const.CATALOG_VIEW_COVER_MODE_WITHOUT && album.containsCover()) { itAlbums.remove(); } } albums = new ArrayList(hsAlbums); // sort albums final int index = jcbSorter.getSelectedIndex(); Collections.sort(albums, new AlbumComparator(index)); // Now process each album Set directories = new HashSet(albums.size()); Iterator it = albums.iterator(); while (it.hasNext()) { Album album = it.next(); // if hide unmounted tracks is set, continue if (Conf.getBoolean(Const.CONF_OPTIONS_HIDE_UNMOUNTED)) { // test if album contains at least one mounted file List trackset = TrackManager.getInstance().getAssociatedTracks(album, false); if (trackset.size() == 0) { it.remove(); continue; } boolean bOK = false; for (Track track : trackset) { if (track.getReadyFiles().size() > 0) { bOK = true; break; } } if (!bOK) { it.remove(); continue; } } // Take first track of album (to get detailed // information) Track anyTrack = album.getAnyTrack(); if (anyTrack != null) { // Take the directory of any file of the track List fileList = anyTrack.getFiles(); if (fileList.size() > 0) { Directory dir = fileList.get(0).getDirectory(); directories.add(dir); } } } // Force thumbs build if required, this is the longest task of this worker // we only keep albums for this page // computes the number of pages int iSize = Conf.getInt(Const.CONF_CATALOG_PAGE_SIZE); if (iSize == 0) { iNbPages = 1; } else { // add one page for trailing items iNbPages = albums.size() / iSize + ((albums.size() % iSize == 0) ? 0 : 1); } // After user changed the number of thumbs on a page, we can be // out of bounds exception so make sure to reinit the page index in // this case if (page >= jcbPage.getItemCount()) { page = 0; } // Add all items int max = albums.size(); // upper limit if (page < (iNbPages - 1)) { // if last page, take simply to total number of // items to display max = (page + 1) * Conf.getInt(Const.CONF_CATALOG_PAGE_SIZE); } // Populate each thumb if required (THIS IS LOOOOOONG) for (int i = page * Conf.getInt(Const.CONF_CATALOG_PAGE_SIZE); i < max; i++) { Album album = albums.get(i); pageAlbums.add(album); ThumbnailManager.refreshThumbnail(album, getSelectedSize()); } } finally { // Make sure to reset the populating flag in case of problem // Note that this flag is reseted here and not in the shortCall() method // because the shortCall method is not called in case of Exception thrown // in the longCall() method. bPopulating = false; } return pageAlbums; } /** * Catalog page display (must be called from the EDT). * * @param in DOCUMENT_ME */ @Override public void shortCall(Object in) { @SuppressWarnings("unchecked") List albums = (List) in; if (in == null) { stopAllBusyLabels(); return; } // Populate each thumb if required (this is short because the thumb should have already been built in the long call ) for (Album album : albums) { final LocalAlbumThumbnail thumb = new LocalAlbumThumbnail(album, getSelectedSize(), true); thumb.populate(); thumbs.add(thumb); // restore previous selected item if still set if (item != null) { if (((Album) thumb.getItem()).equals(item.getItem())) { CatalogView.this.item = thumb; CatalogView.this.item.setSelected(true); } } // Thumb selection mouse listener thumb.getIcon().addMouseListener(new MouseAdapter() { @Override public void mousePressed(MouseEvent e) { LocalAlbumThumbnail thumb = (LocalAlbumThumbnail) ((JLabel) e.getSource()).getParent(); // Unselect previous thumb if (CatalogView.this.item != null && CatalogView.this.item != thumb) { CatalogView.this.item.setSelected(false); } // Select new thumb thumb.setSelected(true); CatalogView.this.item = thumb; } }); } // populate page selector // remove action listener jcbPage.removeActionListener(CatalogView.this); jcbPage.removeAllItems(); // void it for (int i = 0; i < iNbPages; i++) { // add the pages jcbPage.addItem(Messages.getString("CatalogView.11") + " " + (i + 1) + "/" + iNbPages); // start at page 1, not 0 } if (iNbPages > 0) { jcbPage.setSelectedIndex(page); jcbPage.addActionListener(CatalogView.this); } initLayout(); for (LocalAlbumThumbnail thumb : thumbs) { jpItems.add(thumb); } // The scrollbar must be set after current EDT work to be // effective, // so queue it SwingUtilities.invokeLater(new Runnable() { @Override public void run() { jsp.getVerticalScrollBar().setValue(scrollPosition); } }); jtfValue.requestFocusInWindow(); UtilGUI.stopWaiting(); } /* * (non-Javadoc) * * @see org.jajuk.ui.Observer#update(java.lang.String) */ @Override public void update(JajukEvent event) { JajukEvents subject = event.getSubject(); if (JajukEvents.DEVICE_REFRESH.equals(subject) || JajukEvents.COVER_DEFAULT_CHANGED.equals(subject) || JajukEvents.DEVICE_MOUNT.equals(subject) || JajukEvents.DEVICE_UNMOUNT.equals(subject) || JajukEvents.PARAMETERS_CHANGE.equals(subject)) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { populateCatalog(); } }); } // In all cases, update the facts showFacts(); } /* * (non-Javadoc) * * @see org.jajuk.ui.IView#getDesc() */ @Override public String getDesc() { return Messages.getString("CatalogView.0"); } /* * (non-Javadoc) * * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent) */ @Override public void actionPerformed(final ActionEvent e) { if (e.getSource() == jcbFilter) { if (jtfValue.getText().trim().equals("")) { // no need to refresh return; } bNeedSearch = true; lDateTyped = System.currentTimeMillis(); Conf.setProperty(Const.CONF_THUMBS_FILTER, Integer.toString(jcbFilter.getSelectedIndex())); } else if (e.getSource() == jcbSorter) { bNeedSearch = true; lDateTyped = System.currentTimeMillis(); Conf.setProperty(Const.CONF_THUMBS_SORTER, Integer.toString(jcbSorter.getSelectedIndex())); } else if (e.getSource() == jcbShowCover) { Conf.setProperty(Const.CONF_THUMBS_SHOW_COVER, Integer.toString(jcbShowCover.getSelectedIndex())); // Reset page to zero to avoid out of bounds exceptions, when restricting // the filter, less pages are available page = 0; // display thumbs populateCatalog(); } else if (e.getSource() == jbPrev) { if (page > 0) { page--; } else { page = iNbPages - 1; // go to last } populateCatalog(); } else if (e.getSource() == jbNext) { if (page < (iNbPages - 1)) { page++; } else { page = 0; // go to first } populateCatalog(); } else if (e.getSource() == jcbPage) { page = jcbPage.getSelectedIndex(); populateCatalog(); } else { this.item.actionPerformed(e); } } /** * Gets the selected size. * * @return current thumbs size as selected with the combo */ private int getSelectedSize() { return 50 + (50 * jsSize.getValue()); } /** * DOCUMENT_ME. */ private class CatalogViewKeyAdaptor extends KeyAdapter { /* * (non-Javadoc) * * @see java.awt.event.KeyAdapter#keyReleased(java.awt.event.KeyEvent) */ @Override public void keyReleased(KeyEvent e) { // Ignore escape press, they can come from popup closing if (e.getKeyCode() != KeyEvent.VK_ESCAPE) { bNeedSearch = true; lDateTyped = System.currentTimeMillis(); } } } /** * DOCUMENT_ME. */ private class CatalogViewMouseWheelListener extends DefaultMouseWheelListener { /** * Instantiates a new catalog view mouse wheel listener. * * @param js DOCUMENT_ME */ public CatalogViewMouseWheelListener(JSlider js) { super(js); } /* * (non-Javadoc) * * @see * org.jajuk.ui.helpers.DefaultMouseWheelListener#mouseWheelMoved(java.awt.event.MouseWheelEvent * ) */ @Override public void mouseWheelMoved(MouseWheelEvent mwe) { ChangeListener cl = jsSize.getChangeListeners()[0]; // Remove the concurrent change listener jsSize.removeChangeListener(cl); super.mouseWheelMoved(mwe); sliderValueChanged(); // Add again the change listener jsSize.addChangeListener(cl); } } /** * Factorized code for thumb size change. */ private void sliderValueChanged() { // Leave user didn't release the move yet if (jsSize.getValueIsAdjusting()) { return; } // Store size Conf.setProperty(Const.CONF_THUMBS_SIZE, sizes.get(jsSize.getValue())); // display thumbs populateCatalog(); // Adjust tooltips // compute size string for slider tooltip String size = "" + (50 + 50 * jsSize.getValue()) + "x" + "" + (50 + 50 * jsSize.getValue()); jsSize.setToolTipText(Messages.getString("CatalogView.4") + " " + size); } /* * (non-Javadoc) * * @see org.jajuk.ui.views.ViewAdapter#cleanup() */ @Override public void cleanup() { // make sure the timer is not running any more timerSearch.stop(); // we specifically request the focus for jtfValue, therefore we should make sure that we release // that focus to let this be destroyed KeyboardFocusManager.getCurrentKeyboardFocusManager().clearGlobalFocusOwner(); // call the parent class to do more cleanup if necessary super.cleanup(); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/views/AbstractTreeView.java0000644000175000017500000003214711720500104025645 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.views; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Properties; import java.util.Set; import javax.swing.Action; import javax.swing.ActionMap; import javax.swing.InputMap; import javax.swing.JButton; import javax.swing.JComponent; import javax.swing.JMenuItem; import javax.swing.JScrollPane; import javax.swing.JTree; import javax.swing.KeyStroke; import javax.swing.SwingUtilities; import javax.swing.SwingWorker; import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.DefaultTreeModel; import javax.swing.tree.TreePath; import javax.swing.tree.TreeSelectionModel; import org.jajuk.base.Item; import org.jajuk.events.JajukEvent; import org.jajuk.events.JajukEvents; import org.jajuk.ui.actions.ActionManager; import org.jajuk.ui.actions.JajukActions; import org.jajuk.ui.helpers.LazyLoadingTreeExpander; import org.jajuk.ui.helpers.PreferencesJMenu; import org.jajuk.ui.widgets.JajukToggleButton; import org.jajuk.util.Conf; import org.jajuk.util.Const; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; import org.jdesktop.swingx.JXTree; /** * An abstract files or tracks tree view. Contains common methods */ public abstract class AbstractTreeView extends ViewAdapter { /** Generated serialVersionUID. */ private static final long serialVersionUID = 8330315957562739918L; /** The tree scrollpane. */ JScrollPane jspTree; /** The phyical tree. */ JXTree jtree; /** The table/tree sync toggle button. */ JajukToggleButton jtbSync; /** the collapse all button. */ JButton jbCollapseAll; /** Current selection. */ TreePath[] paths; /** Resursive items selection. */ Set selectedRecursively = new HashSet(100); /** Items selection. */ List alSelected = new ArrayList(100); /** Top tree node. */ DefaultMutableTreeNode top; /** DOCUMENT_ME. */ javax.swing.JPopupMenu jmenu; /** DOCUMENT_ME. */ JMenuItem jmiPlay; /** DOCUMENT_ME. */ JMenuItem jmiPush; /** DOCUMENT_ME. */ JMenuItem jmiFrontPush; /** DOCUMENT_ME. */ JMenuItem jmiPlayShuffle; /** DOCUMENT_ME. */ JMenuItem jmiPlayRepeat; /** DOCUMENT_ME. */ JMenuItem jmiCut; /** DOCUMENT_ME. */ JMenuItem jmiCopy; /** DOCUMENT_ME. */ JMenuItem jmiPaste; /** DOCUMENT_ME. */ JMenuItem jmiRename; /** DOCUMENT_ME. */ JMenuItem jmiDelete; /** DOCUMENT_ME. */ JMenuItem jmiNewFolder; /** DOCUMENT_ME. */ JMenuItem jmiAddFavorite; /** DOCUMENT_ME. */ JMenuItem jmiReport; /** DOCUMENT_ME. */ JMenuItem jmiProperties; /** DOCUMENT_ME. */ JMenuItem jmiCDDBWizard; /** DOCUMENT_ME. */ JMenuItem jmiCopyURL; /** Jtree scroller position*. */ private int pos; /** Preference menu. */ PreferencesJMenu pjmTracks; /** Used to differentiate user action tree collapse from code tree collapse. */ boolean bManualAction = true; /** Used to differentiate tree/table sync due to internal events from users's ones. */ boolean bInternalAction = false; /** Flag used to set tree is refreshing */ boolean refreshing = false; /* * (non-Javadoc) * * @see org.jajuk.events.Observer#getRegistrationKeys() */ @Override public Set getRegistrationKeys() { Set eventSubjectSet = new HashSet(); eventSubjectSet.add(JajukEvents.FILE_LAUNCHED); eventSubjectSet.add(JajukEvents.DEVICE_MOUNT); eventSubjectSet.add(JajukEvents.DEVICE_UNMOUNT); eventSubjectSet.add(JajukEvents.DEVICE_REFRESH); eventSubjectSet.add(JajukEvents.CDDB_WIZARD); eventSubjectSet.add(JajukEvents.PARAMETERS_CHANGE); eventSubjectSet.add(JajukEvents.TABLE_SELECTION_CHANGED); return eventSubjectSet; } /** * Creates the tree. DOCUMENT_ME * * @param bLazy DOCUMENT_ME * * @return the j tree */ protected JTree createTree(boolean bLazy) { jtree = new JXTree(top); jtree.putClientProperty("JTree.lineStyle", "Angled"); jtree.getSelectionModel().setSelectionMode(TreeSelectionModel.DISCONTIGUOUS_TREE_SELECTION); setKeystrokes(); // set the special controller for doing lazy loading if used for this View if (bLazy) { final LazyLoadingTreeExpander controller = new LazyLoadingTreeExpander( (DefaultTreeModel) jtree.getModel()); jtree.addTreeWillExpandListener(controller); } return jtree; } /* * (non-Javadoc) * * @see org.jajuk.ui.views.IView#initUI() */ @Override public void initUI() { jmiPlay = new JMenuItem(ActionManager.getAction(JajukActions.PLAY_SELECTION)); jmiPlay.putClientProperty(Const.DETAIL_SELECTION, alSelected); jmiFrontPush = new JMenuItem(ActionManager.getAction(JajukActions.PUSH_FRONT_SELECTION)); jmiFrontPush.putClientProperty(Const.DETAIL_SELECTION, alSelected); jmiPush = new JMenuItem(ActionManager.getAction(JajukActions.PUSH_SELECTION)); jmiPush.putClientProperty(Const.DETAIL_SELECTION, alSelected); jmiPlayShuffle = new JMenuItem(ActionManager.getAction(JajukActions.PLAY_SHUFFLE_SELECTION)); jmiPlayShuffle.putClientProperty(Const.DETAIL_SELECTION, alSelected); jmiPlayRepeat = new JMenuItem(ActionManager.getAction(JajukActions.PLAY_REPEAT_SELECTION)); jmiPlayRepeat.putClientProperty(Const.DETAIL_SELECTION, alSelected); jmiCut = new JMenuItem(ActionManager.getAction(JajukActions.CUT)); jmiCut.putClientProperty(Const.DETAIL_SELECTION, alSelected); jmiCopy = new JMenuItem(ActionManager.getAction(JajukActions.COPY)); jmiCopy.putClientProperty(Const.DETAIL_SELECTION, alSelected); jmiPaste = new JMenuItem(ActionManager.getAction(JajukActions.PASTE)); jmiPaste.putClientProperty(Const.DETAIL_SELECTION, alSelected); jmiRename = new JMenuItem(ActionManager.getAction(JajukActions.RENAME)); jmiRename.putClientProperty(Const.DETAIL_SELECTION, alSelected); jmiDelete = new JMenuItem(ActionManager.getAction(JajukActions.DELETE)); jmiDelete.putClientProperty(Const.DETAIL_SELECTION, alSelected); jmiNewFolder = new JMenuItem(ActionManager.getAction(JajukActions.NEW_FOLDER)); jmiNewFolder.putClientProperty(Const.DETAIL_SELECTION, alSelected); jmiAddFavorite = new JMenuItem(ActionManager.getAction(JajukActions.BOOKMARK_SELECTION)); jmiAddFavorite.putClientProperty(Const.DETAIL_SELECTION, alSelected); jmiCDDBWizard = new JMenuItem(ActionManager.getAction(JajukActions.CDDB_SELECTION)); jmiCDDBWizard.putClientProperty(Const.DETAIL_SELECTION, alSelected); jmiReport = new JMenuItem(ActionManager.getAction(JajukActions.CREATE_REPORT)); // Add custom data to this component in order to allow the ReportAction // to be able to get it jmiReport.putClientProperty(Const.DETAIL_ORIGIN, XML_GENRE); jmiReport.putClientProperty(Const.DETAIL_SELECTION, alSelected); jmiProperties = new JMenuItem(ActionManager.getAction(JajukActions.SHOW_PROPERTIES)); jmiProperties.putClientProperty(Const.DETAIL_SELECTION, alSelected); jmiCopyURL = new JMenuItem(ActionManager.getAction(JajukActions.COPY_TO_CLIPBOARD)); jmiCopyURL.putClientProperty(Const.DETAIL_CONTENT, alSelected); pjmTracks = new PreferencesJMenu(alSelected); // Create the sync toggle button and restore its state jtbSync = new JajukToggleButton(ActionManager.getAction(JajukActions.SYNC_TREE_TABLE)); jtbSync.putClientProperty(Const.DETAIL_VIEW, getID()); jtbSync.setSelected(Conf.getBoolean(Const.CONF_SYNC_TABLE_TREE + "." + getID())); // Create the collapse all button, no need to a dedicated Action here as it // is used only in this class jbCollapseAll = new JButton(IconLoader.getIcon(JajukIcons.REMOVE)); jbCollapseAll.setToolTipText(Messages.getString("AbstractTreeView.0")); jbCollapseAll.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { jtree.collapseAll(); // better to show at least the first level of items jtree.expandRow(0); jtree.setSelectionInterval(0, 0); } }); } /** * Populate tree. DOCUMENT_ME */ abstract void populateTree(); /** * Expand. DOCUMENT_ME */ abstract void expand(); /** * Expand a given item. * * @param item DOCUMENT_ME */ abstract void scrollTo(Item item); /** * Add keystroke support on the tree. */ private void setKeystrokes() { jtree.putClientProperty(Const.DETAIL_SELECTION, alSelected); InputMap inputMap = jtree.getInputMap(JComponent.WHEN_FOCUSED); ActionMap actionMap = jtree.getActionMap(); // Delete Action action = ActionManager.getAction(JajukActions.DELETE); inputMap.put(KeyStroke.getKeyStroke("DELETE"), "delete"); actionMap.put("delete", action); // Ctrl C action = ActionManager.getAction(JajukActions.COPY); inputMap.put(KeyStroke.getKeyStroke("ctrl C"), "copy"); actionMap.put("copy", action); // Ctrl X action = ActionManager.getAction(JajukActions.CUT); inputMap.put(KeyStroke.getKeyStroke("ctrl X"), "cut"); actionMap.put("cut", action); // Ctrl V action = ActionManager.getAction(JajukActions.PASTE); inputMap.put(KeyStroke.getKeyStroke("ctrl V"), "paste"); actionMap.put("paste", action); // Properties ALT/ENTER action = ActionManager.getAction(JajukActions.SHOW_PROPERTIES); inputMap.put(KeyStroke.getKeyStroke("alt ENTER"), "properties"); actionMap.put("properties", action); // Rename / F2 action = ActionManager.getAction(JajukActions.RENAME); inputMap.put(KeyStroke.getKeyStroke("F2"), "rename"); actionMap.put("rename", action); } /* * (non-Javadoc) * * @see org.jajuk.events.Observer#update(org.jajuk.events.JajukEvent) */ @Override public void update(JajukEvent event) { final JajukEvents subject = event.getSubject(); if (subject.equals(JajukEvents.DEVICE_MOUNT) || subject.equals(JajukEvents.DEVICE_UNMOUNT) || subject.equals(JajukEvents.DEVICE_REFRESH) || subject.equals(JajukEvents.PARAMETERS_CHANGE)) { SwingWorker sw = new SwingWorker() { @Override public Void doInBackground() { if (jspTree != null) { pos = jspTree.getVerticalScrollBar().getValue(); } populateTree(); return null; } @Override public void done() { SwingUtilities.updateComponentTreeUI(jtree); bManualAction = false; expand(); bManualAction = true; // Reset last position in tree // The scrollbar must be set after current EDT work to be effective, // so queue it SwingUtilities.invokeLater(new Runnable() { @Override public void run() { if (jspTree != null) { jspTree.getVerticalScrollBar().setValue(pos); } } }); } }; sw.execute(); } else if (JajukEvents.TABLE_SELECTION_CHANGED.equals(subject)) { // Check if the sync tree table option is set for this tree if (Conf.getBoolean(Const.CONF_SYNC_TABLE_TREE + "." + getID())) { // Consume only events from the same perspective and different view // (for table/tree synchronization) Properties details = event.getDetails(); if (details != null) { String sourcePerspective = details.getProperty(Const.DETAIL_PERSPECTIVE); IView sourceView = (IView) details.get(Const.DETAIL_VIEW); if (!(sourcePerspective.equals(getPerspective().getID())) //source view is null if the table is outside a view like CDDB dialog || sourceView == null // Same view ? ignore... || sourceView.getID().equals(getID())) { return; } @SuppressWarnings("unchecked") List selection = (List) details.get(Const.DETAIL_SELECTION); if (selection.size() == 0) { return; } // for tree/table consideration, we only expand the first found item, we don't // support // multiple expands (useful?) final Item item = selection.get(0); SwingUtilities.invokeLater(new Runnable() { @Override public void run() { scrollTo(item); } }); } } } } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/views/AnimationView.java0000644000175000017500000001561711720500104025204 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.views; import com.jgoodies.animation.Animation; import com.jgoodies.animation.Animations; import com.jgoodies.animation.Animator; import com.jgoodies.animation.animations.BasicTextAnimation; import com.jgoodies.animation.components.BasicTextLabel; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Font; import java.awt.FontMetrics; import java.awt.event.ComponentEvent; import java.awt.event.ComponentListener; import java.util.HashSet; import java.util.Set; import javax.swing.SwingUtilities; import org.jajuk.base.File; import org.jajuk.events.JajukEvent; import org.jajuk.events.JajukEvents; import org.jajuk.events.ObservationManager; import org.jajuk.services.players.QueueModel; import org.jajuk.services.webradio.WebRadio; import org.jajuk.ui.windows.JajukMainWindow; import org.jajuk.util.Conf; import org.jajuk.util.Const; import org.jajuk.util.Messages; import org.jajuk.util.UtilFeatures; import org.jajuk.util.UtilString; import org.jajuk.util.error.JajukException; import org.jajuk.util.log.Log; /** * Animation-based view. */ public class AnimationView extends ViewAdapter implements ComponentListener { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** The Constant DEFAULT_FRAME_RATE. DOCUMENT_ME */ private static final int DEFAULT_FRAME_RATE = 25; /** The Constant DEFAULT_DURATION. DOCUMENT_ME */ private static final int DEFAULT_DURATION = 5000; /** The Constant DEFAULT_PAUSE. DOCUMENT_ME */ private static final int DEFAULT_PAUSE = 500; /** Current panel width*. */ private int iSize; /** DOCUMENT_ME. */ private BasicTextLabel btl1; /** DOCUMENT_ME. */ private Animator animator; /** * Instantiates a new animation view. */ public AnimationView() { } /* * (non-Javadoc) * * @see org.jajuk.ui.views.IView#getDesc() */ @Override public String getDesc() { return Messages.getString("AnimationView.0"); } /* * (non-Javadoc) * * @see org.jajuk.ui.views.IView#populate() */ @Override public void initUI() { setLayout(new BorderLayout()); addComponentListener(this); btl1 = new BasicTextLabel(" "); add(btl1); // Force initial message refresh UtilFeatures.updateStatus(this); ObservationManager.register(this); } /* (non-Javadoc) * @see org.jajuk.events.Observer#getRegistrationKeys() */ @Override public Set getRegistrationKeys() { Set eventSubjectSet = new HashSet(); eventSubjectSet.add(JajukEvents.FILE_LAUNCHED); eventSubjectSet.add(JajukEvents.WEBRADIO_LAUNCHED); eventSubjectSet.add(JajukEvents.ZERO); eventSubjectSet.add(JajukEvents.PLAYER_STOP); return eventSubjectSet; } /** * Set the text to be displayed*. * * @param sText DOCUMENT_ME */ public void setText(final String sText) { SwingUtilities.invokeLater(new Runnable() { // this is mandatory to // get actual getWitdth @Override public void run() { iSize = AnimationView.this.getWidth(); // current width. Must be called inside an invoke and wait, // otherwise, returns zero Font font = null; boolean bOk = false; int i = 40; while (!bOk) { font = new Font("verdana", Font.BOLD, i); FontMetrics fontMetrics = JajukMainWindow.getInstance().getFontMetrics(font); int iFontSize = SwingUtilities.computeStringWidth(fontMetrics, sText); if (iFontSize <= iSize - 150) { bOk = true; } else { i--; } } btl1.setFont(font); if (animator != null) { animator.stop(); } Animation animPause = Animations.pause(DEFAULT_PAUSE); Animation anim = null; // select a random animation int iShuffle = (int) (Math.random() * 3); switch (iShuffle) { case 0: anim = BasicTextAnimation.defaultScale(btl1, DEFAULT_DURATION, sText, Color.darkGray); break; case 1: anim = BasicTextAnimation.defaultSpace(btl1, DEFAULT_DURATION, sText, Color.darkGray); break; case 2: anim = BasicTextAnimation.defaultFade(btl1, DEFAULT_DURATION, sText, Color.darkGray); break; } Animation animAll = Animations.sequential(anim, animPause); anim = Animations.repeat(Float.POSITIVE_INFINITY, animAll); animator = new Animator(anim, DEFAULT_FRAME_RATE); animator.start(); } }); } /* * (non-Javadoc) * * @see org.jajuk.ui.Observer#update(java.lang.String) */ @Override public void update(JajukEvent event) { JajukEvents subject = event.getSubject(); if (subject.equals(JajukEvents.FILE_LAUNCHED)) { File file = QueueModel.getPlayingFile(); if (file != null) { String s = ""; try { s = UtilString.applyPattern(file, Conf.getString(Const.CONF_PATTERN_ANIMATION), false, false); } catch (JajukException e) { Log.error(e); } setText(s); } } else if (subject.equals(JajukEvents.ZERO) || subject.equals(JajukEvents.PLAYER_STOP)) { setText(Messages.getString("JajukWindow.18")); } else if (subject.equals(JajukEvents.WEBRADIO_LAUNCHED)) { WebRadio radio = (WebRadio) event.getDetails().get(Const.DETAIL_CONTENT); if (radio != null) { setText(radio.getName()); } } } /* * (non-Javadoc) * * @see java.awt.event.ComponentListener#componentResized(java.awt.event.ComponentEvent) */ @Override public void componentResized(ComponentEvent e) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { iSize = SwingUtilities.getRootPane(AnimationView.this).getWidth(); UtilFeatures.updateStatus(AnimationView.this); } }); } /* (non-Javadoc) * @see org.jajuk.ui.views.ViewAdapter#cleanup() */ @Override public void cleanup() { // make sure animation is stopped if (animator != null) { animator.stop(); animator = null; } super.cleanup(); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/views/AbstractTableView.java0000644000175000017500000006666711720500104026013 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.views; import ext.AutoCompleteDecorator; import java.awt.Color; import java.awt.Insets; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.util.HashSet; import java.util.List; import java.util.Properties; import java.util.Set; import javax.swing.Action; import javax.swing.ActionMap; import javax.swing.BorderFactory; import javax.swing.InputMap; import javax.swing.JComboBox; import javax.swing.JComponent; import javax.swing.JLabel; import javax.swing.JMenuItem; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTable; import javax.swing.JTextField; import javax.swing.KeyStroke; import javax.swing.SwingUtilities; import javax.swing.SwingWorker; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import javax.swing.event.TableModelEvent; import javax.swing.event.TableModelListener; import javax.swing.table.TableColumn; import net.miginfocom.swing.MigLayout; import org.jajuk.base.AlbumArtistManager; import org.jajuk.base.ArtistManager; import org.jajuk.base.File; import org.jajuk.base.GenreManager; import org.jajuk.base.Item; import org.jajuk.base.ItemManager; import org.jajuk.events.JajukEvent; import org.jajuk.events.JajukEvents; import org.jajuk.events.ObservationManager; import org.jajuk.services.players.QueueModel; import org.jajuk.ui.actions.ActionManager; import org.jajuk.ui.actions.JajukActions; import org.jajuk.ui.helpers.FontManager; import org.jajuk.ui.helpers.FontManager.JajukFont; import org.jajuk.ui.helpers.ILaunchCommand; import org.jajuk.ui.helpers.JajukTableModel; import org.jajuk.ui.helpers.PreferencesJMenu; import org.jajuk.ui.helpers.TableTransferHandler; import org.jajuk.ui.helpers.TwoStepsDisplayable; import org.jajuk.ui.widgets.InformationJPanel; import org.jajuk.ui.widgets.JajukTable; import org.jajuk.ui.widgets.JajukToggleButton; import org.jajuk.util.Conf; import org.jajuk.util.Const; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; import org.jajuk.util.UtilFeatures; import org.jajuk.util.UtilGUI; import org.jajuk.util.error.CannotRenameException; import org.jajuk.util.error.JajukException; import org.jajuk.util.error.NoneAccessibleFileException; import org.jajuk.util.log.Log; import org.jdesktop.swingx.autocomplete.ComboBoxCellEditor; import org.jdesktop.swingx.table.DefaultTableColumnModelExt; import org.jdesktop.swingx.table.TableColumnExt; /** * Abstract table view : common implementation for both files and tracks table * views. */ public abstract class AbstractTableView extends ViewAdapter implements ActionListener, ItemListener, TableModelListener, TwoStepsDisplayable, ListSelectionListener { /** Generated serialVersionUID. */ private static final long serialVersionUID = -4418626517605128694L; /** DOCUMENT_ME. */ JajukTable jtable; /** DOCUMENT_ME. */ private JPanel jpControl; /** DOCUMENT_ME. */ JajukToggleButton jtbEditable; /** DOCUMENT_ME. */ private JLabel jlFilter; /** DOCUMENT_ME. */ private JComboBox jcbProperty; /** DOCUMENT_ME. */ private JLabel jlEquals; /** DOCUMENT_ME. */ private JTextField jtfValue; /** Table model. */ JajukTableModel model; /** Currently applied filter. */ private String sAppliedFilter = ""; /** Currently applied criteria. */ private String sAppliedCriteria; /** Do search panel need a search. */ private boolean bNeedSearch = false; /** Default time in ms before launching a search automatically. */ private static final int WAIT_TIME = 300; /** Date last key pressed. */ private long lDateTyped; /** Editable table configuration name, must be overwritten by child classes. */ String editableConf; /** Columns to show table configuration name, must be overwritten by child classes. */ String columnsConf; /** DOCUMENT_ME. */ private JMenuItem jmiPlay; /** DOCUMENT_ME. */ private JMenuItem jmiPush; /** DOCUMENT_ME. */ private JMenuItem jmiFrontPush; /** DOCUMENT_ME. */ JMenuItem jmiDelete; /** DOCUMENT_ME. */ private JMenuItem jmiPlayRepeat; /** DOCUMENT_ME. */ private JMenuItem jmiPlayShuffle; /** DOCUMENT_ME. */ JMenuItem jmiBookmark; /** DOCUMENT_ME. */ JMenuItem jmiProperties; /** DOCUMENT_ME. */ private JMenuItem jmiFileCopyURL; /** DOCUMENT_ME. */ PreferencesJMenu pjmTracks; /** The table/tree sync toggle button. */ JajukToggleButton jtbSync; /** DOCUMENT_ME. */ private boolean bStopThread = false; /** Launches a thread used to perform dynamic filtering when user is typing. */ private Thread filteringThread = new Thread("Dynamic user input filtering thread") { @Override public void run() { while (!bStopThread) { try { Thread.sleep(200); } catch (InterruptedException ie) { Log.error(ie); } if (bNeedSearch && (System.currentTimeMillis() - lDateTyped >= WAIT_TIME)) { sAppliedFilter = jtfValue.getText(); sAppliedCriteria = getApplyCriteria(); applyFilter(sAppliedCriteria, sAppliedFilter); bNeedSearch = false; } } } }; /** * Gets the apply criteria. * * @return Applied criteria */ private String getApplyCriteria() { int indexCombo = jcbProperty.getSelectedIndex(); if (indexCombo == 0) { // first criteria is special: any sAppliedCriteria = XML_ANY; } else { // otherwise, take criteria from model sAppliedCriteria = model.getIdentifier(indexCombo); } return sAppliedCriteria; } /** * Code used in child class SwingWorker for long delay computations (used in * initUI()). * * @return the object */ @Override public Object longCall() { model = populateTable(); return null; } /** * Code used in child class SwingWorker for display computations (used in * initUI()). * * @param in DOCUMENT_ME */ @Override public void shortCall(Object in) { // Add generic menus jmiPlay = new JMenuItem(ActionManager.getAction(JajukActions.PLAY_SELECTION)); jmiPlay.putClientProperty(Const.DETAIL_SELECTION, jtable.getSelection()); jtable.getMenu().add(jmiPlay); jmiFrontPush = new JMenuItem(ActionManager.getAction(JajukActions.PUSH_FRONT_SELECTION)); jmiFrontPush.putClientProperty(Const.DETAIL_SELECTION, jtable.getSelection()); jtable.getMenu().add(jmiFrontPush); jmiPush = new JMenuItem(ActionManager.getAction(JajukActions.PUSH_SELECTION)); jmiPush.putClientProperty(Const.DETAIL_SELECTION, jtable.getSelection()); jtable.getMenu().add(jmiPush); jmiPlayRepeat = new JMenuItem(ActionManager.getAction(JajukActions.PLAY_REPEAT_SELECTION)); jmiPlayRepeat.putClientProperty(Const.DETAIL_SELECTION, jtable.getSelection()); jtable.getMenu().add(jmiPlayRepeat); jmiPlayShuffle = new JMenuItem(ActionManager.getAction(JajukActions.PLAY_SHUFFLE_SELECTION)); jmiPlayShuffle.putClientProperty(Const.DETAIL_SELECTION, jtable.getSelection()); jtable.getMenu().add(jmiPlayShuffle); jtable.getMenu().addSeparator(); jmiDelete = new JMenuItem(ActionManager.getAction(JajukActions.DELETE)); jmiDelete.putClientProperty(Const.DETAIL_SELECTION, jtable.getSelection()); jtable.getMenu().add(jmiDelete); jmiFileCopyURL = new JMenuItem(ActionManager.getAction(JajukActions.COPY_TO_CLIPBOARD)); jmiFileCopyURL.putClientProperty(Const.DETAIL_CONTENT, jtable.getSelection()); jtable.getMenu().add(jmiFileCopyURL); jmiBookmark = new JMenuItem(ActionManager.getAction(JajukActions.BOOKMARK_SELECTION)); jmiBookmark.putClientProperty(Const.DETAIL_SELECTION, jtable.getSelection()); jmiProperties = new JMenuItem(ActionManager.getAction(JajukActions.SHOW_PROPERTIES)); jmiProperties.putClientProperty(Const.DETAIL_SELECTION, jtable.getSelection()); pjmTracks = new PreferencesJMenu(jtable.getSelection()); // Set a default behavior for double click or click on the play column jtable.setCommand(new ILaunchCommand() { @Override public void launch(int nbClicks) { // Ignore event if several rows are selected if (jtable.getSelectedColumnCount() != 1) { return; } int iSelectedCol = jtable.getSelectedColumn(); // Convert column selection as columns may have been moved iSelectedCol = jtable.convertColumnIndexToModel(iSelectedCol); // We launch the selection : // - In any case if user clicked on the play column (column 0) // - Or in case of double click on any column when table is not editable if (iSelectedCol == 0 || // click on play icon // double click on any column and edition state false (nbClicks == 2 && !jtbEditable.isSelected())) { Item item = model.getItemAt(jtable.convertRowIndexToModel(jtable.getSelectedRow())); List files = UtilFeatures.getPlayableFiles(item); if (files.size() > 0) { // launch it QueueModel.push(UtilFeatures.createStackItems(UtilFeatures.applyPlayOption(files), Conf .getBoolean(Const.CONF_STATE_REPEAT_ALL), true), Conf .getBoolean(Const.CONF_OPTIONS_PUSH_ON_CLICK)); } else { Messages.showErrorMessage(10); } } } }); // Control panel jpControl = new JPanel(); jpControl.setBorder(BorderFactory.createEtchedBorder()); jtbEditable = new JajukToggleButton(IconLoader.getIcon(JajukIcons.EDIT)); jtbEditable.setToolTipText(Messages.getString("AbstractTableView.11")); jtbEditable.addActionListener(this); // Create the sync toggle button and restore its state jtbSync = new JajukToggleButton(ActionManager.getAction(JajukActions.SYNC_TREE_TABLE)); jtbSync.putClientProperty(Const.DETAIL_VIEW, getID()); jtbSync.setSelected(Conf.getBoolean(Const.CONF_SYNC_TABLE_TREE + "." + getID())); jlFilter = new JLabel(Messages.getString("AbstractTableView.0")); // properties combo box, fill with columns names expect ID jcbProperty = new JComboBox(); // "any" criteria jcbProperty.addItem(Messages.getString("AbstractTableView.8")); for (int i = 1; i < model.getColumnCount(); i++) { // Others columns except ID jcbProperty.addItem(model.getColumnName(i)); } jcbProperty.setToolTipText(Messages.getString("AbstractTableView.1")); jcbProperty.addItemListener(this); jlEquals = new JLabel(Messages.getString("AbstractTableView.7")); jtfValue = new JTextField(); jtfValue.setFont(FontManager.getInstance().getFont(JajukFont.SEARCHBOX)); jtfValue.setMargin(new Insets(0, 3, 0, 0)); jtfValue.setForeground(new Color(172, 172, 172)); jtfValue.addKeyListener(new KeyAdapter() { @Override public void keyReleased(KeyEvent e) { bNeedSearch = true; lDateTyped = System.currentTimeMillis(); } }); jtfValue.setToolTipText(Messages.getString("AbstractTableView.3")); jpControl.setLayout(new MigLayout("insets 5", "[][20][grow,gp 70][grow]")); jpControl.add(jtbSync, "gapleft 5"); jpControl.add(jtbEditable, "gapright 15"); jpControl.add(jlFilter, "split 2"); jpControl.add(jcbProperty, "grow,gapright 15"); jpControl.add(jlEquals, "split 2"); jpControl.add(jtfValue, "grow,gapright 2"); setCellEditors(); JScrollPane jsp = new JScrollPane(jtable); setLayout(new MigLayout("ins 0", "[grow]", "[][grow]")); add(jpControl, "wrap,grow"); add(jsp, "grow"); jtable.setTransferHandler(new TableTransferHandler(jtable)); jtable.showColumns(jtable.getColumnsConf()); applyFilter(null, null); jtable.getSelectionModel().addListSelectionListener(this); // Register on the list for subject we are interested in ObservationManager.register(this); // refresh columns conf in case of some attributes been removed // or added before view instantiation Properties properties = ObservationManager .getDetailsLastOccurence(JajukEvents.CUSTOM_PROPERTIES_ADD); JajukEvent event = new JajukEvent(JajukEvents.CUSTOM_PROPERTIES_ADD, properties); update(event); initTable(); // perform type-specific init // Start filtering thread filteringThread.start(); // Register keystrokes setKeystrokes(); } /* * (non-Javadoc) * * @see org.jajuk.events.Observer#getRegistrationKeys() */ @Override public Set getRegistrationKeys() { Set eventSubjectSet = new HashSet(); eventSubjectSet.add(JajukEvents.DEVICE_MOUNT); eventSubjectSet.add(JajukEvents.DEVICE_UNMOUNT); eventSubjectSet.add(JajukEvents.DEVICE_REFRESH); eventSubjectSet.add(JajukEvents.CUSTOM_PROPERTIES_ADD); eventSubjectSet.add(JajukEvents.CUSTOM_PROPERTIES_REMOVE); eventSubjectSet.add(JajukEvents.RATE_CHANGED); eventSubjectSet.add(JajukEvents.TABLE_CLEAR_SELECTION); eventSubjectSet.add(JajukEvents.PARAMETERS_CHANGE); eventSubjectSet.add(JajukEvents.VIEW_REFRESH_REQUEST); eventSubjectSet.add(JajukEvents.TREE_SELECTION_CHANGED); return eventSubjectSet; } /** * Apply a filter, to be implemented by files and tracks tables, alter the * model. * * @param sPropertyName DOCUMENT_ME * @param sPropertyValue DOCUMENT_ME */ public void applyFilter(final String sPropertyName, final String sPropertyValue) { SwingWorker sw = new SwingWorker() { @Override public Void doInBackground() { model.removeTableModelListener(AbstractTableView.this); model.populateModel(sPropertyName, sPropertyValue, jtable.getColumnsConf()); model.addTableModelListener(AbstractTableView.this); return null; } @Override public void done() { // Force table repaint (for instance for rating stars update) model.fireTableDataChanged(); UtilGUI.stopWaiting(); } }; UtilGUI.waiting(); sw.execute(); } /* * (non-Javadoc) * * @see org.jajuk.ui.Observer#update(java.lang.String) */ @Override public void update(final JajukEvent event) { SwingUtilities.invokeLater(new Runnable() { @Override @SuppressWarnings("unchecked") public void run() { try { jtable.setAcceptColumnsEvents(false); // flag reloading to avoid wrong // column // events JajukEvents subject = event.getSubject(); if (JajukEvents.TABLE_CLEAR_SELECTION.equals(subject)) { jtable.clearSelection(); } if (JajukEvents.DEVICE_MOUNT.equals(subject) || JajukEvents.DEVICE_UNMOUNT.equals(subject)) { jtable.clearSelection(); // force filter to refresh applyFilter(sAppliedCriteria, sAppliedFilter); } else if (JajukEvents.TREE_SELECTION_CHANGED.equals(subject)) { // Check if the sync tree table option is set for this tree if (jtbSync.isSelected()) { // Consume only events from the same perspective and different view // (for table/tree synchronization) Properties details = event.getDetails(); if (details != null) { String sourcePerspective = details.getProperty(Const.DETAIL_PERSPECTIVE); String sourceView = details.getProperty(Const.DETAIL_VIEW); if (!(sourcePerspective.equals(getPerspective().getID())) || sourceView.equals(getID())) { return; } } // Update model tree selection model.setTreeSelection((Set) details.get(Const.DETAIL_SELECTION)); // force redisplay to apply the filter jtable.clearSelection(); // force filter to refresh applyFilter(sAppliedCriteria, sAppliedFilter); } } else if (JajukEvents.PARAMETERS_CHANGE.equals(subject)) { // force redisplay to apply the filter jtable.clearSelection(); // force filter to refresh applyFilter(sAppliedCriteria, sAppliedFilter); } else if (JajukEvents.DEVICE_REFRESH.equals(subject)) { // force filter to refresh applyFilter(sAppliedCriteria, sAppliedFilter); } else if (JajukEvents.VIEW_REFRESH_REQUEST.equals(subject)) { // force filter to refresh if the events has been triggered by the // table itself after a column change JTable table = (JTable) event.getDetails().get(Const.DETAIL_CONTENT); if (table.equals(jtable)) { applyFilter(sAppliedCriteria, sAppliedFilter); } } else if (JajukEvents.RATE_CHANGED.equals(subject)) { // Ignore the refresh if the event comes from the table itself Properties properties = event.getDetails(); if (properties != null && AbstractTableView.this.equals(properties.get(Const.DETAIL_ORIGIN))) { return; } // Keep current selection and nb of rows int[] selection = jtable.getSelectedRows(); // force filter to refresh applyFilter(sAppliedCriteria, sAppliedFilter); jtable.setSelectedRows(selection); } else if (JajukEvents.CUSTOM_PROPERTIES_ADD.equals(subject)) { Properties properties = event.getDetails(); if (properties == null) { // can be null at view populate return; } model = populateTable(); model.addTableModelListener(AbstractTableView.this); jtable.setModel(model); setCellEditors(); // add new item in configuration columns jtable.addColumnIntoConf((String) properties.get(Const.DETAIL_CONTENT)); jtable.showColumns(jtable.getColumnsConf()); applyFilter(sAppliedCriteria, sAppliedFilter); jcbProperty.addItem(properties.get(Const.DETAIL_CONTENT)); } else if (JajukEvents.CUSTOM_PROPERTIES_REMOVE.equals(subject)) { Properties properties = event.getDetails(); if (properties == null) { // can be null at view // populate return; } // remove item from configuration columns model = populateTable();// create a new model model.addTableModelListener(AbstractTableView.this); jtable.setModel(model); setCellEditors(); jtable.addColumnIntoConf((String) properties.get(Const.DETAIL_CONTENT)); jtable.showColumns(jtable.getColumnsConf()); applyFilter(sAppliedCriteria, sAppliedFilter); jcbProperty.removeItem(properties.get(Const.DETAIL_CONTENT)); } } catch (Exception e) { Log.error(e); } finally { jtable.setAcceptColumnsEvents(true); // make sure to remove this flag } } }); } /** * Add keystroke support. */ private void setKeystrokes() { jtable.putClientProperty(Const.DETAIL_SELECTION, jtable.getSelection()); InputMap inputMap = jtable.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT); ActionMap actionMap = jtable.getActionMap(); // Delete Action action = ActionManager.getAction(JajukActions.DELETE); inputMap.put(KeyStroke.getKeyStroke("DELETE"), "delete"); actionMap.put("delete", action); // Properties ALT/ENTER action = ActionManager.getAction(JajukActions.SHOW_PROPERTIES); inputMap.put(KeyStroke.getKeyStroke("alt ENTER"), "properties"); actionMap.put("properties", action); } /** * Fill the table. * * @return the jajuk table model */ abstract JajukTableModel populateTable(); /** * Sets the cell editors. DOCUMENT_ME */ private void setCellEditors() { for (TableColumn tc : ((DefaultTableColumnModelExt) jtable.getColumnModel()).getColumns(true)) { TableColumnExt col = (TableColumnExt) tc; String sIdentifier = model.getIdentifier(col.getModelIndex()); // create a combo box for genres, note that we can't add new // genres dynamically if (Const.XML_GENRE.equals(sIdentifier)) { JComboBox jcb = new JComboBox(GenreManager.getInstance().getGenresList()); jcb.setEditable(true); AutoCompleteDecorator.decorate(jcb); col.setCellEditor(new ComboBoxCellEditor(jcb)); col.setSortable(true); } // create a combo box for artists, note that we can't add new // artists dynamically else if (Const.XML_ARTIST.equals(sIdentifier)) { JComboBox jcb = new JComboBox(ArtistManager.getArtistsList()); jcb.setEditable(true); AutoCompleteDecorator.decorate(jcb); col.setCellEditor(new ComboBoxCellEditor(jcb)); } // Same for for album-artists else if (Const.XML_ALBUM_ARTIST.equals(sIdentifier)) { JComboBox jcb = new JComboBox(AlbumArtistManager.getAlbumArtistsList()); jcb.setEditable(true); AutoCompleteDecorator.decorate(jcb); col.setCellEditor(new ComboBoxCellEditor(jcb)); } // create a button for playing else if (Const.XML_PLAY.equals(sIdentifier)) { col.setMinWidth(PLAY_COLUMN_SIZE); col.setMaxWidth(PLAY_COLUMN_SIZE); } else if (Const.XML_TRACK_RATE.equals(sIdentifier)) { col.setMinWidth(RATE_COLUMN_SIZE); col.setMaxWidth(RATE_COLUMN_SIZE); } } } /** * Detect property change. * * @param ie DOCUMENT_ME */ @Override public void itemStateChanged(ItemEvent ie) { if (ie.getSource() == jcbProperty) { sAppliedFilter = jtfValue.getText(); sAppliedCriteria = getApplyCriteria(); applyFilter(sAppliedCriteria, sAppliedFilter); } } /* * (non-Javadoc) * * @seejavax.swing.event.TableModelListener#tableChanged(javax.swing.event. TableModelEvent) */ @Override public void tableChanged(TableModelEvent e) { // Check the table change event has not been generated by a // fireModelDataChange call if (e.getColumn() < 0) { return; } String sKey = model.getIdentifier(e.getColumn()); Object oValue = model.getValueAt(e.getFirstRow(), e.getColumn()); /* can be Boolean or String */ Item item = model.getItemAt(e.getFirstRow()); try { // file filter used by physical table view to change only the // file, not all files associated with the track Set filter = null; if (item instanceof File) { filter = new HashSet(); filter.add((File) item); } Item itemNew = ItemManager.changeItem(item, sKey, oValue, filter); model.setItemAt(e.getFirstRow(), itemNew); // update model // user message InformationJPanel.getInstance().setMessage( Messages.getString("PropertiesWizard.8") + ": " + Messages.getHumanPropertyName(sKey), InformationJPanel.MessageType.INFORMATIVE); // Require refresh of all tables Properties properties = new Properties(); properties.put(Const.DETAIL_ORIGIN, AbstractTableView.this); ObservationManager.notify(new JajukEvent(JajukEvents.DEVICE_REFRESH, properties)); } catch (NoneAccessibleFileException none) { Messages.showErrorMessage(none.getCode()); ((JajukTableModel) jtable.getModel()).undo(e.getFirstRow(), e.getColumn()); } catch (CannotRenameException cre) { Messages.showErrorMessage(cre.getCode()); ((JajukTableModel) jtable.getModel()).undo(e.getFirstRow(), e.getColumn()); } catch (JajukException je) { Log.error("104", je); Messages.showErrorMessage(104, je.getMessage()); ((JajukTableModel) jtable.getModel()).undo(e.getFirstRow(), e.getColumn()); } } /** * Table initialization after table display. */ abstract void initTable(); /* * (non-Javadoc) * * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent) */ @Override public void actionPerformed(final ActionEvent e) { // Editable state if (e.getSource() == jtbEditable) { Conf.setProperty(editableConf, Boolean.toString(jtbEditable.isSelected())); model.setEditable(jtbEditable.isSelected()); return; } } /* (non-Javadoc) * @see org.jajuk.ui.views.ViewAdapter#cleanup() */ @Override public void cleanup() { // stop the thread that is waiting for input if (filteringThread != null) { bStopThread = true; try { filteringThread.join(); filteringThread = null; } catch (InterruptedException e) { Log.error(e); } } super.cleanup(); } /** * Called when table selection changed. * * @param e the List selection event */ @Override public void valueChanged(ListSelectionEvent e) { if (e.getValueIsAdjusting()) { // leave during normal refresh return; } // Ignore event if the model is refreshing if (((JajukTableModel) jtable.getModel()).isRefreshing()) { return; } // Call view specific behavior on selection change onSelectionChange(); // Hide the copy url if several items selection. Do not simply disable them // as the getMenu() method enable all menu items jmiFileCopyURL.setVisible(jtable.getSelectedRowCount() < 2); // Compute Information view message if (AbstractTableView.this instanceof TracksTableView) { int rows = jtable.getSelection().size(); StringBuilder sbOut = new StringBuilder().append(rows).append( Messages.getString("TracksTreeView.31")); InformationJPanel.getInstance().setSelection(sbOut.toString()); } else if (AbstractTableView.this instanceof FilesTableView) { // Compute recursive selection size, nb of items... long lSize = 0l; int items = 0; for (Item item : jtable.getSelection()) { if (item instanceof File) { lSize += ((File) item).getSize(); } } items = jtable.getSelection().size(); lSize /= 1048576; // set size in MB StringBuilder sbOut = new StringBuilder().append(items).append( Messages.getString("FilesTreeView.52")); if (lSize > 1024) { // more than 1024 MB -> in GB sbOut.append(lSize / 1024).append('.').append(lSize % 1024).append( Messages.getString("FilesTreeView.53")); } else { sbOut.append(lSize).append(Messages.getString("FilesTreeView.54")); } InformationJPanel.getInstance().setSelection(sbOut.toString()); } // Refresh the preference menu according to the selection pjmTracks.resetUI(jtable.getSelection()); } /** * Callback method called on table selection change. */ void onSelectionChange() { // Do nothing by default Log.debug("Table selection changed for : " + this); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/views/DeviceView.java0000644000175000017500000003725211720500104024463 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.views; import ext.FlowScrollPanel; import java.awt.Component; import java.awt.FlowLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.util.HashSet; import java.util.List; import java.util.Set; import javax.swing.BorderFactory; import javax.swing.BoxLayout; import javax.swing.ImageIcon; import javax.swing.JLabel; import javax.swing.JMenuItem; import javax.swing.JPanel; import javax.swing.JPopupMenu; import javax.swing.JScrollPane; import javax.swing.ScrollPaneConstants; import javax.swing.SwingUtilities; import net.miginfocom.swing.MigLayout; import org.jajuk.base.Device; import org.jajuk.base.DeviceManager; import org.jajuk.events.JajukEvent; import org.jajuk.events.JajukEvents; import org.jajuk.events.ObservationManager; import org.jajuk.ui.helpers.JajukMouseAdapter; import org.jajuk.ui.wizard.DeviceWizard; import org.jajuk.util.Const; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; import org.jajuk.util.UtilGUI; import org.jajuk.util.error.JajukException; /** * Device view used to create and modify Jajuk devices *

    * Configuration perspective. */ public class DeviceView extends ViewAdapter implements IView, ActionListener { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** self instance. */ private static DeviceView dv = new DeviceView(); /** DOCUMENT_ME. */ FlowScrollPanel jpDevices; /** DOCUMENT_ME. */ JPopupMenu jpmenu; /** DOCUMENT_ME. */ JMenuItem jmiDelete; /** DOCUMENT_ME. */ JMenuItem jmiProperties; /** DOCUMENT_ME. */ JMenuItem jmiMount; /** DOCUMENT_ME. */ JMenuItem jmiUnmount; /** DOCUMENT_ME. */ JMenuItem jmiTest; /** DOCUMENT_ME. */ JMenuItem jmiRefresh; /** DOCUMENT_ME. */ JMenuItem jmiSynchronize; /** DOCUMENT_ME. */ DeviceItem diSelected; /** Mouse adapter used over device items to manage action or popup clicks. */ MouseAdapter ma = new JajukMouseAdapter() { @Override public void handleActionSingleClick(final MouseEvent e) { selectItem(e); diSelected.setBorder(BorderFactory.createLineBorder(UtilGUI.getForegroundColor(), 5)); // one device already selected + right click DeviceWizard dw = new DeviceWizard(); dw.updateWidgets(diSelected.getDevice()); dw.pack(); dw.setVisible(true); } @Override public void handlePopup(final MouseEvent e) { selectItem(e); // a new device is selected diSelected.setBorder(BorderFactory.createLineBorder(UtilGUI.getForegroundColor(), 5)); jpmenu.show(e.getComponent(), e.getX(), e.getY()); } }; /** * Instantiates a new device view. */ public DeviceView() { super(); } /* * (non-Javadoc) * * @see org.jajuk.ui.IView#display() */ @Override public void initUI() { // devices jpDevices = new FlowScrollPanel(); JScrollPane jsp = new JScrollPane(jpDevices, ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); jsp.setBorder(BorderFactory.createEmptyBorder(0, 1, 0, 0)); jpDevices.setScroller(jsp); jpDevices.setLayout(new FlowLayout(FlowLayout.LEFT)); // Popup menus jpmenu = new JPopupMenu(); jmiMount = new JMenuItem(Messages.getString("DeviceView.8"), IconLoader .getIcon(JajukIcons.MOUNT)); jmiMount.addActionListener(this); jmiMount.setActionCommand(JajukEvents.DEVICE_MOUNT.toString()); jpmenu.add(jmiMount); jmiUnmount = new JMenuItem(Messages.getString("DeviceView.9"), IconLoader .getIcon(JajukIcons.UNMOUNT)); jmiUnmount.addActionListener(this); jmiUnmount.setActionCommand(JajukEvents.DEVICE_UNMOUNT.toString()); jpmenu.add(jmiUnmount); jmiRefresh = new JMenuItem(Messages.getString("DeviceView.11"), IconLoader .getIcon(JajukIcons.REFRESH)); jmiRefresh.addActionListener(this); jmiRefresh.setActionCommand(JajukEvents.DEVICE_REFRESH.toString()); jpmenu.add(jmiRefresh); jmiTest = new JMenuItem(Messages.getString("DeviceView.10"), IconLoader .getIcon(JajukIcons.TEST)); jmiTest.addActionListener(this); jmiTest.setActionCommand(JajukEvents.DEVICE_TEST.toString()); jpmenu.add(jmiTest); jmiSynchronize = new JMenuItem(Messages.getString("DeviceView.12"), IconLoader .getIcon(JajukIcons.SYNCHRO)); jmiSynchronize.addActionListener(this); jmiSynchronize.setActionCommand(JajukEvents.DEVICE_SYNCHRO.toString()); jpmenu.add(jmiSynchronize); jmiDelete = new JMenuItem(Messages.getString("DeviceView.13"), IconLoader .getIcon(JajukIcons.DELETE)); jmiDelete.addActionListener(this); jmiDelete.setActionCommand(JajukEvents.DEVICE_DELETE.toString()); jpmenu.add(jmiDelete); jmiProperties = new JMenuItem(Messages.getString("DeviceView.14"), IconLoader .getIcon(JajukIcons.CONFIGURATION)); jmiProperties.addActionListener(this); jmiProperties.setActionCommand(JajukEvents.DEVICE_PROPERTIES.toString()); jpmenu.add(jmiProperties); // add devices refreshDevices(); // add components setLayout(new MigLayout("ins 0", "[grow]", "[grow]")); add(jsp, "grow"); // Register on the list for subject we are interested in ObservationManager.register(this); } /* * (non-Javadoc) * * @see org.jajuk.events.Observer#getRegistrationKeys() */ @Override public Set getRegistrationKeys() { Set eventSubjectSet = new HashSet(); eventSubjectSet.add(JajukEvents.DEVICE_MOUNT); eventSubjectSet.add(JajukEvents.DEVICE_UNMOUNT); eventSubjectSet.add(JajukEvents.DEVICE_NEW); eventSubjectSet.add(JajukEvents.DEVICE_REFRESH); return eventSubjectSet; } /** * Refresh devices. DOCUMENT_ME */ private void refreshDevices() { // remove all devices if (jpDevices.getComponentCount() > 0) { jpDevices.removeAll(); } // New device DeviceItem diNew = new DeviceItem(IconLoader.getIcon(JajukIcons.DEVICE_NEW), Messages .getString("DeviceView.17"), null); diNew.setToolTipText(Messages.getString("DeviceView.18")); jpDevices.add(diNew); diNew.addMouseListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { DeviceWizard dw = new DeviceWizard(); dw.updateWidgetsDefault(); dw.pack(); dw.setVisible(true); } }); // Add devices List devices = DeviceManager.getInstance().getDevices(); for (Device device : devices) { ImageIcon icon = IconLoader.getIcon(JajukIcons.DEVICE_DIRECTORY_MOUNTED); String sTooltip = ""; switch ((int) device.getType()) { case 0: sTooltip = Messages.getString("Device_type.directory"); if (device.isMounted()) { icon = IconLoader.getIcon(JajukIcons.DEVICE_DIRECTORY_MOUNTED); } else { icon = IconLoader.getIcon(JajukIcons.DEVICE_DIRECTORY_UNMOUNTED); } break; case 1: sTooltip = Messages.getString("Device_type.file_cd"); if (device.isMounted()) { icon = IconLoader.getIcon(JajukIcons.DEVICE_CD_MOUNTED); } else { icon = IconLoader.getIcon(JajukIcons.DEVICE_CD_UNMOUNTED); } break; case 2: sTooltip = Messages.getString("Device_type.network_drive"); if (device.isMounted()) { icon = IconLoader.getIcon(JajukIcons.DEVICE_NETWORK_DRIVE_MOUNTED); } else { icon = IconLoader.getIcon(JajukIcons.DEVICE_NETWORK_DRIVE_UNMOUNTED); } break; case 3: sTooltip = Messages.getString("Device_type.extdd"); if (device.isMounted()) { icon = IconLoader.getIcon(JajukIcons.DEVICE_EXT_DD_MOUNTED); } else { icon = IconLoader.getIcon(JajukIcons.DEVICE_EXT_DD_UNMOUNTED); } break; case 4: sTooltip = Messages.getString("Device_type.player"); if (device.isMounted()) { icon = IconLoader.getIcon(JajukIcons.DEVICE_PLAYER_MOUNTED); } else { icon = IconLoader.getIcon(JajukIcons.DEVICE_PLAYER_UNMOUNTED); } break; } DeviceItem di = new DeviceItem(icon, device.getName(), device); di.setToolTipText(sTooltip); di.addMouseListener(ma); di.setToolTipText(device.getDeviceTypeS()); di.addKeyListener(new KeyAdapter() { @Override public void keyTyped(KeyEvent e) { super.keyTyped(e); if (e.getKeyChar() == KeyEvent.VK_DELETE) { handleDelete(); } } }); jpDevices.add(di); } } /* * (non-Javadoc) * * @see org.jajuk.ui.views.IView#setVisible(boolean) */ @Override public void setVisible(boolean pVisible) { // don't do anything here } /* * (non-Javadoc) * * @see org.jajuk.ui.views.IView#getComponent() */ @Override public Component getComponent() { return this; } /** * Singleton implementation. * * @return the instance */ public static DeviceView getInstance() { return dv; } /* * (non-Javadoc) * * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent) */ @Override public void actionPerformed(final ActionEvent ae) { if (ae.getActionCommand().equals(JajukEvents.DEVICE_NEW.toString())) { DeviceWizard dw = new DeviceWizard(); dw.updateWidgetsDefault(); dw.pack(); dw.setVisible(true); return; } if (diSelected == null) { // test a device is selected return; } if (ae.getActionCommand().equals(JajukEvents.DEVICE_DELETE.toString())) { handleDelete(); } else if (ae.getActionCommand().equals(JajukEvents.DEVICE_MOUNT.toString())) { try { diSelected.getDevice().mount(true); } catch (JajukException je) { Messages.showErrorMessage(je.getCode()); } catch (Exception e) { Messages.showErrorMessage(11); } } else if (ae.getActionCommand().equals(JajukEvents.DEVICE_UNMOUNT.toString())) { try { diSelected.getDevice().unmount(); } catch (Exception e) { Messages.showErrorMessage(12); } } else if (ae.getActionCommand().equals(JajukEvents.DEVICE_PROPERTIES.toString())) { DeviceWizard dw = new DeviceWizard(); dw.updateWidgets(diSelected.getDevice()); dw.pack(); dw.setVisible(true); } else if (ae.getActionCommand().equals(JajukEvents.DEVICE_REFRESH.toString())) { diSelected.getDevice().refresh(true, true, false, null); // ask deep or fast // scan } else if (ae.getActionCommand().equals(JajukEvents.DEVICE_SYNCHRO.toString())) { diSelected.getDevice().synchronize(true); } else if (ae.getActionCommand().equals(JajukEvents.DEVICE_TEST.toString())) { // Test asynchronously in case of delay (samba issue for ie) new Thread("Asynchronous device test thread") { @Override public void run() { if (diSelected.getDevice().test()) { Messages.showInfoMessage(Messages.getString("DeviceView.21"), IconLoader .getIcon(JajukIcons.OK)); } else { Messages.showInfoMessage(Messages.getString("DeviceView.22"), IconLoader .getIcon(JajukIcons.KO)); } } }.start(); } } /** * Device deleting. */ void handleDelete() { DeviceManager.getInstance().removeDevice(diSelected.getDevice()); jpDevices.remove(diSelected); // refresh views ObservationManager.notify(new JajukEvent(JajukEvents.DEVICE_REFRESH)); } /* * (non-Javadoc) * * @see org.jajuk.ui.IView#getDesc() */ @Override public String getDesc() { return Messages.getString("DeviceView.23"); } /* * (non-Javadoc) * * @see org.jajuk.ui.Observer#update(java.lang.String) */ @Override public void update(JajukEvent event) { JajukEvents subject = event.getSubject(); if (JajukEvents.DEVICE_MOUNT.equals(subject) || JajukEvents.DEVICE_UNMOUNT.equals(subject) || JajukEvents.DEVICE_REFRESH.equals(subject)) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { UtilGUI.waiting(); refreshDevices(); jpDevices.revalidate(); jpDevices.repaint(); UtilGUI.stopWaiting(); } }); } } /** * Select item. DOCUMENT_ME * * @param e DOCUMENT_ME */ private void selectItem(final MouseEvent e) { boolean bSameDevice = ((diSelected != null) && e.getSource().equals(diSelected)); // remove old device item border if needed if (!bSameDevice && diSelected != null) { diSelected.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); } diSelected = (DeviceItem) e.getSource(); diSelected.requestFocusInWindow(); // Test if it is the "NEW" device if (((DeviceItem) e.getSource()).getDevice() == null) { return; } // remove options for non synchronized devices if (diSelected.getDevice().containsProperty(Const.XML_DEVICE_SYNCHRO_SOURCE)) { jmiSynchronize.setEnabled(true); } else { jmiSynchronize.setEnabled(false); } } /* * (non-Javadoc) * * @see java.awt.event.MouseListener#mouseExited(java.awt.event.MouseEvent) */ public void mouseExited(@SuppressWarnings("unused") MouseEvent arg0) { // required by interface, but nothing to do here... } /* * (non-Javadoc) * * @see java.awt.event.MouseListener#mouseEntered(java.awt.event.MouseEvent) */ public void mouseEntered(@SuppressWarnings("unused") MouseEvent e) { // required by interface, but nothing to do here... } /* * (non-Javadoc) * * @see java.awt.event.MouseListener#mouseClicked(java.awt.event.MouseEvent) */ public void mouseClicked(@SuppressWarnings("unused") MouseEvent e) { // required by interface, but nothing to do here... } } /** * A device icon + text Type description */ class DeviceItem extends JPanel { private static final long serialVersionUID = 1L; /** Associated device */ private Device device; /** * Constructor */ DeviceItem(ImageIcon icon, String sName, Device device) { super(); this.device = device; setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); JLabel jlIcon = new JLabel(icon); // Add some insets around the icon jlIcon.setBorder(BorderFactory.createEmptyBorder(1, 1, 1, 1)); add(jlIcon); JLabel jlName = new JLabel(sName); jlName.setBorder(BorderFactory.createEmptyBorder(1, 1, 1, 1)); add(jlName); } /** * @return Returns the device. */ public Device getDevice() { return device; } /** * @param device * The device to set. */ public void setDevice(Device device) { this.device = device; } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/views/IView.java0000644000175000017500000000372011720500104023445 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.views; import com.vlsolutions.swing.docking.Dockable; import java.awt.event.ComponentListener; import org.jajuk.ui.perspectives.IPerspective; /** * A view. */ public interface IView extends ComponentListener, Dockable { /** * Returns the view identifier. * * @return View identifier. */ String getID(); /** * Set view ID. * * @param sID DOCUMENT_ME */ void setID(String sID); /** * Returns the view description as i18n key. * * @return View description. */ String getDesc(); /** * Display view UI. */ void initUI(); /** * Get displayed state. * * @return populated state */ boolean isPopulated(); /** * Sets the is populated. * * @param isDisplayed DOCUMENT_ME */ void setIsPopulated(boolean isDisplayed); /** * Gets the perspective. * * @return current perspective for this view */ IPerspective getPerspective(); /** * Sets the perspective. * * @param perspective DOCUMENT_ME */ void setPerspective(IPerspective perspective); /** * Called when the view perspective is selected. */ void onPerspectiveSelection(); } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/views/CDScanView.java0000644000175000017500000001440311720500104024350 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.views; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.File; import java.net.MalformedURLException; import java.util.Set; import javax.swing.JButton; import javax.swing.JFileChooser; import javax.swing.JLabel; import javax.swing.JTextField; import javax.swing.SwingWorker; import net.miginfocom.swing.MigLayout; import org.jajuk.base.Device; import org.jajuk.base.DeviceManager; import org.jajuk.events.JajukEvent; import org.jajuk.events.JajukEvents; import org.jajuk.events.ObservationManager; import org.jajuk.ui.widgets.JajukFileChooser; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukFileFilter; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; import org.jajuk.util.UtilGUI; import org.jajuk.util.filters.DirectoryFilter; import org.jajuk.util.log.Log; /** * Scan CD to build the collection as fast as possible *

    * Configuration perspective *. */ public class CDScanView extends ViewAdapter implements ActionListener { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** DOCUMENT_ME. */ JTextField jtfName; /** DOCUMENT_ME. */ JLabel jlMountPoint; /** DOCUMENT_ME. */ JTextField jtfMountPoint; /** DOCUMENT_ME. */ JButton jbScan; /** DOCUMENT_ME. */ JButton jbUrl; /** * Constructor. */ public CDScanView() { super(); } /* * (non-Javadoc) * * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent) */ @Override public void actionPerformed(final ActionEvent e) { if (e.getSource() == jbScan) { if ((e.getModifiers() & ActionEvent.CTRL_MASK) == ActionEvent.CTRL_MASK) { try { UtilGUI.showPictureDialog("http://repository.jajuk.info/images/no2.jpg"); } catch (MalformedURLException me) { Log.debug("Ignoring exception in CD-Scan-View: ", me); } return; } SwingWorker sw = new SwingWorker() { @Override public Void doInBackground() { if (!"".equals(jtfName.getText().trim()) && !"".equals(jtfMountPoint.getText().trim())) { Device device = null; device = DeviceManager.getInstance().registerDevice(jtfName.getText().trim(), 1, jtfMountPoint.getText().trim()); try { device.mount(true); // refresh synchronously device.refresh(false, false, false, null); device.unmount(true, true); } catch (Exception ex) { DeviceManager.getInstance().removeDevice(device); Messages.showErrorMessage(16); // refresh views ObservationManager.notify(new JajukEvent(JajukEvents.DEVICE_REFRESH)); } } return null; } @Override public void done() { jtfName.setText(""); jtfName.requestFocusInWindow(); } }; sw.execute(); } else if (e.getSource() == jbUrl) { final JajukFileChooser jfc = new JajukFileChooser(new JajukFileFilter(DirectoryFilter .getInstance())); jfc.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); jfc.setDialogTitle(Messages.getString("DeviceWizard.43")); jfc.setMultiSelectionEnabled(false); jfc.setAcceptDirectories(true); final String sMountPoint = jtfMountPoint.getText(); if (!"".equals(sMountPoint)) { // if url is already set, use it // as root directory // jfc.setCurrentDirectory(new File(sMountPoint)); } final int returnVal = jfc.showOpenDialog(this); if (returnVal == JFileChooser.APPROVE_OPTION) { final java.io.File file = jfc.getSelectedFile(); jtfMountPoint.setText(file.getAbsolutePath()); } } } /* * (non-Javadoc) * * @see org.jajuk.ui.IView#getDesc() */ @Override public String getDesc() { return Messages.getString("CDScanView.12"); } /* * (non-Javadoc) * * @see org.jajuk.ui.IView#display() */ @Override public void initUI() { JLabel jlName = new JLabel(Messages.getString("CDScanView.0")); jlName.setToolTipText(Messages.getString("CDScanView.1")); jtfName = new JTextField(); jtfName.setToolTipText(Messages.getString("CDScanView.2")); jlMountPoint = new JLabel(Messages.getString("CDScanView.3")); jlMountPoint.setToolTipText(Messages.getString("CDScanView.4")); jtfMountPoint = new JTextField(); jtfMountPoint.setToolTipText(Messages.getString("CDScanView.5")); jbScan = new JButton(Messages.getString("CDScanView.6"), IconLoader.getIcon(JajukIcons.REFRESH)); jbScan.setToolTipText(Messages.getString("CDScanView.18")); jbScan.addActionListener(this); jbUrl = new JButton(IconLoader.getIcon(JajukIcons.OPEN_FILE)); jbUrl.setToolTipText(Messages.getString("CDScanView.19")); jbUrl.addActionListener(this); setLayout(new MigLayout("insets 10, gapy 15", "[][grow]")); add(jlName); add(jtfName, "wrap,grow"); add(jlMountPoint); add(jtfMountPoint, "split 2,grow"); add(jbUrl, "wrap"); add(jbScan, "right,span"); } /* * (non-Javadoc) * * @see org.jajuk.events.Observer#getRegistrationKeys() */ @Override public Set getRegistrationKeys() { return null; } /* * (non-Javadoc) * * @see org.jajuk.events.Observer#update(org.jajuk.events.Event) */ @Override public void update(JajukEvent event) { // nothing to do here... } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/views/AlbumsTableView.java0000644000175000017500000001353211720500104025452 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.views; import java.awt.Dimension; import java.awt.MouseInfo; import java.awt.Rectangle; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.MouseMotionListener; import javax.swing.JMenuItem; import org.jajuk.base.Album; import org.jajuk.ui.actions.ActionManager; import org.jajuk.ui.actions.JajukActions; import org.jajuk.ui.helpers.AlbumsTableModel; import org.jajuk.ui.helpers.JajukTableModel; import org.jajuk.ui.thumbnails.LocalAlbumThumbnail; import org.jajuk.ui.thumbnails.ThumbnailPopup; import org.jajuk.ui.widgets.JajukTable; import org.jajuk.util.Conf; import org.jajuk.util.Const; import org.jajuk.util.Messages; import org.jajuk.util.UtilGUI; /** * List collection albums as a table. */ public class AlbumsTableView extends AbstractTableView { /** Generated serialVersionUID. */ private static final long serialVersionUID = 7576455252866971945L; /** DOCUMENT_ME. */ private static ThumbnailPopup popup = null; /** * Instantiates a new albums table view. */ public AlbumsTableView() { super(); columnsConf = CONF_ALBUMS_TABLE_COLUMNS; editableConf = CONF_ALBUMS_TABLE_EDITION; } /* * (non-Javadoc) * * @see org.jajuk.ui.views.IView#getDesc() */ @Override public String getDesc() { return Messages.getString("AlbumsTableView.0"); } /* * (non-Javadoc) * * @see org.jajuk.ui.views.IView#initUI() */ @Override public void initUI() { UtilGUI.populate(this); } /* * (non-Javadoc) * * @see org.jajuk.ui.views.AbstractTableView#initTable() */ @Override void initTable() { jtbEditable.setSelected(Conf.getBoolean(Const.CONF_ALBUMS_TABLE_EDITION)); // Disable edit button, edition not yet implemented jtbEditable.setVisible(false); } /* * (non-Javadoc) * * @see org.jajuk.ui.views.AbstractTableView#populateTable() */ @Override synchronized JajukTableModel populateTable() { // model creation return new AlbumsTableModel(); } /* * (non-Javadoc) * * @see org.jajuk.ui.helpers.TwoStepsDisplayable#longCall() */ @Override public Object longCall() { super.longCall(); return null; } /* * (non-Javadoc) * * @see org.jajuk.ui.helpers.TwoStepsDisplayable#shortCall(java.lang.Object) */ @Override public void shortCall(Object in) { jtable = new JajukTable(model, true, columnsConf); super.shortCall(null); JMenuItem jmiShowAlbumDetails = new JMenuItem(ActionManager .getAction(JajukActions.SHOW_ALBUM_DETAILS)); jmiShowAlbumDetails.putClientProperty(Const.DETAIL_SELECTION, jtable.getSelection()); JMenuItem jmiReport = new JMenuItem(ActionManager.getAction(JajukActions.CREATE_REPORT)); jmiReport.putClientProperty(Const.DETAIL_SELECTION, jtable.getSelection()); // Add this generic menu item manually to ensure it's the last one in // the list for GUI reasons jtable.getMenu().add(jmiDelete); jtable.getMenu().addSeparator(); jtable.getMenu().add(jmiReport); jtable.getMenu().add(jmiShowAlbumDetails); jtable.getMenu().addSeparator(); jtable.getMenu().add(pjmTracks); jtable.getMenu().add(jmiBookmark); jtable.getMenu().addSeparator(); jtable.getMenu().add(jmiProperties); // Add popup feature when mouse rolls over cells jtable.addMouseMotionListener(new MouseMotionListener() { Album current = null; @Override public void mouseMoved(MouseEvent e) { if (!Conf.getBoolean(Const.CONF_SHOW_POPUPS)) { return; } // Do not use getLocationOnScreen() method to support JRE 1.5 java.awt.Point p = MouseInfo.getPointerInfo().getLocation(); int rowIndex = jtable.rowAtPoint(e.getPoint()); if (rowIndex < 0) { return; } JajukTableModel model = (JajukTableModel) jtable.getModel(); rowIndex = jtable.convertRowIndexToModel(rowIndex); Album album = (Album) model.getItemAt(rowIndex); if (album != null && current != album) { current = album; String description = new LocalAlbumThumbnail(album, 200, true).getDescription(); // Close any previous popup if (popup != null) { popup.dispose(); } popup = new ThumbnailPopup(description, new Rectangle(p, new Dimension(20, -50)), true); } } @Override public void mouseDragged(MouseEvent e) { // nothing to do here } }); // Add another listener on view borders (outside the table itself) to // close popups when leaving the table jtable.addMouseListener(new MouseAdapter() { @Override public void mouseExited(MouseEvent e) { super.mouseExited(e); // Do not hide popup if still in the table to allow user to mouse // mouse over the popup (in this case, a table exit event is thrown) if (popup != null && !UtilGUI.isOver(jtable.getLocationOnScreen(), jtable .getPreferredScrollableViewportSize())) { popup.dispose(); } } }); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/views/SuggestionView.java0000644000175000017500000004607311720500104025414 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.views; import ext.FlowScrollPanel; import ext.services.lastfm.AlbumInfo; import ext.services.lastfm.AlbumListInfo; import ext.services.lastfm.ArtistInfo; import ext.services.lastfm.LastFmService; import ext.services.lastfm.SimilarArtistsInfo; import java.awt.FlowLayout; import java.awt.Graphics; import java.awt.Insets; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.net.URL; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; import javax.swing.BoxLayout; import javax.swing.JEditorPane; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTabbedPane; import javax.swing.ScrollPaneConstants; import javax.swing.SwingUtilities; import javax.swing.SwingWorker; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import net.miginfocom.swing.MigLayout; import org.apache.commons.lang.StringUtils; import org.jajuk.base.Album; import org.jajuk.base.AlbumManager; import org.jajuk.base.File; import org.jajuk.events.JajukEvent; import org.jajuk.events.JajukEvents; import org.jajuk.events.ObservationManager; import org.jajuk.services.players.QueueModel; import org.jajuk.ui.perspectives.PerspectiveManager; import org.jajuk.ui.thumbnails.AbstractThumbnail; import org.jajuk.ui.thumbnails.LastFmAlbumThumbnail; import org.jajuk.ui.thumbnails.LastFmArtistThumbnail; import org.jajuk.ui.thumbnails.LocalAlbumThumbnail; import org.jajuk.ui.thumbnails.ThumbnailManager; import org.jajuk.util.Conf; import org.jajuk.util.Const; import org.jajuk.util.DownloadManager; import org.jajuk.util.Messages; import org.jajuk.util.UtilGUI; import org.jajuk.util.log.Log; import org.jdesktop.swingx.JXBusyLabel; /** * Show suggested albums based on current collection (bestof, novelties) and * LAstFM. */ public class SuggestionView extends ViewAdapter { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** DOCUMENT_ME. */ private JTabbedPane tabs; /** DOCUMENT_ME. */ protected String artist; /** * DOCUMENT_ME. */ enum SuggestionType { /** DOCUMENT_ME. */ BEST_OF, /** DOCUMENT_ME. */ NEWEST, /** DOCUMENT_ME. */ RARE, /** DOCUMENT_ME. */ OTHERS_ALBUMS, /** DOCUMENT_ME. */ SIMILAR_ARTISTS } /** DOCUMENT_ME. */ JScrollPane jpBestof; /** DOCUMENT_ME. */ JScrollPane jpNewest; /** DOCUMENT_ME. */ JScrollPane jpRare; /** DOCUMENT_ME. */ JScrollPane jpOthersAlbums; /** DOCUMENT_ME. */ JScrollPane jpSimilarArtists; /** DOCUMENT_ME. */ private int comp = 0; /** DOCUMENT_ME. */ List albumsNewest; /** DOCUMENT_ME. */ List albumsPrefered; /** DOCUMENT_ME. */ List albumsRare; /** Currently selected thumb. */ AbstractThumbnail selectedThumb; /** DOCUMENT_ME. */ private AlbumListInfo albums; /** DOCUMENT_ME. */ private SimilarArtistsInfo similar; /** * DOCUMENT_ME. */ class ThumbMouseListener extends MouseAdapter { /* * (non-Javadoc) * * @see java.awt.event.MouseAdapter#mousePressed(java.awt.event.MouseEvent) */ @Override public void mousePressed(MouseEvent e) { AbstractThumbnail thumb = (AbstractThumbnail) ((JLabel) e.getSource()).getParent(); // remove red border on previous item if // different from this one if (selectedThumb != null && selectedThumb != thumb) { selectedThumb.setSelected(false); } // select the new selected thumb thumb.setSelected(true); selectedThumb = thumb; } } /** * Instantiates a new suggestion view. */ public SuggestionView() { super(); } /* * (non-Javadoc) * * @see org.jajuk.ui.views.IView#getDesc() */ @Override public String getDesc() { return Messages.getString("SuggestionView.0"); } /* * (non-Javadoc) * * @see org.jajuk.ui.views.IView#populate() */ @Override public void initUI() { tabs = new JTabbedPane(); // Remove tab border, see // http://forum.java.sun.com/thread.jspa?threadID=260746&messageID=980405 class MyTabbedPaneUI extends javax.swing.plaf.basic.BasicTabbedPaneUI { @Override protected Insets getContentBorderInsets(int tabPlacement) { return new Insets(0, 0, 0, 0); } @Override protected void paintContentBorder(Graphics g, int tabPlacement, int selectedIndex) { // nothing to do here... } } // Now use the new TabbedPaneUI tabs.setUI(new MyTabbedPaneUI()); // Fill tabs with empty tabs tabs.addTab(Messages.getString("SuggestionView.1"), UtilGUI.getCentredPanel(new JLabel(Messages .getString("WikipediaView.3")))); tabs.addTab(Messages.getString("SuggestionView.2"), UtilGUI.getCentredPanel(new JLabel(Messages .getString("WikipediaView.3")))); tabs.addTab(Messages.getString("SuggestionView.5"), UtilGUI.getCentredPanel(new JLabel(Messages .getString("WikipediaView.3")))); tabs.addTab(Messages.getString("SuggestionView.3"), new JLabel(Messages .getString("SuggestionView.7"))); tabs.addTab(Messages.getString("SuggestionView.4"), new JLabel(Messages .getString("SuggestionView.7"))); // Refresh tabs on demand only, add changelisterner after tab creation to // avoid that the stored tab is overwrited at startup tabs.addChangeListener(new ChangeListener() { @Override public void stateChanged(ChangeEvent arg0) { refreshLastFMCollectionTabs(); // store the selected tab Conf.setProperty(getClass().getName() + "_" + ((getPerspective() == null) ? "solo" : getPerspective().getID()), Integer.toString( tabs.getSelectedIndex()).toString()); } }); if (Conf.containsProperty(getClass().getName() + "_" + ((getPerspective() == null) ? "solo" : getPerspective().getID()))) { int index = Conf.getInt(getClass().getName() + "_" + ((getPerspective() == null) ? "solo" : getPerspective().getID())); if (index > 0 && index < tabs.getTabCount()) { tabs.setSelectedIndex(index); } } // Add panels refreshLocalCollectionTabs(); // Add tabs setLayout(new BoxLayout(this, BoxLayout.X_AXIS)); add(tabs); // Look for events ObservationManager.register(this); } /* * (non-Javadoc) * * @see org.jajuk.events.Observer#getRegistrationKeys() */ @Override public Set getRegistrationKeys() { Set eventSubjectSet = new HashSet(); eventSubjectSet.add(JajukEvents.FILE_LAUNCHED); eventSubjectSet.add(JajukEvents.PARAMETERS_CHANGE); eventSubjectSet.add(JajukEvents.COVER_DEFAULT_CHANGED); eventSubjectSet.add(JajukEvents.SUGGESTIONS_REFRESH); return eventSubjectSet; } /** * Refresh local thumbs. */ private void refreshLocalCollectionTabs() { // Display a busy panel in the mean-time SwingUtilities.invokeLater(new Runnable() { @Override public void run() { JXBusyLabel busy1 = new JXBusyLabel(); busy1.setBusy(true); JXBusyLabel busy2 = new JXBusyLabel(); busy2.setBusy(true); JXBusyLabel busy3 = new JXBusyLabel(); busy3.setBusy(true); // stop all existing busy labels before we add the new ones... stopAllBusyLabels(); tabs.setComponentAt(0, UtilGUI.getCentredPanel(busy1)); tabs.setComponentAt(1, UtilGUI.getCentredPanel(busy2)); tabs.setComponentAt(2, UtilGUI.getCentredPanel(busy3)); } }); SwingWorker sw = new SwingWorker() { JScrollPane jsp1; JScrollPane jsp2; JScrollPane jsp3; @Override public Void doInBackground() { // Refresh thumbs for required albums List albums = new ArrayList(10); albumsPrefered = AlbumManager.getInstance().getBestOfAlbums( Conf.getBoolean(Const.CONF_OPTIONS_HIDE_UNMOUNTED), NB_BESTOF_ALBUMS); albumsNewest = AlbumManager.getInstance().getNewestAlbums( Conf.getBoolean(Const.CONF_OPTIONS_HIDE_UNMOUNTED), NB_BESTOF_ALBUMS); albumsRare = AlbumManager.getInstance().getRarelyListenAlbums( Conf.getBoolean(Const.CONF_OPTIONS_HIDE_UNMOUNTED), NB_BESTOF_ALBUMS); albums.addAll(albumsPrefered); albums.addAll(albumsNewest); albums.addAll(albumsRare); if (albums.size() > 0) { for (Album album : albums) { // Try creating the thumbnail ThumbnailManager.refreshThumbnail(album, 100); } } return null; } @Override public void done() { jsp1 = getLocalSuggestionsPanel(SuggestionType.BEST_OF); jsp2 = getLocalSuggestionsPanel(SuggestionType.NEWEST); jsp3 = getLocalSuggestionsPanel(SuggestionType.RARE); // If panel is void, add a void panel as a null object keeps // previous element stopAllBusyLabels(); tabs.setComponentAt(0, (jsp1 == null) ? new JPanel() : jsp1); tabs.setComponentAt(1, (jsp2 == null) ? new JPanel() : jsp2); tabs.setComponentAt(2, (jsp3 == null) ? new JPanel() : jsp3); } }; sw.execute(); } /** * Refresh last fm collection tabs. * DOCUMENT_ME */ private void refreshLastFMCollectionTabs() { String newArtist = null; File current = QueueModel.getPlayingFile(); if (current != null) { newArtist = current.getTrack().getArtist().getName2(); } // if none track playing if (current == null // Last.FM infos is disable || !Conf.getBoolean(Const.CONF_LASTFM_INFO) // None internet access option is set || Conf.getBoolean(Const.CONF_NETWORK_NONE_INTERNET_ACCESS) // If unknown artist || (newArtist == null || newArtist.equals(Messages.getString(UNKNOWN_ARTIST)))) { // Set empty panels SwingUtilities.invokeLater(new Runnable() { @Override public void run() { stopAllBusyLabels(); tabs.setComponentAt(3, new JLabel(Messages.getString("SuggestionView.7"))); tabs.setComponentAt(4, new JLabel(Messages.getString("SuggestionView.7"))); } }); return; } // Check if artist changed, otherwise, just leave if (newArtist.equals(this.artist)) { return; } // Save current artist artist = newArtist; // Display a busy panel in the mean-time SwingUtilities.invokeLater(new Runnable() { @Override public void run() { JXBusyLabel busy1 = new JXBusyLabel(); busy1.setBusy(true); JXBusyLabel busy2 = new JXBusyLabel(); busy2.setBusy(true); // stop all existing busy labels before we add the new ones... stopAllBusyLabels(); tabs.setComponentAt(3, UtilGUI.getCentredPanel(busy1)); tabs.setComponentAt(4, UtilGUI.getCentredPanel(busy2)); } }); // Use a swing worker as construct takes a lot of time SwingWorker sw = new SwingWorker() { JScrollPane jsp1; JScrollPane jsp2; @Override public Void doInBackground() { try { // Fetch last.fm calls and downloads covers preFetchOthersAlbum(); preFetchSimilarArtists(); } catch (Exception e) { Log.error(e); } return null; } @Override public void done() { jsp1 = getLastFMSuggestionsPanel(SuggestionType.OTHERS_ALBUMS, false); jsp2 = getLastFMSuggestionsPanel(SuggestionType.SIMILAR_ARTISTS, false); stopAllBusyLabels(); tabs.setComponentAt(3, (jsp1 == null) ? new JPanel() : jsp1); tabs.setComponentAt(4, (jsp2 == null) ? new JPanel() : jsp2); } }; sw.execute(); } /** * Pre-load other album (done outside the EDT). * * @throws Exception the exception */ void preFetchOthersAlbum() throws Exception { albums = LastFmService.getInstance().getAlbumList(artist, true, 0); // Perform images downloads and caching if (albums != null && albums.getAlbums().size() > 0) { for (AlbumInfo album : albums.getAlbums()) { String albumUrl = album.getBigCoverURL(); if (StringUtils.isBlank(albumUrl)) { continue; } // Download thumb URL remote = new URL(albumUrl); // Download image and store file reference (to generate the // popup thumb for ie) DownloadManager.downloadToCache(remote); } } } /** * Pre-load other album (done outside the EDT). * * @throws Exception the exception */ void preFetchSimilarArtists() throws Exception { // Perform last.fm calls similar = LastFmService.getInstance().getSimilarArtists(artist); // artists is null for void (unknown) similar artists if (similar != null && similar.getArtists() != null) { List artists = similar.getArtists(); for (ArtistInfo similarArtist : artists) { String artistUrl = similarArtist.getImageUrl(); if (StringUtils.isBlank(artistUrl)) { continue; } // Download thumb URL remote = new URL(artistUrl); // Download the picture and store file reference (to // generate the popup thumb for ie) DownloadManager.downloadToCache(remote); } } } /** * Return the result panel for local albums. * * @param type DOCUMENT_ME * * @return the local suggestions panel */ JScrollPane getLocalSuggestionsPanel(SuggestionType type) { FlowScrollPanel out = new FlowScrollPanel(); out.setLayout(new FlowLayout(FlowLayout.LEFT)); JScrollPane jsp = new JScrollPane(out, ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); jsp.setBorder(null); out.setScroller(jsp); List albums = null; if (type == SuggestionType.BEST_OF) { albums = albumsPrefered; } else if (type == SuggestionType.NEWEST) { albums = albumsNewest; } else if (type == SuggestionType.RARE) { albums = albumsRare; } if (albums != null && albums.size() > 0) { for (Album album : albums) { LocalAlbumThumbnail thumb = new LocalAlbumThumbnail(album, 100, false); thumb.populate(); thumb.getIcon().addMouseListener(new ThumbMouseListener()); out.add(thumb); } } else { out.add(UtilGUI.getCentredPanel(new JLabel(Messages.getString("WikipediaView.3")))); } return jsp; } /** * Return the result panel for lastFM information. * * @param type DOCUMENT_ME * @param artistView DOCUMENT_ME * * @return the last fm suggestions panel */ JScrollPane getLastFMSuggestionsPanel(SuggestionType type, boolean artistView) { FlowScrollPanel flowPanel = new FlowScrollPanel(); JScrollPane jsp = new JScrollPane(flowPanel, ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); jsp.setBorder(null); flowPanel.setScroller(jsp); flowPanel.setLayout(new FlowLayout(FlowLayout.CENTER)); if (type == SuggestionType.OTHERS_ALBUMS) { if (albums != null && albums.getAlbums().size() > 0) { for (AlbumInfo album : albums.getAlbums()) { AbstractThumbnail thumb = new LastFmAlbumThumbnail(album); thumb.setArtistView(artistView); thumb.populate(); if (thumb.getIcon() != null) { thumb.getIcon().addMouseListener(new ThumbMouseListener()); flowPanel.add(thumb); } } } // No result found else { return new JScrollPane(getNothingFoundPanel()); } } else if (type == SuggestionType.SIMILAR_ARTISTS) { if (similar != null) { List artists = similar.getArtists(); for (ArtistInfo similarArtist : artists) { AbstractThumbnail thumb = new LastFmArtistThumbnail(similarArtist); thumb.setArtistView(artistView); thumb.populate(); if (thumb.getIcon() != null) { thumb.getIcon().addMouseListener(new ThumbMouseListener()); flowPanel.add(thumb); } } } // No result found else { return new JScrollPane(getNothingFoundPanel()); } } return jsp; } /* * (non-Javadoc) * * @see org.jajuk.ui.Observer#update(java.lang.String) */ @Override public void update(JajukEvent event) { synchronized (SuggestionView.class) { JajukEvents subject = event.getSubject(); if (subject.equals(JajukEvents.FILE_LAUNCHED)) { comp++; // Change local collection suggestions every 10 track plays if (comp % 10 == 0) { refreshLocalCollectionTabs(); } // update last.fm panels refreshLastFMCollectionTabs(); } else if (subject.equals(JajukEvents.PARAMETERS_CHANGE) && isLastFMTabsVisible()) { // The show/hide unmounted may have changed, refresh local // collection panels refreshLastFMCollectionTabs(); } else if (subject.equals(JajukEvents.COVER_DEFAULT_CHANGED) || subject.equals(JajukEvents.SUGGESTIONS_REFRESH)) { // New default cover, refresh the view refreshLocalCollectionTabs(); } } } /** * [Perf]. * * @return whether LastFM tabs are visible or not */ private boolean isLastFMTabsVisible() { // Refresh artists only if user selected similar artists or albums tab return (tabs.getSelectedIndex() == 3 || tabs.getSelectedIndex() == 4) // Check this view perspective is visible && PerspectiveManager.getCurrentPerspective().equals(this.getPerspective()); } /** * Refresh lastFM tabs on perspective selection if tabs visible. */ @Override public void onPerspectiveSelection() { refreshLastFMCollectionTabs(); } /** * Gets the nothing found panel. * * @return a panel with text explaining why no item has been found */ JPanel getNothingFoundPanel() { JPanel out = new JPanel(new MigLayout("ins 5", "grow")); JEditorPane jteNothing = new JEditorPane("text/html", Messages.getString("SuggestionView.7")); jteNothing.setBorder(null); jteNothing.setEditable(false); jteNothing.setOpaque(false); jteNothing.setToolTipText(Messages.getString("SuggestionView.7")); out.add(jteNothing, "center,grow"); return out; } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/views/TracksTableView.java0000644000175000017500000000731411720500104025457 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.views; import javax.swing.JMenuItem; import org.jajuk.ui.actions.ActionManager; import org.jajuk.ui.actions.JajukActions; import org.jajuk.ui.helpers.JajukTableModel; import org.jajuk.ui.helpers.TracksTableModel; import org.jajuk.ui.helpers.TwoStepsDisplayable; import org.jajuk.ui.widgets.JajukTable; import org.jajuk.util.Conf; import org.jajuk.util.Const; import org.jajuk.util.Messages; import org.jajuk.util.UtilGUI; /** * Logical table view. */ public class TracksTableView extends AbstractTableView implements TwoStepsDisplayable { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** DOCUMENT_ME. */ private JMenuItem jmiTrackPlayAlbum; /** DOCUMENT_ME. */ private JMenuItem jmiTrackPlayArtist; /** * Instantiates a new tracks table view. */ public TracksTableView() { super(); columnsConf = CONF_TRACKS_TABLE_COLUMNS; editableConf = CONF_TRACKS_TABLE_EDITION; } /* * (non-Javadoc) * * @see org.jajuk.ui.IView#getDesc() */ @Override public String getDesc() { return Messages.getString("TracksTableView.0"); } /* * (non-Javadoc) * * @see org.jajuk.ui.views.IView#initUI() */ @Override public void initUI() { UtilGUI.populate(this); } /* * (non-Javadoc) * * @see org.jajuk.ui.helpers.TwoStepsDisplayable#shortCall(java.lang.Object) */ @Override public void shortCall(Object in) { jtable = new JajukTable(model, true, columnsConf); super.shortCall(null); // Track menu jmiTrackPlayAlbum = new JMenuItem(ActionManager.getAction(JajukActions.PLAY_ALBUM_SELECTION)); jmiTrackPlayAlbum.putClientProperty(Const.DETAIL_SELECTION, jtable.getSelection()); jmiTrackPlayArtist = new JMenuItem(ActionManager.getAction(JajukActions.PLAY_ARTIST_SELECTION)); jmiTrackPlayArtist.putClientProperty(Const.DETAIL_SELECTION, jtable.getSelection()); jtable.getMenu().add(jmiTrackPlayAlbum, 4); jtable.getMenu().add(jmiTrackPlayArtist, 5); // Add this generic menu item manually to ensure it's the last one in // the list for GUI reasons jtable.getMenu().addSeparator(); jtable.getMenu().add(pjmTracks); jtable.getMenu().add(jmiBookmark); jtable.getMenu().addSeparator(); jtable.getMenu().add(jmiProperties); } /* * (non-Javadoc) * * @see org.jajuk.ui.helpers.TwoStepsDisplayable#longCall() */ @Override public Object longCall() { super.longCall(); return null; } /** * Fill the table. * * @return the jajuk table model */ @Override public synchronized JajukTableModel populateTable() { // model creation return new TracksTableModel(getID()); } /* * (non-Javadoc) * * @see org.jajuk.ui.views.AbstractTableView#initTable() */ @Override void initTable() { boolean bEditable = Conf.getBoolean(Const.CONF_TRACKS_TABLE_EDITION); jtbEditable.setSelected(bEditable); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/views/ViewFactory.java0000644000175000017500000000625411720500104024671 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.views; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; import org.jajuk.ui.perspectives.IPerspective; /** * View Factory, creates view item and manages their ID. */ public final class ViewFactory { /** * No instantiation *. */ private ViewFactory() { } /** * Create a new view instance. * * @param className view class * @param perspective view perspective * @param id integer id used as vldocking key id * * @return the created view */ public static IView createView(Class className, IPerspective perspective, int id) { IView view; try { view = (IView) className.newInstance(); } catch (Exception e) { throw new RuntimeException(e); } view.setID(className.getName() + '/' + id); view.setPerspective(perspective); return view; } /** * Gets the known views. * * @return All known views sorted by name * * @TODO Refactor this, the known views should be get by reflection (from the * default perspectives XML file ?) */ @SuppressWarnings("unchecked") public static List> getKnownViews() { List> out = new ArrayList>(); // Take one instance of each set of view instances mapped to each view // classname out.add(AnimationView.class); out.add(CatalogView.class); out.add(CDScanView.class); out.add(CoverView.class); out.add(DeviceView.class); out.add(TracksTableView.class); out.add(TracksTreeView.class); out.add(PlaylistView.class); out.add(LyricsView.class); out.add(ParameterView.class); out.add(FilesTableView.class); out.add(FilesTreeView.class); out.add(StatView.class); out.add(SuggestionView.class); out.add(WikipediaView.class); out.add(AlbumsTableView.class); out.add(QueueView.class); out.add(ArtistView.class); Collections.sort(out, new Comparator() { @Override public int compare(Object view1, Object view2) { String s1; String s2; try { s1 = ((IView) ((Class) view1).newInstance()).getDesc(); s2 = ((IView) ((Class) view2).newInstance()).getDesc(); } catch (Exception e) { throw new RuntimeException(e); } return s1.compareTo(s2); } }); return out; } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/views/QueueView.java0000644000175000017500000005712611720500104024352 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.views; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Dimension; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Properties; import java.util.Set; import javax.swing.BorderFactory; import javax.swing.JLabel; import javax.swing.JMenuItem; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTable; import javax.swing.JToolBar; import javax.swing.ListSelectionModel; import javax.swing.SwingUtilities; import javax.swing.event.ListSelectionEvent; import net.miginfocom.swing.MigLayout; import org.jajuk.base.File; import org.jajuk.base.FileManager; import org.jajuk.base.Playlist; import org.jajuk.base.SmartPlaylist; import org.jajuk.events.JajukEvent; import org.jajuk.events.JajukEvents; import org.jajuk.events.ObservationManager; import org.jajuk.services.players.QueueModel; import org.jajuk.services.players.StackItem; import org.jajuk.ui.actions.ActionManager; import org.jajuk.ui.actions.JajukActions; import org.jajuk.ui.helpers.ILaunchCommand; import org.jajuk.ui.helpers.IndexHighlighterPredicate; import org.jajuk.ui.helpers.JajukTableModel; import org.jajuk.ui.helpers.PlaylistEditorTransferHandler; import org.jajuk.ui.helpers.PlaylistTableModel; import org.jajuk.ui.widgets.JajukButton; import org.jajuk.ui.widgets.JajukJToolbar; import org.jajuk.ui.widgets.JajukTable; import org.jajuk.ui.widgets.JajukToggleButton; import org.jajuk.util.Conf; import org.jajuk.util.Const; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; import org.jajuk.util.UtilFeatures; import org.jajuk.util.log.Log; import org.jdesktop.swingx.decorator.ColorHighlighter; import org.jvnet.substance.SubstanceLookAndFeel; import org.jvnet.substance.api.SubstanceColorScheme; import org.jvnet.substance.api.SubstanceSkin; /** * Adapter for playlists editors *. */ public class QueueView extends PlaylistView { /** Generated serialVersionUID. */ private static final long serialVersionUID = -2851288035506442507L; /** DOCUMENT_ME. */ private JScrollPane jsp; /** DOCUMENT_ME. */ private JajukToggleButton jtbAutoScroll; /** Last scrolled-item *. */ private StackItem lastScrolledItem; /* * (non-Javadoc) * * @see org.jajuk.ui.IView#display() */ @Override public void initUI() { plf = new SmartPlaylist(Playlist.Type.QUEUE, Integer.toString(Playlist.Type.QUEUE.ordinal()), null, null); // Control panel jpEditorControl = new JPanel(); jpEditorControl.setBorder(BorderFactory.createEtchedBorder()); jbSave = new JajukButton(IconLoader.getIcon(JajukIcons.SAVE)); jbSave.setToolTipText(Messages.getString("AbstractPlaylistEditorView.3")); jbSave.addActionListener(this); jbRemove = new JajukButton(IconLoader.getIcon(JajukIcons.REMOVE)); jbRemove.setToolTipText(Messages.getString("AbstractPlaylistEditorView.5")); jbRemove.addActionListener(this); jbUp = new JajukButton(IconLoader.getIcon(JajukIcons.UP)); jbUp.setToolTipText(Messages.getString("AbstractPlaylistEditorView.6")); jbUp.addActionListener(this); jbDown = new JajukButton(IconLoader.getIcon(JajukIcons.DOWN)); jbDown.setToolTipText(Messages.getString("AbstractPlaylistEditorView.7")); jbDown.addActionListener(this); jbAddShuffle = new JajukButton(IconLoader.getIcon(JajukIcons.ADD_SHUFFLE)); jbAddShuffle.setToolTipText(Messages.getString("AbstractPlaylistEditorView.10")); jbAddShuffle.addActionListener(this); jlTitle = new JLabel(" [" + QueueModel.getQueue().size() + "]"); jbClear = new JajukButton(IconLoader.getIcon(JajukIcons.CLEAR)); jbClear.setToolTipText(Messages.getString("QueueView.1")); jbClear.addActionListener(this); jtbAutoScroll = new JajukToggleButton(IconLoader.getIcon(JajukIcons.AUTOSCROLL)); jtbAutoScroll.setToolTipText(Messages.getString("QueueView.2")); jtbAutoScroll.setSelected(Conf.getBoolean(Const.CONF_AUTO_SCROLL)); jtbAutoScroll.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { Conf.setProperty(Const.CONF_AUTO_SCROLL, Boolean.toString(jtbAutoScroll.isSelected())); if (jtbAutoScroll.isSelected()) { autoScroll(); } } }); JToolBar jtb = new JajukJToolbar(); jtb.add(jbSave); jtb.add(jbRemove); jtb.add(jbAddShuffle); jtb.add(jbUp); jtb.add(jbDown); jtb.addSeparator(); jtb.add(jbClear); // Add items jpEditorControl.setLayout(new MigLayout("insets 5", "[][grow][]")); jpEditorControl.add(jtb, "left,gapright 15::"); jpEditorControl.add(jlTitle, "center,gapright 5,grow"); jpEditorControl.add(jtbAutoScroll, "right"); editorModel = new PlaylistTableModel(true); editorTable = new JajukTable(editorModel, CONF_QUEUE_COLUMNS); editorModel.populateModel(editorTable.getColumnsConf()); editorTable.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); // multi-row // selection editorTable.setSortable(false); editorTable.setTransferHandler(new PlaylistEditorTransferHandler(editorTable)); setRenderers(); // just an icon editorTable.getColumnModel().getColumn(0).setPreferredWidth(20); editorTable.getColumnModel().getColumn(0).setMaxWidth(20); editorTable.getTableHeader().setPreferredSize(new Dimension(0, 20)); editorTable.showColumns(editorTable.getColumnsConf()); setLayout(new BorderLayout()); add(jpEditorControl, BorderLayout.NORTH); jsp = new JScrollPane(editorTable); jsp.setBorder(BorderFactory.createEmptyBorder(0, 1, 0, 0)); add(jsp, BorderLayout.CENTER); // menu items jmiFilePlay = new JMenuItem(Messages.getString("TracksTableView.7"), IconLoader .getIcon(JajukIcons.PLAY_16X16)); // We don't use regular action for the play because it has very special // behavior here in the queue view : it must go to selection without keeping // previous FIFO jmiFilePlay.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { goToSelection(); } }); initMenuItems(); SubstanceSkin theme = SubstanceLookAndFeel.getCurrentSkin(); SubstanceColorScheme scheme = theme.getMainActiveColorScheme(); Color queueHighlighterColor = null; if (scheme.isDark()) { queueHighlighterColor = scheme.getUltraLightColor(); } else { queueHighlighterColor = scheme.getLineColor(); } ColorHighlighter colorHighlighter = new ColorHighlighter(new IndexHighlighterPredicate(), queueHighlighterColor, null); editorTable.addHighlighter(colorHighlighter); // register events ObservationManager.register(this); // Add key listener to enable row suppression using SUPR key editorTable.addKeyListener(new KeyAdapter() { @Override public void keyPressed(KeyEvent e) { // The fact that a selection can be removed or not is // in the jbRemove state if (e.getKeyCode() == KeyEvent.VK_DELETE && jbRemove.isEnabled()) { removeSelection(); // Refresh table refreshQueue(); } } }); // Add specific behavior on left click editorTable.setCommand(new ILaunchCommand() { @Override public void launch(int nbClicks) { int iSelectedCol = editorTable.getSelectedColumn(); // Convert column selection as columns may have been moved iSelectedCol = editorTable.convertColumnIndexToModel(iSelectedCol); // double click, launches selected track and all after if (nbClicks == 2 // click on play icon || (nbClicks == 1 && iSelectedCol == 0)) { StackItem item = editorModel.getStackItem(editorTable.getSelectedRow()); if (item.isPlanned()) { item.setPlanned(false); item.setRepeat(Conf.getBoolean(Const.CONF_STATE_REPEAT_ALL)); item.setUserLaunch(true); QueueModel.push(item, Conf.getBoolean(Const.CONF_OPTIONS_PUSH_ON_CLICK)); } else { // non planned items goToSelection(); } } } }); // Note : don't add a ListSelectionListener here, see JajukTable code, // all the event code is centralized over there editorTable.addListSelectionListener(this); // Register keystrokes over table super.setKeystrokes(); // Force a first need refresh event update(new JajukEvent(JajukEvents.QUEUE_NEED_REFRESH)); } /** * Go to selected row, do it asynchronously because FIFO.goTO() can freeze the * GUI */ private void goToSelection() { new Thread("Queue Selection Thread") { @Override public void run() { try { QueueModel.goTo(editorTable.getSelectedRow()); // remove selection for planned tracks ListSelectionModel lsm = editorTable.getSelectionModel(); editorModel.setRefreshing(true); editorTable.getSelectionModel().removeSelectionInterval(lsm.getMinSelectionIndex(), lsm.getMaxSelectionIndex()); } catch (Exception e) { Log.error(e); } finally { editorModel.setRefreshing(false); } } }.start(); } /* * (non-Javadoc) * * @see org.jajuk.ui.views.PlaylistView#getRegistrationKeys() */ @Override public Set getRegistrationKeys() { Set eventSubjectSet = new HashSet(); eventSubjectSet.add(JajukEvents.QUEUE_NEED_REFRESH); eventSubjectSet.add(JajukEvents.DEVICE_REFRESH); eventSubjectSet.add(JajukEvents.DEVICE_MOUNT); eventSubjectSet.add(JajukEvents.DEVICE_UNMOUNT); eventSubjectSet.add(JajukEvents.CUSTOM_PROPERTIES_ADD); eventSubjectSet.add(JajukEvents.CUSTOM_PROPERTIES_REMOVE); eventSubjectSet.add(JajukEvents.VIEW_REFRESH_REQUEST); eventSubjectSet.add(JajukEvents.RATE_CHANGED); eventSubjectSet.add(JajukEvents.PARAMETERS_CHANGE); return eventSubjectSet; } /* * (non-Javadoc) * * @see org.jajuk.ui.IView#getDesc() */ @Override public String getDesc() { return Messages.getString("PlaylistFileItem.5"); } /* * (non-Javadoc) * * @see org.jajuk.ui.Observer#update(java.lang.String) */ @Override public void update(final JajukEvent event) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { try { JajukEvents subject = event.getSubject(); editorTable.setAcceptColumnsEvents(false); // flag reloading to avoid // wrong if (JajukEvents.QUEUE_NEED_REFRESH.equals(subject) || JajukEvents.DEVICE_REFRESH.equals(subject) || JajukEvents.DEVICE_MOUNT.equals(subject) || JajukEvents.DEVICE_UNMOUNT.equals(subject) || JajukEvents.RATE_CHANGED.equals(subject) || JajukEvents.PARAMETERS_CHANGE.equals(subject)) { editorModel.getItems().clear(); editorModel.getPlanned().clear(); refreshQueue(); // Only scroll if song actually changed, otherwise, any queue refresh // would scroll and annoy users if (Conf.getBoolean(CONF_AUTO_SCROLL) && QueueModel.getCurrentItem() != null && !QueueModel.getCurrentItem().equals(lastScrolledItem)) { autoScroll(); lastScrolledItem = QueueModel.getCurrentItem(); } } else if (JajukEvents.CUSTOM_PROPERTIES_ADD.equals(subject)) { Properties properties = event.getDetails(); if (properties == null) { // can be null at view populate return; } // create a new model editorModel = new PlaylistTableModel(true); editorModel.populateModel(editorTable.getColumnsConf()); editorTable.setModel(editorModel); setRenderers(); editorTable.addColumnIntoConf((String) properties.get(Const.DETAIL_CONTENT)); editorTable.showColumns(editorTable.getColumnsConf()); editorModel.getItems().clear(); editorModel.getPlanned().clear(); refreshQueue(); } else if (JajukEvents.CUSTOM_PROPERTIES_REMOVE.equals(subject)) { Properties properties = event.getDetails(); if (properties == null) { // can be null at view // populate return; } editorModel = new PlaylistTableModel(true); editorModel.populateModel(editorTable.getColumnsConf()); editorTable.setModel(editorModel); setRenderers(); // remove item from configuration cols editorTable.removeColumnFromConf((String) properties.get(Const.DETAIL_CONTENT)); editorTable.showColumns(editorTable.getColumnsConf()); editorModel.getItems().clear(); editorModel.getPlanned().clear(); refreshQueue(); } else if (JajukEvents.VIEW_REFRESH_REQUEST.equals(subject)) { // force filter to refresh if the events has been triggered by the // table itself after a column change JTable table = (JTable) event.getDetails().get(Const.DETAIL_CONTENT); if (table.equals(editorTable)) { editorModel.getItems().clear(); editorModel.getPlanned().clear(); refreshQueue(); } } } catch (Exception e) { Log.error(e); } finally { editorTable.setAcceptColumnsEvents(true); // Update number of tracks remaining jlTitle.setText(" [" + QueueModel.getQueue().size() + "]"); } } }); } /** * Auto scroll to played track if option is enabled. */ private void autoScroll() { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { if (QueueModel.getQueueSize() > 0) { double index = QueueModel.getIndex(); double size = QueueModel.getQueueSize() + QueueModel.getPlanned().size(); double factor = (index / size); int value = (int) (factor * jsp.getVerticalScrollBar().getMaximum()); // 'center' played track value -= (jsp.getVerticalScrollBar().getHeight() / 2) - (editorTable.getRowHeight() / 2); if (value < 0) { value = 0; } if (value >= jsp.getVerticalScrollBar().getMinimum() && value <= jsp.getVerticalScrollBar().getMaximum()) { jsp.getVerticalScrollBar().setValue(value); } } } }); } /** * Refresh queue. DOCUMENT_ME */ private void refreshQueue() { // when nothing is selected, set default button state if (editorTable.getSelectionModel().getMinSelectionIndex() == -1) { setDefaultButtonState(); } editorModel.setItems(QueueModel.getQueue()); editorModel.setPlanned(QueueModel.getPlanned()); ((JajukTableModel) editorTable.getModel()).populateModel(editorTable.getColumnsConf()); // save selection to avoid reseting selection the user is doing int[] rows = editorTable.getSelectedRows(); try { editorModel.setRefreshing(true); // force table refresh editorModel.fireTableDataChanged(); for (int element : rows) { // set saved selection after a refresh editorTable.getSelectionModel().addSelectionInterval(element, element); } } finally { editorModel.setRefreshing(false); } // Refresh the preference menu according to the selection // (useful on rating change for a single-row model for ie) pjmFilesEditor.resetUI(editorTable.getSelection()); } /** * Set default button state. */ private void setDefaultButtonState() { // set buttons jbUp.setEnabled(false); // set it to false just for startup // because nothing is selected jbDown.setEnabled(false); // set it to false just for startup // because nothing is selected jbAddShuffle.setEnabled(true);// add at the FIFO end by // default even with no // selection jbRemove.setEnabled(false); // set it to false just for startup // because cursor is over first track // and it can't be removed in queue mode // disable prepare party for queue playlist } /* * (non-Javadoc) * * @see org.jajuk.ui.views.PlaylistView#actionPerformed(java.awt.event.ActionEvent) */ @Override public void actionPerformed(ActionEvent ae) { try { if (ae.getSource() == jbSave) { // special playlist, same behavior than a save as plf.saveAs(); // notify playlist repository to refresh ObservationManager.notify(new JajukEvent(JajukEvents.DEVICE_REFRESH)); } else if (ae.getSource() == jbDown || ae.getSource() == jbUp || ae.getSource() == jmiFileDown || ae.getSource() == jmiFileUp) { int iRow = editorTable.getSelectedRow(); if (iRow != -1) { // -1 means nothing is selected if (ae.getSource() == jbDown || ae.getSource() == jmiFileDown) { plf.down(iRow); if (iRow < editorTable.getModel().getRowCount() - 1) { // force immediate table refresh refreshQueue(); editorTable.getSelectionModel().setSelectionInterval(iRow + 1, iRow + 1); } } else if (ae.getSource() == jbUp || ae.getSource() == jmiFileUp) { plf.up(iRow); if (iRow > 0) { // force immediate table refresh refreshQueue(); editorTable.getSelectionModel().setSelectionInterval(iRow - 1, iRow - 1); } } } } else if (ae.getSource() == jbRemove || ae.getSource() == jmiFileRemove) { removeSelection(); refreshQueue(); } else if (ae.getSource() == jbAddShuffle) { int iRow = editorTable.getSelectedRow(); if (iRow < 0 // no row is selected, add to the end || iRow > QueueModel.getQueue().size()) { // row can be on planned track if user select a planned track and if // fifo is reduced after tracks have been played iRow = QueueModel.getQueue().size(); } File file = FileManager.getInstance().getShuffleFile(); List files = new ArrayList(); files.add(file); QueueModel.insert(UtilFeatures.createStackItems(files, Conf .getBoolean(Const.CONF_STATE_REPEAT_ALL), true), iRow); refreshQueue(); } else if (ae.getSource() == jbClear) { // Reset the FIFO QueueModel.reset(); // reinit all variables try { ActionManager.getAction(JajukActions.STOP_TRACK).perform(null); ObservationManager.notify(new JajukEvent(JajukEvents.ZERO)); } catch (Exception e) { Log.error(e); } } } catch (Exception e2) { Log.error(e2); } } /** * Removes the selection. DOCUMENT_ME */ private void removeSelection() { int[] iRows = editorTable.getSelectedRows(); if (iRows.length > 1) {// if multiple selection, remove // selection editorTable.getSelectionModel().removeIndexInterval(0, editorTable.getRowCount() - 1); } for (int i = 0; i < iRows.length; i++) { // don't forget that index changes when removing plf.remove(iRows[i] - i); } // set selection to last line if end reached int iLastRow = editorTable.getRowCount() - 1; if (iRows[0] == editorTable.getRowCount()) { editorTable.getSelectionModel().setSelectionInterval(iLastRow, iLastRow); } } /** * Called when table selection changed. * * @param e DOCUMENT_ME */ @Override public void valueChanged(ListSelectionEvent e) { ListSelectionModel selection = (ListSelectionModel) e.getSource(); if (!selection.isSelectionEmpty()) { updateSelection(); updateInformationView(selectedFiles); // Refresh the preference menu according to the selection pjmFilesEditor.resetUI(editorTable.getSelection()); int selectedRow = selection.getMaxSelectionIndex(); // true if selected line is a planned track boolean bPlanned = false; if (selectedRow > editorModel.getItems().size() - 1) { // means it is a planned track bPlanned = true; } // -- now analyze each button -- // Remove button if (bPlanned) { jbRemove.setEnabled(false); jmiFileRemove.setEnabled(false); } else { // check for current track case : we can't remove currently // played track jbRemove.setEnabled(!selectionContainsCurrentTrack(selection)); jmiFileRemove.setEnabled(!selectionContainsCurrentTrack(selection)); } // Add shuffle button // No adding for planned track jbAddShuffle.setEnabled(!bPlanned); // Up button if (selection.getMinSelectionIndex() != selection.getMaxSelectionIndex()) { // check if several rows have been selected : // doesn't supported yet jbUp.setEnabled(false); jmiFileUp.setEnabled(false); } else { // still here ? if (bPlanned) { // No up/down buttons for planned tracks jbUp.setEnabled(false); jmiFileUp.setEnabled(false); } else { // normal item if (selection.getMinSelectionIndex() == 0) { // already at the top jbUp.setEnabled(false); jmiFileUp.setEnabled(false); } else { jbUp.setEnabled(true); jmiFileUp.setEnabled(true); } } } // Down button if (selection.getMinSelectionIndex() != selection.getMaxSelectionIndex()) { // check if several rows have been selected : // doesn't supported yet jbDown.setEnabled(false); jmiFileDown.setEnabled(false); } else { // yet here ? if (bPlanned) { // No up/down buttons for planned tracks jbDown.setEnabled(false); jmiFileDown.setEnabled(false); } else { // normal item if (selection.getMaxSelectionIndex() < editorModel.getItems().size() - 1) { // a normal item can't go in the planned items jbDown.setEnabled(true); jmiFileDown.setEnabled(true); } else { jbDown.setEnabled(false); jmiFileDown.setEnabled(false); } } } } } /** * Return whether a given row selection contains the current played track. * * @param selection the selection * * @return whether a given row selection contains the current played track */ private boolean selectionContainsCurrentTrack(ListSelectionModel selection) { for (int i = selection.getMinSelectionIndex(); i <= selection.getMaxSelectionIndex(); i++) { if (QueueModel.getItem(i).equals(QueueModel.getCurrentItem())) { return true; } } return false; } }jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/views/PlaylistView.java0000644000175000017500000012102711720500104025057 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.views; import java.awt.Color; import java.awt.Dimension; import java.awt.FlowLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Properties; import java.util.Set; import javax.swing.ActionMap; import javax.swing.BorderFactory; import javax.swing.BoxLayout; import javax.swing.InputMap; import javax.swing.JComponent; import javax.swing.JLabel; import javax.swing.JMenuItem; import javax.swing.JPanel; import javax.swing.JPopupMenu; import javax.swing.JScrollPane; import javax.swing.JSplitPane; import javax.swing.JTable; import javax.swing.JToolBar; import javax.swing.KeyStroke; import javax.swing.ListSelectionModel; import javax.swing.MenuElement; import javax.swing.SwingUtilities; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import javax.swing.table.TableColumn; import net.miginfocom.swing.MigLayout; import org.jajuk.base.Device; import org.jajuk.base.DeviceManager; import org.jajuk.base.Directory; import org.jajuk.base.DirectoryManager; import org.jajuk.base.File; import org.jajuk.base.FileManager; import org.jajuk.base.Item; import org.jajuk.base.Playlist; import org.jajuk.base.Playlist.Type; import org.jajuk.events.JajukEvent; import org.jajuk.events.JajukEvents; import org.jajuk.events.ObservationManager; import org.jajuk.services.players.QueueModel; import org.jajuk.services.players.StackItem; import org.jajuk.ui.actions.ActionManager; import org.jajuk.ui.actions.JajukAction; import org.jajuk.ui.actions.JajukActions; import org.jajuk.ui.helpers.ILaunchCommand; import org.jajuk.ui.helpers.JajukMouseAdapter; import org.jajuk.ui.helpers.JajukTableModel; import org.jajuk.ui.helpers.PlayHighlighterPredicate; import org.jajuk.ui.helpers.PlaylistEditorTransferHandler; import org.jajuk.ui.helpers.PlaylistRepositoryTableModel; import org.jajuk.ui.helpers.PlaylistTableModel; import org.jajuk.ui.helpers.PreferencesJMenu; import org.jajuk.ui.helpers.TwoStepsDisplayable; import org.jajuk.ui.widgets.InformationJPanel; import org.jajuk.ui.widgets.JajukButton; import org.jajuk.ui.widgets.JajukJSplitPane; import org.jajuk.ui.widgets.JajukJToolbar; import org.jajuk.ui.widgets.JajukTable; import org.jajuk.ui.widgets.SmartPlaylistView; import org.jajuk.util.Conf; import org.jajuk.util.Const; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; import org.jajuk.util.UtilFeatures; import org.jajuk.util.UtilGUI; import org.jajuk.util.UtilSystem; import org.jajuk.util.error.JajukException; import org.jajuk.util.log.Log; import org.jdesktop.swingx.decorator.ColorHighlighter; /** * Adapter for playlists editors *. */ public class PlaylistView extends ViewAdapter implements ActionListener, ListSelectionListener { /** Generated serialVersionUID. */ private static final long serialVersionUID = -2851288035506442507L; /* * Some widgets are private to make sure QueueView that extends this class will not use them * TODO refactoring : check for unifying smart and regular playlists (a single mouse adapter for ie) */ /** DOCUMENT_ME. */ private JajukJSplitPane split; // --Editor-- /** DOCUMENT_ME. */ private JPanel jpEditor; /** DOCUMENT_ME. */ JPanel jpEditorControl; /** DOCUMENT_ME. */ private JajukButton jbRun; /** DOCUMENT_ME. */ JajukButton jbSave; /** DOCUMENT_ME. */ JajukButton jbRemove; /** DOCUMENT_ME. */ JajukButton jbUp; /** DOCUMENT_ME. */ JajukButton jbDown; /** DOCUMENT_ME. */ JajukButton jbAddShuffle; /** DOCUMENT_ME. */ JajukButton jbClear; /** DOCUMENT_ME. */ JLabel jlTitle; /** DOCUMENT_ME. */ JajukTable editorTable; /** DOCUMENT_ME. */ JMenuItem jmiFilePlay; /** DOCUMENT_ME. */ private JMenuItem jmiFilePush; /** DOCUMENT_ME. */ private JMenuItem jmiFileFrontPush; /** DOCUMENT_ME. */ private JMenuItem jmiFileAddFavorites; /** DOCUMENT_ME. */ JMenuItem jmiFileRemove; /** DOCUMENT_ME. */ JMenuItem jmiFileUp; /** DOCUMENT_ME. */ JMenuItem jmiFileDown; /** DOCUMENT_ME. */ private JMenuItem jmiFileProperties; /** DOCUMENT_ME. */ private JMenuItem jmiFileCopyURL; /** Current playlist. */ Playlist plf; /** Editor Model. */ protected PlaylistTableModel editorModel; /** DOCUMENT_ME. */ PreferencesJMenu pjmFilesEditor; // --- Repository --- /** DOCUMENT_ME. */ private PlaylistRepository repositoryPanel; /** DOCUMENT_ME. */ private SmartPlaylistView spNew; /** DOCUMENT_ME. */ private SmartPlaylistView spNovelties; /** DOCUMENT_ME. */ private SmartPlaylistView spBookmark; /** DOCUMENT_ME. */ private SmartPlaylistView spBestof; /** Selected smart playlist. */ private SmartPlaylistView spSelected; /** List of selected files in the editor table. We don't just rely upon JajukTable's selection because we need here a deep selection computation including playlists contents */ List selectedFiles = new ArrayList(20); /** Mouse adapter for smart playlist items. */ MouseAdapter ma = new JajukMouseAdapter() { @Override public void handleAction(final MouseEvent e) { SmartPlaylistView sp = (SmartPlaylistView) e.getComponent(); if (sp == spSelected) { List files; try { files = sp.getPlaylist().getFiles(); } catch (JajukException e1) { Log.error(e1); return; } if ((files == null) || (files.size() == 0)) { Messages.showErrorMessage(18); } else { QueueModel.push(UtilFeatures.createStackItems(UtilFeatures.applyPlayOption(files), Conf .getBoolean(Const.CONF_STATE_REPEAT_ALL), true), false); } } else { // user changed of smart playlist selection selectSmartPlaylist(sp); } } @Override public void handlePopup(final MouseEvent e) { SmartPlaylistView sp = (SmartPlaylistView) e.getComponent(); if (sp == spSelected) { // right click showSmartMenu(e); } else { selectSmartPlaylist(sp); showSmartMenu(e); } } /** * Display the playlist menu */ private void showSmartMenu(MouseEvent e) { // We use for smart playlists panels the same popup menu than the one from // the repository table // but we disable some items like delete or properties // Add generic menus JPopupMenu menu = new JPopupMenu(); JMenuItem jmiPlay = new JMenuItem(ActionManager.getAction(JajukActions.PLAY_SELECTION)); JMenuItem jmiFrontPush = new JMenuItem(ActionManager .getAction(JajukActions.PUSH_FRONT_SELECTION)); JMenuItem jmiPush = new JMenuItem(ActionManager.getAction(JajukActions.PUSH_SELECTION)); JMenuItem jmiPlayRepeat = new JMenuItem(ActionManager .getAction(JajukActions.PLAY_REPEAT_SELECTION)); JMenuItem jmiPlayShuffle = new JMenuItem(ActionManager .getAction(JajukActions.PLAY_SHUFFLE_SELECTION)); JMenuItem jmiPrepareParty = new JMenuItem(ActionManager.getAction(JajukActions.PREPARE_PARTY)); JMenuItem jmiRepositorySaveAs = new JMenuItem(ActionManager.getAction(JajukActions.SAVE_AS)); menu.add(jmiPlay); menu.add(jmiFrontPush); menu.add(jmiPush); menu.add(jmiPlayRepeat); menu.add(jmiPlayShuffle); menu.addSeparator(); menu.add(jmiPrepareParty); menu.add(jmiRepositorySaveAs); for (MenuElement item : menu.getSubElements()) { ((JComponent) item).putClientProperty(Const.DETAIL_SELECTION, spSelected.getPlaylist()); } menu.show(e.getComponent(), e.getX(), e.getY()); } }; /** * Select smart playlist. * * @param sp the smart playlist */ void selectSmartPlaylist(SmartPlaylistView sp) { // remove table selection so an event will be thrown if user click on the table repositoryPanel.jtable.getSelectionModel().clearSelection(); // remove item border if (spSelected != null) { spSelected.getIcon().setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); } sp.getIcon().setBorder(BorderFactory.createLineBorder(Color.ORANGE, 5)); // set new item spSelected = sp; try { selectedFiles.clear(); selectedFiles.addAll(sp.getPlaylist().getFiles()); } catch (JajukException e) { Log.error(e); return; } // Update playlist editor selectPlaylist(sp.getPlaylist()); } /** * Return the editor table. * * @return the editor table */ public JajukTable getTable() { return this.editorTable; } /** * Inits the editor panel. */ public void initEditorPanel() { jpEditor = new JPanel(); // Control panel jpEditorControl = new JPanel(); jpEditorControl.setBorder(BorderFactory.createEtchedBorder()); jbRun = new JajukButton(IconLoader.getIcon(JajukIcons.RUN)); jbRun.setToolTipText(Messages.getString("AbstractPlaylistEditorView.2")); jbRun.addActionListener(this); jbSave = new JajukButton(IconLoader.getIcon(JajukIcons.SAVE)); jbSave.setToolTipText(Messages.getString("AbstractPlaylistEditorView.3")); jbSave.addActionListener(this); jbRemove = new JajukButton(IconLoader.getIcon(JajukIcons.REMOVE)); jbRemove.setToolTipText(Messages.getString("AbstractPlaylistEditorView.5")); jbRemove.addActionListener(this); jbUp = new JajukButton(IconLoader.getIcon(JajukIcons.UP)); jbUp.setToolTipText(Messages.getString("AbstractPlaylistEditorView.6")); jbUp.addActionListener(this); jbDown = new JajukButton(IconLoader.getIcon(JajukIcons.DOWN)); jbDown.setToolTipText(Messages.getString("AbstractPlaylistEditorView.7")); jbDown.addActionListener(this); jbAddShuffle = new JajukButton(IconLoader.getIcon(JajukIcons.ADD_SHUFFLE)); jbAddShuffle.setToolTipText(Messages.getString("AbstractPlaylistEditorView.10")); jbAddShuffle.addActionListener(this); jbClear = new JajukButton(IconLoader.getIcon(JajukIcons.CLEAR)); jbClear.setToolTipText(Messages.getString("AbstractPlaylistEditorView.9")); jbClear.addActionListener(this); jlTitle = new JLabel(""); JToolBar jtb = new JajukJToolbar(); // Add items jpEditorControl.setLayout(new MigLayout("ins 0", "[][grow][]")); jtb.add(jbRun); jtb.add(jbSave); jtb.add(jbRemove); jtb.add(jbAddShuffle); jtb.add(jbUp); jtb.add(jbDown); jtb.addSeparator(); jtb.add(jbClear); jpEditorControl.add(jtb, "left,gapright 5::"); jpEditorControl.add(jlTitle, "center"); editorModel = new PlaylistTableModel(false); editorTable = new JajukTable(editorModel, CONF_PLAYLIST_EDITOR_COLUMNS); editorModel.populateModel(editorTable.getColumnsConf()); editorTable.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); // multi-row // selection editorTable.setSortable(false); editorTable.setTransferHandler(new PlaylistEditorTransferHandler(editorTable)); setRenderers(); // just an icon editorTable.getColumnModel().getColumn(0).setPreferredWidth(20); editorTable.getColumnModel().getColumn(0).setMaxWidth(20); editorTable.getTableHeader().setPreferredSize(new Dimension(0, 20)); editorTable.showColumns(editorTable.getColumnsConf()); // Note : don't add a ListSelectionListener here, see JajukTable code, // all the event code is centralized over there editorTable.addListSelectionListener(this); jpEditor.setLayout(new MigLayout("ins 0", "[grow]")); jpEditor.add(jpEditorControl, "growx,wrap"); JScrollPane jsp = new JScrollPane(editorTable); jpEditor.add(jsp, "growx"); initMenuItems(); ColorHighlighter colorHighlighter = new ColorHighlighter(new PlayHighlighterPredicate( editorModel), Color.ORANGE, null); editorTable.addHighlighter(colorHighlighter); // register events ObservationManager.register(this); // -- force a refresh -- // Add key listener to enable row suppression using SUPR key editorTable.addKeyListener(new KeyAdapter() { @Override public void keyPressed(KeyEvent e) { // The fact that a selection can be removed or not is // in the jbRemove state if (e.getKeyCode() == KeyEvent.VK_DELETE && jbRemove.isEnabled()) { removeSelection(); // Refresh table refreshCurrentPlaylist(); } } }); // Add specific behavior on left click editorTable.setCommand(new ILaunchCommand() { @Override public void launch(int nbClicks) { int iSelectedCol = editorTable.getSelectedColumn(); // Convert column selection as columns may have been moved iSelectedCol = editorTable.convertColumnIndexToModel(iSelectedCol); // double click, launches selected track and all after if (nbClicks == 2 // click on play icon || (nbClicks == 1 && iSelectedCol == 0)) { StackItem item = editorModel.getStackItem(editorTable.getSelectedRow()); if (item != null) { // We launch all tracks from this // position // to the end of playlist QueueModel.push(editorModel.getItemsFrom(editorTable.getSelectedRow()), Conf .getBoolean(Const.CONF_OPTIONS_PUSH_ON_CLICK)); } } } }); } /** * This factorizes edit panel code between regular playlist view and queue * view for all menu items except the play that is queue-specific. */ void initMenuItems() { jmiFilePlay = new JMenuItem(ActionManager.getAction(JajukActions.PLAY_SELECTION)); jmiFilePlay.putClientProperty(Const.DETAIL_SELECTION, editorTable.getSelection()); jmiFileFrontPush = new JMenuItem(ActionManager.getAction(JajukActions.PUSH_FRONT_SELECTION)); jmiFileFrontPush.putClientProperty(Const.DETAIL_SELECTION, editorTable.getSelection()); jmiFilePush = new JMenuItem(ActionManager.getAction(JajukActions.PUSH_SELECTION)); jmiFilePush.putClientProperty(Const.DETAIL_SELECTION, editorTable.getSelection()); jmiFileAddFavorites = new JMenuItem(ActionManager.getAction(JajukActions.BOOKMARK_SELECTION)); jmiFileAddFavorites.putClientProperty(Const.DETAIL_SELECTION, editorTable.getSelection()); jmiFileProperties = new JMenuItem(ActionManager.getAction(JajukActions.SHOW_PROPERTIES)); jmiFileProperties.putClientProperty(Const.DETAIL_SELECTION, editorTable.getSelection()); jmiFileRemove = new JMenuItem(Messages.getString("AbstractPlaylistEditorView.5"), IconLoader .getIcon(JajukIcons.REMOVE)); jmiFileRemove.addActionListener(this); jmiFileUp = new JMenuItem(Messages.getString("AbstractPlaylistEditorView.6"), IconLoader .getIcon(JajukIcons.UP)); jmiFileUp.addActionListener(this); jmiFileDown = new JMenuItem(Messages.getString("AbstractPlaylistEditorView.7"), IconLoader .getIcon(JajukIcons.DOWN)); jmiFileDown.addActionListener(this); pjmFilesEditor = new PreferencesJMenu(editorTable.getSelection()); jmiFileCopyURL = new JMenuItem(ActionManager.getAction(JajukActions.COPY_TO_CLIPBOARD)); jmiFileCopyURL.putClientProperty(Const.DETAIL_CONTENT, editorTable.getSelection()); editorTable.getMenu().add(jmiFilePlay); editorTable.getMenu().add(jmiFileFrontPush); editorTable.getMenu().add(jmiFilePush); editorTable.getMenu().addSeparator(); editorTable.getMenu().add(jmiFileRemove); editorTable.getMenu().add(jmiFileUp); editorTable.getMenu().add(jmiFileDown); editorTable.getMenu().addSeparator(); editorTable.getMenu().add(jmiFileCopyURL); editorTable.getMenu().addSeparator(); editorTable.getMenu().add(pjmFilesEditor); editorTable.getMenu().add(jmiFileAddFavorites); editorTable.getMenu().addSeparator(); editorTable.getMenu().add(jmiFileProperties); } /* * (non-Javadoc) * * @see org.jajuk.ui.IView#display() */ @Override public void initUI() { initEditorPanel(); spNew = new SmartPlaylistView(Type.NEW); spNew.addMouseListener(ma); spBestof = new SmartPlaylistView(Type.BESTOF); spBestof.addMouseListener(ma); spNovelties = new SmartPlaylistView(Type.NOVELTIES); spNovelties.addMouseListener(ma); spBookmark = new SmartPlaylistView(Type.BOOKMARK); spBookmark.addMouseListener(ma); JPanel jpSmartPlaylists = new JPanel(); jpSmartPlaylists.setLayout(new FlowLayout(FlowLayout.LEFT)); jpSmartPlaylists.add(spNew); jpSmartPlaylists.add(spBestof); jpSmartPlaylists.add(spNovelties); jpSmartPlaylists.add(spBookmark); JPanel jpRepository = new JPanel(new MigLayout("ins 0", "[grow]")); repositoryPanel = new PlaylistRepository(); repositoryPanel.initUI(); repositoryPanel.setPerspective(getPerspective()); jpRepository.add(jpSmartPlaylists, "growx,wrap"); jpRepository.add(repositoryPanel, "growx"); split = new JajukJSplitPane(JSplitPane.VERTICAL_SPLIT); split.setDividerLocation(0.5d); split.add(jpRepository); split.add(jpEditor); setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); add(split); // Register keystrokes over table setKeystrokes(); } /** * Add keystroke support. */ protected void setKeystrokes() { // Bind keystrokes and selection editorTable.putClientProperty(Const.DETAIL_SELECTION, editorTable.getSelection()); InputMap inputMap = editorTable.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT); ActionMap actionMap = editorTable.getActionMap(); // Properties ALT/ENTER JajukAction action = ActionManager.getAction(JajukActions.SHOW_PROPERTIES); inputMap.put(KeyStroke.getKeyStroke("alt ENTER"), "properties"); actionMap.put("properties", action); } /* * (non-Javadoc) * * @see org.jajuk.events.Observer#getRegistrationKeys() */ @Override public Set getRegistrationKeys() { Set eventSubjectSet = new HashSet(); eventSubjectSet.add(JajukEvents.CUSTOM_PROPERTIES_ADD); eventSubjectSet.add(JajukEvents.CUSTOM_PROPERTIES_REMOVE); eventSubjectSet.add(JajukEvents.DEVICE_MOUNT); eventSubjectSet.add(JajukEvents.DEVICE_UNMOUNT); eventSubjectSet.add(JajukEvents.DEVICE_REFRESH); eventSubjectSet.add(JajukEvents.VIEW_REFRESH_REQUEST); eventSubjectSet.add(JajukEvents.QUEUE_NEED_REFRESH); eventSubjectSet.add(JajukEvents.PARAMETERS_CHANGE); eventSubjectSet.add(JajukEvents.RATE_CHANGED); return eventSubjectSet; } /* * (non-Javadoc) * * @see org.jajuk.ui.IView#getDesc() */ @Override public String getDesc() { return Messages.getString("AbstractPlaylistEditorView.15"); } /** * Sets the renderers. DOCUMENT_ME */ void setRenderers() { // set right cell renderer for play and rate icons // Play icon TableColumn col = editorTable.getColumnModel().getColumn(0); col.setMinWidth(PLAY_COLUMN_SIZE); col.setMaxWidth(PLAY_COLUMN_SIZE); // rate col = editorTable.getColumnModel().getColumn(5); col.setMinWidth(RATE_COLUMN_SIZE); col.setMaxWidth(RATE_COLUMN_SIZE); } /* * (non-Javadoc) * * @see org.jajuk.ui.Observer#update(java.lang.String) */ @Override public void update(final JajukEvent event) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { try { JajukEvents subject = event.getSubject(); editorTable.setAcceptColumnsEvents(false); // flag reloading to avoid // wrong // column changed of playlist // current playlist has changed if (JajukEvents.DEVICE_REFRESH.equals(subject) // We listen this event to paint the new running track in table || JajukEvents.QUEUE_NEED_REFRESH.equals(subject) || JajukEvents.RATE_CHANGED.equals(subject) || JajukEvents.DEVICE_MOUNT.equals(subject) || JajukEvents.DEVICE_UNMOUNT.equals(subject) || JajukEvents.PARAMETERS_CHANGE.equals(subject)) { refreshCurrentPlaylist(); } else if (JajukEvents.CUSTOM_PROPERTIES_ADD.equals(subject)) { Properties properties = event.getDetails(); if (properties == null) { // can be null at view populate return; } // create a new model editorModel = new PlaylistTableModel(false); editorModel.populateModel(editorTable.getColumnsConf()); editorTable.setModel(editorModel); setRenderers(); editorTable.addColumnIntoConf((String) properties.get(Const.DETAIL_CONTENT)); editorTable.showColumns(editorTable.getColumnsConf()); } else if (JajukEvents.CUSTOM_PROPERTIES_REMOVE.equals(subject)) { Properties properties = event.getDetails(); if (properties == null) { // can be null at view // populate return; } editorModel = new PlaylistTableModel(false); editorModel.populateModel(editorTable.getColumnsConf()); editorTable.setModel(editorModel); setRenderers(); // remove item from configuration cols editorTable.removeColumnFromConf((String) properties.get(Const.DETAIL_CONTENT)); editorTable.showColumns(editorTable.getColumnsConf()); } else if (JajukEvents.VIEW_REFRESH_REQUEST.equals(subject)) { // force filter to refresh if the events has been triggered by the // table itself after a column change JTable table = (JTable) event.getDetails().get(Const.DETAIL_CONTENT); if (table.equals(editorTable)) { refreshCurrentPlaylist(); } } } catch (Exception e) { Log.error(e); } finally { editorTable.setAcceptColumnsEvents(true); } } }); } /** * Refresh current playlist. DOCUMENT_ME */ private void refreshCurrentPlaylist() { if (plf == null) { // nothing ? leave return; } List files = null; // Try to get playlist content try { files = plf.getFiles(); // When nothing is selected, set default button state if (editorTable.getSelectionModel().getMinSelectionIndex() == -1) { setButtonState(); } editorModel.setItems(UtilFeatures.createStackItems(files, Conf .getBoolean(Const.CONF_STATE_REPEAT_ALL), true)); editorModel.populateModel(editorTable.getColumnsConf()); int[] rows = editorTable.getSelectedRows(); try { editorModel.setRefreshing(true); // Force table refreshing editorModel.fireTableDataChanged(); // Save selection for (int element : rows) { // set saved selection after a refresh editorTable.getSelectionModel().addSelectionInterval(element, element); } } finally { editorModel.setRefreshing(false); } // Refresh the preference menu according to the selection // (useful on rating change for a single-row model for ie) pjmFilesEditor.resetUI(editorTable.getSelection()); } catch (JajukException je) { Log.warn("Cannot parse playlist : " + plf.getAbsolutePath()); // Clear the model so we don't keep previous playlist tracks editorModel.clear(); } } /** * Select playlist. * * @param plf the playlist (smart or not) */ private void selectPlaylist(Playlist plf) { // remove selection editorTable.getSelectionModel().clearSelection(); PlaylistView.this.plf = plf; // set title label jlTitle.setText(plf.getName()); if (plf.getType() == Playlist.Type.BESTOF) { jlTitle.setIcon(IconLoader.getIcon(JajukIcons.BESTOF_16X16)); } else if (plf.getType() == Playlist.Type.BOOKMARK) { jlTitle.setIcon(IconLoader.getIcon(JajukIcons.PLAYLIST_BOOKMARK_SMALL)); } else if (plf.getType() == Playlist.Type.NEW) { jlTitle.setIcon(IconLoader.getIcon(JajukIcons.PLAYLIST_NEW_SMALL)); } else if (plf.getType() == Playlist.Type.NOVELTIES) { jlTitle.setIcon(IconLoader.getIcon(JajukIcons.NOVELTIES_16X16)); } else { // remove last smart playlist item border if (spSelected != null) { spSelected.getIcon().setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); spSelected = null; } jlTitle.setIcon(IconLoader.getIcon(JajukIcons.PLAYLIST_FILE)); } jlTitle.setToolTipText(plf.getName()); setButtonState(); refreshCurrentPlaylist(); updatePlaylistMenuItems(); UtilGUI.stopWaiting(); // stop waiting } /** * Update buttons state. */ private void setButtonState() { try { if (plf == null) { jbRun.setEnabled(false); jbClear.setEnabled(false); jbDown.setEnabled(false); jbAddShuffle.setEnabled(false); jbRemove.setEnabled(false); jbUp.setEnabled(false); jbSave.setEnabled(false); } else { if (plf.getType() == Playlist.Type.BESTOF || plf.getType() == Playlist.Type.NOVELTIES) { jbClear.setEnabled(false); jbDown.setEnabled(false); jbAddShuffle.setEnabled(false); jbRemove.setEnabled(false); jbUp.setEnabled(false); } else if (plf.getType() == Playlist.Type.BOOKMARK) { jbClear.setEnabled(true); jbDown.setEnabled(false); jbAddShuffle.setEnabled(false); jbRemove.setEnabled(false); jbUp.setEnabled(false); } else { jbClear.setEnabled(true); // set it to false just for startup because nothing is selected jbDown.setEnabled(false); // set it to false just for startup because nothing is selected jbUp.setEnabled(false); // add at the FIFO end by default even with no selection jbAddShuffle.setEnabled(true); // set it to false just for startup because nothing is selected jbRemove.setEnabled(false); } // Run button is available only if the playlist is not void jbRun.setEnabled(plf.isReady() && plf.getFiles().size() > 0); } } catch (Exception e) { Log.error(e); } } /* * (non-Javadoc) * * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent) */ @Override public void actionPerformed(ActionEvent ae) { try { if (ae.getSource() == jbRun) { plf.play(); } else if (ae.getSource() == jbSave) { // normal playlist if (plf.getType() == Playlist.Type.NORMAL) { try { plf.commit(); InformationJPanel.getInstance().setMessage( Messages.getString("AbstractPlaylistEditorView.22"), InformationJPanel.MessageType.INFORMATIVE); } catch (JajukException je) { Log.error(je); Messages.showErrorMessage(je.getCode()); } } else { // Save as for normal playlists new Thread("Playlist Action Thread") { @Override public void run() { UtilGUI.waiting(); try { // special playlist, same behavior than a save as plf.saveAs(); // If the new playlist is saved in a known device location, // force a // refresh to make it visible immediately (issue #1263) boolean known = false; Device knownDevice = null; for (Device device : DeviceManager.getInstance().getDevices()) { if (UtilSystem.isAncestor(device.getFio(), plf.getFIO())) { known = true; knownDevice = device; break; } } if (known) { Directory directory = DirectoryManager.getInstance().getDirectoryForIO( plf.getFIO().getParentFile(), knownDevice); directory.refresh(false); // Force a table refresh to show the new playlist if it has // been // saved in a known device ObservationManager.notify(new JajukEvent(JajukEvents.DEVICE_REFRESH)); } } catch (JajukException je) { Log.error(je); Messages.showErrorMessage(je.getCode()); } catch (Exception e) { Log.error(e); Messages.showErrorMessage(0, e.getMessage()); } finally { UtilGUI.stopWaiting(); } } }.start(); } } else if (ae.getSource() == jbClear) { // if it is the queue playlist, stop the selection plf.clear(); } else if (ae.getSource() == jbDown || ae.getSource() == jbUp || ae.getSource() == jmiFileDown || ae.getSource() == jmiFileUp) { int iRow = editorTable.getSelectedRow(); if (iRow != -1) { // -1 means nothing is selected if (ae.getSource() == jbDown || ae.getSource() == jmiFileDown) { plf.down(iRow); if (iRow < editorTable.getModel().getRowCount() - 1) { editorTable.getSelectionModel().setSelectionInterval(iRow + 1, iRow + 1); } } else if (ae.getSource() == jbUp || ae.getSource() == jmiFileUp) { plf.up(iRow); if (iRow > 0) { editorTable.getSelectionModel().setSelectionInterval(iRow - 1, iRow - 1); } } } } else if (ae.getSource() == jbRemove || ae.getSource() == jmiFileRemove) { removeSelection(); } else if (ae.getSource() == jbAddShuffle) { int iRow = editorTable.getSelectedRow(); if (iRow < 0 || iRow > editorTable.getRowCount()) { // no or invalid row is selected, add to the end iRow = editorTable.getRowCount(); } File file = FileManager.getInstance().getShuffleFile(); try { plf.addFile(iRow, file); jbRemove.setEnabled(true); } catch (JajukException je) { Messages.showErrorMessage(je.getCode()); Log.error(je); } } } catch (Exception e2) { Log.error(e2); } finally { // force immediate table refresh refreshCurrentPlaylist(); } } /** * Import files, used when drag / dropping for ie. * * @param files files to be imported * @param position DOCUMENT_ME */ public void importFiles(List files, int position) { plf.addFiles(UtilFeatures.applyPlayOption(files), position); refreshCurrentPlaylist(); } /** * Removes the selection. DOCUMENT_ME */ private void removeSelection() { int[] iRows = editorTable.getSelectedRows(); if (iRows.length > 1) {// if multiple selection, remove // selection editorTable.getSelectionModel().removeIndexInterval(0, editorTable.getRowCount() - 1); } for (int i = 0; i < iRows.length; i++) { // don't forget that index changes when removing plf.remove(iRows[i] - i); } // set selection to last line if end reached int iLastRow = editorTable.getRowCount() - 1; if (iRows[0] == editorTable.getRowCount()) { editorTable.getSelectionModel().setSelectionInterval(iLastRow, iLastRow); } } /** * Gets the current playlist. * * @return Returns current playlist */ public Playlist getCurrentPlaylist() { return plf; } /** * Called when table selection changed. * * @param e DOCUMENT_ME */ @Override public void valueChanged(ListSelectionEvent e) { ListSelectionModel selection = (ListSelectionModel) e.getSource(); if (!selection.isSelectionEmpty()) { updateSelection(); updateInformationView(selectedFiles); // Refresh the preference menu according to the selection pjmFilesEditor.resetUI(editorTable.getSelection()); // -- now analyze each button -- // Remove button // check for first row remove case : we can't remove currently // played track if (plf.getType() == Playlist.Type.BESTOF || plf.getType() == Playlist.Type.NOVELTIES) { // neither for bestof nor novelties playlist jbRemove.setEnabled(false); } else { jbRemove.setEnabled(true); } // Add shuffle button if (plf.getType() == Playlist.Type.BESTOF // neither for bestof playlist || plf.getType() == Playlist.Type.NOVELTIES || plf.getType() == Playlist.Type.BOOKMARK || selection.getMinSelectionIndex() != selection.getMaxSelectionIndex() // multiple selection not supported ) { jbAddShuffle.setEnabled(false); } else { jbAddShuffle.setEnabled(true); } // Up button if (selection.getMinSelectionIndex() != selection.getMaxSelectionIndex() // check if several rows have been selected : // doesn't supported yet || plf.getType() == Playlist.Type.BESTOF || plf.getType() == Playlist.Type.NOVELTIES || plf.getType() == Playlist.Type.BOOKMARK) { // neither for bestof nor novelties playlist jbUp.setEnabled(false); } else { // still here ? if (selection.getMinSelectionIndex() == 0) { // check if we selected second track just after current // tracks jbUp.setEnabled(false); // already at the top } else { jbUp.setEnabled(true); } } // Down button if (selection.getMinSelectionIndex() != selection.getMaxSelectionIndex() // check if several rows have been selected : // doesn't supported yet || plf.getType() == Playlist.Type.BESTOF || plf.getType() == Playlist.Type.NOVELTIES || plf.getType() == Playlist.Type.BOOKMARK) { jbDown.setEnabled(false); } else { // yet here ? if (selection.getMaxSelectionIndex() < editorModel.getItems().size() - 1) { // a normal item can't go in the planned items jbDown.setEnabled(true); } else { jbDown.setEnabled(false); } } } } /** * Update the Information View with selection size. * * @param files : selection to consider */ void updateInformationView(List files) { // Update information view // Compute recursive selection size, nb of items... long lSize = 0l; for (File file : files) { lSize += file.getSize(); } lSize /= 1048576; // set size in MB StringBuilder sbOut = new StringBuilder().append(files.size()).append( Messages.getString("FilesTreeView.52")); if (lSize > 1024) { // more than 1024 MB -> in GB sbOut.append(lSize / 1024).append('.').append(lSize % 1024).append( Messages.getString("FilesTreeView.53")); } else { sbOut.append(lSize).append(Messages.getString("FilesTreeView.54")); } InformationJPanel.getInstance().setSelection(sbOut.toString()); } /** * Update editor files selection. */ void updateSelection() { selectedFiles.clear(); for (Item item : editorTable.getSelection()) { File file = (File) item; selectedFiles.add(file); } } /** * Disables some tracks menu items if in smart playlist. */ private void updatePlaylistMenuItems() { final boolean isReadOnly = (plf.getType() == Playlist.Type.BESTOF || plf.getType() == Playlist.Type.NOVELTIES || plf.getType() == Playlist.Type.BOOKMARK); jmiFileDown.setEnabled(!isReadOnly); jmiFileUp.setEnabled(!isReadOnly); jmiFileRemove.setEnabled(!isReadOnly); } /** * This class is not a view but the playlist upper panel of the PlaylistView * It leverages the Abstract Playlist code (filters...) */ class PlaylistRepository extends AbstractTableView implements TwoStepsDisplayable { /** Generated serialVersionUID. */ private static final long serialVersionUID = 3842568503545896845L; /** DOCUMENT_ME. */ JMenuItem jmiRepositorySaveAs; /** DOCUMENT_ME. */ JMenuItem jmiPrepareParty; /** List of playlists for which we already displayed a warning message if it contains old or external entries. */ private final List alreadyWarned = new ArrayList(10); /** * Instantiates a new playlist repository. */ public PlaylistRepository() { super(); columnsConf = CONF_PLAYLIST_REPOSITORY_COLUMNS; } /* * (non-Javadoc) * * @see org.jajuk.ui.views.AbstractTableView#initTable() */ @Override void initTable() { // required by abstract superclass, but nothing to do here... } /* * (non-Javadoc) * * @see org.jajuk.ui.views.AbstractTableView#populateTable() */ @Override JajukTableModel populateTable() { return new PlaylistRepositoryTableModel(); } /* * (non-Javadoc) * * @see org.jajuk.ui.views.IView#getDesc() */ @Override public String getDesc() { return null; } /** * Override this method to make sure to provide a non-null view ID when * required. * * @return the ID */ @Override public String getID() { return PlaylistView.this.getID() + "/PlaylistRepository"; } /* * (non-Javadoc) * * @see org.jajuk.ui.views.IView#initUI() */ @Override public void initUI() { UtilGUI.populate(this); } /* * (non-Javadoc) * * @see org.jajuk.ui.helpers.TwoStepsDisplayable#shortCall(java.lang.Object) */ @Override public void shortCall(Object in) { jtable = new JajukTable(model, true, columnsConf); super.shortCall(null); jmiRepositorySaveAs = new JMenuItem(ActionManager.getAction(JajukActions.SAVE_AS)); jmiRepositorySaveAs.putClientProperty(Const.DETAIL_SELECTION, jtable.getSelection()); jmiPrepareParty = new JMenuItem(ActionManager.getAction(JajukActions.PREPARE_PARTY)); jmiPrepareParty.putClientProperty(Const.DETAIL_SELECTION, jtable.getSelection()); pjmTracks = new PreferencesJMenu(jtable.getSelection()); jtable.getMenu().add(jmiPrepareParty); jtable.getMenu().add(jmiRepositorySaveAs); jtable.getMenu().addSeparator(); jtable.getMenu().add(pjmTracks); jtable.getMenu().addSeparator(); // Add this generic menu item manually to ensure it's the last one in // the list for GUI reasons jtable.getMenu().add(jmiProperties); jtbEditable.setVisible(false); jtbSync.setVisible(false); // Select "New" playlist as default selectSmartPlaylist(spNew); } /* * (non-Javadoc) * * @see org.jajuk.ui.helpers.TwoStepsDisplayable#longCall() */ @Override public Object longCall() { super.longCall(); return null; } /* (non-Javadoc) * @see org.jajuk.ui.views.AbstractTableView#onSelectionChange() */ @Override void onSelectionChange() { Playlist playlist = null; List files = null; try { int selectedRow = jtable.getSelectedRow(); if (selectedRow < 0) { return; } int row = jtable.convertRowIndexToModel(selectedRow); JajukTableModel model = (JajukTableModel) jtable.getModel(); playlist = (Playlist) model.getItemAt(row); // load the playlist files = playlist.getFiles(); if (!alreadyWarned.contains(playlist) && playlist.containsExtFiles()) { Messages.showWarningMessage(Messages.getErrorMessage(142)); alreadyWarned.add(playlist); } } catch (JajukException e1) { // Display a warning if the playlist is not parsable but still select it Log.warn("Cannot parse playlist : " + plf.getAbsolutePath()); } // Select the playlist even if it cannot be read (we still have some titles) selectPlaylist(playlist); if (files != null) { updateInformationView(files); } else { // Reset selection tip InformationJPanel.getInstance().setSelection(Messages.getString("InformationJPanel.9")); } } } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/views/TracksTreeView.java0000644000175000017500000011110611720500104025322 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.views; import java.awt.Component; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseEvent; import java.util.ArrayList; import java.util.Collections; import java.util.Date; import java.util.Enumeration; import java.util.List; import java.util.Properties; import javax.swing.Action; import javax.swing.BorderFactory; import javax.swing.JComboBox; import javax.swing.JLabel; import javax.swing.JMenuItem; import javax.swing.JPopupMenu; import javax.swing.JScrollPane; import javax.swing.JTree; import javax.swing.SwingUtilities; import javax.swing.SwingWorker; import javax.swing.event.TreeExpansionEvent; import javax.swing.event.TreeExpansionListener; import javax.swing.event.TreeSelectionEvent; import javax.swing.event.TreeSelectionListener; import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.DefaultTreeModel; import javax.swing.tree.TreePath; import net.miginfocom.swing.MigLayout; import org.jajuk.base.Album; import org.jajuk.base.Artist; import org.jajuk.base.File; import org.jajuk.base.Genre; import org.jajuk.base.Item; import org.jajuk.base.Track; import org.jajuk.base.TrackComparator.TrackComparatorType; import org.jajuk.base.TrackManager; import org.jajuk.base.Year; import org.jajuk.events.JajukEvent; import org.jajuk.events.JajukEvents; import org.jajuk.events.ObservationManager; import org.jajuk.services.players.QueueModel; import org.jajuk.services.players.StackItem; import org.jajuk.ui.actions.ActionManager; import org.jajuk.ui.actions.JajukActions; import org.jajuk.ui.helpers.FontManager; import org.jajuk.ui.helpers.FontManager.JajukFont; import org.jajuk.ui.helpers.JajukMouseAdapter; import org.jajuk.ui.helpers.TreeRootElement; import org.jajuk.ui.helpers.TreeTransferHandler; import org.jajuk.ui.perspectives.PerspectiveManager; import org.jajuk.ui.widgets.InformationJPanel; import org.jajuk.util.Conf; import org.jajuk.util.Const; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; import org.jajuk.util.UtilGUI; import org.jajuk.util.error.JajukException; import org.jajuk.util.log.Log; import org.jvnet.substance.api.renderers.SubstanceDefaultTreeCellRenderer; /** * Logical tree view. */ public class TracksTreeView extends AbstractTreeView implements ActionListener { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** Sorting method selection combo. */ private JComboBox jcbSort; /* * (non-Javadoc) * * @see org.jajuk.ui.IView#getDesc() */ @Override public String getDesc() { return Messages.getString("TracksTreeView.0"); } /** * Constructor. */ public TracksTreeView() { super(); } /* * (non-Javadoc) * * @see org.jajuk.ui.IView#display() */ @Override public void initUI() { super.initUI(); // ComboBox sort JLabel jlSort = new JLabel(Messages.getString("Sort")); jcbSort = new JComboBox(); jcbSort.addItem(Messages.getHumanPropertyName(Const.XML_GENRE)); // sort by // Genre/Artist/Album jcbSort.addItem(Messages.getHumanPropertyName(Const.XML_ARTIST)); // sort by // Artist/Album jcbSort.addItem(Messages.getHumanPropertyName(Const.XML_ALBUM)); // sort by Album jcbSort.addItem(Messages.getHumanPropertyName(Const.XML_YEAR)); // sort by Year jcbSort.addItem(Messages.getString("TracksTreeView.35")); // sort by // Discovery Date jcbSort.addItem(Messages.getHumanPropertyName(Const.XML_TRACK_RATE)); // sort by rate jcbSort.addItem(Messages.getHumanPropertyName(Const.XML_TRACK_HITS)); // sort by hits // Load stored index, reset to index 0 in case of out of bounds (can happen after a version // upgrade) if (Conf.getInt(Const.CONF_LOGICAL_TREE_SORT_ORDER) >= jcbSort.getItemCount()) { Conf.setProperty(Const.CONF_LOGICAL_TREE_SORT_ORDER, "0"); } jcbSort.setSelectedIndex(Conf.getInt(Const.CONF_LOGICAL_TREE_SORT_ORDER)); jcbSort.setActionCommand(JajukEvents.LOGICAL_TREE_SORT.toString()); jcbSort.addActionListener(this); // Album details final JMenuItem jmiShowAlbumDetails = new JMenuItem( ActionManager.getAction(JajukActions.SHOW_ALBUM_DETAILS)); jmiShowAlbumDetails.putClientProperty(Const.DETAIL_SELECTION, alSelected); top = new TreeRootElement(Messages.getString("TracksTreeView.27")); // Register on the list for subject we are interested in ObservationManager.register(this); // populate the tree populateTree(); // create tree createTree(false); jtree.setCellRenderer(new TracksTreeCellRenderer()); /** * CAUTION ! we register several listeners against this tree Swing can't * ensure the order where listeners will treat them so don't rely on the * mouse listener to get correct selection from selection listener */ // Tree selection listener to detect a selection jtree.addTreeSelectionListener(new TracksTreeSelectionListener()); // Listen for double click jtree.addMouseListener(new TracksMouseAdapter(jmiShowAlbumDetails)); // Expansion analyze to keep expended state jtree.addTreeExpansionListener(new TracksTreeExpansionListener()); jtree.setAutoscrolls(true); // DND support jtree.setTransferHandler(new TreeTransferHandler(jtree)); jtree.setDragEnabled(true); jspTree = new JScrollPane(jtree); jspTree.setBorder(BorderFactory.createEmptyBorder(0, 1, 0, 0)); setLayout(new MigLayout("ins 3", "[][grow][][]", "[][grow]")); add(jlSort, "left,gapx 5::"); add(jcbSort, "grow,left"); add(jtbSync, "right"); add(jbCollapseAll, "right,wrap"); add(jspTree, "grow,span"); expand(); } /** * Fill the tree. */ @Override public void populateTree() { // Use a refreshing flag, not a 'synchronized' here (see deadlock, bug #1756 (Deadlock in AbstractTreeView and PerspectiveManager) if (refreshing) { Log.debug("Tree view already refreshing. Leaving."); return; } try { refreshing = true; // delete previous tree top.removeAllChildren(); // see http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6472844 for a // small memory leak that is caused here... if (jtree != null && jtree.getModel() != null) { ((DefaultTreeModel) (jtree.getModel())).reload(); } TrackComparatorType comparatorType = TrackComparatorType.values()[Conf .getInt(Const.CONF_LOGICAL_TREE_SORT_ORDER)]; if (comparatorType == TrackComparatorType.GENRE_ARTIST_ALBUM) { populateTreeByGenre(); }// Artist/album else if (comparatorType == TrackComparatorType.ARTIST_ALBUM) { populateTreeByArtist(); } // Album else if (comparatorType == TrackComparatorType.ALBUM) { populateTreeByAlbum(); } // Year / album else if (comparatorType == TrackComparatorType.YEAR_ALBUM) { populateTreeByYear(); } // discovery date / album else if (comparatorType == TrackComparatorType.DISCOVERY_ALBUM) { populateTreeByDiscovery(); } // Rate / album else if (comparatorType == TrackComparatorType.RATE_ALBUM) { populateTreeByRate(); } // Hits / album else if (comparatorType == TrackComparatorType.HITS_ALBUM) { populateTreeByHits(); } } finally { refreshing = false; } } /** * Fill the tree by genre. */ @SuppressWarnings("unchecked") public void populateTreeByGenre() { List tracks = TrackManager.getInstance().getTracks(); Collections.sort(tracks, TrackManager.getInstance().getComparator()); for (Track track : tracks) { if (!track.shouldBeHidden()) { GenreNode genreNode = null; Genre genre = track.getGenre(); ArtistNode artistNode = null; Artist artist = track.getArtist(); AlbumNode albumNode = null; Album album = track.getAlbum(); // create genre Enumeration e = top.children(); boolean b = false; while (e.hasMoreElements()) { // check the genre doesn't // already exist GenreNode sn = (GenreNode) e.nextElement(); if (sn.getGenre().equals(genre)) { b = true; genreNode = sn; break; } } if (!b) { genreNode = new GenreNode(genre); top.add(genreNode); } // create artist if (genreNode != null) { e = genreNode.children(); } else { continue; } b = false; while (e.hasMoreElements()) { // check if the artist doesn't // already exist ArtistNode an = (ArtistNode) e.nextElement(); if (an.getArtist().equals(artist)) { b = true; artistNode = an; break; } } if (!b) { artistNode = new ArtistNode(artist); genreNode.add(artistNode); } // create album if (artistNode != null) { e = artistNode.children(); } else { continue; } b = false; while (e.hasMoreElements()) { AlbumNode an = (AlbumNode) e.nextElement(); if (an.getAlbum().equals(album)) { b = true; albumNode = an; break; } } if (!b) { albumNode = new AlbumNode(album); artistNode.add(albumNode); } // create track assert albumNode != null; albumNode.add(new TrackNode(track)); } } } /** * Fill the tree by artist. */ @SuppressWarnings("unchecked") public void populateTreeByArtist() { List tracks = TrackManager.getInstance().getTracks(); Collections.sort(tracks, TrackManager.getInstance().getComparator()); for (Track track : tracks) { if (!track.shouldBeHidden()) { ArtistNode artistNode = null; Artist artist = track.getArtist(); AlbumNode albumNode = null; Album album = track.getAlbum(); // create artist Enumeration e = top.children(); boolean b = false; while (e.hasMoreElements()) { // check if the artist doesn't // already exist ArtistNode an = (ArtistNode) e.nextElement(); if (an.getArtist().equals(artist)) { b = true; artistNode = an; break; } } if (!b) { artistNode = new ArtistNode(artist); top.add(artistNode); } // create album if (artistNode != null) { e = artistNode.children(); } else { continue; } b = false; while (e.hasMoreElements()) { // check if the album doesn't // already exist AlbumNode an = (AlbumNode) e.nextElement(); if (an.getAlbum().equals(album)) { b = true; albumNode = an; break; } } if (!b) { albumNode = new AlbumNode(album); artistNode.add(albumNode); } // create track if (albumNode != null) { albumNode.add(new TrackNode(track)); } } } } /** * Fill the tree by year. */ @SuppressWarnings("unchecked") public void populateTreeByYear() { List tracks = TrackManager.getInstance().getTracks(); Collections.sort(tracks, TrackManager.getInstance().getComparator()); for (Track track : tracks) { if (!track.shouldBeHidden()) { YearNode yearNode = null; AlbumNode albumNode = null; Album album = track.getAlbum(); Year year = track.getYear(); // create Year Enumeration e = top.children(); boolean b = false; // check if the artist doesn't already exist while (e.hasMoreElements()) { YearNode yn = (YearNode) e.nextElement(); if (yn.getYear().equals(year)) { b = true; yearNode = yn; break; } } if (!b) { yearNode = new YearNode(year); top.add(yearNode); } // create album if (yearNode != null) { e = yearNode.children(); } else { continue; } b = false; while (e.hasMoreElements()) { // check if the album doesn't // already exist AlbumNode an = (AlbumNode) e.nextElement(); if (an.getAlbum().equals(album)) { b = true; albumNode = an; break; } } if (!b) { albumNode = new AlbumNode(album); yearNode.add(albumNode); } // create track if (albumNode != null) { albumNode.add(new TrackNode(track)); } } } } /** * Fill the tree. */ public void populateTreeByAlbum() { List tracks = TrackManager.getInstance().getTracks(); Collections.sort(tracks, TrackManager.getInstance().getComparator()); for (Track track : tracks) { if (!track.shouldBeHidden()) { addTrackAndAlbum(top, track); } } } /** * Fill the tree by discovery. */ public void populateTreeByDiscovery() { List tracks = TrackManager.getInstance().getTracks(); Collections.sort(tracks, TrackManager.getInstance().getComparator()); // Create separator nodes DefaultMutableTreeNode nodeWeekly = new DiscoveryDateNode( Messages.getString("TracksTreeView.36")); DefaultMutableTreeNode nodeMontly = new DiscoveryDateNode( Messages.getString("TracksTreeView.37")); DefaultMutableTreeNode nodeThreeMontly = new DiscoveryDateNode( Messages.getString("TracksTreeView.44")); DefaultMutableTreeNode nodeSixMontly = new DiscoveryDateNode( Messages.getString("TracksTreeView.38")); DefaultMutableTreeNode nodeYearly = new DiscoveryDateNode( Messages.getString("TracksTreeView.40")); DefaultMutableTreeNode nodeTwoYearly = new DiscoveryDateNode( Messages.getString("TracksTreeView.41")); DefaultMutableTreeNode nodeFiveYearly = new DiscoveryDateNode( Messages.getString("TracksTreeView.42")); DefaultMutableTreeNode nodeTenYearly = new DiscoveryDateNode( Messages.getString("TracksTreeView.43")); DefaultMutableTreeNode nodeOlder = new DiscoveryDateNode( Messages.getString("TracksTreeView.39")); // Add separator nodes top.add(nodeWeekly); top.add(nodeMontly); top.add(nodeThreeMontly); top.add(nodeSixMontly); top.add(nodeYearly); top.add(nodeTwoYearly); top.add(nodeFiveYearly); top.add(nodeTenYearly); top.add(nodeOlder); Date today = new Date(); // Sort tracks into these categories for (Track track : tracks) { if (track.shouldBeHidden()) { continue; } // less than one week ? long diff = today.getTime() - track.getDiscoveryDate().getTime(); if (diff < 604800000l) { addTrackAndAlbum(nodeWeekly, track); } else if (diff < 2628000000l) { addTrackAndAlbum(nodeMontly, track); } else if (diff < 7884000000l) { addTrackAndAlbum(nodeThreeMontly, track); } else if (diff < 15768000000l) { addTrackAndAlbum(nodeSixMontly, track); } else if (diff < 31536000000l) { addTrackAndAlbum(nodeYearly, track); } else if (diff < 63072000000l) { addTrackAndAlbum(nodeTwoYearly, track); } else if (diff < 157680000000l) { addTrackAndAlbum(nodeFiveYearly, track); } else if (diff < 315360000000l) { addTrackAndAlbum(nodeTenYearly, track); } else { addTrackAndAlbum(nodeOlder, track); } } } /** * Fill the tree by Rate. */ public void populateTreeByRate() { List tracks = TrackManager.getInstance().getTracks(); Collections.sort(tracks, TrackManager.getInstance().getComparator()); for (Track track : tracks) { if (!track.shouldBeHidden()) { addTrackAndAlbum(top, track); } } } /** * Fill the tree by Hits. */ public void populateTreeByHits() { List tracks = TrackManager.getInstance().getTracks(); Collections.sort(tracks, TrackManager.getInstance().getComparator()); for (Track track : tracks) { if (!track.shouldBeHidden()) { addTrackAndAlbum(top, track); } } } /** * Utility method used by populateByDiscovery method. * * @param node DOCUMENT_ME * @param track DOCUMENT_ME */ @SuppressWarnings("unchecked") private void addTrackAndAlbum(DefaultMutableTreeNode node, Track track) { boolean bAlbumExists = false; AlbumNode currentAlbum = null; Enumeration e = node.children(); while (e.hasMoreElements()) { AlbumNode an = e.nextElement(); if (an.getAlbum().equals(track.getAlbum())) { bAlbumExists = true; currentAlbum = an; break; } } if (!bAlbumExists) { currentAlbum = new AlbumNode(track.getAlbum()); node.add(currentAlbum); } // create track if (currentAlbum != null) { currentAlbum.add(new TrackNode(track)); } } /* * (non-Javadoc) * * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent) */ @Override public void actionPerformed(final ActionEvent e) { if (e.getSource() == jcbSort) { UtilGUI.waiting(); SwingWorker sw = new SwingWorker() { @Override public Void doInBackground() { // Set comparator Conf.setProperty(Const.CONF_LOGICAL_TREE_SORT_ORDER, Integer.toString(jcbSort.getSelectedIndex())); populateTree(); return null; } @Override public void done() { SwingUtilities.updateComponentTreeUI(jtree); UtilGUI.stopWaiting(); } }; sw.execute(); } } /** * Manages auto-expand. */ @Override void expand() { // expand all for (int i = 0; i < jtree.getRowCount(); i++) { boolean bExp = false; Object o = jtree.getPathForRow(i).getLastPathComponent(); if (o instanceof GenreNode) { Genre genre = ((GenreNode) o).getGenre(); bExp = genre.getBooleanValue(Const.XML_EXPANDED); } else if (o instanceof ArtistNode) { Artist artist = ((ArtistNode) o).getArtist(); bExp = artist.getBooleanValue(Const.XML_EXPANDED); } else if (o instanceof AlbumNode) { Album album = ((AlbumNode) o).getAlbum(); bExp = album.getBooleanValue(Const.XML_EXPANDED); } else if (o instanceof YearNode) { Year year = ((YearNode) o).getYear(); bExp = year.getBooleanValue(Const.XML_EXPANDED); } // now expand row if it should be expanded if (bExp) { jtree.expandRow(i); } } } // needs to be inner class as it accesses various members /** * DOCUMENT_ME. */ class TracksTreeSelectionListener implements TreeSelectionListener { /* * (non-Javadoc) * * @see javax.swing.event.TreeSelectionListener#valueChanged(javax.swing.event * .TreeSelectionEvent) */ @Override public void valueChanged(TreeSelectionEvent e) { TreePath[] tpSelected = jtree.getSelectionModel().getSelectionPaths(); if (tpSelected == null) { return; } // get all components recursively alSelected.clear(); selectedRecursively.clear(); int items = handleSelected(tpSelected); StringBuilder sbOut = new StringBuilder().append(items).append( Messages.getString("TracksTreeView.31")); InformationJPanel.getInstance().setSelection(sbOut.toString()); // Notify the tree selection change (used by tree/table sync) if (!bInternalAction) { Properties properties = new Properties(); properties.put(Const.DETAIL_SELECTION, selectedRecursively); properties .put(Const.DETAIL_PERSPECTIVE, PerspectiveManager.getCurrentPerspective().getID()); properties.put(Const.DETAIL_VIEW, getID()); ObservationManager.notify(new JajukEvent(JajukEvents.TREE_SELECTION_CHANGED, properties)); } // Update preference menu pjmTracks.resetUI(alSelected); } /** * Handle selected. * * @param tpSelected DOCUMENT_ME * * @return the int */ @SuppressWarnings("unchecked") private int handleSelected(TreePath[] tpSelected) { int items = 0; for (TreePath element : tpSelected) { Object o = element.getLastPathComponent(); if (o instanceof TreeRootElement) { // collection node items = TrackManager.getInstance().getElementCount(); List allTracks = TrackManager.getInstance().getTracks(); selectedRecursively.addAll(allTracks); break; } else { Object userObject = ((DefaultMutableTreeNode) o).getUserObject(); if (userObject instanceof Item) { alSelected.add((Item) userObject); } } // return all child nodes recursively Enumeration e2 = ((DefaultMutableTreeNode) o) .depthFirstEnumeration(); while (e2.hasMoreElements()) { DefaultMutableTreeNode node = e2.nextElement(); if (node instanceof TrackNode) { Track track = ((TrackNode) node).getTrack(); // don't count the same track several time // if user select directory and then tracks // inside selectedRecursively.add(track); items++; } } } return items; } } /** * Tracks Tree view mouse adapter. */ class TracksMouseAdapter extends JajukMouseAdapter { /** DOCUMENT_ME. */ private final JMenuItem jmiShowAlbumDetails; /** * Instantiates a new tracks mouse adapter. * * @param jmiShowAlbumDetails DOCUMENT_ME */ public TracksMouseAdapter(JMenuItem jmiShowAlbumDetails) { super(); this.jmiShowAlbumDetails = jmiShowAlbumDetails; } /* (non-Javadoc) * @see org.jajuk.ui.helpers.JajukMouseAdapter#handleActionSeveralClicks(java.awt.event.MouseEvent) */ @Override public void handleActionSeveralClicks(final MouseEvent e) { TreePath path = jtree.getPathForLocation(e.getX(), e.getY()); if (path != null) { Object o = path.getLastPathComponent(); if (o instanceof TrackNode) { Track track = ((TrackNode) o).getTrack(); File file = track.getBestFile(false); if (file != null) { try { QueueModel.push(new StackItem(file, Conf.getBoolean(Const.CONF_STATE_REPEAT_ALL), true), Conf.getBoolean(Const.CONF_OPTIONS_PUSH_ON_CLICK)); } catch (JajukException je) { Log.error(je); } } else { Messages.showErrorMessage(10, track.getName()); } } } } /* (non-Javadoc) * @see org.jajuk.ui.helpers.JajukMouseAdapter#handlePopup(java.awt.event.MouseEvent) */ @Override public void handlePopup(final MouseEvent e) { TreePath path = jtree.getPathForLocation(e.getX(), e.getY()); if (path == null) { return; } // right click on a selected node set right click behavior // identical to konqueror tree: // if none or 1 node is selected, a right click on // another node select it. if more than 1, we keep selection and // display a popup for them if (jtree.getSelectionCount() < 2) { jtree.getSelectionModel().setSelectionPath(path); } paths = jtree.getSelectionModel().getSelectionPaths(); // test mix between types ( not allowed ) String sClass = paths[0].getLastPathComponent().getClass().toString(); for (int i = 0; i < paths.length; i++) { if (!paths[i].getLastPathComponent().getClass().toString().equals(sClass)) { return; } } // display menus according node type buildMenu(e); } /** * Builds the menu. * * @param e DOCUMENT_ME */ private void buildMenu(final MouseEvent e) { if (paths[0].getLastPathComponent() instanceof TrackNode) { jmenu = new JPopupMenu(); jmenu.add(jmiPlay); jmenu.add(jmiFrontPush); jmenu.add(jmiPush); jmenu.addSeparator(); jmenu.add(jmiDelete); jmenu.addSeparator(); jmenu.add(pjmTracks); jmenu.add(jmiAddFavorite); jmenu.addSeparator(); jmenu.add(jmiProperties); jmenu.show(jtree, e.getX(), e.getY()); } else if (paths[0].getLastPathComponent() instanceof AlbumNode) { jmenu = new JPopupMenu(); jmenu.add(jmiPlay); jmenu.add(jmiFrontPush); jmenu.add(jmiPush); jmenu.add(jmiPlayShuffle); jmenu.add(jmiPlayRepeat); jmenu.addSeparator(); jmenu.add(jmiDelete); jmenu.addSeparator(); jmenu.add(jmiCDDBWizard); jmenu.add(jmiReport); jmenu.add(jmiShowAlbumDetails); jmenu.addSeparator(); jmenu.add(jmiAddFavorite); jmenu.add(pjmTracks); jmenu.addSeparator(); jmenu.add(jmiProperties); jmenu.show(jtree, e.getX(), e.getY()); } else if (paths[0].getLastPathComponent() instanceof ArtistNode) { jmenu = new JPopupMenu(); jmenu.add(jmiPlay); jmenu.add(jmiFrontPush); jmenu.add(jmiPush); jmenu.add(jmiPlayShuffle); jmenu.add(jmiPlayRepeat); jmenu.addSeparator(); jmenu.add(jmiDelete); jmenu.addSeparator(); jmenu.add(jmiReport); jmenu.addSeparator(); jmenu.add(pjmTracks); jmenu.addSeparator(); jmenu.add(jmiProperties); jmenu.show(jtree, e.getX(), e.getY()); } else if (paths[0].getLastPathComponent() instanceof GenreNode) { jmenu = new JPopupMenu(); jmenu.add(jmiPlay); jmenu.add(jmiFrontPush); jmenu.add(jmiPush); jmenu.add(jmiPlayShuffle); jmenu.add(jmiPlayRepeat); jmenu.addSeparator(); jmenu.add(jmiDelete); jmenu.addSeparator(); jmenu.add(jmiReport); jmenu.addSeparator(); jmenu.add(pjmTracks); jmenu.addSeparator(); jmenu.add(jmiProperties); jmenu.show(jtree, e.getX(), e.getY()); } else if (paths[0].getLastPathComponent() instanceof YearNode) { jmenu = new JPopupMenu(); jmenu.add(jmiPlay); jmenu.add(jmiFrontPush); jmenu.add(jmiPush); jmenu.add(jmiPlayShuffle); jmenu.add(jmiPlayRepeat); jmenu.addSeparator(); jmenu.add(pjmTracks); jmenu.addSeparator(); jmenu.add(jmiProperties); jmenu.show(jtree, e.getX(), e.getY()); } else if (paths[0].getLastPathComponent() instanceof DefaultMutableTreeNode) { // Collection menu JPopupMenu jmenuCollection = new JPopupMenu(); // Collection Report Action actionReportCollection = ActionManager.getAction(JajukActions.CREATE_REPORT); JMenuItem jmiCollectionReport = new JMenuItem(actionReportCollection); // Add custom data to this component in order to allow the ReportAction // to be able to get it jmiCollectionReport.putClientProperty(Const.DETAIL_ORIGIN, COLLECTION_LOGICAL); jmenuCollection.add(jmiCollectionReport); // Find duplicate files Action actionDuplicateFiles = ActionManager.getAction(JajukActions.FIND_DUPLICATE_FILES); JMenuItem jmiCollectionDuplicateFiles = new JMenuItem(actionDuplicateFiles); jmenuCollection.add(jmiCollectionDuplicateFiles); jmenuCollection.show(jtree, e.getX(), e.getY()); } } } /* * (non-Javadoc) * * @see org.jajuk.ui.views.AbstractTreeView#scrollTo(org.jajuk.base.Item) */ @Override void scrollTo(Item item) { // Set manual change because we force here tree selection and // we don't want to force table views to synchronize bInternalAction = true; try { // Clear selection so we only select new synchronized item jtree.getSelectionModel().clearSelection(); // make sure the main element is expanded jtree.expandRow(0); Track track = null; // received item is a file when the event comes from a queue view in the // track perspective if (item instanceof File) { track = ((File) item).getTrack(); } else { track = (Track) item; } for (int i = 0; i < jtree.getRowCount(); i++) { Object o = jtree.getPathForRow(i).getLastPathComponent(); if (o instanceof AlbumNode) { Album testedAlbum = ((AlbumNode) o).getAlbum(); if (track.getAlbum().equals(testedAlbum)) { jtree.expandRow(i); jtree.scrollPathToVisible(jtree.getPathForRow(i)); } } else if (o instanceof ArtistNode) { Artist testedArtist = ((ArtistNode) o).getArtist(); if (track.getArtist().equals(testedArtist)) { jtree.expandRow(i); jtree.scrollPathToVisible(jtree.getPathForRow(i)); } } else if (o instanceof GenreNode) { Genre testedGenre = ((GenreNode) o).getGenre(); if (track.getGenre().equals(testedGenre)) { jtree.expandRow(i); jtree.scrollPathToVisible(jtree.getPathForRow(i)); } } else if (o instanceof YearNode) { Year testedYear = ((YearNode) o).getYear(); if (track.getYear().equals(testedYear)) { jtree.expandRow(i); jtree.scrollPathToVisible(jtree.getPathForRow(i)); } } else if (o instanceof TrackNode) { Track tested = ((TrackNode) o).getTrack(); // == here thanks to .intern optimization if (tested.getID() == track.getID()) { jtree.expandRow(i); jtree.scrollPathToVisible(jtree.getPathForRow(i)); jtree.getSelectionModel().addSelectionPath(jtree.getPathForRow(i)); } } } } finally { bInternalAction = false; } } } /** * Genre node */ class GenreNode extends DefaultMutableTreeNode { private static final long serialVersionUID = 1L; /** * Constructor * * @param track */ public GenreNode(Genre track) { super(track); } /** * return a string representation of this track node */ @Override public String toString() { return getGenre().getName2(); } /** * @return Returns the track. */ public Genre getGenre() { return (Genre) super.getUserObject(); } } /** * Artist node */ class ArtistNode extends DefaultMutableTreeNode { /** * */ private static final long serialVersionUID = 1L; /** * Constructor * * @param artist */ public ArtistNode(Artist artist) { super(artist); } /** * return a string representation of this artist node */ @Override public String toString() { return getArtist().getName2(); } /** * @return Returns the artist. */ public Artist getArtist() { return (Artist) super.getUserObject(); } } /** * Year node */ class YearNode extends DefaultMutableTreeNode { /** * */ private static final long serialVersionUID = 1L; /** * Constructor * * @param artist */ public YearNode(Year year) { super(year); } /** * return a string representation of this node */ @Override public String toString() { if (getYear().getValue() > 0) { return getYear().getName(); } else { return Messages.getString("unknown_year"); } } /** * @return Returns the year. */ public Year getYear() { return (Year) super.getUserObject(); } } /** * Album node */ class AlbumNode extends DefaultMutableTreeNode { private static final long serialVersionUID = 1L; /** * Constructor * * @param album */ public AlbumNode(Album album) { super(album); } /** * return a string representation of this album node */ @Override public String toString() { return getAlbum().getName2(); } /** * @return Returns the album. */ public Album getAlbum() { return (Album) super.getUserObject(); } } /** * Track node */ class TrackNode extends DefaultMutableTreeNode { private static final long serialVersionUID = 1L; /** * Constructor * * @param track */ public TrackNode(Track track) { super(track); } /** * return a string representation of this track node */ @Override public String toString() { return getTrack().getName(); } /** * @return Returns the track. */ public Track getTrack() { return (Track) super.getUserObject(); } } /** * * Discovery date filter tree node */ class DiscoveryDateNode extends DefaultMutableTreeNode { /** * @param string */ public DiscoveryDateNode(String string) { super(string); } /** * We have to override this method for drag and drop * whish waits for an item. A period is not an item. * * @see DefaultMutableTreeNode.getUserObject() */ @SuppressWarnings("unchecked") @Override public Object getUserObject() { List out = new ArrayList(10); Enumeration childrens = children(); while (childrens.hasMoreElements()) { DefaultMutableTreeNode node = childrens.nextElement(); out.add((Item) node.getUserObject()); } return out; } private static final long serialVersionUID = 7123195836014138019L; } class TracksTreeCellRenderer extends SubstanceDefaultTreeCellRenderer { private static final long serialVersionUID = 1L; @Override public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean expanded, boolean leaf, int row, boolean hasFocus) { super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus); setFont(FontManager.getInstance().getFont(JajukFont.PLAIN)); if (value instanceof GenreNode) { setIcon(IconLoader.getIcon(JajukIcons.GENRE)); } else if (value instanceof ArtistNode) { setIcon(IconLoader.getIcon(JajukIcons.ARTIST)); } else if (value instanceof YearNode) { setIcon(IconLoader.getIcon(JajukIcons.YEAR)); } else if (value instanceof AlbumNode) { setIcon(IconLoader.getIcon(JajukIcons.ALBUM)); } else if (value instanceof TrackNode) { setIcon(IconLoader.getIcon(JajukIcons.TRACK)); // Discovery date filter } else if (value instanceof DiscoveryDateNode) { setIcon(IconLoader.getIcon(JajukIcons.DISCOVERY_DATE)); // collection node } else { setIcon(IconLoader.getIcon(JajukIcons.LIST)); } return this; } } class TracksTreeExpansionListener implements TreeExpansionListener { @Override public void treeCollapsed(TreeExpansionEvent event) { Object o = event.getPath().getLastPathComponent(); if (o instanceof GenreNode) { Genre genre = ((GenreNode) o).getGenre(); genre.removeProperty(Const.XML_EXPANDED); } else if (o instanceof ArtistNode) { Artist artist = ((ArtistNode) o).getArtist(); artist.removeProperty(Const.XML_EXPANDED); } else if (o instanceof AlbumNode) { Album album = ((AlbumNode) o).getAlbum(); album.removeProperty(Const.XML_EXPANDED); } else if (o instanceof YearNode) { Year year = ((YearNode) o).getYear(); year.removeProperty(Const.XML_EXPANDED); } } @Override public void treeExpanded(TreeExpansionEvent event) { Object o = event.getPath().getLastPathComponent(); if (o instanceof GenreNode) { Genre genre = ((GenreNode) o).getGenre(); genre.setProperty(Const.XML_EXPANDED, true); } else if (o instanceof ArtistNode) { Artist artist = ((ArtistNode) o).getArtist(); artist.setProperty(Const.XML_EXPANDED, true); } else if (o instanceof AlbumNode) { Album album = ((AlbumNode) o).getAlbum(); album.setProperty(Const.XML_EXPANDED, true); } else if (o instanceof YearNode) { Year year = ((YearNode) o).getYear(); year.setProperty(Const.XML_EXPANDED, true); } } }jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/views/ViewAdapter.java0000644000175000017500000002020611720500104024633 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.views; import com.vlsolutions.swing.docking.DockKey; import java.awt.Component; import java.awt.Container; import java.awt.event.ComponentEvent; import java.awt.event.KeyListener; import org.jajuk.events.JajukEvent; import org.jajuk.events.JajukEvents; import org.jajuk.events.ObservationManager; import org.jajuk.events.Observer; import org.jajuk.ui.perspectives.IPerspective; import org.jajuk.ui.widgets.JajukTable; import org.jajuk.util.Const; import org.jdesktop.swingx.JXBusyLabel; import org.jdesktop.swingx.JXPanel; /** * Default implementation for views. */ public abstract class ViewAdapter extends JXPanel implements IView, Const, Comparable, Observer { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1526958318911770642L; /** Populated state. */ private boolean bIsPopulated = false; /** View ID; note that a same view can be used several times in the same or in others perspectives. */ private String sID; /** Associated perspective*. */ private IPerspective perspective; /** Associated DockKey. */ private final DockKey key; /** * Constructor. */ public ViewAdapter() { super(); // create a new DockKey (note that ID is set in setID() method) key = new DockKey(); // View title key.setName(getDesc()); key.setResizeWeight(0.5f); setOpaque(true); } /** * toString method. * * @return the string */ @Override public String toString() { return "View[name=" + getID() + " description='" + getDesc() + "']"; } /** * Checks if is populated. * * @return Returns the bIsPopulated. */ @Override public boolean isPopulated() { return bIsPopulated; } /** * Sets the is populated. * * @param isPopulated Defines, if this View is populated fully. */ @Override public void setIsPopulated(boolean isPopulated) { bIsPopulated = isPopulated; } /* * (non-Javadoc) * * @see * java.awt.event.ComponentListener#componentHidden(java.awt.event.ComponentEvent * ) */ @Override public void componentHidden(ComponentEvent e) { // required by interface, but nothing to do here... } /* * (non-Javadoc) * * @see * java.awt.event.ComponentListener#componentMoved(java.awt.event.ComponentEvent * ) */ @Override public void componentMoved(ComponentEvent e) { // required by interface, but nothing to do here... } /* * (non-Javadoc) * * @see * java.awt.event.ComponentListener#componentResized(java.awt.event.ComponentEvent * ) */ @Override public void componentResized(ComponentEvent e) { // required by interface, but nothing to do here... } /* * (non-Javadoc) * * @see * java.awt.event.ComponentListener#componentShown(java.awt.event.ComponentEvent * ) */ @Override public void componentShown(ComponentEvent e) { // required by interface, but nothing to do here... } /* * (non-Javadoc) * * @see com.vlsolutions.swing.docking.Dockable#getDockKey() */ @Override public DockKey getDockKey() { return key; } /* * (non-Javadoc) * * @see com.vlsolutions.swing.docking.Dockable#getComponent() */ @Override public Component getComponent() { return this; } /** * Default impl for ID. * * @return the ID */ @Override public String getID() { return sID; } /** * Set the view ID. * * @param sID The new ID of this view. */ @Override public void setID(String sID) { key.setKey(sID); this.sID = sID; } /* * (non-Javadoc) * * @see org.jajuk.ui.IView#getPerspective() */ @Override public IPerspective getPerspective() { return perspective; } /* * (non-Javadoc) * * @see org.jajuk.ui.IView#setPerspective(org.jajuk.ui.IPerspective) */ @Override public void setPerspective(IPerspective perspective) { this.perspective = perspective; } /** * Compare this view with another view-object. * * @param other The second view to compare to. * * @return Natural order */ @Override public int compareTo(IView other) { return getDesc().compareTo(other.getDesc()); } /** * Called when the view perspective is selected. */ @Override public void onPerspectiveSelection() { // required by interface, but nothing to do here... } /* * (non-Javadoc) * * @see java.awt.Container#removeAll() */ @Override public void removeAll() { // We have to override removeAll() to work around a memory leak related to // JXBusyLabel.. // first look for any JXBusyLabel and stop it stopAllBusyLabels(this); super.removeAll(); } /** * walk through the list of components and stop any BusyLabel. */ public void stopAllBusyLabels() { stopAllBusyLabels(this); } /** * walk through the list of components and stop any BusyLabel. * * @param c DOCUMENT_ME */ private static void stopAllBusyLabels(Container c) { for (int i = 0; i < c.getComponentCount(); i++) { Component comp = c.getComponent(i); if (comp instanceof JXBusyLabel) { JXBusyLabel busy = (JXBusyLabel) comp; if (busy.isBusy()) { // make sure we correctly stop the BusyLabel in all cases here, // sometimes this did not work... // this can probably removed after upgrading swingx, see // https://swingx.dev.java.net/issues/show_bug.cgi?id=626 busy.setBusy(false); } } else if (comp instanceof Container) { // recursively call the Container to also look at it's components stopAllBusyLabels((Container) comp); } } } /** * Cleanup. * DOCUMENT_ME */ public void cleanup() { // unregister any component that is still registered as observer cleanupRecursive(this); } /** * walk through the list of components and unregister any Observer to free all references. * * @param c DOCUMENT_ME */ private static void cleanupRecursive(Container c) { for (int i = 0; i < c.getComponentCount(); i++) { Component comp = c.getComponent(i); // unregister any Observer that is contained as Component here, e.g. JajukTable instances if (comp instanceof Observer) { ObservationManager.unregister((Observer) comp); } // iterate over all KeyListeners and remove them for (KeyListener key : comp.getKeyListeners()) { comp.removeKeyListener(key); } if (comp instanceof JajukTable) { // JajukTable sends TABLE_SELECTION_CHANGED with views as part of the properties. Therefore try to clean up these references // here for every JajukTable that we find by sending an empty TABLE_SELECTION_CHANGED event which clears the last one that is still stored // in the ObservationManager ObservationManager.notifySync(new JajukEvent(JajukEvents.TABLE_SELECTION_CHANGED, null)); } // if the component is a nested ViewAdapter (e.g. PlaylistView$PlaylistRepository, // we need to do this cleanup in the nested object as well if (comp instanceof ViewAdapter) { // we also need to cleanup the RepositoryPanel ((ViewAdapter) comp).cleanup(); } // recursively call any Container to also look at it's components if (comp instanceof Container) { cleanupRecursive((Container) comp); } } } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/views/ParameterView.java0000644000175000017500000023101111720500104025171 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.views; import java.awt.Component; import java.awt.SystemTray; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import java.util.HashSet; import java.util.Locale; import java.util.Map; import java.util.Properties; import java.util.Set; import java.util.TreeSet; import javax.swing.BorderFactory; import javax.swing.ButtonGroup; import javax.swing.InputVerifier; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JComboBox; import javax.swing.JComponent; import javax.swing.JFormattedTextField; import javax.swing.JLabel; import javax.swing.JList; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JPasswordField; import javax.swing.JRadioButton; import javax.swing.JScrollPane; import javax.swing.JSlider; import javax.swing.JTabbedPane; import javax.swing.JTextField; import javax.swing.SwingConstants; import javax.swing.SwingUtilities; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import javax.swing.event.ListSelectionEvent; import javax.swing.plaf.basic.BasicComboBoxRenderer; import net.miginfocom.swing.MigLayout; import org.apache.commons.lang.StringUtils; import org.jajuk.base.AlbumManager; import org.jajuk.base.DeviceManager; import org.jajuk.base.File; import org.jajuk.base.FileManager; import org.jajuk.base.SearchResult; import org.jajuk.base.SearchResult.SearchResultType; import org.jajuk.events.JajukEvent; import org.jajuk.events.JajukEvents; import org.jajuk.events.ObservationManager; import org.jajuk.services.core.RatingManager; import org.jajuk.services.core.SessionService; import org.jajuk.services.notification.NotificatorTypes; import org.jajuk.services.webradio.WebRadio; import org.jajuk.services.webradio.WebRadioManager; import org.jajuk.ui.actions.ActionManager; import org.jajuk.ui.actions.JajukActions; import org.jajuk.ui.helpers.DefaultMouseWheelListener; import org.jajuk.ui.helpers.PatternInputVerifier; import org.jajuk.ui.thumbnails.ThumbnailManager; import org.jajuk.ui.widgets.InformationJPanel; import org.jajuk.ui.widgets.JajukButton; import org.jajuk.ui.widgets.PathSelector; import org.jajuk.ui.widgets.SearchBox; import org.jajuk.ui.widgets.SteppedComboBox; import org.jajuk.ui.widgets.ToggleLink; import org.jajuk.util.Conf; import org.jajuk.util.Const; import org.jajuk.util.DownloadManager; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; import org.jajuk.util.LocaleManager; import org.jajuk.util.Messages; import org.jajuk.util.UtilGUI; import org.jajuk.util.UtilString; import org.jajuk.util.UtilSystem; import org.jajuk.util.log.Log; import org.jdesktop.swingx.HorizontalLayout; import org.jdesktop.swingx.JXCollapsiblePane; import org.jdesktop.swingx.VerticalLayout; import org.jvnet.substance.SubstanceLookAndFeel; import org.jvnet.substance.skin.SkinInfo; /** * View used to set Jajuk parameters. *

    * Configuration perspective * */ public class ParameterView extends ViewAdapter implements ActionListener, ItemListener, ChangeListener { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** The Constant NOTIFICATOR_PREFIX. DOCUMENT_ME */ private static final String NOTIFICATOR_PREFIX = "Notificator."; /** DOCUMENT_ME. */ private JTabbedPane jtpMain; /** DOCUMENT_ME. */ private JTextField jtfHistory; /** DOCUMENT_ME. */ private JButton jbClearHistory; /** DOCUMENT_ME. */ private JButton jbResetRatings; /** DOCUMENT_ME. */ private JButton jbResetPreferences; /** DOCUMENT_ME. */ private ButtonGroup bgStart; /** DOCUMENT_ME. */ private JRadioButton jrbNothing; /** DOCUMENT_ME. */ private JRadioButton jrbLast; /** DOCUMENT_ME. */ private JRadioButton jrbLastKeepPos; /** DOCUMENT_ME. */ private JRadioButton jrbShuffle; /** DOCUMENT_ME. */ private JRadioButton jrbBestof; /** DOCUMENT_ME. */ private JRadioButton jrbNovelties; /** DOCUMENT_ME. */ private JRadioButton jrbFile; /** DOCUMENT_ME. */ private SearchBox sbSearch; /** DOCUMENT_ME. */ private JPanel jpConfirmations; /** DOCUMENT_ME. */ private JCheckBox jcbBeforeDelete; /** DOCUMENT_ME. */ private JCheckBox jcbBeforeExit; /** DOCUMENT_ME. */ private JCheckBox jcbBeforeRemoveDevice; /** DOCUMENT_ME. */ private JCheckBox jcbBeforeDeleteCover; /** DOCUMENT_ME. */ private JCheckBox jcbBeforeClearingHistory; /** DOCUMENT_ME. */ private JCheckBox jcbBeforeResetingRatings; /** DOCUMENT_ME. */ private JCheckBox jcbBeforeRefactorFiles; /** DOCUMENT_ME. */ private JPanel jpOptions; /** DOCUMENT_ME. */ private JCheckBox jcbDisplayUnmounted; /** DOCUMENT_ME. */ private JCheckBox jcbAudioScrobbler; /** DOCUMENT_ME. */ private JLabel jlASUser; /** DOCUMENT_ME. */ private JTextField jtfASUser; /** DOCUMENT_ME. */ private JLabel jlASPassword; /** DOCUMENT_ME. */ private JPasswordField jpfASPassword; /** DOCUMENT_ME. */ private SteppedComboBox scbLanguage; /** DOCUMENT_ME. */ private JTextField jtfFrameTitle; /** Balloon notifier pattern text field. */ private JTextField jtfBalloonNotifierPattern; /** Information pattern textfield. */ private JTextField jtfInformationPattern; /** DOCUMENT_ME. */ private JLabel jlLAF; /** DOCUMENT_ME. */ private SteppedComboBox scbLAF; /** DOCUMENT_ME. */ private SteppedComboBox scbLogLevel; /** DOCUMENT_ME. */ private JSlider introPosition; /** DOCUMENT_ME. */ private JSlider introLength; /** DOCUMENT_ME. */ private JTextField jtfBestofSize; /** DOCUMENT_ME. */ private JTextField jtfNoveltiesAge; /** DOCUMENT_ME. */ private JTextField jtfVisiblePlanned; /** DOCUMENT_ME. */ private JSlider crossFadeDuration; /** DOCUMENT_ME. */ private JCheckBox jcbDefaultActionClick; /** DOCUMENT_ME. */ private JCheckBox jcbDefaultActionDrop; /** DOCUMENT_ME. */ private JLabel jlNotificationType; /** DOCUMENT_ME. */ private JComboBox jcbNotificationType; /** DOCUMENT_ME. */ private JCheckBox jcbHotkeys; /** DOCUMENT_ME. */ private JPanel jpTags; /** DOCUMENT_ME. */ private JCheckBox jcbUseParentDir; /** DOCUMENT_ME. */ private JFormattedTextField jtfRefactorPattern; /** DOCUMENT_ME. */ private JTextField jtfAnimationPattern; /** DOCUMENT_ME. */ private JPanel jpAdvanced; /** DOCUMENT_ME. */ private JCheckBox jcbBackup; /** DOCUMENT_ME. */ private JSlider backupSize; /** DOCUMENT_ME. */ private JComboBox jcbCollectionEncoding; /** DOCUMENT_ME. */ private JCheckBox jcbRegexp; /** DOCUMENT_ME. */ private JPanel jpNetwork; /** DOCUMENT_ME. */ private ButtonGroup bgProxy; /** DOCUMENT_ME. */ private JCheckBox jcbNoneInternetAccess; /** DOCUMENT_ME. */ private JRadioButton jcbProxyNone; /** DOCUMENT_ME. */ private JRadioButton jcbProxyHttp; /** DOCUMENT_ME. */ private JRadioButton jcbProxySocks; /** DOCUMENT_ME. */ private JLabel jlProxyHostname; /** DOCUMENT_ME. */ private JTextField jtfProxyHostname; /** DOCUMENT_ME. */ private JLabel jlProxyPort; /** DOCUMENT_ME. */ private JTextField jtfProxyPort; /** DOCUMENT_ME. */ private JLabel jlProxyLogin; /** DOCUMENT_ME. */ private JTextField jtfProxyLogin; /** DOCUMENT_ME. */ private JLabel jlProxyPwd; /** DOCUMENT_ME. */ private JPasswordField jtfProxyPwd; /** DOCUMENT_ME. */ private JLabel jlConnectionTO; /** DOCUMENT_ME. */ private JSlider connectionTO; /** DOCUMENT_ME. */ private JPanel jpCovers; /** DOCUMENT_ME. */ private JCheckBox jcbAutoCover; /** DOCUMENT_ME. */ private JCheckBox jcbShuffleCover; /** DOCUMENT_ME. */ private JLabel jlCoverSize; /** DOCUMENT_ME. */ private JComboBox jcbCoverSize; /** DOCUMENT_ME. */ private JTextField jtfMPlayerArgs; /** DOCUMENT_ME. */ private JTextField jtfEnvVariables; /** DOCUMENT_ME. */ private JTextField jtfMPlayerPath; /** DOCUMENT_ME. */ private PathSelector psJajukWorkspace; /** DOCUMENT_ME. */ private JLabel jlCatalogPages; /** DOCUMENT_ME. */ private JSlider jsCatalogPages; /** DOCUMENT_ME. */ private JButton jbCatalogRefresh; /** DOCUMENT_ME. */ private JCheckBox jcbShowPopups; /** DOCUMENT_ME. */ private JCheckBox jcbShowSystray; /** DOCUMENT_ME. */ private JCheckBox jcbMinimizeToTray; /** DOCUMENT_ME. */ private JPanel jpUI; /** DOCUMENT_ME. */ private JLabel jlFonts; /** DOCUMENT_ME. */ private JSlider jsFonts; /** DOCUMENT_ME. */ private JPanel jpLastFM; /** DOCUMENT_ME. */ private JCheckBox jcbEnableLastFMInformation; /** DOCUMENT_ME. */ private JButton jbOK; /** DOCUMENT_ME. */ private JButton jbDefault; /** DOCUMENT_ME. */ private JCheckBox jcbCheckUpdates; /** DOCUMENT_ME. */ private JCheckBox jcbForceFileDate; /** DOCUMENT_ME. */ private JSlider jsPerspectiveSize; /** DOCUMENT_ME. */ private JCheckBox jcbUseVolnorm; /** DOCUMENT_ME. */ private boolean someOptionsAppliedAtNextStartup = false; /** DOCUMENT_ME. */ private JTextField jtfExplorerPath; /** Whether the "theme will be token into account" message has been already displayed. */ boolean bLAFMessage = false; /** DOCUMENT_ME. */ private JLabel jlDefaultCoverSearchPattern; /** DOCUMENT_ME. */ private JTextField jtfDefaultCoverSearchPattern; /** DOCUMENT_ME. */ private JCheckBox jcbSaveExplorerFriendly; /** DOCUMENT_ME. */ private JCheckBox jcbDropPlayedTracksFromQueue; /** DOCUMENT_ME. */ private JCheckBox jcb3dCover; /** * View providing main jajuk configuration GUI. Known in the doc as * "Preferences view" */ public ParameterView() { super(); } /* * (non-Javadoc) * * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent) */ public void actionPerformed(final ActionEvent e) { if (e.getSource() == jbClearHistory) { // show confirmation message if required if (Conf.getBoolean(Const.CONF_CONFIRMATIONS_CLEAR_HISTORY)) { final int iResu = Messages.getChoice(Messages.getString("Confirmation_clear_history"), JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE); if (iResu != JOptionPane.YES_OPTION) { return; } } ObservationManager.notify(new JajukEvent(JajukEvents.CLEAR_HISTORY)); } else if (e.getSource() == scbLAF) { // Refresh full GUI at each LAF change as a preview UtilGUI.setupSubstanceLookAndFeel((String) scbLAF.getSelectedItem()); UtilGUI.updateAllUIs(); } else if (e.getSource() == jbResetRatings) { // show confirmation message if required if (Conf.getBoolean(Const.CONF_CONFIRMATIONS_RESET_RATINGS)) { final int iResu = Messages.getChoice(Messages.getString("Confirmation_reset_ratings"), JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE); if (iResu != JOptionPane.YES_OPTION) { return; } } ObservationManager.notify(new JajukEvent(JajukEvents.RATE_RESET)); } else if (e.getSource() == jbResetPreferences) { // show confirmation message if required if (Conf.getBoolean(Const.CONF_CONFIRMATIONS_RESET_RATINGS)) { final int iResu = Messages.getChoice(Messages.getString("Confirmation_reset_preferences"), JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE); if (iResu != JOptionPane.YES_OPTION) { return; } } if (!DeviceManager.getInstance().isAnyDeviceRefreshing()) { ObservationManager.notify(new JajukEvent(JajukEvents.PREFERENCES_RESET)); } else { Messages.showErrorMessage(120); } } else if (e.getSource() == jbOK) { applyParameters(); // Notify any client than wait for parameters updates final Properties details = new Properties(); details.put(Const.DETAIL_ORIGIN, this); if (someOptionsAppliedAtNextStartup) { // Inform user that some parameters will apply only at // next startup Messages.showInfoMessage(Messages.getString("ParameterView.198")); someOptionsAppliedAtNextStartup = false; } } else if (e.getSource() == jbDefault) { int resu = Messages.getChoice(Messages.getString("Confirmation_defaults"), JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.INFORMATION_MESSAGE); if (resu == JOptionPane.OK_OPTION) { Conf.setDefaultProperties(); updateSelection();// update UI InformationJPanel.getInstance().setMessage(Messages.getString("ParameterView.110"), InformationJPanel.MessageType.INFORMATIVE); applyParameters(); Messages.showInfoMessage(Messages.getString("ParameterView.198")); } } else if (e.getSource() == jcbBackup) { // if backup option is unchecked, reset backup size if (jcbBackup.isSelected()) { backupSize.setEnabled(true); backupSize.setValue(Conf.getInt(Const.CONF_BACKUP_SIZE)); } else { backupSize.setEnabled(false); backupSize.setValue(0); } } else if ((e.getSource() == jcbProxyNone) || (e.getSource() == jcbProxyHttp) || (e.getSource() == jcbProxySocks)) { final boolean bUseProxy = !jcbProxyNone.isSelected(); jtfProxyHostname.setEnabled(bUseProxy); jtfProxyPort.setEnabled(bUseProxy); jtfProxyLogin.setEnabled(bUseProxy); jtfProxyPwd.setEnabled(bUseProxy); jlProxyHostname.setEnabled(bUseProxy); jlProxyPort.setEnabled(bUseProxy); jlProxyLogin.setEnabled(bUseProxy); jlProxyPwd.setEnabled(bUseProxy); } else if (e.getSource() == jcbAutoCover) { if (jcbAutoCover.isSelected()) { jcbCoverSize.setEnabled(true); jlCoverSize.setEnabled(true); } else { jlCoverSize.setEnabled(false); jcbCoverSize.setEnabled(false); } } else if (e.getSource() == jcbAudioScrobbler) { if (jcbAudioScrobbler.isSelected()) { jlASUser.setEnabled(true); jtfASUser.setEnabled(true); jlASPassword.setEnabled(true); jpfASPassword.setEnabled(true); } else { jlASUser.setEnabled(false); jtfASUser.setEnabled(false); jlASPassword.setEnabled(false); jpfASPassword.setEnabled(false); } } else if (e.getSource() == scbLanguage) { Locale locale = LocaleManager.getLocaleForDesc(((JLabel) scbLanguage.getSelectedItem()) .getText()); final String sLocal = locale.getLanguage(); final String sPreviousLocal = LocaleManager.getLocale().getLanguage(); if (!sPreviousLocal.equals(sLocal)) { // local has changed someOptionsAppliedAtNextStartup = true; } } else if (e.getSource() == jcbHotkeys) { someOptionsAppliedAtNextStartup = true; } else if (e.getSource() == jbCatalogRefresh) { new Thread("Parameter Catalog refresh Thread") { @Override public void run() { UtilGUI.waiting(); // Force albums to search for new covers AlbumManager.getInstance().resetCoverCache(); // Clean thumbs ThumbnailManager.cleanThumbs(THUMBNAIL_SIZE_50X50); ThumbnailManager.cleanThumbs(THUMBNAIL_SIZE_100X100); ThumbnailManager.cleanThumbs(THUMBNAIL_SIZE_150X150); ThumbnailManager.cleanThumbs(THUMBNAIL_SIZE_200X200); ThumbnailManager.cleanThumbs(THUMBNAIL_SIZE_250X250); ThumbnailManager.cleanThumbs(THUMBNAIL_SIZE_300X300); UtilGUI.stopWaiting(); // For catalog view's update ObservationManager.notify(new JajukEvent(JajukEvents.DEVICE_REFRESH)); // Display a message Messages.showInfoMessage(Messages.getString("Success")); } }.start(); } } /** * Apply parameters. */ private void applyParameters() { // **Read all parameters** // Options Conf.setProperty(Const.CONF_OPTIONS_HIDE_UNMOUNTED, Boolean.toString(jcbDisplayUnmounted.isSelected())); Conf.setProperty(Const.CONF_OPTIONS_PUSH_ON_CLICK, Boolean.toString(jcbDefaultActionClick.isSelected())); Conf.setProperty(Const.CONF_OPTIONS_PUSH_ON_DROP, Boolean.toString(jcbDefaultActionDrop.isSelected())); Conf.setProperty(Const.CONF_OPTIONS_HOTKEYS, Boolean.toString(jcbHotkeys.isSelected())); Conf.setProperty(Const.CONF_LASTFM_AUDIOSCROBBLER_ENABLE, Boolean.toString(jcbAudioScrobbler.isSelected())); Conf.setProperty(Const.CONF_LASTFM_INFO, Boolean.toString(jcbEnableLastFMInformation.isSelected())); Conf.setProperty(Const.CONF_LASTFM_USER, jtfASUser.getText()); Conf.setProperty(Const.CONF_LASTFM_PASSWORD, UtilString.rot13(new String(jpfASPassword.getPassword()))); final int iLogLevel = scbLogLevel.getSelectedIndex(); Log.setVerbosity(iLogLevel); Conf.setProperty(Const.CONF_OPTIONS_LOG_LEVEL, Integer.toString(iLogLevel)); Conf.setProperty(Const.CONF_OPTIONS_INTRO_BEGIN, Integer.toString(introPosition.getValue())); Conf.setProperty(Const.CONF_OPTIONS_INTRO_LENGTH, Integer.toString(introLength.getValue())); Conf.setProperty(Const.CONF_TAGS_USE_PARENT_DIR, Boolean.toString(jcbUseParentDir.isSelected())); Conf.setProperty(Const.CONF_DROP_PLAYED_TRACKS_FROM_QUEUE, Boolean.toString(jcbDropPlayedTracksFromQueue.isSelected())); final String sBestofSize = jtfBestofSize.getText(); if (!sBestofSize.isEmpty()) { Conf.setProperty(Const.CONF_BESTOF_TRACKS_SIZE, sBestofSize); } Locale locale = LocaleManager.getLocaleForDesc(((JLabel) scbLanguage.getSelectedItem()) .getText()); final String sLocal = locale.getLanguage(); Conf.setProperty(Const.CONF_OPTIONS_LANGUAGE, sLocal); // force refresh of bestof files RatingManager.setRateHasChanged(true); final String sNoveltiesAge = jtfNoveltiesAge.getText(); if (!sNoveltiesAge.isEmpty()) { Conf.setProperty(Const.CONF_OPTIONS_NOVELTIES_AGE, sNoveltiesAge); } final String sVisiblePlanned = jtfVisiblePlanned.getText(); if (!sVisiblePlanned.isEmpty()) { Conf.setProperty(Const.CONF_OPTIONS_VISIBLE_PLANNED, sVisiblePlanned); } final int oldDuration = Conf.getInt(Const.CONF_FADE_DURATION); // Show an hideable message if user set cross fade under linux for sound // server information if (UtilSystem.isUnderLinux() && (oldDuration == 0) && (oldDuration != crossFadeDuration.getValue())) { Messages.showHideableWarningMessage(Messages.getString("ParameterView.210"), Const.CONF_NOT_SHOW_AGAIN_CROSS_FADE); } Conf.setProperty(Const.CONF_FADE_DURATION, Integer.toString(crossFadeDuration.getValue())); // Startup if (jrbNothing.isSelected()) { Conf.setProperty(Const.CONF_STARTUP_MODE, Const.STARTUP_MODE_NOTHING); } else if (jrbLast.isSelected()) { Conf.setProperty(Const.CONF_STARTUP_MODE, Const.STARTUP_MODE_LAST); } else if (jrbLastKeepPos.isSelected()) { Conf.setProperty(Const.CONF_STARTUP_MODE, Const.STARTUP_MODE_LAST_KEEP_POS); } else if (jrbShuffle.isSelected()) { Conf.setProperty(Const.CONF_STARTUP_MODE, Const.STARTUP_MODE_SHUFFLE); } else if (jrbFile.isSelected()) { Conf.setProperty(Const.CONF_STARTUP_MODE, Const.STARTUP_MODE_ITEM); } else if (jrbBestof.isSelected()) { Conf.setProperty(Const.CONF_STARTUP_MODE, Const.STARTUP_MODE_BESTOF); } else if (jrbNovelties.isSelected()) { Conf.setProperty(Const.CONF_STARTUP_MODE, Const.STARTUP_MODE_NOVELTIES); } // Confirmations Conf.setProperty(Const.CONF_CONFIRMATIONS_DELETE_FILE, Boolean.toString(jcbBeforeDelete.isSelected())); Conf.setProperty(Const.CONF_CONFIRMATIONS_EXIT, Boolean.toString(jcbBeforeExit.isSelected())); Conf.setProperty(Const.CONF_CONFIRMATIONS_REMOVE_DEVICE, Boolean.toString(jcbBeforeRemoveDevice.isSelected())); Conf.setProperty(Const.CONF_CONFIRMATIONS_DELETE_COVER, Boolean.toString(jcbBeforeDeleteCover.isSelected())); Conf.setProperty(Const.CONF_CONFIRMATIONS_CLEAR_HISTORY, Boolean.toString(jcbBeforeClearingHistory.isSelected())); Conf.setProperty(Const.CONF_CONFIRMATIONS_RESET_RATINGS, Boolean.toString(jcbBeforeResetingRatings.isSelected())); // History final String sHistoryDuration = jtfHistory.getText(); if (!sHistoryDuration.isEmpty()) { Conf.setProperty(Const.CONF_HISTORY, sHistoryDuration); } // Patterns Conf.setProperty(Const.CONF_PATTERN_REFACTOR, jtfRefactorPattern.getText()); Conf.setProperty(Const.CONF_PATTERN_ANIMATION, jtfAnimationPattern.getText()); Conf.setProperty(Const.CONF_PATTERN_FRAME_TITLE, jtfFrameTitle.getText()); Conf.setProperty(Const.CONF_PATTERN_BALLOON_NOTIFIER, jtfBalloonNotifierPattern.getText()); Conf.setProperty(Const.CONF_PATTERN_INFORMATION, jtfInformationPattern.getText()); // Advanced Conf.setProperty(Const.CONF_BACKUP_SIZE, Integer.toString(backupSize.getValue())); Conf.setProperty(Const.CONF_COLLECTION_CHARSET, jcbCollectionEncoding.getSelectedItem() .toString()); Conf.setProperty(Const.CONF_REGEXP, Boolean.toString(jcbRegexp.isSelected())); Conf.setProperty(Const.CONF_USE_VOLNORM, Boolean.toString(jcbUseVolnorm.isSelected())); Conf.setProperty(Const.CONF_CHECK_FOR_UPDATE, Boolean.toString(jcbCheckUpdates.isSelected())); Conf.setProperty(Const.CONF_FORCE_FILE_DATE, Boolean.toString(jcbForceFileDate.isSelected())); // Apply new mplayer path and display a warning message if changed final String oldMplayerPath = Conf.getString(Const.CONF_MPLAYER_PATH_FORCED); if (!(oldMplayerPath.equals(jtfMPlayerPath.getText()))) { this.someOptionsAppliedAtNextStartup = true; } Conf.setProperty(Const.CONF_MPLAYER_PATH_FORCED, jtfMPlayerPath.getText()); Conf.setProperty(Const.CONF_MPLAYER_ARGS, jtfMPlayerArgs.getText()); Conf.setProperty(Const.CONF_ENV_VARIABLES, jtfEnvVariables.getText()); Conf.setProperty(Const.CONF_EXPLORER_PATH, jtfExplorerPath.getText()); // GUI Conf.setProperty(Const.CONF_CATALOG_PAGE_SIZE, Integer.toString(jsCatalogPages.getValue())); Conf.setProperty(Const.CONF_SHOW_POPUPS, Boolean.toString(jcbShowPopups.isSelected())); final int oldFont = Conf.getInt(Const.CONF_FONTS_SIZE); // Display a message if font size changed if (oldFont != jsFonts.getValue()) { someOptionsAppliedAtNextStartup = true; } Conf.setProperty(Const.CONF_FONTS_SIZE, Integer.toString(jsFonts.getValue())); // Notificator type String notificatorTypeDisplayed = (String) jcbNotificationType.getSelectedItem(); for (NotificatorTypes notificatorType : NotificatorTypes.values()) { if (Messages.getString(NOTIFICATOR_PREFIX + notificatorType).equals(notificatorTypeDisplayed)) { Conf.setProperty(Const.CONF_UI_NOTIFICATOR_TYPE, notificatorType.name()); } } // Message if show systray is changed final boolean bOldShowSystray = Conf.getBoolean(Const.CONF_SHOW_SYSTRAY); if (bOldShowSystray != jcbShowSystray.isSelected()) { someOptionsAppliedAtNextStartup = true; } Conf.setProperty(Const.CONF_SHOW_SYSTRAY, Boolean.toString(jcbShowSystray.isSelected())); // Minimize to tray Conf.setProperty(Const.CONF_MINIMIZE_TO_TRAY, Boolean.toString(jcbMinimizeToTray.isSelected())); final int oldPerspectiveSize = Conf.getInt(Const.CONF_PERSPECTIVE_ICONS_SIZE); // If we perspective size changed and no font message have been already // displayed, display a message if (oldPerspectiveSize != jsPerspectiveSize.getValue()) { someOptionsAppliedAtNextStartup = true; } Conf.setProperty(Const.CONF_PERSPECTIVE_ICONS_SIZE, Integer.toString(jsPerspectiveSize.getValue())); // LAF change final String oldTheme = Conf.getString(Const.CONF_OPTIONS_LNF); Conf.setProperty(Const.CONF_OPTIONS_LNF, (String) scbLAF.getSelectedItem()); if (!oldTheme.equals(scbLAF.getSelectedItem())) { // theme will be applied at next startup Messages.showHideableWarningMessage(Messages.getString("ParameterView.233"), Const.CONF_NOT_SHOW_AGAIN_LAF_CHANGE); bLAFMessage = true; } // If jajuk home changes, write new path in bootstrap file if ((SessionService.getWorkspace() != null) && !SessionService.getWorkspace().equals(psJajukWorkspace.getUrl())) { // Check workspace directory if (!psJajukWorkspace.getUrl().trim().isEmpty()) { // Check workspace presence and create it if required final java.io.File fWorkspace = new java.io.File(psJajukWorkspace.getUrl()); if (!fWorkspace.exists() && !fWorkspace.mkdirs()) { Log.warn("Could not create directory " + fWorkspace.toString()); } if (!fWorkspace.canRead()) { Messages.showErrorMessage(165); return; } } try { final String newWorkspace = psJajukWorkspace.getUrl(); // If target workspace doesn't exist, copy current repository to // the new workspace // (keep old repository for security and for use // by others users in multi-session mode) boolean bPreviousPathExist = true; // bPreviousPathExist is true if destination workspace already // exists, // it is then only a workspace switch if (!new java.io.File(psJajukWorkspace.getUrl() + '/' + (SessionService.isTestMode() ? ".jajuk_test_" + Const.TEST_VERSION : ".jajuk")) .exists()) { UtilGUI.waiting(); final java.io.File from = SessionService.getConfFileByPath(""); final java.io.File dest = new java.io.File(newWorkspace + '/' + (SessionService.isTestMode() ? ".jajuk_test_" + Const.TEST_VERSION : ".jajuk")); // Remove the session file to avoid getting a message when // switching to new workspace java.io.File session = SessionService.getSessionIdFile(); session.delete(); UtilSystem.copyRecursively(from, dest); bPreviousPathExist = false; } // Change the workspace so the very last conf (like current // track) // will be saved directly to target workspace. We don't do // this if the workspace already exist to avoid overwriting other // configuration. SessionService.setWorkspace(psJajukWorkspace.getUrl()); //Commit the bootstrap file SessionService.commitBootstrapFile(); UtilGUI.stopWaiting(); // Display a warning message and restart Jajuk if (bPreviousPathExist) { Messages.getChoice(Messages.getString("ParameterView.247"), JOptionPane.DEFAULT_OPTION, JOptionPane.INFORMATION_MESSAGE); } else { Messages.getChoice(Messages.getString("ParameterView.209"), JOptionPane.DEFAULT_OPTION, JOptionPane.INFORMATION_MESSAGE); } // Exit Jajuk try { ActionManager.getAction(JajukActions.EXIT).perform(null); } catch (Exception e1) { Log.error(e1); } } catch (final Exception e) { Messages.showErrorMessage(24); Log.error(e); } } // Network Conf.setProperty(Const.CONF_NETWORK_NONE_INTERNET_ACCESS, Boolean.toString(jcbNoneInternetAccess.isSelected())); Conf.setProperty(Const.CONF_NETWORK_USE_PROXY, Boolean.toString(!jcbProxyNone.isSelected())); if (jcbProxyHttp.isSelected()) { Conf.setProperty(Const.CONF_NETWORK_PROXY_TYPE, Const.PROXY_TYPE_HTTP); } else if (jcbProxySocks.isSelected()) { Conf.setProperty(Const.CONF_NETWORK_PROXY_TYPE, Const.PROXY_TYPE_SOCKS); } Conf.setProperty(Const.CONF_NETWORK_PROXY_HOSTNAME, jtfProxyHostname.getText()); Conf.setProperty(Const.CONF_NETWORK_PROXY_PORT, jtfProxyPort.getText()); Conf.setProperty(Const.CONF_NETWORK_PROXY_LOGIN, jtfProxyLogin.getText()); Conf.setProperty(Const.CONF_NETWORK_PROXY_PWD, UtilString.rot13(new String(jtfProxyPwd.getPassword()))); Conf.setProperty(Const.CONF_NETWORK_CONNECTION_TO, Integer.toString(connectionTO.getValue())); // Force global reload of proxy variables DownloadManager.setDefaultProxySettings(); // Covers Conf.setProperty(Const.CONF_COVERS_MIRROW_COVER, Boolean.toString(jcb3dCover.isSelected())); ObservationManager.notify(new JajukEvent(JajukEvents.COVER_NEED_REFRESH)); Conf.setProperty(Const.CONF_COVERS_AUTO_COVER, Boolean.toString(jcbAutoCover.isSelected())); Conf.setProperty(Const.CONF_COVERS_SHUFFLE, Boolean.toString(jcbShuffleCover.isSelected())); Conf.setProperty(Const.CONF_COVERS_SAVE_EXPLORER_FRIENDLY, Boolean.toString(jcbSaveExplorerFriendly.isSelected())); Conf.setProperty(Const.CONF_COVERS_SIZE, Integer.toString(jcbCoverSize.getSelectedIndex())); Conf.setProperty(Const.FILE_DEFAULT_COVER, jtfDefaultCoverSearchPattern.getText()); // configuration try { Conf.commit(); } catch (final Exception e) { Log.error(113, e); Messages.showErrorMessage(113); } // Force a full refresh (useful for catalog view for instance) ObservationManager.notify(new JajukEvent(JajukEvents.DEVICE_REFRESH)); // display a message InformationJPanel.getInstance().setMessage(Messages.getString("ParameterView.109"), InformationJPanel.MessageType.INFORMATIVE); } /* * (non-Javadoc) * * @see org.jajuk.ui.IView#getDesc() */ public String getDesc() { return Messages.getString("ParameterView.87"); } /* * (non-Javadoc) * * @see org.jajuk.events.Observer#getRegistrationKeys() */ public Set getRegistrationKeys() { final Set eventSubjectSet = new HashSet(); eventSubjectSet.add(JajukEvents.PARAMETERS_CHANGE); return eventSubjectSet; } /* * (non-Javadoc) * * @see org.jajuk.ui.IView#display() */ public void initUI() { // Use this common action listener for UI options that need to launch // event final ActionListener alUI = new ActionListener() { public void actionPerformed(ActionEvent e) { // Store configuration Conf.setProperty(Const.CONF_SHOW_POPUPS, Boolean.toString(jcbShowPopups.isSelected())); Conf.setProperty(Const.CONF_NETWORK_NONE_INTERNET_ACCESS, Boolean.toString(jcbNoneInternetAccess.isSelected())); // Launch an event that can be trapped by the tray to // synchronize the state Properties details = new Properties(); details.put(Const.DETAIL_ORIGIN, ParameterView.this); ObservationManager.notify(new JajukEvent(JajukEvents.PARAMETERS_CHANGE, details)); } }; // --History JPanel jpHistory = new JPanel(new MigLayout("insets 10, gapy 15")); jtfHistory = new JTextField(); jtfHistory.setInputVerifier(new InputVerifier() { @Override public boolean shouldYieldFocus(final JComponent input) { return verify(input); } @Override public boolean verify(final JComponent input) { final JTextField tf = (JTextField) input; final String sText = tf.getText(); try { final int iValue = Integer.parseInt(sText); if (iValue < -1) { jbOK.setEnabled(false); return false; } } catch (final Exception e) { jbOK.setEnabled(false); return false; } jbOK.setEnabled(true); return true; } }); jtfHistory.setToolTipText(Messages.getString("ParameterView.2")); jbClearHistory = new JButton(Messages.getString("ParameterView.3"), IconLoader.getIcon(JajukIcons.CLEAR)); jbClearHistory.setToolTipText(Messages.getString("ParameterView.4")); jbClearHistory.addActionListener(this); jbResetRatings = new JButton(Messages.getString("ParameterView.186"), IconLoader.getIcon(JajukIcons.CLEAR)); jbResetRatings.setToolTipText(Messages.getString("ParameterView.187")); jbResetRatings.addActionListener(this); jbResetPreferences = new JButton(Messages.getString("ParameterView.249"), IconLoader.getIcon(JajukIcons.CLEAR)); jbResetPreferences.setToolTipText(Messages.getString("ParameterView.250")); jbResetPreferences.addActionListener(this); JLabel jlHistory = new JLabel(Messages.getString("ParameterView.0")); jlHistory.setToolTipText(Messages.getString("ParameterView.2")); jpHistory.add(jlHistory); jpHistory.add(jtfHistory, "wrap,grow"); jpHistory.add(jbClearHistory, "wrap"); jpHistory.add(jbResetRatings); jpHistory.add(jbResetPreferences); // --Startup JPanel jpStart = new JPanel(new MigLayout("insets 10,gapy 15", "[][grow][]")); bgStart = new ButtonGroup(); jrbNothing = new JRadioButton(Messages.getString("ParameterView.10")); jrbNothing.setToolTipText(Messages.getString("ParameterView.11")); jrbNothing.addItemListener(this); jrbLast = new JRadioButton(Messages.getString("ParameterView.12")); jrbLast.setToolTipText(Messages.getString("ParameterView.13")); jrbLast.addItemListener(this); jrbLastKeepPos = new JRadioButton(Messages.getString("ParameterView.135")); jrbLastKeepPos.setToolTipText(Messages.getString("ParameterView.136")); jrbLastKeepPos.addItemListener(this); jrbShuffle = new JRadioButton(Messages.getString("ParameterView.14")); jrbShuffle.setToolTipText(Messages.getString("ParameterView.15")); jrbShuffle.addItemListener(this); jrbBestof = new JRadioButton(Messages.getString("ParameterView.131")); jrbBestof.setToolTipText(Messages.getString("ParameterView.132")); jrbBestof.addItemListener(this); jrbNovelties = new JRadioButton(Messages.getString("ParameterView.133")); jrbNovelties.setToolTipText(Messages.getString("ParameterView.134")); jrbNovelties.addItemListener(this); jrbFile = new JRadioButton(Messages.getString("ParameterView.16")); jrbFile.setToolTipText(Messages.getString("ParameterView.17")); jrbFile.addItemListener(this); sbSearch = new SearchBox() { private static final long serialVersionUID = 1L; @Override public void valueChanged(final ListSelectionEvent e) { if (!e.getValueIsAdjusting()) { final SearchResult sr = sbSearch.getResult(); if (sr.getType() == SearchResultType.FILE) { Conf.setProperty(Const.CONF_STARTUP_ITEM, SearchResultType.FILE.name() + '/' + sr.getFile().getID()); sbSearch.setText(sr.getFile().getTrack().getName()); } else if (sr.getType() == SearchResultType.WEBRADIO) { Conf.setProperty(Const.CONF_STARTUP_ITEM, SearchResultType.WEBRADIO.name() + '/' + sr.getWebradio().getName()); sbSearch.setText(sr.getWebradio().getName()); } sbSearch.hidePopup(); } } }; // disabled by default, is enabled only if jrbFile is enabled sbSearch.setEnabled(false); sbSearch.setToolTipText(Messages.getString("ParameterView.18")); bgStart.add(jrbNothing); bgStart.add(jrbLast); bgStart.add(jrbLastKeepPos); bgStart.add(jrbShuffle); bgStart.add(jrbBestof); bgStart.add(jrbNovelties); bgStart.add(jrbFile); jpStart.add(jrbNothing, "wrap"); jpStart.add(jrbLast, "wrap"); jpStart.add(jrbLastKeepPos, "wrap"); jpStart.add(jrbShuffle, "wrap"); jpStart.add(jrbBestof, "wrap"); jpStart.add(jrbNovelties, "wrap"); jpStart.add(jrbFile); jpStart.add(sbSearch, "grow,wrap"); // --Confirmations jpConfirmations = new JPanel(new MigLayout("insets 10,gapy 15")); jcbBeforeDelete = new JCheckBox(Messages.getString("ParameterView.27")); jcbBeforeDelete.setToolTipText(Messages.getString("ParameterView.28")); jcbBeforeExit = new JCheckBox(Messages.getString("ParameterView.29")); jcbBeforeExit.setToolTipText(Messages.getString("ParameterView.30")); jcbBeforeRemoveDevice = new JCheckBox(Messages.getString("ParameterView.164")); jcbBeforeRemoveDevice.setToolTipText(Messages.getString("ParameterView.165")); jcbBeforeDeleteCover = new JCheckBox(Messages.getString("ParameterView.171")); jcbBeforeDeleteCover.setToolTipText(Messages.getString("ParameterView.172")); jcbBeforeClearingHistory = new JCheckBox(Messages.getString("ParameterView.188")); jcbBeforeClearingHistory.setToolTipText(Messages.getString("ParameterView.188")); jcbBeforeResetingRatings = new JCheckBox(Messages.getString("ParameterView.189")); jcbBeforeResetingRatings.setToolTipText(Messages.getString("ParameterView.189")); jcbBeforeRefactorFiles = new JCheckBox(Messages.getString("ParameterView.194")); jcbBeforeRefactorFiles.setToolTipText(Messages.getString("ParameterView.194")); jpConfirmations.add(jcbBeforeDelete, "wrap"); jpConfirmations.add(jcbBeforeExit, "wrap"); jpConfirmations.add(jcbBeforeRemoveDevice, "wrap"); jpConfirmations.add(jcbBeforeDeleteCover, "wrap"); jpConfirmations.add(jcbBeforeClearingHistory, "wrap"); jpConfirmations.add(jcbBeforeResetingRatings, "wrap"); jpConfirmations.add(jcbBeforeRefactorFiles, "wrap"); // --- Modes --- // Intro // intro position introPosition = new JSlider(0, 100, 0); introPosition.setMajorTickSpacing(20); introPosition.setMinorTickSpacing(10); introPosition.setPaintTicks(true); introPosition.setPaintLabels(true); introPosition.setToolTipText(Messages.getString("ParameterView.60")); introPosition.addMouseWheelListener(new DefaultMouseWheelListener(introPosition)); // intro length JLabel jlIntroLength = new JLabel(Messages.getString("ParameterView.61")); jlIntroLength.setToolTipText(Messages.getString("ParameterView.62")); introLength = new JSlider(0, 30, 20); introLength.setMajorTickSpacing(10); introLength.setMinorTickSpacing(1); introLength.setPaintTicks(true); introLength.setPaintLabels(true); introLength.setToolTipText(Messages.getString("ParameterView.62")); introLength.addMouseWheelListener(new DefaultMouseWheelListener(introLength)); // Best of size JLabel jlBestofSize = new JLabel(Messages.getString("ParameterView.111")); jlBestofSize.setToolTipText(Messages.getString("ParameterView.112")); jtfBestofSize = new JTextField(3); jtfBestofSize.setToolTipText(Messages.getString("ParameterView.112")); jtfBestofSize.setInputVerifier(new InputVerifier() { @Override public boolean shouldYieldFocus(final JComponent input) { return verify(input); } @Override public boolean verify(final JComponent input) { final JTextField tf = (JTextField) input; final String sText = tf.getText(); try { final int iValue = Integer.parseInt(sText); if ((iValue < 1) || (iValue > 100)) { jbOK.setEnabled(false); return false; } } catch (final Exception e) { return false; } jbOK.setEnabled(true); return true; } }); // novelties age JLabel jlNoveltiesAge = new JLabel(Messages.getString("ParameterView.129")); jlNoveltiesAge.setToolTipText(Messages.getString("ParameterView.130")); jtfNoveltiesAge = new JTextField(3); jtfNoveltiesAge.setToolTipText(Messages.getString("ParameterView.130")); jtfNoveltiesAge.setInputVerifier(new InputVerifier() { @Override public boolean shouldYieldFocus(final JComponent input) { return verify(input); } @Override public boolean verify(final JComponent input) { final JTextField tf = (JTextField) input; final String sText = tf.getText(); try { final int iValue = Integer.parseInt(sText); if (iValue < 0) { // if adding age =0, it mean today, no // max limit jbOK.setEnabled(false); return false; } } catch (final Exception e) { return false; } jbOK.setEnabled(true); return true; } }); // number of visible tracks JLabel jlVisiblePlanned = new JLabel(Messages.getString("ParameterView.177")); jlVisiblePlanned.setToolTipText(Messages.getString("ParameterView.178")); jtfVisiblePlanned = new JTextField(3); jtfVisiblePlanned.setToolTipText(Messages.getString("ParameterView.178")); jtfVisiblePlanned.setInputVerifier(new InputVerifier() { @Override public boolean shouldYieldFocus(final JComponent input) { return verify(input); } @Override public boolean verify(final JComponent input) { final JTextField tf = (JTextField) input; final String sText = tf.getText(); try { final int iValue = Integer.parseInt(sText); // number of planned tracks between 0 and 100 if ((iValue < 0) || (iValue > 100)) { return false; } } catch (final Exception e) { return false; } jbOK.setEnabled(true); return true; } }); JLabel jlCrossFadeDuration = new JLabel(Messages.getString("ParameterView.190")); jlCrossFadeDuration.setToolTipText(Messages.getString("ParameterView.191")); crossFadeDuration = new JSlider(0, 30, 0); crossFadeDuration.setMajorTickSpacing(10); crossFadeDuration.setMinorTickSpacing(1); crossFadeDuration.setPaintTicks(true); crossFadeDuration.setPaintLabels(true); crossFadeDuration.setToolTipText(Messages.getString("ParameterView.191")); crossFadeDuration.addMouseWheelListener(new DefaultMouseWheelListener(crossFadeDuration)); jcbUseVolnorm = new JCheckBox(Messages.getString("ParameterView.262")); jcbUseVolnorm.setToolTipText(Messages.getString("ParameterView.263")); // add panels JPanel jpModes = new JPanel(new MigLayout("insets 10,gapy 15,gapx 10", "[][grow,200:300:300][fill]")); jpModes.add(new JLabel(Messages.getString("ParameterView.59"))); jpModes.add(introPosition, "grow,wrap"); jpModes.add(jlIntroLength); jpModes.add(introLength, "grow,wrap"); jpModes.add(jlCrossFadeDuration); jpModes.add(crossFadeDuration, "grow,wrap"); jpModes.add(jlBestofSize); jpModes.add(jtfBestofSize, "grow,wrap"); jpModes.add(jlNoveltiesAge); jpModes.add(jtfNoveltiesAge, "grow,wrap"); jpModes.add(jlVisiblePlanned); jpModes.add(jtfVisiblePlanned, "grow,wrap"); jpModes.add(jcbUseVolnorm); // --Options jcbDisplayUnmounted = new JCheckBox(Messages.getString("JajukJMenuBar.24")); jcbDisplayUnmounted.setToolTipText(Messages.getString("ParameterView.35")); jcbDisplayUnmounted.addActionListener(alUI); jcbDefaultActionClick = new JCheckBox(Messages.getString("ParameterView.179")); jcbDefaultActionClick.setToolTipText(Messages.getString("ParameterView.180")); jcbDefaultActionDrop = new JCheckBox(Messages.getString("ParameterView.181")); jcbDefaultActionDrop.setToolTipText(Messages.getString("ParameterView.182")); jcbHotkeys = new JCheckBox(Messages.getString("ParameterView.196")); jcbHotkeys.addActionListener(this); jcbHotkeys.setToolTipText(Messages.getString("ParameterView.197")); // Disable this option if not under windows jcbHotkeys.setEnabled(UtilSystem.isUnderWindows()); scbLanguage = new SteppedComboBox(); scbLanguage.setRenderer(new BasicComboBoxRenderer() { private static final long serialVersionUID = -6943363556191659895L; @Override public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); JLabel jl = (JLabel) value; setIcon(jl.getIcon()); setText(jl.getText()); return this; } }); scbLanguage.removeAllItems(); for (String sDesc : LocaleManager.getLocalesDescs()) { scbLanguage.addItem(new JLabel(sDesc, Messages.getIcon(sDesc), SwingConstants.LEFT)); } scbLanguage.setToolTipText(Messages.getString("ParameterView.42")); scbLanguage.addActionListener(this); jcbUseParentDir = new JCheckBox(Messages.getString("ParameterView.101")); jcbUseParentDir.setToolTipText(Messages.getString("ParameterView.102")); jcbDropPlayedTracksFromQueue = new JCheckBox(Messages.getString("ParameterView.266")); jcbDropPlayedTracksFromQueue.setToolTipText(Messages.getString("ParameterView.267")); jpOptions = new JPanel(new MigLayout("insets 10, gapy 15, wrap 1")); jpOptions.add(new JLabel(Messages.getString("ParameterView.38")), "split 2,gapleft 5"); jpOptions.add(scbLanguage); jpOptions.add(jcbDisplayUnmounted); jpOptions.add(jcbDefaultActionClick); jpOptions.add(jcbDefaultActionDrop); jpOptions.add(jcbHotkeys); jpOptions.add(jcbUseParentDir); jpOptions.add(jcbDropPlayedTracksFromQueue); // --Patterns jpTags = new JPanel(new MigLayout("insets 10, gapy 15, wrap 2", "[][grow]")); JLabel jlRefactorPattern = new JLabel(Messages.getString("ParameterView.192")); jlRefactorPattern.setToolTipText(Messages.getString("ParameterView.193")); jtfRefactorPattern = new JFormattedTextField(); jtfRefactorPattern.setToolTipText(Messages.getString("ParameterView.193")); jtfRefactorPattern.setInputVerifier(new PatternInputVerifier()); JLabel jlAnimationPattern = new JLabel(Messages.getString("ParameterView.195")); jlAnimationPattern.setToolTipText(Messages.getString("ParameterView.193")); jtfAnimationPattern = new JTextField(); jtfAnimationPattern.setToolTipText(Messages.getString("ParameterView.193")); // Frame Title Options JLabel jlFrameTitle = new JLabel(Messages.getString("ParameterView.248")); jlFrameTitle.setToolTipText(Messages.getString("ParameterView.193")); jtfFrameTitle = new JTextField(); jtfFrameTitle.setToolTipText(Messages.getString("ParameterView.193")); // Balloon Notifier pattern JLabel jlBalloonNotifierPattern = new JLabel(Messages.getString("ParameterView.277")); jlBalloonNotifierPattern.setToolTipText(Messages.getString("ParameterView.278")); jtfBalloonNotifierPattern = new JTextField(); jtfBalloonNotifierPattern.setToolTipText(Messages.getString("ParameterView.278")); // Information view pattern JLabel jlInformationPattern = new JLabel(Messages.getString("ParameterView.279")); jlInformationPattern.setToolTipText(Messages.getString("ParameterView.280")); jtfInformationPattern = new JTextField(); jtfInformationPattern.setToolTipText(Messages.getString("ParameterView.280")); jpTags.add(jlRefactorPattern); jpTags.add(jtfRefactorPattern, "grow"); jpTags.add(jlAnimationPattern); jpTags.add(jtfAnimationPattern, "grow"); jpTags.add(jlFrameTitle); jpTags.add(jtfFrameTitle, "grow"); jpTags.add(jlBalloonNotifierPattern); jpTags.add(jtfBalloonNotifierPattern, "grow"); jpTags.add(jlInformationPattern); jpTags.add(jtfInformationPattern, "grow"); // --Advanced jcbBackup = new JCheckBox(Messages.getString("ParameterView.116")); jcbBackup.addActionListener(this); jcbBackup.setToolTipText(Messages.getString("ParameterView.117")); backupSize = new JSlider(0, 100); backupSize.setMajorTickSpacing(20); backupSize.setMinorTickSpacing(10); backupSize.setPaintTicks(true); backupSize.setPaintLabels(true); backupSize.setToolTipText(Messages.getString("ParameterView.119")); backupSize.addMouseWheelListener(new DefaultMouseWheelListener(backupSize)); JLabel jlCollectionEncoding = new JLabel(Messages.getString("ParameterView.120")); jlCollectionEncoding.setToolTipText(Messages.getString("ParameterView.121")); jcbCollectionEncoding = new JComboBox(); jcbCollectionEncoding.setToolTipText(Messages.getString("ParameterView.121")); jcbRegexp = new JCheckBox(Messages.getString("ParameterView.113")); jcbRegexp.setSelected(Conf.getBoolean(Const.CONF_REGEXP)); jcbRegexp.setToolTipText(Messages.getString("ParameterView.114")); jcbCollectionEncoding.addItem("UTF-8"); jcbCollectionEncoding.addItem("UTF-16"); JLabel jlLogLevel = new JLabel(Messages.getString("ParameterView.46")); scbLogLevel = new SteppedComboBox(); scbLogLevel.addItem(Messages.getString("ParameterView.47")); scbLogLevel.addItem(Messages.getString("ParameterView.48")); scbLogLevel.addItem(Messages.getString("ParameterView.49")); scbLogLevel.addItem(Messages.getString("ParameterView.50")); scbLogLevel.addItem(Messages.getString("ParameterView.51")); scbLogLevel.setToolTipText(Messages.getString("ParameterView.52")); JLabel jlMPlayerPath = new JLabel(Messages.getString("ParameterView.242")); jlMPlayerPath.setToolTipText(Messages.getString("ParameterView.243")); jtfMPlayerPath = new JTextField(); jtfMPlayerPath.setToolTipText(Messages.getString("ParameterView.243")); JLabel jlMPlayerArgs = new JLabel(Messages.getString("ParameterView.205")); jlMPlayerArgs.setToolTipText(Messages.getString("ParameterView.206")); jtfMPlayerArgs = new JTextField(); jtfMPlayerArgs.setToolTipText(Messages.getString("ParameterView.206")); JLabel jlEnvVariables = new JLabel(Messages.getString("ParameterView.219")); jlEnvVariables.setToolTipText(Messages.getString("ParameterView.220")); jtfEnvVariables = new JTextField(); jtfEnvVariables.setToolTipText(Messages.getString("ParameterView.220")); JLabel jlJajukWorkspace = new JLabel(Messages.getString("ParameterView.207")); jlJajukWorkspace.setToolTipText(Messages.getString("ParameterView.208")); // Directory selection psJajukWorkspace = new PathSelector(SessionService.getWorkspace()); psJajukWorkspace.setToolTipText(Messages.getString("ParameterView.208")); // If user provided a forced workspace, he can't change it again here if (SessionService.isForcedWorkspace()) { jlJajukWorkspace.setEnabled(false); psJajukWorkspace.setEnabled(false); } jcbCheckUpdates = new JCheckBox(Messages.getString("ParameterView.234")); jcbCheckUpdates.setToolTipText(Messages.getString("ParameterView.234")); jcbCheckUpdates.setSelected(Conf.getBoolean(Const.CONF_CHECK_FOR_UPDATE)); jcbForceFileDate = new JCheckBox(Messages.getString("ParameterView.244")); jcbForceFileDate.setToolTipText(Messages.getString("ParameterView.245")); jcbForceFileDate.setSelected(Conf.getBoolean(Const.CONF_FORCE_FILE_DATE)); JLabel jlExplorer = new JLabel(Messages.getString("ParameterView.269")); jlExplorer.setToolTipText(Messages.getString("ParameterView.270")); jtfExplorerPath = new JTextField(); jtfExplorerPath.setToolTipText(Messages.getString("ParameterView.270")); jpAdvanced = new JPanel(new MigLayout("insets 10,gapy 15, gapx 10", "[][grow][fill]")); jpAdvanced.add(jcbBackup); jpAdvanced.add(backupSize, "wrap,grow"); jpAdvanced.add(jlCollectionEncoding); jpAdvanced.add(jcbCollectionEncoding, "wrap,grow"); jpAdvanced.add(jlLogLevel); jpAdvanced.add(scbLogLevel, "wrap,grow"); jpAdvanced.add(jlMPlayerPath); jpAdvanced.add(jtfMPlayerPath, "wrap,grow"); jpAdvanced.add(jlMPlayerArgs); jpAdvanced.add(jtfMPlayerArgs, "wrap,grow"); jpAdvanced.add(jlEnvVariables); jpAdvanced.add(jtfEnvVariables, "wrap,grow"); jpAdvanced.add(jlJajukWorkspace); jpAdvanced.add(psJajukWorkspace, "wrap,grow"); jpAdvanced.add(jlExplorer); jpAdvanced.add(jtfExplorerPath, "grow,wrap"); jpAdvanced.add(jcbRegexp, "wrap"); jpAdvanced.add(jcbCheckUpdates, "wrap"); jpAdvanced.add(jcbForceFileDate, "wrap"); // - Network bgProxy = new ButtonGroup(); jcbProxyNone = new JRadioButton(Messages.getString("ParameterView.236")); jcbProxyNone.setToolTipText(Messages.getString("ParameterView.236")); jcbProxyNone.addActionListener(this); jcbNoneInternetAccess = new JCheckBox(Messages.getString("ParameterView.264")); jcbNoneInternetAccess.setToolTipText(Messages.getString("ParameterView.265")); jcbNoneInternetAccess.addActionListener(alUI); jcbProxyHttp = new JRadioButton(Messages.getString("ParameterView.237")); jcbProxyHttp.setToolTipText(Messages.getString("ParameterView.237")); jcbProxyHttp.addActionListener(this); jcbProxySocks = new JRadioButton(Messages.getString("ParameterView.238")); jcbProxySocks.setToolTipText(Messages.getString("ParameterView.238")); jcbProxySocks.addActionListener(this); bgProxy.add(jcbProxyNone); bgProxy.add(jcbProxyHttp); bgProxy.add(jcbProxySocks); jlProxyHostname = new JLabel(Messages.getString("ParameterView.144")); jlProxyHostname.setToolTipText(Messages.getString("ParameterView.145")); jtfProxyHostname = new JTextField(); jtfProxyHostname.setToolTipText(Messages.getString("ParameterView.145")); jlProxyPort = new JLabel(Messages.getString("ParameterView.146")); jlProxyPort.setToolTipText(Messages.getString("ParameterView.147")); jtfProxyPort = new JTextField(); jtfProxyPort.setToolTipText(Messages.getString("ParameterView.147")); jtfProxyPort.setInputVerifier(new InputVerifier() { @Override public boolean shouldYieldFocus(final JComponent input) { return verify(input); } @Override public boolean verify(final JComponent input) { final JTextField tf = (JTextField) input; final String sText = tf.getText(); try { final int iValue = Integer.parseInt(sText); if ((iValue < 0) || (iValue > 65535)) { // port is between 0 and 65535 jbOK.setEnabled(false); return false; } } catch (final Exception e) { return false; } jbOK.setEnabled(true); return true; } }); jlProxyLogin = new JLabel(Messages.getString("ParameterView.142")); jlProxyLogin.setToolTipText(Messages.getString("ParameterView.143")); jtfProxyLogin = new JTextField(); jtfProxyLogin.setToolTipText(Messages.getString("ParameterView.143")); jlProxyPwd = new JLabel(Messages.getString("ParameterView.239")); jlProxyPwd.setToolTipText(Messages.getString("ParameterView.239")); jtfProxyPwd = new JPasswordField(); jtfProxyPwd.setToolTipText(Messages.getString("ParameterView.239")); jlConnectionTO = new JLabel(Messages.getString("ParameterView.160")); jlConnectionTO.setToolTipText(Messages.getString("ParameterView.160")); connectionTO = new JSlider(0, 60); connectionTO.setMajorTickSpacing(10); connectionTO.setMinorTickSpacing(5); connectionTO.setPaintTicks(true); connectionTO.setPaintLabels(true); connectionTO.setToolTipText(Messages.getString("ParameterView.161")); connectionTO.addMouseWheelListener(new DefaultMouseWheelListener(connectionTO)); // Add items JPanel jpProxy = new JPanel(new MigLayout("insets 10,gapy 15, gapx 10", "[][grow,100:300:300]")); jpProxy.setBorder(BorderFactory.createTitledBorder(Messages.getString("ParameterView.268"))); jpProxy.add(jcbProxyNone, "wrap"); jpProxy.add(jcbProxyHttp, "wrap"); jpProxy.add(jcbProxySocks, "wrap"); jpProxy.add(jlProxyHostname); jpProxy.add(jtfProxyHostname, "wrap,grow"); jpProxy.add(jlProxyPort); jpProxy.add(jtfProxyPort, "wrap,grow"); jpProxy.add(jlProxyLogin); jpProxy.add(jtfProxyLogin, "wrap,grow"); jpProxy.add(jlProxyPwd); jpProxy.add(jtfProxyPwd, "wrap,grow"); jpNetwork = new JPanel(new MigLayout("insets 10,gapy 15, gapx 10", "[grow]")); jpNetwork.add(jcbNoneInternetAccess, "wrap"); jpNetwork.add(jlConnectionTO, "split 2"); jpNetwork.add(connectionTO, "wrap,grow,width 200!"); jpNetwork.add(jpProxy, "span"); // - Last.FM jcbAudioScrobbler = new JCheckBox(Messages.getString("ParameterView.199")); jcbAudioScrobbler.setToolTipText(Messages.getString("ParameterView.200")); jcbAudioScrobbler.addActionListener(this); jlASUser = new JLabel(Messages.getString("ParameterView.201")); jtfASUser = new JTextField(); jtfASUser.setToolTipText(Messages.getString("ParameterView.202")); jlASPassword = new JLabel(Messages.getString("ParameterView.203")); jpfASPassword = new JPasswordField(); jpfASPassword.setToolTipText(Messages.getString("ParameterView.204")); jcbEnableLastFMInformation = new JCheckBox(Messages.getString("ParameterView.240")); jcbEnableLastFMInformation.setToolTipText(Messages.getString("ParameterView.241")); // Add items jpLastFM = new JPanel(new MigLayout("insets 10,gapy 15,gapx 10", "[grow]")); jpLastFM.add(jcbEnableLastFMInformation, "wrap"); jpLastFM.add(jcbAudioScrobbler, "wrap"); jpLastFM.add(jlASUser); jpLastFM.add(jtfASUser, "wrap,grow,width 100:300:300"); jpLastFM.add(jlASPassword); jpLastFM.add(jpfASPassword, "wrap,grow,width 100:300:300"); // - Cover jcbAutoCover = new JCheckBox(Messages.getString("ParameterView.148")); jcbAutoCover.setToolTipText(Messages.getString("ParameterView.149")); jcbAutoCover.addActionListener(this); jcbShuffleCover = new JCheckBox(Messages.getString("ParameterView.166")); jcbShuffleCover.setToolTipText(Messages.getString("ParameterView.167")); jcbShuffleCover.addActionListener(this); jlCoverSize = new JLabel(Messages.getString("ParameterView.150")); jlCoverSize.setToolTipText(Messages.getString("ParameterView.151")); jcbCoverSize = new JComboBox(); jcbCoverSize.setToolTipText(Messages.getString("ParameterView.151")); jcbCoverSize.addItem(Messages.getString("ParameterView.211")); jcbCoverSize.addItem(Messages.getString("ParameterView.212")); jcbCoverSize.addItem(Messages.getString("ParameterView.213")); jcbCoverSize.addItem(Messages.getString("ParameterView.214")); jcbCoverSize.addItem(Messages.getString("ParameterView.215")); jcb3dCover = new JCheckBox(Messages.getString("ParameterView.273")); jcb3dCover.setToolTipText(Messages.getString("ParameterView.274")); jlDefaultCoverSearchPattern = new JLabel(); jlDefaultCoverSearchPattern.setText(Messages.getString("ParameterView.256")); jlDefaultCoverSearchPattern.setToolTipText(Messages.getString("ParameterView.257")); jtfDefaultCoverSearchPattern = new JTextField(); jtfDefaultCoverSearchPattern.setToolTipText(Messages.getString("ParameterView.257")); jcbSaveExplorerFriendly = new JCheckBox(Messages.getString("ParameterView.260")); jcbSaveExplorerFriendly.setToolTipText(Messages.getString("ParameterView.261")); jcbSaveExplorerFriendly.addActionListener(this); // Add items jpCovers = new JPanel(new MigLayout("insets 10,gapy 15,gapx 10", "[40%][40%]")); jpCovers.add(jcbShuffleCover, "wrap"); jpCovers.add(jcbAutoCover, "wrap"); jpCovers.add(jcb3dCover, "wrap"); jpCovers.add(jcbSaveExplorerFriendly, "wrap"); jpCovers.add(jlCoverSize); jpCovers.add(jcbCoverSize, "wrap,grow"); jpCovers.add(jlDefaultCoverSearchPattern); jpCovers.add(jtfDefaultCoverSearchPattern, "wrap,grow"); // -- User interface -- // Catalog view jlCatalogPages = new JLabel(Messages.getString("ParameterView.221")); jlCatalogPages.setToolTipText(Messages.getString("ParameterView.222")); jsCatalogPages = new JSlider(0, 1000, Conf.getInt(Const.CONF_CATALOG_PAGE_SIZE)); jsCatalogPages.setMinorTickSpacing(100); jsCatalogPages.setMajorTickSpacing(200); jsCatalogPages.setPaintTicks(true); jsCatalogPages.setPaintLabels(true); jsCatalogPages.setToolTipText(Integer.toString(jsCatalogPages.getValue())); jsCatalogPages.addChangeListener(new ChangeListener() { public void stateChanged(ChangeEvent e) { jsCatalogPages.setToolTipText(Integer.toString(jsCatalogPages.getValue())); } }); jcbShowPopups = new JCheckBox(Messages.getString("ParameterView.228")); jcbShowPopups.addActionListener(alUI); jcbShowSystray = new JCheckBox(Messages.getString("ParameterView.271")); // Disable this option if the tray is not supported by the platform jcbShowSystray.setEnabled(SystemTray.isSupported()); // Disable minimize to systray optino if unchecked jcbShowSystray.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { jcbMinimizeToTray.setSelected(jcbShowSystray.isSelected()); jcbMinimizeToTray.setEnabled(jcbShowSystray.isSelected()); } }); jcbShowSystray.setToolTipText(Messages.getString("ParameterView.272")); jcbMinimizeToTray = new JCheckBox(Messages.getString("ParameterView.281")); // Disable this option if the tray is not supported by the platform jcbMinimizeToTray.setEnabled(SystemTray.isSupported()); jcbMinimizeToTray.setToolTipText(Messages.getString("ParameterView.282")); JLabel jlPerspectiveSize = new JLabel(Messages.getString("ParameterView.246")); jsPerspectiveSize = new JSlider(16, 45, Conf.getInt(Const.CONF_PERSPECTIVE_ICONS_SIZE)); jsPerspectiveSize.setSnapToTicks(true); jsPerspectiveSize.setMajorTickSpacing(8); jsPerspectiveSize.setMinorTickSpacing(1); jsPerspectiveSize.setPaintTicks(true); jsPerspectiveSize.setPaintLabels(true); jsPerspectiveSize.setToolTipText(Messages.getString("ParameterView.246")); jbCatalogRefresh = new JajukButton(Messages.getString("CatalogView.19"), IconLoader.getIcon(JajukIcons.REFRESH)); jbCatalogRefresh.setToolTipText(Messages.getString("CatalogView.3")); jbCatalogRefresh.addActionListener(this); final JXCollapsiblePane catalogView = new JXCollapsiblePane(); catalogView.setLayout(new VerticalLayout(10)); catalogView.setCollapsed(true); final ToggleLink toggle = new ToggleLink(Messages.getString("ParameterView.229"), catalogView); final JPanel jpCatalogSize = new JPanel(); jpCatalogSize.setLayout(new HorizontalLayout()); jpCatalogSize.add(jlCatalogPages); jpCatalogSize.add(jsCatalogPages); catalogView.add(jpCatalogSize); catalogView.add(jbCatalogRefresh); // Font selector jlFonts = new JLabel(Messages.getString("ParameterView.223")); jsFonts = new JSlider(8, 16, Conf.getInt(Const.CONF_FONTS_SIZE)); jsFonts.setSnapToTicks(true); jsFonts.setMajorTickSpacing(1); jsFonts.setMinorTickSpacing(1); jsFonts.setPaintTicks(true); jsFonts.setPaintLabels(true); jsFonts.setToolTipText(Messages.getString("ParameterView.224")); // Notification type jlNotificationType = new JLabel(Messages.getString("ParameterView.275")); jlNotificationType.setToolTipText(Messages.getString("ParameterView.276")); jcbNotificationType = new JComboBox(); jcbNotificationType.setToolTipText(Messages.getString("ParameterView.276")); for (NotificatorTypes type : NotificatorTypes.values()) { String notificatorType = Messages.getString(NOTIFICATOR_PREFIX + type); jcbNotificationType.addItem(notificatorType); } // LaF jlLAF = new JLabel(Messages.getString("ParameterView.43")); jlLAF.setToolTipText(Messages.getString("ParameterView.44")); scbLAF = new SteppedComboBox(); final Map map = SubstanceLookAndFeel.getAllSkins(); // Use a tree set to sort themes alphabetically final Set themes = new TreeSet(map.keySet()); // Add each theme to the combo box for (final String theme : themes) { scbLAF.addItem(theme); } scbLAF.setToolTipText(Messages.getString("ParameterView.44")); // Refresh full GUI at each LAF change as a preview scbLAF.addActionListener(this); // Add items jpUI = new JPanel(new MigLayout("insets 10,gapx 10,gapy 15")); jpUI.add(jcbShowPopups, "wrap"); jpUI.add(jcbShowSystray, "split 2"); jpUI.add(jcbMinimizeToTray, "wrap"); jpUI.add(jlFonts); jpUI.add(jsFonts, "wrap,grow"); jpUI.add(jlNotificationType); jpUI.add(jcbNotificationType, "wrap,grow"); jpUI.add(jlLAF); jpUI.add(scbLAF, "wrap,grow"); jpUI.add(jlPerspectiveSize); jpUI.add(jsPerspectiveSize, "wrap,grow"); jpUI.add(toggle, "wrap,grow"); jpUI.add(catalogView, "wrap,grow,span"); // --OK/cancel panel jbOK = new JButton(Messages.getString("ParameterView.85"), IconLoader.getIcon(JajukIcons.OK)); jbOK.addActionListener(this); jbDefault = new JButton(Messages.getString("ParameterView.86"), IconLoader.getIcon(JajukIcons.DEFAULTS_BIG)); jbDefault.addActionListener(this); // --Global layout // add main panels jtpMain = new JTabbedPane(SwingConstants.TOP); // ScrollPane without border class JajukJScrollPane extends JScrollPane { private static final long serialVersionUID = 4564343623724771988L; private JajukJScrollPane(final Component view) { super(view); setBorder(null); } } jtpMain.addTab(Messages.getString("ParameterView.33"), new JajukJScrollPane(jpOptions)); jtpMain.addTab(Messages.getString("ParameterView.226"), new JajukJScrollPane(jpModes)); jtpMain.addTab(Messages.getString("ParameterView.225"), new JajukJScrollPane(jpUI)); jtpMain.addTab(Messages.getString("ParameterView.19"), new JajukJScrollPane(jpStart)); jtpMain.addTab(Messages.getString("ParameterView.98"), new JajukJScrollPane(jpTags)); jtpMain.addTab(Messages.getString("ParameterView.8"), new JajukJScrollPane(jpHistory)); jtpMain.addTab(Messages.getString("ParameterView.235"), new JajukJScrollPane(jpLastFM)); jtpMain.addTab(Messages.getString("ParameterView.159"), new JajukJScrollPane(jpCovers)); jtpMain.addTab(Messages.getString("ParameterView.26"), new JajukJScrollPane(jpConfirmations)); jtpMain.addTab(Messages.getString("ParameterView.139"), new JajukJScrollPane(jpNetwork)); jtpMain.addTab(Messages.getString("ParameterView.115"), new JajukJScrollPane(jpAdvanced)); try { // Reload stored selected index jtpMain.setSelectedIndex(Conf.getInt(Const.CONF_OPTIONS_TAB)); } catch (final Exception e) { // an error can occur if a new release brings or remove tabs Log.error(e); jtpMain.setSelectedIndex(0); } jtpMain.addChangeListener(this); setLayout(new MigLayout("insets 10,gapx 10", "[grow]", "[grow][]")); add(jtpMain, "wrap,span,grow"); add(jbOK, "split 2,right,sg group1"); add(jbDefault, "sg group1"); // update widgets state updateSelection(); ObservationManager.register(this); } /* * (non-Javadoc) * * @see java.awt.event.ItemListener#itemStateChanged(java.awt.event.ItemEvent) */ public void itemStateChanged(final ItemEvent e) { if (e.getSource() == jrbFile) { // jrbFile has been selected or // deselected sbSearch.setEnabled(jrbFile.isSelected()); } } /* * (non-Javadoc) * * @see javax.swing.event.ChangeListener#stateChanged(javax.swing.event.ChangeEvent ) */ public void stateChanged(final ChangeEvent e) { // when changing tab, store it for future jajuk sessions Conf.setProperty(Const.CONF_OPTIONS_TAB, Integer.toString(jtpMain.getSelectedIndex())); } /* * (non-Javadoc) * * @see org.jajuk.base.Observer#update(org.jajuk.base.Event) */ public void update(final JajukEvent event) { final JajukEvents subject = event.getSubject(); if (JajukEvents.PARAMETERS_CHANGE.equals(subject)) { // Ignore this event is thrown by this view itself (to avoid loosing // already set options) if ((event.getDetails() != null) && (event.getDetails().get(Const.DETAIL_ORIGIN) != null) && event.getDetails().get(Const.DETAIL_ORIGIN).equals(this)) { return; } SwingUtilities.invokeLater(new Runnable() { @Override public void run() { updateSelection(); } }); } } /** * Set widgets to specified value in options. */ private void updateSelection() { jtfHistory.setText(Conf.getString(Const.CONF_HISTORY)); if (Conf.getString(Const.CONF_STARTUP_MODE).equals(Const.STARTUP_MODE_ITEM)) { jrbFile.setSelected(true); sbSearch.setEnabled(true); } else if (Conf.getString(Const.CONF_STARTUP_MODE).equals(Const.STARTUP_MODE_LAST)) { jrbLast.setSelected(true); } else if (Conf.getString(Const.CONF_STARTUP_MODE).equals(Const.STARTUP_MODE_LAST_KEEP_POS)) { jrbLastKeepPos.setSelected(true); } else if (Conf.getString(Const.CONF_STARTUP_MODE).equals(Const.STARTUP_MODE_NOTHING)) { jrbNothing.setSelected(true); } else if (Conf.getString(Const.CONF_STARTUP_MODE).equals(Const.STARTUP_MODE_SHUFFLE)) { jrbShuffle.setSelected(true); } else if (Conf.getString(Const.CONF_STARTUP_MODE).equals(Const.STARTUP_MODE_BESTOF)) { jrbBestof.setSelected(true); } else if (Conf.getString(Const.CONF_STARTUP_MODE).equals(Const.STARTUP_MODE_NOVELTIES)) { jrbNovelties.setSelected(true); } // set chosen track in file selection String conf = Conf.getString(Const.CONF_STARTUP_ITEM); String item = conf.substring(conf.indexOf('/') + 1, conf.length()); if (!StringUtils.isBlank(item)) { if (conf.matches(SearchResultType.FILE.name() + ".*")) { File file = FileManager.getInstance().getFileByID(item); if (file != null) { sbSearch.setText(file.getTrack().getName()); } else { // the file exists no more, remove its id as startup file Conf.setProperty(Const.CONF_STARTUP_ITEM, ""); } } else if (conf.matches(SearchResultType.WEBRADIO.name() + ".*")) { WebRadio radio = WebRadioManager.getInstance().getWebRadioByName(item); if (radio != null) { sbSearch.setText(radio.getName()); } else { // the file exists no more, remove its id as startup file Conf.setProperty(Const.CONF_STARTUP_ITEM, ""); } } } else { sbSearch.setText(""); } // Confirmations jcbBeforeDelete.setSelected(Conf.getBoolean(Const.CONF_CONFIRMATIONS_DELETE_FILE)); jcbBeforeExit.setSelected(Conf.getBoolean(Const.CONF_CONFIRMATIONS_EXIT)); jcbBeforeRemoveDevice.setSelected(Conf.getBoolean(Const.CONF_CONFIRMATIONS_REMOVE_DEVICE)); jcbBeforeDeleteCover.setSelected(Conf.getBoolean(Const.CONF_CONFIRMATIONS_DELETE_COVER)); jcbBeforeClearingHistory.setSelected(Conf.getBoolean(Const.CONF_CONFIRMATIONS_CLEAR_HISTORY)); jcbBeforeResetingRatings.setSelected(Conf.getBoolean(Const.CONF_CONFIRMATIONS_RESET_RATINGS)); jcbBeforeRefactorFiles.setSelected(Conf.getBoolean(Const.CONF_CONFIRMATIONS_REFACTOR_FILES)); // options jcbDisplayUnmounted.setSelected(Conf.getBoolean(Const.CONF_OPTIONS_HIDE_UNMOUNTED)); jcbDefaultActionClick.setSelected(Conf.getBoolean(Const.CONF_OPTIONS_PUSH_ON_CLICK)); jcbDefaultActionDrop.setSelected(Conf.getBoolean(Const.CONF_OPTIONS_PUSH_ON_DROP)); jcbHotkeys.setSelected(Conf.getBoolean(Const.CONF_OPTIONS_HOTKEYS)); String rightLanguageDesc = LocaleManager.getDescForLocale(Conf .getString(Const.CONF_OPTIONS_LANGUAGE)); // Select the right language int index = 0; for (String desc : LocaleManager.getLocalesDescs()) { if (desc.equals(rightLanguageDesc)) { scbLanguage.setSelectedIndex(index); break; } index++; } scbLanguage.addActionListener(this); scbLogLevel.setSelectedIndex(Integer.parseInt(Conf.getString(Const.CONF_OPTIONS_LOG_LEVEL))); introLength.setValue(Conf.getInt(Const.CONF_OPTIONS_INTRO_LENGTH)); introPosition.setValue(Conf.getInt(Const.CONF_OPTIONS_INTRO_BEGIN)); jtfBestofSize.setText(Conf.getString(Const.CONF_BESTOF_TRACKS_SIZE)); jtfNoveltiesAge.setText(Conf.getString(Const.CONF_OPTIONS_NOVELTIES_AGE)); jtfVisiblePlanned.setText(Conf.getString(Const.CONF_OPTIONS_VISIBLE_PLANNED)); crossFadeDuration.setValue(Conf.getInt(Const.CONF_FADE_DURATION)); jcbUseParentDir.setSelected(Conf.getBoolean(Const.CONF_TAGS_USE_PARENT_DIR)); jcbDropPlayedTracksFromQueue.setSelected(Conf .getBoolean(Const.CONF_DROP_PLAYED_TRACKS_FROM_QUEUE)); jcbUseVolnorm.setSelected(Conf.getBoolean(Const.CONF_USE_VOLNORM)); // advanced final int iBackupSize = Conf.getInt(Const.CONF_BACKUP_SIZE); if (iBackupSize <= 0) { // backup size =0 means no backup jcbBackup.setSelected(false); backupSize.setEnabled(false); } else { jcbBackup.setSelected(true); backupSize.setEnabled(true); } backupSize.setValue(iBackupSize); jcbCollectionEncoding.setSelectedItem(Conf.getString(Const.CONF_COLLECTION_CHARSET)); jtfRefactorPattern.setText(Conf.getString(Const.CONF_PATTERN_REFACTOR)); jtfAnimationPattern.setText(Conf.getString(Const.CONF_PATTERN_ANIMATION)); jtfFrameTitle.setText(Conf.getString(Const.CONF_PATTERN_FRAME_TITLE)); jtfBalloonNotifierPattern.setText(Conf.getString(Const.CONF_PATTERN_BALLOON_NOTIFIER)); jtfInformationPattern.setText(Conf.getString(Const.CONF_PATTERN_INFORMATION)); jtfMPlayerPath.setText(Conf.getString(Const.CONF_MPLAYER_PATH_FORCED)); jtfMPlayerArgs.setText(Conf.getString(Const.CONF_MPLAYER_ARGS)); jtfEnvVariables.setText(Conf.getString(Const.CONF_ENV_VARIABLES)); jtfExplorerPath.setText(Conf.getString(Const.CONF_EXPLORER_PATH)); // Network jcbNoneInternetAccess.setSelected(Conf.getBoolean(Const.CONF_NETWORK_NONE_INTERNET_ACCESS)); final boolean bUseProxy = Conf.getBoolean(Const.CONF_NETWORK_USE_PROXY); jcbProxyNone.setSelected(bUseProxy); jtfProxyHostname.setText(Conf.getString(Const.CONF_NETWORK_PROXY_HOSTNAME)); jtfProxyHostname.setEnabled(bUseProxy); jlProxyHostname.setEnabled(bUseProxy); jtfProxyPort.setText(Conf.getString(Const.CONF_NETWORK_PROXY_PORT)); jtfProxyPort.setEnabled(bUseProxy); jlProxyPort.setEnabled(bUseProxy); jtfProxyLogin.setText(Conf.getString(Const.CONF_NETWORK_PROXY_LOGIN)); jtfProxyLogin.setEnabled(bUseProxy); jlProxyLogin.setEnabled(bUseProxy); jtfProxyPwd.setText(UtilString.rot13(Conf.getString(Const.CONF_NETWORK_PROXY_PWD))); jtfProxyPwd.setEnabled(bUseProxy); jlProxyPwd.setEnabled(bUseProxy); connectionTO.setValue(Conf.getInt(Const.CONF_NETWORK_CONNECTION_TO)); if (!Conf.getBoolean(Const.CONF_NETWORK_USE_PROXY)) { jcbProxyNone.setSelected(true); } else if (Const.PROXY_TYPE_HTTP.equals(Conf.getString(Const.CONF_NETWORK_PROXY_TYPE))) { jcbProxyHttp.setSelected(true); } else if (Const.PROXY_TYPE_SOCKS.equals(Conf.getString(Const.CONF_NETWORK_PROXY_TYPE))) { jcbProxySocks.setSelected(true); } // Covers jcbAutoCover.setSelected(Conf.getBoolean(Const.CONF_COVERS_AUTO_COVER)); jlCoverSize.setEnabled(Conf.getBoolean(Const.CONF_COVERS_AUTO_COVER)); jcb3dCover.setSelected(Conf.getBoolean(Const.CONF_COVERS_MIRROW_COVER)); jcbCoverSize.setEnabled(Conf.getBoolean(Const.CONF_COVERS_AUTO_COVER)); jcbCoverSize.setSelectedIndex(Conf.getInt(Const.CONF_COVERS_SIZE)); jcbShuffleCover.setSelected(Conf.getBoolean(Const.CONF_COVERS_SHUFFLE)); jcbSaveExplorerFriendly.setSelected(Conf.getBoolean(Const.CONF_COVERS_SAVE_EXPLORER_FRIENDLY)); jtfDefaultCoverSearchPattern.setText(Conf.getString(Const.FILE_DEFAULT_COVER)); jcbAudioScrobbler.setSelected(Conf.getBoolean(Const.CONF_LASTFM_AUDIOSCROBBLER_ENABLE)); jcbEnableLastFMInformation.setSelected(Conf.getBoolean(Const.CONF_LASTFM_INFO)); jtfASUser.setText(Conf.getString(Const.CONF_LASTFM_USER)); jpfASPassword.setText(UtilString.rot13(Conf.getString(Const.CONF_LASTFM_PASSWORD))); if (!Conf.getBoolean(Const.CONF_LASTFM_AUDIOSCROBBLER_ENABLE)) { jlASUser.setEnabled(false); jtfASUser.setEnabled(false); jlASPassword.setEnabled(false); jpfASPassword.setEnabled(false); } // UI String notificatorType = Messages.getString(NOTIFICATOR_PREFIX + Conf.getString(Const.CONF_UI_NOTIFICATOR_TYPE)); jcbNotificationType.setSelectedItem(notificatorType); jcbShowSystray.setSelected(Conf.getBoolean(Const.CONF_SHOW_SYSTRAY)); jcbMinimizeToTray.setSelected(Conf.getBoolean(Const.CONF_MINIMIZE_TO_TRAY)); scbLAF.removeActionListener(this); scbLAF.setSelectedItem(Conf.getString(Const.CONF_OPTIONS_LNF)); scbLAF.addActionListener(this); jsPerspectiveSize.setValue(Conf.getInt(Const.CONF_PERSPECTIVE_ICONS_SIZE)); } /* * (non-Javadoc) * * @see java.awt.Container#removeAll() */ @Override public void removeAll() { // We have to override removeAll() to work around a memory leak related to SearchBox.. // make sure that the search box stops waking to free up the reference to the Timer sbSearch.close(); super.removeAll(); } /* * (non-Javadoc) * * @see org.jajuk.ui.views.ViewAdapter#cleanup() */ @Override public void cleanup() { // make sure that the search box stops to free up the reference to the Timer sbSearch.close(); super.cleanup(); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/views/WikipediaView.java0000644000175000017500000002736311720500104025174 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.views; import java.awt.FlowLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.FileNotFoundException; import java.net.URL; import java.util.HashSet; import java.util.Locale; import java.util.Set; import javax.swing.BorderFactory; import javax.swing.ButtonGroup; import javax.swing.JButton; import javax.swing.JComboBox; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JToggleButton; import javax.swing.JToolBar; import net.miginfocom.swing.MigLayout; import org.jajuk.events.JajukEvent; import org.jajuk.events.JajukEvents; import org.jajuk.events.ObservationManager; import org.jajuk.services.players.QueueModel; import org.jajuk.ui.actions.ActionManager; import org.jajuk.ui.actions.JajukAction; import org.jajuk.ui.actions.JajukActions; import org.jajuk.ui.widgets.JajukHtmlPanel; import org.jajuk.ui.widgets.JajukJToolbar; import org.jajuk.util.Conf; import org.jajuk.util.Const; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; import org.jajuk.util.LocaleManager; import org.jajuk.util.Messages; import org.jajuk.util.UtilFeatures; import org.jajuk.util.UtilSystem; import org.jajuk.util.log.Log; /** * Wikipedia view. */ public class WikipediaView extends ViewAdapter implements ActionListener { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** DOCUMENT_ME. */ JLabel jlLanguage; /** DOCUMENT_ME. */ JComboBox jcbLanguage; /** Cobra web browser. */ JajukHtmlPanel browser; /** DOCUMENT_ME. */ JButton jbCopy; /** DOCUMENT_ME. */ JButton jbLaunchInExternalBrowser; /** DOCUMENT_ME. */ JToggleButton jbArtistSearch; /** DOCUMENT_ME. */ JToggleButton jbAlbumSearch; /** DOCUMENT_ME. */ JToggleButton jbTrackSearch; /** Language index. */ int indexLang = 0; /** * DOCUMENT_ME. */ enum Type { /** DOCUMENT_ME. */ ARTIST, /** DOCUMENT_ME. */ ALBUM, /** DOCUMENT_ME. */ TRACK } /** DOCUMENT_ME. */ Type type = Type.ARTIST; /** Current search. */ String search = null; /* * (non-Javadoc) * * @see org.jajuk.ui.views.IView#getDesc() */ @Override public String getDesc() { return Messages.getString("WikipediaView.0"); } /* * (non-Javadoc) * * @see org.jajuk.ui.views.IView#populate() */ @Override public void initUI() { jlLanguage = new JLabel(Messages.getString("WikipediaView.1")); jcbLanguage = new JComboBox(); for (String sDesc : LocaleManager.getLocalesDescs()) { jcbLanguage.addItem(sDesc); } // get stored language jcbLanguage.setSelectedItem(LocaleManager.getDescForLocale(Conf .getString(Const.CONF_WIKIPEDIA_LANGUAGE))); jcbLanguage.addActionListener(this); // Buttons JajukAction aCopy = ActionManager.getAction(JajukActions.COPY_TO_CLIPBOARD); jbCopy = new JButton(aCopy); if (UtilSystem.isBrowserSupported()) { jbLaunchInExternalBrowser = new JButton(ActionManager .getAction(JajukActions.LAUNCH_IN_BROWSER)); // Remove text inside the buttons jbLaunchInExternalBrowser.setText(null); } jbCopy.setText(null); ButtonGroup bg = new ButtonGroup(); jbArtistSearch = new JToggleButton(IconLoader.getIcon(JajukIcons.ARTIST), false); jbArtistSearch.setToolTipText(Messages.getString("WikipediaView.5")); // Select artist search (default) jbArtistSearch.setSelected(true); jbArtistSearch.addActionListener(this); jbAlbumSearch = new JToggleButton(IconLoader.getIcon(JajukIcons.ALBUM), true); jbAlbumSearch.setToolTipText(Messages.getString("WikipediaView.6")); jbAlbumSearch.addActionListener(this); jbTrackSearch = new JToggleButton(IconLoader.getIcon(JajukIcons.TRACK), false); jbTrackSearch.setToolTipText(Messages.getString("WikipediaView.7")); jbTrackSearch.addActionListener(this); // Group this three mutual exclusive buttons bg.add(jbArtistSearch); bg.add(jbAlbumSearch); bg.add(jbTrackSearch); JToolBar jtb = new JajukJToolbar(); jtb.setBorder(BorderFactory.createEmptyBorder(0, 5, 0, 5)); // Add items jtb.add(jbArtistSearch); jtb.add(jbAlbumSearch); jtb.add(jbTrackSearch); jtb.addSeparator(); jtb.add(jbCopy); if (UtilSystem.isBrowserSupported()) { jtb.add(jbLaunchInExternalBrowser); jtb.addSeparator(); } jtb.add(jcbLanguage); JPanel jpCommand = new JPanel(); jpCommand.setBorder(BorderFactory.createEtchedBorder()); jpCommand.setLayout(new FlowLayout(FlowLayout.LEFT)); jpCommand.add(jtb); // global layout setLayout(new MigLayout("ins 0", "[grow]", "[][grow]")); browser = new JajukHtmlPanel(); add(jpCommand, "growx,wrap"); add(browser, "grow"); // Display default page at startup is none track launch // avoid to launch this if a track is playing // to avoid thread concurrency if (QueueModel.getPlayingFile() == null) { reset(); } // subscriptions to events ObservationManager.register(WikipediaView.this); // Force initial message refresh UtilFeatures.updateStatus(this); } /* (non-Javadoc) * @see org.jajuk.events.Observer#getRegistrationKeys() */ @Override public Set getRegistrationKeys() { Set eventSubjectSet = new HashSet(); eventSubjectSet.add(JajukEvents.FILE_LAUNCHED); eventSubjectSet.add(JajukEvents.ZERO); eventSubjectSet.add(JajukEvents.WEBRADIO_LAUNCHED); eventSubjectSet.add(JajukEvents.ARTIST_CHANGED); eventSubjectSet.add(JajukEvents.ALBUM_CHANGED); eventSubjectSet.add(JajukEvents.TRACK_CHANGED); eventSubjectSet.add(JajukEvents.PERSPECTIVE_CHANGED); return eventSubjectSet; } /* * (non-Javadoc) * * @see org.jajuk.ui.Observer#update(java.lang.String) */ @Override public void update(JajukEvent event) { JajukEvents subject = event.getSubject(); // Make a search after a stop period if (subject.equals(JajukEvents.FILE_LAUNCHED) || subject.equals(JajukEvents.PERSPECTIVE_CHANGED) || subject.equals(JajukEvents.WEBRADIO_LAUNCHED)) { // If current state is stopped, reset page if (!QueueModel.isPlayingTrack()) { reset(); return; } // Launch search launchSearch(false); } // Reset the page when stopping else if (subject.equals(JajukEvents.ZERO)) { reset(); } // User changed current track tags, so we have to reload // new artist wikipedia page else if (subject.equals(JajukEvents.ARTIST_CHANGED) || subject.equals(JajukEvents.ALBUM_CHANGED) || subject.equals(JajukEvents.TRACK_CHANGED)) { update(new JajukEvent(JajukEvents.FILE_LAUNCHED)); } } /** * Perform wikipedia search. * * @param bForceReload force the page display */ private void launchSearch(final boolean bForceReload) { // do nothing without internet, // TODO: display useful text that states this... if (Conf.getBoolean(Const.CONF_NETWORK_NONE_INTERNET_ACCESS)) { try { browser.setUnknown(); } catch (Exception e) { Log.error(e); } return; } Thread t = new Thread("Wikipedia Search Thread") { @Override public void run() { try { String lSearch = null; if (QueueModel.getPlayingFile() != null) { if (type == Type.ARTIST) { lSearch = QueueModel.getPlayingFile().getTrack().getArtist().getName2(); // don't display page if item is unknown if (Messages.getString(UNKNOWN_ARTIST).equals(lSearch)) { lSearch = null; } } else if (type == Type.ALBUM) { lSearch = QueueModel.getPlayingFile().getTrack().getAlbum().getName2(); // don't display page if item is unknown if (Messages.getString(UNKNOWN_ALBUM).equals(lSearch)) { lSearch = null; } } else if (type == Type.TRACK) { lSearch = QueueModel.getPlayingFile().getTrack().getName(); } } // If search is still null, display an nothing found page if (lSearch == null) { browser.setUnknown(); return; } // Avoid reloading an existing page if (!bForceReload && lSearch.equals(WikipediaView.this.search)) { return; } // Store the search to avoid future identical searches WikipediaView.this.search = lSearch; URL url = new URL(("http://" + LocaleManager.getLocaleForDesc((String) jcbLanguage.getSelectedItem()) + ".wikipedia.org/wiki/" + lSearch).replaceAll(" ", "_")); Log.debug("Wikipedia search: {{" + url + "}}"); jbCopy.putClientProperty(Const.DETAIL_CONTENT, url.toExternalForm()); if (UtilSystem.isBrowserSupported()) { jbLaunchInExternalBrowser.putClientProperty(Const.DETAIL_CONTENT, url.toExternalForm()); } browser.setURL(url, LocaleManager .getLocaleForDesc((String) jcbLanguage.getSelectedItem()).toString()); } catch (FileNotFoundException e) { // only report a warning for FileNotFoundException and do not show a // stacktrace in the logfile as it is expected in many cases where the // name is not found on Wikipedia Log.warn("Could not load URL, no content found at specified address: {{" + e.getMessage() + "}}"); } catch (Exception e) { Log.error(e); } } }; t.setPriority(Thread.MIN_PRIORITY); t.start(); } /* * Reset view */ /** * Reset. * DOCUMENT_ME */ private void reset() { // Reset current search this.search = null; // Display jajuk page (in a thread to avoid freezing UI) new Thread("Wikipedia Reset Thread") { @Override public void run() { if (browser != null) { try { browser.clearDocument(); browser.setToolTipText(""); } catch (Exception e) { Log.error(e); } } } }.start(); } /* * (non-Javadoc) * * @see javax.swing.event.ChangeListener#stateChanged(javax.swing.event.ChangeEvent) */ @Override public void actionPerformed(ActionEvent arg0) { if (arg0.getSource() == jcbLanguage) { // update index Locale locale = LocaleManager.getLocaleForDesc((String) jcbLanguage.getSelectedItem()); Conf.setProperty(Const.CONF_WIKIPEDIA_LANGUAGE, locale.getLanguage()); // force launch wikipedia search for this language launchSearch(true); } else if (arg0.getSource() == jbAlbumSearch) { type = Type.ALBUM; // force event launchSearch(true); } else if (arg0.getSource() == jbArtistSearch) { type = Type.ARTIST; // force event launchSearch(true); } else if (arg0.getSource() == jbTrackSearch) { type = Type.TRACK; // force event launchSearch(true); } } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/views/StatView.java0000644000175000017500000004242611720500104024176 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.views; import java.text.DateFormat; import java.text.NumberFormat; import java.text.SimpleDateFormat; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Set; import javax.swing.SwingUtilities; import net.miginfocom.swing.MigLayout; import org.jajuk.base.Device; import org.jajuk.base.DeviceManager; import org.jajuk.base.File; import org.jajuk.base.FileManager; import org.jajuk.base.Genre; import org.jajuk.base.GenreManager; import org.jajuk.base.Track; import org.jajuk.base.TrackManager; import org.jajuk.events.JajukEvent; import org.jajuk.events.JajukEvents; import org.jajuk.events.ObservationManager; import org.jajuk.util.Messages; import org.jajuk.util.ReadOnlyIterator; import org.jajuk.util.UtilGUI; import org.jajuk.util.UtilString; import org.jajuk.util.log.Log; import org.jfree.chart.ChartFactory; import org.jfree.chart.ChartPanel; import org.jfree.chart.JFreeChart; import org.jfree.chart.axis.CategoryAxis; import org.jfree.chart.axis.CategoryAxis3D; import org.jfree.chart.axis.CategoryLabelPosition; import org.jfree.chart.axis.CategoryLabelPositions; import org.jfree.chart.axis.CategoryLabelWidthType; import org.jfree.chart.axis.NumberAxis3D; import org.jfree.chart.axis.ValueAxis; import org.jfree.chart.labels.StandardCategoryToolTipGenerator; import org.jfree.chart.labels.StandardPieSectionLabelGenerator; import org.jfree.chart.labels.StandardPieToolTipGenerator; import org.jfree.chart.plot.CategoryPlot; import org.jfree.chart.plot.PiePlot; import org.jfree.chart.plot.PlotOrientation; import org.jfree.chart.renderer.category.BarRenderer3D; import org.jfree.chart.urls.StandardCategoryURLGenerator; import org.jfree.data.category.CategoryDataset; import org.jfree.data.general.DatasetUtilities; import org.jfree.data.general.DefaultPieDataset; import org.jfree.text.TextBlockAnchor; import org.jfree.ui.RectangleAnchor; import org.jfree.ui.TextAnchor; import org.jfree.util.SortOrder; /** * Statistics view *

    * Help perspective. */ public class StatView extends ViewAdapter { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /* * (non-Javadoc) * * @see org.jajuk.ui.IView#display() */ @Override public void initUI() { setLayout(new MigLayout("ins 0,gapx 4,gapy 5", "[grow][grow]", "[grow][grow]")); ObservationManager.register(this); update(new JajukEvent(JajukEvents.DEVICE_REFRESH)); } /* (non-Javadoc) * @see org.jajuk.events.Observer#getRegistrationKeys() */ @Override public Set getRegistrationKeys() { Set eventSubjectSet = new HashSet(); eventSubjectSet.add(JajukEvents.DEVICE_DELETE); eventSubjectSet.add(JajukEvents.DEVICE_REFRESH); return eventSubjectSet; } /** * Genre repartition pie. * * @return the chart */ private ChartPanel createGenreRepartition() { try { DefaultPieDataset pdata = null; JFreeChart jfchart = null; // data pdata = new DefaultPieDataset(); int iTotal = TrackManager.getInstance().getElementCount(); double dOthers = 0; // Prepare a map genre -> nb tracks Map genreNbTracks = new HashMap(GenreManager.getInstance() .getElementCount()); ReadOnlyIterator it = TrackManager.getInstance().getTracksIterator(); while (it.hasNext()) { Track track = it.next(); Genre genre = track.getGenre(); Integer nbTracks = genreNbTracks.get(genre); if (nbTracks == null) { genreNbTracks.put(genre, 1); } else { genreNbTracks.put(genre, nbTracks + 1); } } // Cleanup genre with weight < 5 % for (Map.Entry entry : genreNbTracks.entrySet()) { double d = entry.getValue(); if (iTotal > 0 && d / iTotal < 0.05) { // less than 5% -> go to others dOthers += d; } else { double dValue = Math.round(100 * (d / iTotal)); pdata.setValue(entry.getKey().getName2(), dValue); } } if (iTotal > 0 && dOthers > 0) { double dValue = Math.round(100 * (dOthers / iTotal)); pdata.setValue(Messages.getString("StatView.0"), dValue); } // chart jfchart = ChartFactory.createPieChart3D(Messages.getString("StatView.1"), pdata, true, true, true); // set the background color for the chart... PiePlot plot = (PiePlot) jfchart.getPlot(); plot.setLabelFont(PiePlot.DEFAULT_LABEL_FONT); plot.setNoDataMessage(Messages.getString("StatView.2")); plot.setForegroundAlpha(0.5f); plot.setBackgroundAlpha(0.5f); plot.setLabelGenerator(new StandardPieSectionLabelGenerator("{0} = {2}")); plot.setToolTipGenerator(new StandardPieToolTipGenerator("{0} = {2}")); return new ChartPanel(jfchart); } catch (RuntimeException e) { Log.error(e); return null; } } /** * Device size pie. * * @return the chart */ private ChartPanel createDeviceRepartition() { try { DefaultPieDataset pdata = null; JFreeChart jfchart = null; // data pdata = new DefaultPieDataset(); // prepare devices long lTotalSize = 0; double dOthers = 0; List devices = DeviceManager.getInstance().getDevices(); long[] lSizes = new long[DeviceManager.getInstance().getElementCount()]; ReadOnlyIterator it = FileManager.getInstance().getFilesIterator(); while (it.hasNext()) { File file = it.next(); lTotalSize += file.getSize(); lSizes[devices.indexOf(file.getDirectory().getDevice())] += file.getSize(); } for (Device device : devices) { long lSize = lSizes[devices.indexOf(device)]; if (lTotalSize > 0 && (double) lSize / lTotalSize < 0.05) { // less than 5% -> go to others dOthers += lSize; } else { double dValue = Math.round((double) lSize / 1073741824); pdata.setValue(device.getName(), dValue); } } if (dOthers > 0) { double dValue = Math.round((dOthers / 1073741824)); pdata.setValue(Messages.getString("StatView.3"), dValue); } // chart jfchart = ChartFactory.createPieChart3D(Messages.getString("StatView.4"), pdata, true, true, true); // set the background color for the chart... PiePlot plot = (PiePlot) jfchart.getPlot(); plot.setLabelFont(PiePlot.DEFAULT_LABEL_FONT); plot.setNoDataMessage(Messages.getString("StatView.5")); plot.setForegroundAlpha(0.5f); plot.setBackgroundAlpha(0.5f); plot.setLabelGenerator(new StandardPieSectionLabelGenerator("{0} = {1} GB ({2})")); plot.setToolTipGenerator(new StandardPieToolTipGenerator("{0} = {1} GB ({2})")); return new ChartPanel(jfchart); } catch (RuntimeException e) { Log.error(e); return null; } } /** * Collection size bars. * * @return the chart */ private ChartPanel createCollectionSize() { try { final DateFormat additionFormatter = UtilString.getAdditionDateFormatter(); CategoryDataset cdata = null; JFreeChart jfchart = null; int iMonthsNumber = 5; // number of mounts we show, mounts // before are set together in 'before' long lSizeByMonth[] = new long[iMonthsNumber + 1]; // contains size ( in Go ) for each month, first cell is before // data int[] iMonths = getMonths(iMonthsNumber); ReadOnlyIterator tracks = TrackManager.getInstance().getTracksIterator(); while (tracks.hasNext()) { Track track = tracks.next(); int i = Integer.parseInt(additionFormatter.format(track.getDiscoveryDate())) / 100; for (int j = 0; j < iMonthsNumber + 1; j++) { if (i <= iMonths[j]) { lSizeByMonth[j] += track.getTotalSize(); } } } double[][] data = new double[1][iMonthsNumber + 1]; for (int i = 0; i < iMonthsNumber + 1; i++) { data[0][i] = (double) lSizeByMonth[i] / 1073741824; } cdata = DatasetUtilities.createCategoryDataset(new String[] { "" }, getMonthsLabels(iMonthsNumber), data); // chart, use local copy of method to use better format string for // tooltips jfchart = createBarChart3D(Messages.getString("StatView.7"), // chart // title Messages.getString("StatView.8"), // domain axis label Messages.getString("StatView.9"), // range axis label cdata, // data PlotOrientation.VERTICAL, // orientation false, // include legend true, // tooltips false, // urls "{1} = {2} GB"); CategoryPlot plot = jfchart.getCategoryPlot(); CategoryAxis axis = plot.getDomainAxis(); new CategoryLabelPosition(RectangleAnchor.TOP, TextBlockAnchor.TOP_RIGHT, TextAnchor.TOP_RIGHT, -Math.PI / 8.0, CategoryLabelWidthType.CATEGORY, 0); axis.setCategoryLabelPositions(CategoryLabelPositions.STANDARD); // set the background color for the chart... plot.setNoDataMessage(Messages.getString("StatView.10")); plot.setForegroundAlpha(0.5f); plot.setBackgroundAlpha(0.5f); // plot.setBackgroundImage(IconLoader.IMAGES_STAT_PAPER).getImage()); return new ChartPanel(jfchart); } catch (Exception e) { Log.error(e); return null; } } // copied method from ChartFactory to overwrite format of tooltips which is // otherwise hardcoded in ChartFactory /** * Creates the bar chart3 d. * DOCUMENT_ME * * @param title DOCUMENT_ME * @param categoryAxisLabel DOCUMENT_ME * @param valueAxisLabel DOCUMENT_ME * @param dataset DOCUMENT_ME * @param orientation DOCUMENT_ME * @param legend DOCUMENT_ME * @param tooltips DOCUMENT_ME * @param urls DOCUMENT_ME * @param format DOCUMENT_ME * * @return the j free chart */ public static JFreeChart createBarChart3D(String title, String categoryAxisLabel, String valueAxisLabel, CategoryDataset dataset, PlotOrientation orientation, boolean legend, boolean tooltips, boolean urls, String format) { if (orientation == null) throw new IllegalArgumentException("Null 'orientation' argument."); CategoryAxis categoryAxis = new CategoryAxis3D(categoryAxisLabel); ValueAxis valueAxis = new NumberAxis3D(valueAxisLabel); BarRenderer3D renderer = new BarRenderer3D(); if (tooltips) renderer.setBaseToolTipGenerator(new StandardCategoryToolTipGenerator(format, NumberFormat .getInstance())); if (urls) renderer.setBaseItemURLGenerator(new StandardCategoryURLGenerator()); CategoryPlot plot = new CategoryPlot(dataset, categoryAxis, valueAxis, renderer); plot.setOrientation(orientation); if (orientation == PlotOrientation.HORIZONTAL) { plot.setRowRenderingOrder(SortOrder.DESCENDING); plot.setColumnRenderingOrder(SortOrder.DESCENDING); } plot.setForegroundAlpha(0.75F); JFreeChart chart = new JFreeChart(title, JFreeChart.DEFAULT_TITLE_FONT, plot, legend); ChartFactory.getChartTheme().apply(chart); return chart; } /** * Track number bars. * * @return the chart */ private ChartPanel createTrackNumber() { try { final DateFormat additionFormatter = UtilString.getAdditionDateFormatter(); CategoryDataset cdata = null; JFreeChart jfchart = null; // number of months we show, mounts // before are set together in 'before' int iMonthsNumber = 5; // contains number of tracks for each month, first cell is 'before' // data int iTracksByMonth[] = new int[iMonthsNumber + 1]; int[] iMounts = getMonths(iMonthsNumber); ReadOnlyIterator tracks = TrackManager.getInstance().getTracksIterator(); while (tracks.hasNext()) { Track track = tracks.next(); int i = Integer.parseInt(additionFormatter.format(track.getDiscoveryDate())) / 100; for (int j = 0; j < iMonthsNumber + 1; j++) { if (i <= iMounts[j]) { iTracksByMonth[j]++; } } } double[][] data = new double[1][iMonthsNumber + 1]; // cannot use System.arraycopy() here because we have different types in // the arrays... // System.arraycopy(iTracksByMonth, 0, data[0], 0, iMonthsNumber); for (int i = 0; i < iMonthsNumber + 1; i++) { data[0][i] = iTracksByMonth[i]; } cdata = DatasetUtilities.createCategoryDataset(new String[] { "" }, getMonthsLabels(iMonthsNumber), data); // chart, use local copy of method to use better format string for // tooltips jfchart = createBarChart3D(Messages.getString("StatView.12"), // chart // title Messages.getString("StatView.13"), // domain axis label Messages.getString("StatView.14"), // range axis label cdata, // data PlotOrientation.VERTICAL, // orientation false, // include legend true, // tooltips false, // urls "{1} = {2}"); CategoryPlot plot = jfchart.getCategoryPlot(); CategoryAxis axis = plot.getDomainAxis(); new CategoryLabelPosition(RectangleAnchor.TOP, TextBlockAnchor.TOP_RIGHT, TextAnchor.TOP_RIGHT, -Math.PI / 8.0, CategoryLabelWidthType.CATEGORY, 0); axis.setCategoryLabelPositions(CategoryLabelPositions.STANDARD); // set the background color for the chart... plot.setNoDataMessage(Messages.getString("StatView.15")); plot.setForegroundAlpha(0.5f); plot.setBackgroundAlpha(0.5f); // plot.setBackgroundImage(IconLoader.IMAGES_STAT_PAPER).getImage()); return new ChartPanel(jfchart); } catch (Exception e) { Log.error(e); return null; } } /* * (non-Javadoc) * * @see org.jajuk.ui.IView#getDesc() */ @Override public String getDesc() { return Messages.getString("StatView.16"); } /* * (non-Javadoc) * * @see org.jajuk.ui.Observer#update(java.lang.String) */ @Override public void update(JajukEvent event) { JajukEvents subject = event.getSubject(); if (JajukEvents.DEVICE_REFRESH.equals(subject) || JajukEvents.DEVICE_DELETE.equals(subject)) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { try { UtilGUI.waiting(); if (getComponentCount() > 0) { removeAll(); } ChartPanel cp1 = createGenreRepartition(); if (cp1 != null) { add(cp1); } ChartPanel cp2 = createCollectionSize(); if (cp2 != null) { add(cp2, "wrap"); } ChartPanel cp3 = createTrackNumber(); if (cp3 != null) { add(cp3); } ChartPanel cp4 = createDeviceRepartition(); if (cp4 != null) { add(cp4, "wrap"); } revalidate(); repaint(); } finally { UtilGUI.stopWaiting(); } } }); } } /** * Computes mounts labels. * * @param iMonthsNumber : number of mounts ( without 'before' ) you want * * @return the mounts labels */ private String[] getMonthsLabels(int iMonthsNumber) { int iNow = Integer.parseInt(new SimpleDateFormat(DATE_FILE, Locale.getDefault()) .format(new Date())) / 100; // reference // month String sMonths[] = new String[iMonthsNumber + 1]; // contains number of tracks for each month, first cell is 'before' int iYear = iNow / 100; int iMonth = Integer.parseInt(Integer.toString(iNow).substring(4, 6)); for (int k = 0; k < iMonthsNumber; k++) { sMonths[iMonthsNumber - k] = new StringBuilder().append((iMonth / 10 == 0) ? "0" : "") .append(Integer.toString(iMonth)).append('/').append(Integer.toString(iYear)).toString(); iMonth--; if (iMonth == 0) { iMonth = 12; iYear--; } } sMonths[0] = Messages.getString("StatView.24"); return sMonths; } /** * Get months as integers. * * @param iMonthsNumber DOCUMENT_ME * * @return the months */ private int[] getMonths(int iMonthsNumber) { int[] iMonths = new int[iMonthsNumber + 1]; String[] sMonths = getMonthsLabels(iMonthsNumber + 1); for (int i = 0; i < iMonthsNumber + 1; i++) { iMonths[i] = Integer .parseInt(sMonths[i + 1].substring(3, 7) + sMonths[i + 1].substring(0, 2)); } return iMonths; } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/views/ArtistView.java0000644000175000017500000002047411720500104024530 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.views; import ext.services.lastfm.ArtistInfo; import ext.services.lastfm.LastFmService; import java.awt.Dimension; import java.awt.Insets; import java.net.UnknownHostException; import java.util.HashSet; import java.util.Set; import javax.swing.JScrollPane; import javax.swing.JTextArea; import javax.swing.ScrollPaneConstants; import javax.swing.SwingUtilities; import net.miginfocom.swing.MigLayout; import org.apache.commons.lang.StringUtils; import org.jajuk.base.Artist; import org.jajuk.events.JajukEvent; import org.jajuk.events.JajukEvents; import org.jajuk.events.ObservationManager; import org.jajuk.services.players.QueueModel; import org.jajuk.services.players.StackItem; import org.jajuk.ui.helpers.TwoStepsDisplayable; import org.jajuk.ui.thumbnails.LastFmArtistThumbnail; import org.jajuk.util.Conf; import org.jajuk.util.Const; import org.jajuk.util.Messages; import org.jajuk.util.UtilFeatures; import org.jajuk.util.UtilGUI; import org.jajuk.util.log.Log; import org.jdesktop.swingx.JXBusyLabel; /** * Display Artist bio and albums. */ public class ArtistView extends SuggestionView implements TwoStepsDisplayable { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** The artist picture + labels. */ private LastFmArtistThumbnail artistThumb; /** The artist bio (from last.fm wiki) */ private JTextArea jtaArtistDesc; /** DOCUMENT_ME. */ private JScrollPane jspAlbums; /** DOCUMENT_ME. */ private String bio; /** DOCUMENT_ME. */ private ArtistInfo artistInfo; /* * (non-Javadoc) * * @see org.jajuk.ui.views.IView#getDesc() */ @Override public String getDesc() { return Messages.getString("ArtistView.0"); } /* * (non-Javadoc) * * @see org.jajuk.ui.views.IView#initUI() */ @Override public void initUI() { // register to player events ObservationManager.register(this); // by default, show reseted view reset(); // Update initial status UtilFeatures.updateStatus(this); } /* * (non-Javadoc) * * @see org.jajuk.events.Observer#getRegistrationKeys() */ @Override public Set getRegistrationKeys() { Set eventSubjectSet = new HashSet(); eventSubjectSet.add(JajukEvents.WEBRADIO_LAUNCHED); eventSubjectSet.add(JajukEvents.ZERO); eventSubjectSet.add(JajukEvents.FILE_LAUNCHED); return eventSubjectSet; } /** * Build the GUI for a given artist *

    * Must be called from the EDT *

    . */ private void displayArtist() { UtilGUI.populate(this); } /* * (non-Javadoc) * * @see org.jajuk.events.Observer#update(org.jajuk.events.JajukEvent) */ @Override public void update(final JajukEvent event) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { // If internet access or lastfm is disable, just reset if (Conf.getBoolean(Const.CONF_NETWORK_NONE_INTERNET_ACCESS) || !Conf.getBoolean(Const.CONF_LASTFM_INFO)) { reset(); return; } JajukEvents subject = event.getSubject(); if (JajukEvents.WEBRADIO_LAUNCHED.equals(subject) || JajukEvents.ZERO.equals(event.getSubject())) { reset(); } else if (JajukEvents.FILE_LAUNCHED.equals(subject)) { // If no playing track, reset the view StackItem currentItem = QueueModel.getCurrentItem(); if (currentItem == null) { reset(); return; } Artist artist = currentItem.getFile().getTrack().getArtist(); // If we already display the artist, leave if (artist.getName().equals(ArtistView.this.artist)) { return; } else { // Display a busy panel in the mean-time setLayout(new MigLayout("ins 5", "[grow]", "[grow]")); JXBusyLabel busy1 = new JXBusyLabel(new Dimension(50, 50)); busy1.setBusy(true); removeAll(); add(busy1, "center"); revalidate(); repaint(); ArtistView.this.artist = artist.getName(); // Display the panel only if the artist is not unknown if (!artist.seemsUnknown()) { // This is done in a swing worker displayArtist(); } else { reset(); } } } } }); } /* (non-Javadoc) * @see org.jajuk.ui.views.SuggestionView#onPerspectiveSelection() */ @Override public void onPerspectiveSelection() { // override the suggestion view behavior } /** * Show reseted view (show a message) *

    * Must be called from the EDT *

    . */ private void reset() { ArtistView.this.artist = null; removeAll(); setLayout(new MigLayout("ins 5,gapy 5", "[grow]")); add(getNothingFoundPanel()); revalidate(); repaint(); } /* * (non-Javadoc) * * @see org.jajuk.ui.helpers.TwoStepsDisplayable#longCall() */ @Override public Object longCall() { // Call last.fm wiki bio = LastFmService.getInstance().getWikiText(artist); artistInfo = LastFmService.getInstance().getArtist(artist); // Prefetch artist thumbs try { preFetchOthersAlbum(); preFetchSimilarArtists(); } catch (UnknownHostException e) { Log.warn("Could not contact host for loading album information: {{" + e.getMessage() + "}}"); } catch (Exception e) { Log.error(e); } return null; } /* * (non-Javadoc) * * @see org.jajuk.ui.helpers.TwoStepsDisplayable#shortCall(java.lang.Object) */ @Override public void shortCall(Object in) { removeAll(); jspAlbums = getLastFMSuggestionsPanel(SuggestionType.OTHERS_ALBUMS, true); // Artist unknown from last.fm, leave if (artistInfo == null // If image url is void, last.fm doesn't provide enough data about this // artist, we reset the view || StringUtils.isBlank(artistInfo.getImageUrl())) { reset(); return; } artistThumb = new LastFmArtistThumbnail(artistInfo); // No known icon next to artist thumb artistThumb.setArtistView(true); artistThumb.populate(); jtaArtistDesc = new JTextArea(bio) { private static final long serialVersionUID = 9217998016482118852L; // We set the margin this way, setMargin() doesn't work due to // existing border @Override public Insets getInsets() { return new Insets(2, 4, 0, 4); } }; jtaArtistDesc.setBorder(null); jtaArtistDesc.setEditable(false); jtaArtistDesc.setLineWrap(true); jtaArtistDesc.setWrapStyleWord(true); jtaArtistDesc.setOpaque(false); JScrollPane jspWiki = new JScrollPane(jtaArtistDesc); jspWiki.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); jspWiki.setBorder(null); jspWiki.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED); // Add items, layout is different according wiki text availability if (StringUtils.isNotBlank(jtaArtistDesc.getText())) { setLayout(new MigLayout("ins 5,gapy 5", "[grow]", "[grow][20%!][grow]")); add(artistThumb, "center,wrap"); // don't add the textarea if no wiki text available add(jspWiki, "growx,wrap"); add(jspAlbums, "grow,wrap"); } else { setLayout(new MigLayout("ins 5,gapy 5", "[grow]")); add(artistThumb, "center,wrap"); // don't add the textarea if no wiki text available add(jspAlbums, "grow,wrap"); } revalidate(); repaint(); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/thumbnails/0000755000175000017500000000000011720500104022566 5ustar drazzibdrazzibjajuk-1.9.6.orig/src/main/java/org/jajuk/ui/thumbnails/package.html0000644000175000017500000000017111720500104025046 0ustar drazzibdrazzib DOCUMENT_ME jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/thumbnails/LocalAlbumThumbnail.java0000644000175000017500000002376211720500104027322 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.thumbnails; import com.vlsolutions.swing.docking.ShadowBorder; import java.awt.Color; import java.io.File; import java.net.MalformedURLException; import java.util.ArrayList; import java.util.Collections; import java.util.List; import javax.swing.Action; import javax.swing.ActionMap; import javax.swing.ImageIcon; import javax.swing.InputMap; import javax.swing.JComponent; import javax.swing.JLabel; import javax.swing.KeyStroke; import javax.swing.border.EmptyBorder; import net.miginfocom.swing.MigLayout; import org.jajuk.base.Album; import org.jajuk.base.Item; import org.jajuk.base.Track; import org.jajuk.base.TrackComparator; import org.jajuk.base.TrackComparator.TrackComparatorType; import org.jajuk.base.TrackManager; import org.jajuk.services.core.SessionService; import org.jajuk.ui.actions.ActionManager; import org.jajuk.ui.actions.JajukActions; import org.jajuk.ui.helpers.CatalogViewTransferHandler; import org.jajuk.ui.helpers.FontManager; import org.jajuk.ui.helpers.FontManager.JajukFont; import org.jajuk.ui.helpers.PreferencesJMenu; import org.jajuk.ui.helpers.StarsHelper; import org.jajuk.util.Const; import org.jajuk.util.Messages; import org.jajuk.util.UtilGUI; import org.jajuk.util.UtilString; import org.jajuk.util.UtilSystem; import org.jajuk.util.log.Log; /** * Album thumb represented as album cover + (optionally) others text information * and some features like dnd, menu item to play, search cover, album popup * display... */ public class LocalAlbumThumbnail extends AbstractThumbnail { /** Generated serialVersionUID. */ private static final long serialVersionUID = -282669695411453802L; /** Associated album. */ private Album album; /** DOCUMENT_ME. */ private JLabel jlArtist; /** DOCUMENT_ME. */ private JLabel jlAlbum; /** DOCUMENT_ME. */ private final boolean bShowFullText; /** DOCUMENT_ME. */ private PreferencesJMenu pjmFiles; /** * Constructor. * * @param album : * associated album * @param size : * size of the thumbnail * @param bShowText : * Display full album / artist information under the icon or not ? */ public LocalAlbumThumbnail(Album album, int size, boolean bShowText) { super(size); this.album = album; this.bShowFullText = bShowText; this.fCover = ThumbnailManager.getThumbBySize(album, size); } /* * (non-Javadoc) * * @see org.jajuk.ui.thumbnails.AbstractThumbnail#populate() */ @Override public synchronized void populate() { if (!album.isThumbAvailable(size)) { // create the thumbnail if it doesn't exist boolean thumbCreated = ThumbnailManager.refreshThumbnail(album, size); if (!thumbCreated) { this.fCover = null; } } ImageIcon ii = album.getThumbnail(size); jlIcon = new JLabel(ii); if (fCover != null) { jlIcon.setBorder(new ShadowBorder(false)); } if (bShowFullText) { int iRows = 7 + 7 * ((size / 50) - 1); String artistName = album.getArtistOrALbumArtist(); jlArtist = new JLabel(UtilString.getLimitedString(artistName, iRows)); jlArtist.setToolTipText(artistName); jlArtist.setFont(FontManager.getInstance().getFont(JajukFont.BOLD)); // we have to use a empty border to avoid getting default border jlArtist.setBorder(new EmptyBorder(0, 0, 0, 0)); jlAlbum = new JLabel(UtilString.getLimitedString(album.getName2(), iRows)); jlAlbum.setToolTipText(album.getName2()); jlAlbum.setBorder(new EmptyBorder(0, 0, 0, 0)); jlIcon.setToolTipText(artistName + "/" + album.getName2()); // Add items setLayout(new MigLayout("ins 0", "[grow]", "[" + (size + 10) + "!][grow][grow]")); add(jlIcon, "wrap,center"); add(jlArtist, "wrap,center"); add(jlAlbum, "wrap,center"); } else { setLayout(new MigLayout("ins 0,gapy 2")); add(jlIcon, "center,wrap"); int iRows = 7 + 6 * (size / 50 - 1); String fullTitle = album.getName2(); JLabel jlTitle = new JLabel(UtilString.getLimitedString(fullTitle, iRows)); jlTitle.setToolTipText(fullTitle); jlTitle.setToolTipText(fullTitle); add(jlTitle, "left"); } // Add dnd support jlIcon.setTransferHandler(new CatalogViewTransferHandler(this)); postPopulate(); // Add the preference menu in popup pjmFiles = new PreferencesJMenu(getItem()); jmenu.add(pjmFiles, 9); // disable inadequate menu items if (UtilSystem.isBrowserSupported()) { jmenu.remove(jmiOpenLastFMSite); } // Set keystrokes setKeystrokes(); } /** * Gets the cover file. * * @return the cover file */ public File getCoverFile() { return fCover; } /* * (non-Javadoc) * * @see org.jajuk.ui.thumbnails.AbstractThumbnail#getItem() */ @Override public Item getItem() { return album; } /* * (non-Javadoc) * * @see org.jajuk.ui.thumbnails.AbstractThumbnail#getDescription() */ @Override public String getDescription() { int lSize = 200; ThumbnailManager.refreshThumbnail(album, lSize); java.io.File cover = ThumbnailManager.getThumbBySize(album, lSize); List tracks = new ArrayList(TrackManager.getInstance().getAssociatedTracks(album, true)); Collections.sort(tracks, new TrackComparator(TrackComparatorType.ORDER)); Track firstTrack = tracks.iterator().next(); Color bgcolor = UtilGUI.getUltraLightColor(); Color fgcolor = UtilGUI.getForegroundColor(); String sOut = "
    " + album.getName2() + "

    "; // display cover if (cover.exists()) { sOut += "
    "; } // TODO : add AlbumArtist value and hyperlink here // Display artist as global value only if it is a single artist album // We use file://? as HTML hyperlink format if (album.getArtist() != null) { sOut += "
    " + Messages.getHumanPropertyName(Const.XML_ARTIST) + ": " + firstTrack.getArtist().getName2() + ""; } // Display genre if (album.getGenre() != null) { sOut += "
    " + Messages.getHumanPropertyName(Const.XML_GENRE) + ": " + UtilString.getLimitedString(firstTrack.getGenre().getName2(), 20) + ""; } // Display year if (album.getYear() != null) { sOut += "
    " + Messages.getHumanPropertyName(Const.XML_YEAR) + ": " + firstTrack.getYear().getName() + ""; } // display rating (sum of all tracks rating) try { sOut += "
    " + Messages.getHumanPropertyName(Const.XML_TRACK_RATE) + ": (" + album.getRate() + ")"; } catch (MalformedURLException e) { Log.error(e); } // Compute total length in secs long length = album.getDuration(); sOut += "
    " + Messages.getHumanPropertyName(Const.XML_TRACK_LENGTH) + ": " + UtilString.formatTimeBySec(length) + "

    "; // Show each track detail for (Track track : tracks) { sOut += "
    "; if (track.getOrder() > 0) { sOut += UtilString.padNumber(track.getOrder(), 2) + ": "; } sOut += "" + "" + UtilString.getLimitedString(track.getName(), 50) + "" + " ("; sOut += UtilString.formatTimeBySec(track.getDuration()) + ") "; if (album.getYear() == null && track.getYear().getValue() != 0) { sOut += " - " + track.getYear().getValue() + " "; } // Show artist if known and if it is not already shown at album // level if (album.getArtist() == null && !track.getArtist().getName2().equals(Messages.getString(Const.UNKNOWN_ARTIST))) { sOut += " - " + UtilString.getLimitedString(track.getArtist().getName2(), 20) + " "; } } sOut += "
    "; return sOut; } /* * (non-Javadoc) * * @see org.jajuk.ui.thumbnails.AbstractThumbnail#launch() */ @Override public void launch() { // play the album jmiPlay.doClick(); } /** * Add keystroke support on the tree. */ private void setKeystrokes() { putClientProperty(Const.DETAIL_SELECTION, album); InputMap inputMap = getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT); ActionMap actionMap = getActionMap(); // Delete Action action = ActionManager.getAction(JajukActions.DELETE); inputMap.put(KeyStroke.getKeyStroke("DELETE"), "delete"); actionMap.put("delete", action); // Properties ALT/ENTER action = ActionManager.getAction(JajukActions.SHOW_PROPERTIES); inputMap.put(KeyStroke.getKeyStroke("alt ENTER"), "properties"); actionMap.put("properties", action); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/thumbnails/ThumbnailManager.java0000644000175000017500000002110111720500104026642 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.thumbnails; import java.awt.Image; import java.awt.MediaTracker; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; import java.util.Properties; import java.util.StringTokenizer; import javax.imageio.ImageIO; import javax.swing.ImageIcon; import org.jajuk.base.Album; import org.jajuk.base.AlbumManager; import org.jajuk.events.JajukEvent; import org.jajuk.events.JajukEvents; import org.jajuk.events.ObservationManager; import org.jajuk.services.core.SessionService; import org.jajuk.util.Const; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; import org.jajuk.util.UtilGUI; import org.jajuk.util.UtilSystem; import org.jajuk.util.error.JajukRuntimeException; import org.jajuk.util.log.Log; /** * Manage thumbnails. */ public final class ThumbnailManager { /** * No instances. */ private ThumbnailManager() { } /** * Delete all thumbs for a given size. * * @param size size, eg: Const.THUMBNAIL_SIZE_150x150 */ public static void cleanThumbs(String size) { File fThumb = SessionService.getConfFileByPath(Const.FILE_THUMBS + '/' + size); if (fThumb.exists()) { File[] files = fThumb.listFiles(); for (File file : files) { if (!file.getAbsolutePath().matches(".*" + Const.FILE_THUMB_NO_COVER)) { try { UtilSystem.deleteFile(file); } catch (IOException e) { Log.error(e); } } } // Refresh default cover File fDefault = SessionService.getConfFileByPath(Const.FILE_THUMBS + "/" + size + "/" + Const.FILE_THUMB_NO_COVER); if (fDefault.exists()) { if (!fDefault.delete()) { Log.warn("Could not delete " + fDefault.toString()); } } try { int iSize = Integer.parseInt(new StringTokenizer(size, "x").nextToken()); createThumbnail(IconLoader.getIcon(JajukIcons.NO_COVER), fDefault, iSize); } catch (Exception e) { Log.error(e); } } // Reset all thumbs cache for (Album album : AlbumManager.getInstance().getAlbums()) { cleanThumbs(album); } } /** * Delete all thumbs for a given album. * * @param album DOCUMENT_ME */ public static void cleanThumbs(Album album) { // Now delete thumb files for (int size = 50; size <= 300; size += 50) { File fThumb = ThumbnailManager.getThumbBySize(album, size); if (fThumb.exists()) { boolean out = fThumb.delete(); if (!out) { Log.warn("Cannot delete thumb for album: " + album); } } album.setAvailableThumb(size, false); } } /** * Reads an image in a file and creates a thumbnail in another file. Will be * created if necessary. the thumbnail must be maxDim pixels or less. Thanks * Marco Schmidt * http://schmidt.devlib.org/java/save-jpeg-thumbnail.html#source * * @param orig source image * @param thumb destination file * @param maxDim required size * * @throws IOException Signals that an I/O exception has occurred. * @throws InterruptedException the interrupted exception */ public static void createThumbnail(final File orig, final File thumb, final int maxDim) throws InterruptedException, IOException { // do not use URL object has it can corrupt special paths ImageIcon ii = new ImageIcon(orig.getAbsolutePath()); if (ii.getImageLoadStatus() != MediaTracker.COMPLETE) { throw new JajukRuntimeException("Cannot load image : " + orig.getAbsolutePath()); } createThumbnail(ii, thumb, maxDim); } /** * Reads an image in a file and creates a thumbnail in another file. Use this * method to get thumbs from images inside jar files, some bugs in URL * encoding makes impossible to create the image from a file. Will be created * if necessary. the thumbnail must be maxDim pixels or less. Thanks Marco * Schmidt http://schmidt.devlib.org/java/save-jpeg-thumbnail.html#source * * @param thumb destination file (jpg) * @param maxDim required size * @param ii DOCUMENT_ME * * @throws InterruptedException the interrupted exception * @throws IOException Signals that an I/O exception has occurred. * @throws Exception */ public static void createThumbnail(final ImageIcon ii, final File thumb, final int maxDim) throws InterruptedException, IOException { // Synchronize the file to avoid any concurrency between several threads refreshing the thumb // like the catalog view and the artist view. // Don't lock the thumb file itself because we have to write in in this method and // Windows doesn't support share mode for locks but only exclusive File thumbLock = new File(thumb.getAbsolutePath() + ".lock"); thumbLock.createNewFile(); synchronized (thumbLock.getAbsolutePath().intern()) { // Note that at this point, the image is fully loaded (done in the ImageIcon constructor) final Image image = ii.getImage(); // determine thumbnail size from WIDTH and HEIGHT int thumbWidth = maxDim; int thumbHeight = maxDim; final double thumbRatio = (double) thumbWidth / (double) thumbHeight; final int imageWidth = image.getWidth(null); final int imageHeight = image.getHeight(null); final double imageRatio = (double) imageWidth / (double) imageHeight; if (thumbRatio < imageRatio) { thumbHeight = (int) (thumbWidth / imageRatio); } else { thumbWidth = (int) (thumbHeight * imageRatio); } // draw original image to thumbnail image object and // scale it to the new size on-the-fly final BufferedImage thumbImage = UtilGUI.toBufferedImage(image, thumbWidth, thumbHeight); // save thumbnail image to OUTFILE ImageIO.write(thumbImage, UtilSystem.getExtension(thumb), thumb); // Free thumb memory thumbImage.flush(); } } /** * Check all thumbs existence for performance reasons. * * @param size size of thumbs to be checked */ public static void populateCache(final int size) { for (Album album : AlbumManager.getInstance().getAlbums()) { File fThumb = ThumbnailManager.getThumbBySize(album, size); album.setAvailableThumb(size, fThumb.exists() && fThumb.length() > 0); } } /** * Make thumbnail file exists (album id.jpg or.gif or .png) in thumbs * directory if it doesn't exist yet * * @param album DOCUMENT_ME * @param size DOCUMENT_ME * * @return whether a new cover has been created */ public static boolean refreshThumbnail(final Album album, final int size) { // Check if the thumb is known in cache if (album.isThumbAvailable(size)) { return false; } final File fThumb = getThumbBySize(album, size); final File fCover = album.findCover(); if (fCover != null) { try { createThumbnail(fCover, fThumb, size); // Update thumb availability album.setAvailableThumb(size, true); // Notify the thumb creation Properties details = new Properties(); details.put(Const.DETAIL_CONTENT, album); ObservationManager.notify(new JajukEvent(JajukEvents.THUMB_CREATED, details)); return true; } catch (final Exception e) { Log.error(e); } } return false; // thumb already exists or source file cannot be read (an exception occurred) } /** * Return thumb file by album and size. * * @param album the album * @param size the size (like 50) * * @return thumb file by album and size */ public static File getThumbBySize(Album album, int size) { StringBuilder thumb = new StringBuilder(Const.FILE_THUMBS).append('/').append(size).append('x') .append(size).append('/').append(album.getID()).append('.').append(Const.EXT_THUMB); return SessionService.getConfFileByPath(thumb.toString()); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/thumbnails/AbstractThumbnail.java0000644000175000017500000003350711720500104027050 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.thumbnails; import com.vlsolutions.swing.docking.ShadowBorder; import java.awt.Dimension; import java.awt.Point; import java.awt.Rectangle; import java.awt.datatransfer.DataFlavor; import java.awt.datatransfer.Transferable; import java.awt.datatransfer.UnsupportedFlavorException; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseEvent; import java.awt.event.MouseMotionAdapter; import java.io.File; import java.io.IOException; import java.util.List; import javax.swing.BorderFactory; import javax.swing.JComponent; import javax.swing.JDialog; import javax.swing.JLabel; import javax.swing.JMenuItem; import javax.swing.JPanel; import javax.swing.JPopupMenu; import javax.swing.Timer; import javax.swing.TransferHandler; import javax.swing.WindowConstants; import org.jajuk.base.Item; import org.jajuk.base.Track; import org.jajuk.base.TrackManager; import org.jajuk.ui.actions.ActionManager; import org.jajuk.ui.actions.JajukAction; import org.jajuk.ui.actions.JajukActions; import org.jajuk.ui.helpers.JajukMouseAdapter; import org.jajuk.ui.views.CoverView; import org.jajuk.ui.windows.JajukMainWindow; import org.jajuk.util.Conf; import org.jajuk.util.Const; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; import org.jajuk.util.UtilGUI; import org.jajuk.util.UtilSystem; import org.jajuk.util.log.Log; /** * Album thumb represented as album cover + (optionally) others text information * and some features like dnd, menu item to play, search cover, album popup * display... */ public abstract class AbstractThumbnail extends JPanel implements ActionListener, Transferable { /** Generated serialVersionUID. */ private static final long serialVersionUID = -6396225563540281695L; /** Size. */ int size; /** DOCUMENT_ME. */ protected JLabel jlIcon; /** DOCUMENT_ME. */ private static long lDateLastMove; /** DOCUMENT_ME. */ private static Point lastPosition; /** DOCUMENT_ME. */ JPopupMenu jmenu; /** DOCUMENT_ME. */ JMenuItem jmiPlay; /** DOCUMENT_ME. */ JMenuItem jmiPush; /** DOCUMENT_ME. */ JMenuItem jmiFrontPush; /** DOCUMENT_ME. */ JMenuItem jmiDelete; /** DOCUMENT_ME. */ JMenuItem jmiPlayShuffle; /** DOCUMENT_ME. */ JMenuItem jmiPlayRepeat; /** DOCUMENT_ME. */ JMenuItem jmiGetCovers; /** DOCUMENT_ME. */ private JMenuItem jmiShowPopup; /** DOCUMENT_ME. */ JMenuItem jmiCDDBWizard; /** DOCUMENT_ME. */ JMenuItem jmiProperties; /** DOCUMENT_ME. */ JMenuItem jmiOpenLastFMSite; /** Dragging flag used to disable simple click behavior. */ private static boolean bDragging = false; /** Current details dialog. */ private static ThumbnailPopup details; /** DOCUMENT_ME. */ private static AbstractThumbnail last; /** DOCUMENT_ME. */ private static AbstractThumbnail mouseOverItem = null; /** Whether this thumb is used in artist view *. */ private boolean artistView; /** Associated file. */ File fCover; /** Timer used to launch popup */ static { Timer timerPopup = new Timer(200, new ActionListener() { @Override public void actionPerformed(ActionEvent arg0) { try { // Close popup ASAP when over none catalog item if (mouseOverItem == null) { if (details != null) { details.dispose(); details = null; } last = null; // display a popup after n seconds only if item changed } else if ((System.currentTimeMillis() - lDateLastMove >= 700) && mouseOverItem != last && !bDragging) { // Store current item last = mouseOverItem; // Finally display the popup (Leave if user unselected // the option "Show catalog popups" if (Conf.getBoolean(Const.CONF_SHOW_POPUPS)) { mouseOverItem.displayPopup(); } } bDragging = false; } catch (Exception e) { // Make sure not to exit Log.error(e); } } }); timerPopup.start(); } /** * Constructor. * * @param size : * size of the thumbnail */ protected AbstractThumbnail(int size) { this.size = size; setSelected(false); } /** * Checks if is artist view. * * @return true, if is artist view */ protected boolean isArtistView() { return artistView; } /** * Sets the artist view. * * @param artistBioThumb the new artist view */ public void setArtistView(boolean artistBioThumb) { this.artistView = artistBioThumb; } /** * display a popup over the catalog item. */ private void displayPopup() { // close popup if any visible if (details != null) { details.dispose(); details = null; } // don't show details if the contextual popup menu // is visible if (jmenu.isVisible()) { return; } UtilGUI.waiting(); String description = getDescription(); if (description != null) { details = new ThumbnailPopup(description, new Rectangle(jlIcon.getLocationOnScreen(), new Dimension(jlIcon.getWidth(), jlIcon.getHeight())), true); UtilGUI.stopWaiting(); } } /** * Populate. DOCUMENT_ME */ public abstract void populate(); /** * Return HTML text to display in the popup. * * @return the description */ public abstract String getDescription(); /** * Performs common UI operations for any kind of thumb. */ void postPopulate() { // do this only once as it might be a costly operation... Item item = getItem(); // Album menu jmenu = new JPopupMenu(); jmiPlay = new JMenuItem(ActionManager.getAction(JajukActions.PLAY_SELECTION)); jmiPlay.putClientProperty(Const.DETAIL_SELECTION, item); jmiPush = new JMenuItem(ActionManager.getAction(JajukActions.PUSH_SELECTION)); jmiPush.putClientProperty(Const.DETAIL_SELECTION, item); jmiFrontPush = new JMenuItem(ActionManager.getAction(JajukActions.PUSH_FRONT_SELECTION)); jmiFrontPush.putClientProperty(Const.DETAIL_SELECTION, item); jmiDelete = new JMenuItem(ActionManager.getAction(JajukActions.DELETE)); jmiDelete.putClientProperty(Const.DETAIL_SELECTION, item); jmiPlayShuffle = new JMenuItem(ActionManager.getAction(JajukActions.PLAY_SHUFFLE_SELECTION)); jmiPlayShuffle.putClientProperty(Const.DETAIL_SELECTION, item); jmiPlayRepeat = new JMenuItem(ActionManager.getAction(JajukActions.PLAY_REPEAT_SELECTION)); jmiPlayRepeat.putClientProperty(Const.DETAIL_SELECTION, item); jmiGetCovers = new JMenuItem(Messages.getString("CatalogView.7"), IconLoader .getIcon(JajukIcons.COVER_16X16)); jmiGetCovers.addActionListener(this); jmiShowPopup = new JMenuItem(Messages.getString("CatalogView.20"), IconLoader .getIcon(JajukIcons.POPUP)); jmiShowPopup.addActionListener(this); jmiCDDBWizard = new JMenuItem(ActionManager.getAction(JajukActions.CDDB_SELECTION)); jmiCDDBWizard.putClientProperty(Const.DETAIL_SELECTION, item); jmiProperties = new JMenuItem(ActionManager.getAction(JajukActions.SHOW_PROPERTIES)); jmiProperties.putClientProperty(Const.DETAIL_SELECTION, item); if (UtilSystem.isBrowserSupported()) { JajukAction actionOpenLastFM = ActionManager.getAction(JajukActions.LAUNCH_IN_BROWSER); // Change action label jmiOpenLastFMSite = new JMenuItem(actionOpenLastFM); jmiOpenLastFMSite.setText(Messages.getString("AbstractThumbnail.0")); jmiOpenLastFMSite.setToolTipText(Messages.getString("AbstractThumbnail.0")); } // We add all menu items, each implementation of this class should hide // (setVisible(false)) menu items that are not available in their // context jmenu.add(jmiPlay); jmenu.add(jmiFrontPush); jmenu.add(jmiPush); jmenu.add(jmiPlayShuffle); jmenu.add(jmiPlayRepeat); jmenu.addSeparator(); jmenu.add(jmiDelete); jmenu.addSeparator(); jmenu.add(jmiCDDBWizard); jmenu.add(jmiGetCovers); jmenu.add(jmiShowPopup); if (UtilSystem.isBrowserSupported()) { jmenu.add(jmiOpenLastFMSite); } jmenu.addSeparator(); jmenu.add(jmiProperties); jlIcon.addMouseMotionListener(new MouseMotionAdapter() { @Override public void mouseDragged(MouseEvent e) { // Notify the mouse listener that we are dragging bDragging = true; JComponent c = (JComponent) e.getSource(); TransferHandler handler = c.getTransferHandler(); handler.exportAsDrag(c, e, TransferHandler.COPY); } @Override public void mouseMoved(MouseEvent e) { super.mouseMoved(e); lDateLastMove = System.currentTimeMillis(); lastPosition = e.getPoint(); } }); jlIcon.addMouseListener(new JajukMouseAdapter() { @Override public void handlePopup(MouseEvent e) { if (e.getSource() == jlIcon) { // Show contextual menu jmenu.show(jlIcon, e.getX(), e.getY()); // Hide any details frame if (details != null) { details.dispose(); details = null; } } } @Override public void handleActionSeveralClicks(MouseEvent e) { launch(); } @Override public void mousePressed(MouseEvent e) { if (bDragging) { return; } super.mousePressed(e); } @Override public void mouseEntered(MouseEvent e) { mouseOverItem = AbstractThumbnail.this; } @Override public void mouseExited(MouseEvent e) { // Consider an exit only if mouse really moved to avoid // closing popup when popup appears over the mouse cursor // (then, a mouseExit event is thrown) if (!e.getPoint().equals(lastPosition) && // Don't close popup if user is still over it !(details != null && details.contains(e.getPoint()))) { mouseOverItem = null; } } @Override public void mouseReleased(MouseEvent e) { // Leave if already dragging if (bDragging) { return; } super.mouseReleased(e); } }); } /** * Sets the selected. * * @param b DOCUMENT_ME */ public final void setSelected(boolean b) { requestFocusInWindow(); // Add a shadow for selected items if (b) { setBorder(new ShadowBorder(false)); } else { // add an empty border of the same size than the border to avoid // image moves when setting borders setBorder(BorderFactory.createEmptyBorder(1, 1, 5, 5)); } } /** * Launch. DOCUMENT_ME */ public abstract void launch(); /** * If the thumb represents something (album, artist...) known in the * collection, the implementation of this method should return the associated * item * * @return the collection item */ public abstract Item getItem(); /* * (non-Javadoc) * * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent) */ @Override public void actionPerformed(ActionEvent e) { if (e.getSource() == jmiGetCovers) { // This item is enabled only for albums JDialog jd = new JDialog(JajukMainWindow.getInstance(), Messages.getString("CatalogView.18")); org.jajuk.base.File file = null; // We sort associated tracks because we want to analyze the first file of the set // as it is more likely to contain global cover tag. List tracks = TrackManager.getInstance().getAssociatedTracks(getItem(), true); if (tracks.size() > 0) { // Take first track found Track track = tracks.iterator().next(); file = track.getBestFile(false); } CoverView cv = null; if (file != null) { cv = new CoverView(file); cv.setID("catalog/0"); cv.initUI(); jd.add(cv); jd.setSize(600, 450); // Keep it unresizable to keep things simple with cover view // resizing issues, see @CoverView.CoverResetThread comments. jd.setResizable(false); UtilGUI.centerWindow(jd); jd.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); jd.setVisible(true); } else { Messages.showErrorMessage(166); } } else if (e.getSource() == jmiShowPopup) { displayPopup(); } } /* * (non-Javadoc) * * @see java.awt.datatransfer.Transferable#getTransferData(java.awt.datatransfer.DataFlavor) */ @Override public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, IOException { return null; } /* * (non-Javadoc) * * @see java.awt.datatransfer.Transferable#getTransferDataFlavors() */ @Override public DataFlavor[] getTransferDataFlavors() { return null; } /* * (non-Javadoc) * * @see java.awt.datatransfer.Transferable#isDataFlavorSupported(java.awt.datatransfer.DataFlavor) */ @Override public boolean isDataFlavorSupported(DataFlavor flavor) { return false; } /** * Gets the icon. * * @return the icon */ public JLabel getIcon() { return jlIcon; } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/thumbnails/LastFmArtistThumbnail.java0000644000175000017500000001725411720500104027663 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.thumbnails; import ext.services.lastfm.AlbumInfo; import ext.services.lastfm.ArtistInfo; import ext.services.lastfm.LastFmService; import java.awt.Color; import java.awt.image.BufferedImage; import java.net.URL; import java.net.UnknownHostException; import java.util.List; import javax.imageio.IIOException; import javax.imageio.ImageIO; import javax.swing.ImageIcon; import javax.swing.JLabel; import net.miginfocom.swing.MigLayout; import org.apache.commons.lang.StringUtils; import org.jajuk.base.ArtistManager; import org.jajuk.base.Item; import org.jajuk.ui.helpers.FontManager; import org.jajuk.ui.helpers.FontManager.JajukFont; import org.jajuk.util.Const; import org.jajuk.util.DownloadManager; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; import org.jajuk.util.UtilGUI; import org.jajuk.util.UtilString; import org.jajuk.util.UtilSystem; import org.jajuk.util.log.Log; import org.jdesktop.swingx.border.DropShadowBorder; /** * Last.FM Album thumb represented as artists label + (optionally) others text * information display... */ public class LastFmArtistThumbnail extends AbstractThumbnail { /** Generated serialVersionUID. */ private static final long serialVersionUID = -804471264407148566L; /** Associated artist. */ private final ArtistInfo artist; /** Is this artist known in collection ?. */ private final boolean bKnown; /** Thumb associated image *. */ private ImageIcon ii; /** * The Constructor. * * @param artist DOCUMENT_ME */ public LastFmArtistThumbnail(ArtistInfo artist) { super(100); this.artist = artist; bKnown = (ArtistManager.getInstance().getArtistByName(artist.getName()) != null); } /* * (non-Javadoc) * * @see org.jajuk.ui.thumbnails.AbstractThumbnail#getItem() */ @Override public Item getItem() { org.jajuk.base.Artist item = ArtistManager.getInstance().getArtistByName(artist.getName()); if (item != null) { return item; } return null; } /* * (non-Javadoc) * * @see org.jajuk.ui.thumbnails.AbstractThumbnail#getDescription() */ @Override public String getDescription() { Color bgcolor = UtilGUI.getUltraLightColor(); Color fgcolor = UtilGUI.getForegroundColor(); String sOut = ""; // Show each album for this Artist List albums = LastFmService.getInstance().getAlbumList(artist.getName(), true, 0) .getAlbums(); if (albums != null && albums.size() > 0) { sOut += "
    " + "" + artist.getName() + "" + "

    "; // display picture sOut += "
    "; for (AlbumInfo album : albums) { sOut += ""; if (!StringUtils.isBlank(album.getYear())) { sOut += album.getYear() + " "; } sOut += "" + album.getTitle() + "" + "
    "; } } sOut += "
    "; return sOut; } /* * (non-Javadoc) * * @see org.jajuk.ui.thumbnails.AbstractThumbnail#launch() */ @Override public void launch() { if (bKnown) { // Play the artist jmiPlay.doClick(); } else { // Open the last.FM page jmiOpenLastFMSite.doClick(); } } /** * Long part of the populating process. Longest parts (images download) should * have already been done by the caller outside the EDT. we only pop the image * from the cache here. */ private void preLoad() { try { // Check if artist is null String artistUrl = artist.getImageUrl(); if (StringUtils.isBlank(artistUrl)) { return; } // Download thumb URL remote = new URL(artistUrl); // Download the picture and store file reference (to // generate the popup thumb for ie) fCover = DownloadManager.downloadToCache(remote); if (fCover == null) { Log.warn("Could not read remote file: {{" + remote.toString() + "}}"); return; } BufferedImage image = ImageIO.read(fCover); if (image == null) { Log.warn("Could not read image data in file: {{" + fCover + "}}"); return; } ImageIcon downloadedImage = new ImageIcon(image); // In artist view, do not reduce artist picture if (isArtistView()) { ii = downloadedImage; } else { ii = UtilGUI.getScaledImage(downloadedImage, 100); } // Free images memory downloadedImage.getImage().flush(); image.flush(); } catch (IIOException e) { // report IIOException only as warning here as we can expect this to // happen frequently with images on the net Log.warn("Could not read image: {{" + artist.getImageUrl().toString() + "}} Cache: {{" + fCover + "}}", e.getMessage()); } catch (UnknownHostException e) { Log.warn("Could not contact host for loading images: {{" + e.getMessage() + "}}"); } catch (Exception e) { Log.error(e); } } /** * Thumb populating done in EDT. */ @Override public void populate() { preLoad(); if (ii == null) { return; } jlIcon = new JLabel(); postPopulate(); jlIcon.setIcon(ii); setLayout(new MigLayout("ins 0,gapy 2")); // Use a panel to allow text to be bigger than image under it add(jlIcon, "center,wrap"); int textLength = 15; // In artist view, we have plenty of free space if (isArtistView()) { textLength = 50; } JLabel jlTitle = new JLabel(UtilString.getLimitedString(artist.getName(), textLength)); jlTitle.setToolTipText(artist.getName()); jlIcon.setToolTipText(artist.getName()); if (bKnown && !isArtistView()) { // Artist known in collection, display its name in bold jlTitle.setIcon(IconLoader.getIcon(JajukIcons.ARTIST)); jlTitle.setFont(FontManager.getInstance().getFont(JajukFont.BOLD)); } else { jlTitle.setFont(FontManager.getInstance().getFont(JajukFont.PLAIN)); } if (isArtistView()) { add(jlTitle, "center"); } else { add(jlTitle, "left"); } jlIcon.setBorder(new DropShadowBorder(Color.BLACK, 5, 0.5f, 5, false, true, false, true)); // disable inadequate menu items jmiCDDBWizard.setEnabled(false); jmiGetCovers.setEnabled(false); if (getItem() == null) { jmiDelete.setEnabled(false); jmiPlay.setEnabled(false); jmiPlayRepeat.setEnabled(false); jmiPlayShuffle.setEnabled(false); jmiFrontPush.setEnabled(false); jmiPush.setEnabled(false); jmiProperties.setEnabled(false); } // Set URL to open if (UtilSystem.isBrowserSupported()) { jmiOpenLastFMSite.putClientProperty(Const.DETAIL_CONTENT, artist.getUrl()); } } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/thumbnails/LastFmAlbumThumbnail.java0000644000175000017500000002037411720500104027452 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.thumbnails; import ext.services.lastfm.AlbumInfo; import ext.services.lastfm.LastFmService; import ext.services.lastfm.TrackInfo; import java.awt.Color; import java.awt.image.BufferedImage; import java.io.FileNotFoundException; import java.net.SocketTimeoutException; import java.net.URL; import javax.imageio.ImageIO; import javax.swing.ImageIcon; import javax.swing.JLabel; import javax.swing.SwingConstants; import net.miginfocom.swing.MigLayout; import org.apache.commons.lang.StringUtils; import org.jajuk.base.Album; import org.jajuk.base.AlbumManager; import org.jajuk.base.Item; import org.jajuk.ui.helpers.FontManager; import org.jajuk.ui.helpers.FontManager.JajukFont; import org.jajuk.util.Const; import org.jajuk.util.DownloadManager; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; import org.jajuk.util.UtilGUI; import org.jajuk.util.UtilString; import org.jajuk.util.UtilSystem; import org.jajuk.util.log.Log; import org.jdesktop.swingx.border.DropShadowBorder; /** * Last.FM Album thumb represented as album cover + (optionally) others text * information display... */ public class LastFmAlbumThumbnail extends AbstractThumbnail { /** Generated serialVersionUID. */ private static final long serialVersionUID = -804471264407148566L; /** Associated album. */ private AlbumInfo album; /** Is this artist known in collection ?. */ private final boolean bKnown; /** Thumb associated image *. */ private ImageIcon ii; /** * The Constructor. * * @param album : * associated album */ public LastFmAlbumThumbnail(AlbumInfo album) { super(100); this.album = album; bKnown = (AlbumManager.getInstance().getAlbumByName(album.getTitle()) != null); } /* * (non-Javadoc) * * @see org.jajuk.ui.thumbnails.AbstractThumbnail#getItem() */ @Override public Item getItem() { Album item = AlbumManager.getInstance().getAlbumByName(album.getTitle()); if (item != null) { return item; } return null; } /* * (non-Javadoc) * * @see org.jajuk.ui.thumbnails.AbstractThumbnail#getDescription() */ @Override public String getDescription() { // populate album detail if (album.getTracks() == null) { AlbumInfo lAlbum = LastFmService.getInstance().getAlbum(this.album.getArtist(), this.album.getTitle()); if (lAlbum != null) { this.album = lAlbum; } } Color bgcolor = UtilGUI.getUltraLightColor(); Color fgcolor = UtilGUI.getForegroundColor(); String sOut = "
    " + "" + album.getTitle() + "" + "

    "; // display cover sOut += "
    "; // Display artist as global value only if it is a single artist album // We use file://? as HTML hyperlink format sOut += "
    " + Messages.getHumanPropertyName(Const.XML_ARTIST) + " : " + "" + album.getArtist() + ""; // Display year if available String year = album.getYear(); if (!StringUtils.isBlank(year)) { sOut += "
    " + Messages.getHumanPropertyName(Const.XML_YEAR) + " : " + year; } sOut += "
    "; // Show each track detail if available if (album.getTracks() != null) { for (TrackInfo track : album.getTracks()) { sOut += "" + "" + track.getTitle() + "
    "; } } sOut += "
    "; return sOut; } /* * (non-Javadoc) * * @see org.jajuk.ui.thumbnails.AbstractThumbnail#launch() */ @Override public void launch() { if (getItem() != null) { // play the album jmiPlay.doClick(); } else { // Open the last.FM page jmiOpenLastFMSite.doClick(); } } /** * Long part of the populating process. Longest parts (images download) should * have already been done by the caller outside the EDT. we only pop the image * from the cache here. */ private void preLoad() { try { // Check if album image is null String albumUrl = album.getBigCoverURL(); if (StringUtils.isBlank(albumUrl)) { return; } // Download thumb URL remote = new URL(albumUrl); // Download image and store file reference (to generate the // popup thumb for ie) fCover = DownloadManager.downloadToCache(remote); BufferedImage image = ImageIO.read(fCover); if (image == null) { Log.warn("Could not read cover from: {{" + fCover.getAbsolutePath() + "}}"); return; } ImageIcon downloadedImage = new ImageIcon(image); ii = UtilGUI.getScaledImage(downloadedImage, 100); // Free images memory downloadedImage.getImage().flush(); image.flush(); } catch (FileNotFoundException e) { // only report a warning for FileNotFoundException and do not show a // stack trace in the logfile as it is happening frequently Log.warn("Could not load image, no content found at address: {{" + e.getMessage() + "}}"); } catch (SocketTimeoutException e) { // only report a warning for FileNotFoundException and do not show a // stacktrace in the logfile as it is happening frequently Log.warn("Could not load image, timed out while reading address: {{" + e.getMessage() + "}}"); } catch (Exception e) { Log.error(e); } } /** * Thumb populating done in EDT. */ @Override public void populate() { preLoad(); if (ii == null) { return; } jlIcon = new JLabel(); postPopulate(); jlIcon.setIcon(ii); setLayout(new MigLayout("ins 0,gapy 2")); add(jlIcon, "center,wrap"); JLabel jlTitle; String fullTitle = album.getTitle(); // Add year if available String releaseDate = album.getReleaseDateString(); if (StringUtils.isNotBlank(releaseDate)) { fullTitle += " (" + releaseDate + ")"; } int textLength = 15; if (isArtistView()) { textLength = 50; } if (bKnown) { // Album known in collection, display its name in bold jlTitle = new JLabel(UtilString.getLimitedString(fullTitle, textLength), IconLoader .getIcon(JajukIcons.ALBUM), SwingConstants.CENTER); jlTitle.setFont(FontManager.getInstance().getFont(JajukFont.BOLD)); } else { jlTitle = new JLabel(UtilString.getLimitedString(fullTitle, textLength)); jlTitle.setFont(FontManager.getInstance().getFont(JajukFont.PLAIN)); } jlTitle.setToolTipText(album.getTitle()); jlIcon.setToolTipText(album.getTitle()); add(jlTitle, "center"); jlIcon.setBorder(new DropShadowBorder(Color.BLACK, 5, 0.5f, 5, false, true, false, true)); // disable inadequate menu items jmiCDDBWizard.setEnabled(false); jmiGetCovers.setEnabled(false); if (getItem() == null) { jmiDelete.setEnabled(false); jmiPlay.setEnabled(false); jmiPlayRepeat.setEnabled(false); jmiPlayShuffle.setEnabled(false); jmiFrontPush.setEnabled(false); jmiPush.setEnabled(false); jmiProperties.setEnabled(false); } // Set URL to open if (UtilSystem.isBrowserSupported()) { jmiOpenLastFMSite.putClientProperty(Const.DETAIL_CONTENT, album.getUrl()); } } } jajuk-1.9.6.orig/src/main/java/org/jajuk/ui/thumbnails/ThumbnailPopup.java0000644000175000017500000002245211720500104026405 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.thumbnails; import java.awt.KeyEventDispatcher; import java.awt.KeyboardFocusManager; import java.awt.Rectangle; import java.awt.Toolkit; import java.awt.event.KeyEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.net.URI; import java.net.URL; import java.util.ArrayList; import java.util.Collections; import java.util.List; import javax.swing.JEditorPane; import javax.swing.JScrollPane; import javax.swing.JWindow; import javax.swing.SwingUtilities; import javax.swing.event.HyperlinkEvent; import javax.swing.event.HyperlinkEvent.EventType; import javax.swing.event.HyperlinkListener; import org.jajuk.base.Artist; import org.jajuk.base.ArtistManager; import org.jajuk.base.File; import org.jajuk.base.Genre; import org.jajuk.base.GenreManager; import org.jajuk.base.Track; import org.jajuk.base.TrackManager; import org.jajuk.base.Year; import org.jajuk.base.YearManager; import org.jajuk.services.players.QueueModel; import org.jajuk.ui.helpers.FontManager; import org.jajuk.ui.helpers.FontManager.JajukFont; import org.jajuk.util.Conf; import org.jajuk.util.Const; import org.jajuk.util.UtilFeatures; import org.jajuk.util.UtilGUI; import org.jajuk.util.log.Log; /** * HTML popup displayed over a thumbnail, it details album informations and * tracks *

    * It is displayed nicely from provided jlabel position *

    *

    * We use a JWindow instead of a JDialog because the painting is faster *

    . */ public class ThumbnailPopup extends JWindow { /** Generated serialVersionUID. */ private static final long serialVersionUID = -8131528719972829954L; /** DOCUMENT_ME. */ private final JEditorPane text; /** DOCUMENT_ME. */ private KeyEventDispatcher dispatcher = null; /** * Launch selection and set right cursor. * * @param tracks DOCUMENT_ME */ private void launchLink(List tracks) { List toPlay = new ArrayList(1); for (Track track : tracks) { File file = track.getBestFile(true); if (file != null) { toPlay.add(file); } } text.setCursor(UtilGUI.WAIT_CURSOR); QueueModel.push(UtilFeatures.createStackItems(UtilFeatures.applyPlayOption(toPlay), Conf .getBoolean(Const.CONF_STATE_REPEAT_ALL), true), Conf .getBoolean(Const.CONF_OPTIONS_PUSH_ON_CLICK)); // Change icon cursor and wait a while so user can see it in case // the PUSH_ON_CLICK option is set, otherwise, user may think // nothing appened. try { Thread.sleep(250); } catch (InterruptedException e1) { Log.error(e1); } text.setCursor(UtilGUI.LINK_CURSOR); } /** * The Constructor. * * @param description HTML text to display (HTML 3.0) * @param origin : * coordinates of the origin item on whish we want to display the * popup * @param autoclose : * whether the popup should close when mouse leave the origin item or * is displayed as a regular Dialog */ public ThumbnailPopup(String description, Rectangle origin, boolean autoclose) { getRootPane().setOpaque(true); text = new JEditorPane("text/html", description); text.setEditable(false); text.putClientProperty(JEditorPane.HONOR_DISPLAY_PROPERTIES, Boolean.TRUE); text.setFont(FontManager.getInstance().getFont(JajukFont.DEFAULT)); text.addHyperlinkListener(new HyperlinkListener() { @Override public void hyperlinkUpdate(HyperlinkEvent e) { if (e.getEventType() == EventType.ACTIVATED) { URL url = e.getURL(); if (Const.XML_ARTIST.equals(url.getHost())) { Artist artist = (Artist) ArtistManager.getInstance().getItemByID(url.getQuery()); List tracks = TrackManager.getInstance().getAssociatedTracks(artist, false); Collections.shuffle(tracks); launchLink(tracks); } else if (Const.XML_GENRE.equals(url.getHost())) { Genre genre = (Genre) GenreManager.getInstance().getItemByID(url.getQuery()); List tracks = TrackManager.getInstance().getAssociatedTracks(genre, false); Collections.shuffle(tracks); launchLink(tracks); } else if (Const.XML_YEAR.equals(url.getHost())) { Year year = (Year) YearManager.getInstance().getItemByID(url.getQuery()); List tracks = TrackManager.getInstance().getAssociatedTracks(year, false); Collections.shuffle(tracks); launchLink(tracks); } else if (Const.XML_URL.equals(url.getHost())) { try { java.awt.Desktop.getDesktop().browse(new URI(url.getQuery())); } catch (Exception e1) { Log.error(e1); } } else if (Const.XML_TRACK.equals(url.getHost())) { List tracks = new ArrayList(1); Track track = (Track) TrackManager.getInstance().getItemByID(url.getQuery()); tracks.add(track); launchLink(tracks); } } // change cursor on entering or leaving // hyperlinks else if (e.getEventType() == EventType.ENTERED) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { text.setCursor(UtilGUI.LINK_CURSOR); } }); } else if (e.getEventType() == EventType.EXITED) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { text.setCursor(UtilGUI.DEFAULT_CURSOR); } }); } } }); final JScrollPane jspText = new JScrollPane(text); add(jspText); if (autoclose) { // Make sure to close this popup when it lost focus text.addMouseListener(new MouseAdapter() { @Override public void mouseExited(MouseEvent e) { // Test if mouse is really outside the popup, for unknown reason, // this event is catch when entering the popup (Windows) if (!jspText.contains(e.getPoint())) { dispose(); } } }); } if (origin != null) { // compute dialog position ( note that setRelativeTo // is buggy and that we need more advanced positioning) int x = (int) origin.getX() + (int) (0.6 * origin.getWidth()); // set position at 60 % of the picture int y = (int) origin.getY() + (int) (0.6 * origin.getHeight()); int screenWidth = (int) Toolkit.getDefaultToolkit().getScreenSize().getWidth(); int screenHeight = (int) Toolkit.getDefaultToolkit().getScreenSize().getHeight(); // Adjust position if details are located outside // the screen // in x-axis if ((x + 500) > screenWidth) { x = screenWidth - 510; } if ((y + 400) > screenHeight) { x = (int) origin.getX() + (int) (0.6 * origin.getWidth()); if ((x + 500) > screenWidth) { x = screenWidth - 510; } y = (int) origin.getY() + (int) (0.4 * origin.getHeight()) - 350; } setLocation(x, y); } else { setLocationByPlatform(true); } setSize(500, 400); setVisible(true); // Force scrollbar to stay on top SwingUtilities.invokeLater(new Runnable() { @Override public void run() { jspText.getVerticalScrollBar().setValue(0); } }); setKeystrokes(); } /** * Add keystroke to dispose the popup when escape is pressed For unknown * reasons, registerKeyboardAction() against JWindow doesn't work (it does for * JFrame) but we need to use JWindow for performance reasons. for that * reason, we add a keyboard focus manager which is called before any focus * consideration * * Note that for a JFrame, we would use * rootPane.registerKeyboardAction(actionListener, stroke, * JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT); */ private void setKeystrokes() { removeKeystrokes(); dispatcher = new KeyEventDispatcher() { @Override public boolean dispatchKeyEvent(KeyEvent e) { dispose(); return false; } }; KeyboardFocusManager.getCurrentKeyboardFocusManager().addKeyEventDispatcher(dispatcher); } /** * Removes the keystrokes. * DOCUMENT_ME */ private void removeKeystrokes() { if (dispatcher != null) { KeyboardFocusManager.getCurrentKeyboardFocusManager().removeKeyEventDispatcher(dispatcher); dispatcher = null; } } /* (non-Javadoc) * @see java.awt.Window#dispose() */ @Override public void dispose() { removeKeystrokes(); super.dispose(); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/events/0000755000175000017500000000000011720500104021307 5ustar drazzibdrazzibjajuk-1.9.6.orig/src/main/java/org/jajuk/events/ObserverRegistry.java0000644000175000017500000001175511720500104025503 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.events; import java.util.ArrayList; import java.util.HashMap; import java.util.Hashtable; import java.util.Iterator; import java.util.List; import java.util.Map; import org.jajuk.util.Const; import org.jajuk.util.log.Log; /** * Registry of Observers for each of the JajukEvents. Used by ObservationManager * to handle informing observers about events happening in other objects. */ class ObserverRegistry { /** The list of Observers per JajukEvents. */ private final Map> hEventComponents = new Hashtable>( 10); /** Number of current executions for a given event. */ private static Map canals = new HashMap(10); /** * Calls the update method for each observer
    * We manage execution canals to limit the number of concurrent executions for * a given event type. This allow to avoid thread number explosion in some * error cases * * @param event The event to execute */ @SuppressWarnings("unchecked") void notifySync(JajukEvent event) { // do the synchronization on canals in two parts to do the "update" without // holding the lock synchronized (canals) { int numberOfExecutions = 0; if (canals.containsKey(event)) { numberOfExecutions = canals.get(event); } if (numberOfExecutions > Const.MAX_EVENT_EXECUTIONS) { Log.warn("Event overflow for : " + event); return; } canals.put(event, numberOfExecutions + 1); } try { JajukEvents subject = event.getSubject(); List observers = hEventComponents.get(subject); if (observers == null) { return; } // Iterate on a cloned list to avoid concurrent exceptions observers = (List) ((ArrayList) observers).clone(); Iterator it = observers.iterator(); while (it.hasNext()) { Observer obs = it.next(); if (obs != null) { try { obs.update(event); } catch (Throwable t) { Log.error(t); } } } } finally { synchronized (canals) { int numberOfExecutions = canals.get(event); assert (numberOfExecutions > 0); canals.put(event, numberOfExecutions - 1); // to avoid adding more and more memory via the canals-map, we should remove items when they // reach zero again // the effect on memory is rather small, but it shows up after some time in memory profiles // nevertheless. if (canals.get(event) == 0) { canals.remove(event); } } } } /** * Register an Observer for an event. * * @param subject The event to register for. * @param observer The Observer that should be informed about * the event as soon as it is reported somewhere else. */ synchronized void register(JajukEvents subject, Observer observer) { List observers = hEventComponents.get(subject); if (observers == null) { observers = new ArrayList(1); hEventComponents.put(subject, observers); } // Add the observer, if it is a high priority observer, put it first in // queue if (!observers.contains(observer)) { if (observer instanceof HighPriorityObserver) { observers.add(0, observer); } else { observers.add(observer); } } } /** * Unregister the Observer from an event. * * @param subject The event to unregister from. * @param observer The Observer that is no longer interested in this event. * * @return true if the event was unregistered, false if it was not * registered (any more) and thus did not need to be removed */ synchronized boolean unregister(JajukEvents subject, Observer observer) { List alComponents = hEventComponents.get(subject); if (alComponents != null) { return alComponents.remove(observer); } return false; } /** * Remove any registered item. This is mainly used in UnitTests to * get a clean state again. */ synchronized public void clear() { hEventComponents.clear(); synchronized (canals) { canals.clear(); } } } jajuk-1.9.6.orig/src/main/java/org/jajuk/events/package.html0000644000175000017500000000017111720500104023567 0ustar drazzibdrazzib DOCUMENT_ME jajuk-1.9.6.orig/src/main/java/org/jajuk/events/ObservationManager.java0000644000175000017500000001750611720500104025751 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.events; import java.util.HashMap; import java.util.Map; import java.util.Properties; import java.util.Set; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeUnit; import org.jajuk.services.core.ExitService; import org.jajuk.util.log.Log; /** * This is a mediator managing relationships between subjects and observers *

    * All notification methods are synchronized to assure event order. */ public final class ObservationManager { /** one event -> list of components. */ static ObserverRegistry observerRegistry = new ObserverRegistry(); /** Last event for a given subject (used for new objects that just registrated to this subject). */ static Map hLastEventBySubject = new HashMap(10); /** The queue itself. Must be synchronized, so we use a ConcurrentLinkedQueue which is thread-safe */ static BlockingQueue queue = new LinkedBlockingQueue(); /** The observation fifo. */ private static ObservationManagerThread observationThread; /** * Empty constructor to avoid instantiating this utility class. */ private ObservationManager() { } /** * Register a component for a list of subjects. This calls the * interface @see Observer.getRegistrationKeys() to retrieve * a list of events which the Observer is interested in. * * @param observer The Observer to register. */ public static synchronized void register(Observer observer) { Set eventSubjectSet = observer.getRegistrationKeys(); for (JajukEvents subject : eventSubjectSet) { Log.debug("Register: \"" + subject + "\" by: " + observer); observerRegistry.register(subject, observer); } } /** * Unregister a component for a list of subjects. * * @param observer The Observer to unregister. * * @see Observer.getRegistrationKeys() is called on the Observer * to get the list of events. */ public static synchronized void unregister(Observer observer) { Set eventSubjectSet = observer.getRegistrationKeys(); // can return null if no keys are registered if (eventSubjectSet == null) { return; } for (JajukEvents subject : eventSubjectSet) { boolean bRemoved = observerRegistry.unregister(subject, observer); if (bRemoved) { Log.debug("Unregister: \"" + subject + "\" from: " + observer); } } } /** * Notify all components having registered for the given subject. * * @param event The event that is triggered including any additional * data that is of interest as part of the event. */ public static void notify(JajukEvent event) { // asynchronous notification by default to avoid // exception throw in the register current thread try { /* * do not launch it in a regular thread because EDT waits thread end to * display */ queue.add(event); // synchronize here to avoid creating more than one observation manager // thread synchronized (ObservationManager.class) { if (observationThread == null || !observationThread.isAlive()) { // If the thread is terminated, a new thread must be instantiated // Otherwise an IllegalThreadStateException is thrown Log.debug("Observation Manager thread not running, start a new one"); observationThread = new ObservationManagerThread(); observationThread.start(); } } } catch (Error e) { // Make sure to catch any error (Memory or IllegalThreadStateException for // ie, this notification musn't stop the current work) Log.error(e); } } /** * Notify synchronously all components having registered for the given subject. * * @param event The event that is triggered including any additional * data that is of interest as part of the event. */ public static void notifySync(JajukEvent event) { JajukEvents subject = event.getSubject(); Log.debug("Notify: " + subject); // save last event hLastEventBySubject.put(subject, event.getDetails()); observerRegistry.notifySync(event); } /** * Return whether the event already occurred at least once. * * @param subject The type of event to check for. * * @return true, if contains event, false otherwise. */ public static boolean containsEvent(JajukEvents subject) { return hLastEventBySubject.containsKey(subject); } /** * Return the details for last event of the given subject, or null if there is * no details. * * @param subject The type of event to check for. * @param sDetailName The detailed piece of information to fetch. * * @return the detail as an object or null if the event or the detail doesn't * exist */ public static Object getDetailLastOccurence(JajukEvents subject, String sDetailName) { Properties pDetails = hLastEventBySubject.get(subject); if (pDetails != null) { return pDetails.get(sDetailName); } return null; } /** * Return the details for an event, or null if there is no details. * * @param event The event to retrieve the detail from. * @param sDetailName The detailed piece of information to fetch. * * @return the detail as an object or null if the event or the detail doesn't * exist */ public static Object getDetail(JajukEvent event, String sDetailName) { Properties pDetails = event.getDetails(); if (pDetails != null) { return pDetails.get(sDetailName); } return null; } /** * Return the details for an event, or null if there is no details. * * @param subject The event to query for. * * @return the details or null there are not details */ public static Properties getDetailsLastOccurence(JajukEvents subject) { return hLastEventBySubject.get(subject); } /** * Remove all registered Observers. This is mainly used in Unit Tests * to get a clean state again. */ public static void clear() { hLastEventBySubject.clear(); queue.clear(); observerRegistry.clear(); } } /** * Observation manager thread that consumes events asynchronously */ class ObservationManagerThread extends Thread { ObservationManagerThread() { super("Observation Manager Thread"); } @Override public void run() { // Stop to execute events is thread flag is set or if Jajuk is exiting while (!ExitService.isExiting()) { try { final JajukEvent event = ObservationManager.queue.poll(1000, TimeUnit.MILLISECONDS); if (event != null) { // launch action asynchronously new Thread("Event Executor for: " + event.toString()) { @Override public void run() { ObservationManager.notifySync(event); } }.start(); } // Make sure to handle any exception or error to avoid the observation // system to die. Throwable covers all types of Exceptions/Errors. } catch (Throwable e) { Log.error(e); } } } } jajuk-1.9.6.orig/src/main/java/org/jajuk/events/HighPriorityObserver.java0000644000175000017500000000170411720500104026305 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.events; /** * Special Observer whish must be updated before any other. */ public interface HighPriorityObserver extends Observer { } jajuk-1.9.6.orig/src/main/java/org/jajuk/events/Observer.java0000644000175000017500000000253011720500104023741 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.events; import java.util.Set; /** * GoF Observer pattern Observer. */ public interface Observer { /** * Action to be done when receiving an event with this ID. * * @param event The JajukEvent maps a subject and details of the event */ void update(JajukEvent event); /** * Used by @see ObservationManager to retrieve all the events on which * the Observer wants to listen to. * * @return A set of JajukEvents on which the Observer would like to listen. */ Set getRegistrationKeys(); } jajuk-1.9.6.orig/src/main/java/org/jajuk/events/JajukEvents.java0000644000175000017500000001101011720500104024374 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.events; /** * DOCUMENT_ME. */ public enum JajukEvents { /** repeat mode changed. */ REPEAT_MODE_STATUS_CHANGED, /** new device. */ DEVICE_NEW, /** removed device. */ DEVICE_DELETE, /** parameters change. */ PARAMETERS_CHANGE, /** device properties display. */ DEVICE_PROPERTIES, /** mount device. */ DEVICE_MOUNT, /** unmount a device. */ DEVICE_UNMOUNT, /** test a device. */ DEVICE_TEST, /** refresh a device. */ DEVICE_REFRESH, /** sync. a device */ DEVICE_SYNCHRO, /** refresh a view is required. */ VIEW_REFRESH_REQUEST, /** the stop button has been pressed. */ PLAYER_STOP, /** the play button has been pressed. */ PLAYER_PLAY, /** the pause button has been pressed. */ PLAYER_PAUSE, /** the resume button has been pressed. */ PLAYER_RESUME, /** Queue should be refreshed. */ QUEUE_NEED_REFRESH, /** a file has been launched by the fifo. */ FILE_LAUNCHED, /** heart beat for general use to refresh subscribers. */ /** every n secs */ HEART_BEAT, /** a web radio has been launched. */ WEBRADIO_LAUNCHED, /** a reinit has been required. */ ZERO, /** special mode (global shuffle, novelties, bestof...) */ SPECIAL_MODE, /** an error occurred during a play. */ PLAY_ERROR, /** A track is opening. */ PLAY_OPENING, /** mute state changed. */ MUTE_STATE, /** clear history. */ CLEAR_HISTORY, /** launch first time wizard. */ WIZARD, /** volume changed. */ VOLUME_CHANGED, /** new custom property. */ CUSTOM_PROPERTIES_ADD, /** remove custom property. */ CUSTOM_PROPERTIES_REMOVE, /** file name change. */ FILE_NAME_CHANGED, /** Genre name change. */ GENRE_NAME_CHANGED, /** file rate change. */ RATE_CHANGED, /** Cddb wizard required. */ CDDB_WIZARD, /** logical tree sorting method changed. */ LOGICAL_TREE_SORT, /** cover default changed. */ COVER_DEFAULT_CHANGED, /** clear table selection. */ TABLE_CLEAR_SELECTION, /** DJ creation or removal. */ DJS_CHANGE, /** One or more ambiences have been. */ /** removed/added/changed */ AMBIENCES_CHANGE, /** One or more webradios have been. */ /** removed/added/changed */ WEBRADIOS_CHANGE, /** user changed current ambience. */ AMBIENCES_SELECTION_CHANGE, /** An ambience has been removed. */ AMBIENCE_REMOVED, /** Current played track artist name has been. */ /** changed */ ARTIST_CHANGED, /** Current played track album name has been. */ /** changed */ ALBUM_CHANGED, /** Current played track album name has been. */ /** changed */ TRACK_CHANGED, /** Language changed. */ LANGUAGE_CHANGED, /** Perspective changed. */ PERSPECTIVE_CHANGED, /** Current track is finished. */ FILE_FINISHED, /** Lyrics data has been downloaded. */ LYRICS_DOWNLOADED, /** A file has been copied (used by prepare party). */ FILE_COPIED, /** A file is converted from one media type to another. */ FILE_CONVERSION, /** Covers should be refreshed. */ COVER_NEED_REFRESH, /** Ratings have to be reseted. */ RATE_RESET, /** Preferences have been reset. */ PREFERENCES_RESET, /** Suggestion view should be refreshed. */ SUGGESTIONS_REFRESH, /** Table selection changed. */ TABLE_SELECTION_CHANGED, /** Tree selection changed. */ TREE_SELECTION_CHANGED, /** Playing track has been banned. */ BANNED, /** ALARMS CHANGED (REMOVED, ADDED). */ ALARMS_CHANGE, /** Thumb created. */ THUMB_CREATED, /** Exiting Jajuk. */ EXITING, /** D-Bus command that shows the notification with the currently played file. */ SHOW_CURRENTLY_PLAYING, /** Inform the interested objects about a change in the visibility of the slimbar. */ SLIMBAR_VISIBILTY_CHANGED } jajuk-1.9.6.orig/src/main/java/org/jajuk/events/JajukEvent.java0000644000175000017500000000640611720500104024226 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.events; import java.util.Properties; /** * Jajuk event (Observer pattern). */ public class JajukEvent { /** Event subject. */ private final JajukEvents subject; /** Event properties. */ private Properties pDetails; /** * Event constructor. * * @param subject DOCUMENT_ME * @param pDetails DOCUMENT_ME */ public JajukEvent(JajukEvents subject, Properties pDetails) { this.subject = subject; if (pDetails != null) { this.pDetails = pDetails; } } /** * Event constructor. * * @param subject DOCUMENT_ME */ public JajukEvent(JajukEvents subject) { this(subject, null); } /** * Gets the details. * * @return Returns the pDetails. */ public Properties getDetails() { return pDetails; } /** * Gets the subject. * * @return Returns the sSubject. */ public JajukEvents getSubject() { return subject; } /** * ToString method. * * @return the string */ @Override public String toString() { // Do not display details, that can cause severe performance issue if (pDetails == null) { return subject + " no details"; } else { return subject.toString(); } } /** * event equals method. * * @param obj DOCUMENT_ME * * @return true, if equals */ @Override public boolean equals(Object obj) { if (!(obj instanceof JajukEvent)) { return false; } JajukEvent event = (JajukEvent) obj; boolean bOut = false; if (this.subject.equals(event.getSubject())) { if (this.pDetails == null && event.pDetails == null) { bOut = true; } else if (this.pDetails != null && event.pDetails != null && this.pDetails.equals(event.getDetails())) { bOut = true; } } return bOut; } /* (non-Javadoc) * @see java.lang.Object#hashCode() */ @Override public int hashCode() { // very simple implementation, needs to be revisited if this object is used // heavily in HashMaps/HashSets // for now just combine name and id to a hashcode // idea taken from // http://www.geocities.com/technofundo/tech/java/equalhash.html int hash = 7; hash = 31 * hash + subject.hashCode(); if (pDetails != null) { // Use only properties size, not hashcode because it is too heavy for large selection // in properties and causes concurrent modification exceptions hash = 31 * hash + pDetails.size(); } return hash; } } jajuk-1.9.6.orig/src/main/java/org/jajuk/base/0000755000175000017500000000000011720500104020715 5ustar drazzibdrazzibjajuk-1.9.6.orig/src/main/java/org/jajuk/base/YearManager.java0000644000175000017500000000613311720500104023756 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.base; import java.util.Iterator; import java.util.List; import org.jajuk.util.Const; import org.jajuk.util.ReadOnlyIterator; /** * Convenient class to manage years. */ public final class YearManager extends ItemManager { /** Self instance. */ private static YearManager singleton = new YearManager(); /** * No constructor available, only static access. */ private YearManager() { super(); // register properties // ID registerProperty(new PropertyMetaInformation(Const.XML_ID, false, true, false, false, false, String.class, null)); // Name registerProperty(new PropertyMetaInformation(Const.XML_NAME, false, true, true, true, false, String.class, null)); // Expand registerProperty(new PropertyMetaInformation(Const.XML_EXPANDED, false, false, false, false, true, Boolean.class, false)); } /** * Gets the instance. * * @return singleton */ public static YearManager getInstance() { return singleton; } /** * Register a year. * * @param pYear DOCUMENT_ME * * @return the year */ public Year registerYear(String pYear) { String sId = pYear; return registerYear(sId, pYear); } /** * Register a year with a known id. * * @param sId DOCUMENT_ME * @param pYear DOCUMENT_ME * * @return the year */ public Year registerYear(String sId, String pYear) { Year year = getYearByID(sId); if (year != null) { return year; } year = new Year(sId, pYear); registerItem(year); return year; } /* * (non-Javadoc) * * @see org.jajuk.base.ItemManager#getIdentifier() */ @Override public String getLabel() { return Const.XML_YEARS; } /** * Gets the year by id. * * @param sID Item ID * * @return Element */ public Year getYearByID(String sID) { return (Year) getItemByID(sID); } /** * Gets the years. * * @return ordered years list */ @SuppressWarnings("unchecked") public List getYears() { return (List) getItems(); } /** * Gets the years iterator. * * @return years iterator */ @SuppressWarnings("unchecked") public ReadOnlyIterator getYearsIterator() { return new ReadOnlyIterator((Iterator) getItemsIterator()); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/base/ArtistManager.java0000644000175000017500000001610011720500104024317 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.base; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; import java.util.Vector; import org.jajuk.events.JajukEvent; import org.jajuk.events.JajukEvents; import org.jajuk.events.ObservationManager; import org.jajuk.services.players.QueueModel; import org.jajuk.util.Const; import org.jajuk.util.ReadOnlyIterator; import org.jajuk.util.error.JajukException; /** * Convenient class to manage artists. */ public final class ArtistManager extends ItemManager { /** Self instance. */ private static ArtistManager singleton = new ArtistManager(); /** List of all known artists. */ private Vector artistsList = new Vector(100); // NOPMD /** * No constructor available, only static access. * Not private to allow AlbumArtistManager extends */ ArtistManager() { super(); // register properties // ID registerProperty(new PropertyMetaInformation(Const.XML_ID, false, true, false, false, false, String.class, null)); // Name registerProperty(new PropertyMetaInformation(Const.XML_NAME, false, true, true, true, false, String.class, null)); // Expand registerProperty(new PropertyMetaInformation(Const.XML_EXPANDED, false, false, false, false, true, Boolean.class, false)); } /** * Gets the instance. * * @return singleton */ public static ArtistManager getInstance() { return singleton; } /** * Register an artist. * * @param sName The name of the artist to search for. * * @return the artist */ public Artist registerArtist(String sName) { String sId = createID(sName); return registerArtist(sId, sName); } /** * Register an artist with a known id. * * @param sId the ID of the new artist. * @param sName The name of the new artist. * @return the artist */ public Artist registerArtist(String sId, String sName) { Artist artist = getArtistByID(sId); // if we have this artist already, simply return the existing one if (artist != null) { return artist; } artist = new Artist(sId, sName); registerItem(artist); // add it in genres list if new if (!artistsList.contains(sName)) { artistsList.add(artist.getName2()); // Sort items ignoring case Collections.sort(artistsList, new Comparator() { @Override public int compare(String o1, String o2) { return o1.compareToIgnoreCase(o2); } }); } return artist; } /** * Change the item name. * * @param old The name of the artist to update. * @param sNewName The new name of the artist. * * @return The new Album-Instance. * * @throws JajukException Thrown if adjusting the name fails for some reason. */ public Artist changeArtistName(Artist old, String sNewName) throws JajukException { // check if there is actually a change if (old.getName2().equals(sNewName)) { return old; } // find out if the QueueModel is playing this track before we change the track! boolean queueNeedsUpdate = false; if (QueueModel.getPlayingFile() != null && QueueModel.getPlayingFile().getTrack().getArtist().equals(old)) { queueNeedsUpdate = true; } Artist newItem = registerArtist(sNewName); // re apply old properties from old item newItem.cloneProperties(old); // update tracks for (Track track : TrackManager.getInstance().getTracks()) { if (track.getArtist().equals(old)) { TrackManager.getInstance().changeTrackArtist(track, sNewName, null); } } // if current track artist name is changed, notify it if (queueNeedsUpdate) { ObservationManager.notify(new JajukEvent(JajukEvents.ARTIST_CHANGED)); } return newItem; } /* * (non-Javadoc) * * @see org.jajuk.base.ItemManager#getIdentifier() */ @Override public String getLabel() { return Const.XML_ARTISTS; } /** * Gets the artists list. * * @return artists as a string list (used for artists combos) */ public static Vector getArtistsList() { return getInstance().artistsList; } /** * Gets the artist by id. * * @param sID Item ID * * @return Element */ public Artist getArtistByID(String sID) { return (Artist) getItemByID(sID); } /** * Gets the artists. * * @return ordered albums list */ @SuppressWarnings("unchecked") public List getArtists() { return (List) getItems(); } /** * Gets the artists iterator. * * @return artists iterator */ @SuppressWarnings("unchecked") public ReadOnlyIterator getArtistsIterator() { return new ReadOnlyIterator((Iterator) getItemsIterator()); } /** * Get ordered list of artists associated with this item. * * @param item The artist item to look for. * * @return the associated artists */ public List getAssociatedArtists(Item item) { lock.readLock().lock(); try { List out; if (item instanceof Track) { out = new ArrayList(1); out.add(((Track) item).getArtist()); } else { // [Perf] If item is a track, just return its artist // Use a set to avoid dups Set artistSet = new HashSet(); List tracks = TrackManager.getInstance().getAssociatedTracks(item, true); for (Track track : tracks) { artistSet.add(track.getArtist()); } out = new ArrayList(artistSet); Collections.sort(out); } return out; } finally { lock.readLock().unlock(); } } /** * Gets the artist by name. * * @param name The name of the artist. * * @return associated artist (case insensitive) or null if no match */ public Artist getArtistByName(String name) { lock.readLock().lock(); try { Artist out = null; for (ReadOnlyIterator it = getArtistsIterator(); it.hasNext();) { Artist artist = it.next(); if (artist.getName().equals(name)) { out = artist; break; } } return out; } finally { lock.readLock().unlock(); } } } jajuk-1.9.6.orig/src/main/java/org/jajuk/base/package.html0000644000175000017500000000015211720500104023174 0ustar drazzibdrazzib Contains Jajuk base classes : business domain classes like tracks, files... jajuk-1.9.6.orig/src/main/java/org/jajuk/base/AlbumManager.java0000644000175000017500000004164011720500104024120 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.base; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import org.jajuk.base.TrackComparator.TrackComparatorType; import org.jajuk.events.JajukEvent; import org.jajuk.events.JajukEvents; import org.jajuk.events.ObservationManager; import org.jajuk.events.Observer; import org.jajuk.services.players.QueueModel; import org.jajuk.util.Const; import org.jajuk.util.MD5Processor; import org.jajuk.util.ReadOnlyIterator; import org.jajuk.util.error.JajukException; import org.jajuk.util.error.JajukRuntimeException; /** * Convenient class to manage Albums. */ public final class AlbumManager extends ItemManager implements Observer { /** Self instance. */ private static AlbumManager singleton = new AlbumManager(); /** Album max rating. */ private long maxRate = 0l; /** DOCUMENT_ME. */ private int comp = 0; /** * No constructor available, only static access. */ private AlbumManager() { super(); // register properties // ID registerProperty(new PropertyMetaInformation(Const.XML_ID, false, true, false, false, false, String.class, null)); // Name registerProperty(new PropertyMetaInformation(Const.XML_NAME, false, true, true, true, false, String.class, null)); // Expand registerProperty(new PropertyMetaInformation(Const.XML_EXPANDED, false, false, false, false, true, Boolean.class, false)); // Discovered Cover path registerProperty(new PropertyMetaInformation(Const.XML_ALBUM_DISCOVERED_COVER, false, false, false, false, false, String.class, null)); // Selected Cover path registerProperty(new PropertyMetaInformation(Const.XML_ALBUM_SELECTED_COVER, false, false, false, false, false, String.class, null)); // Disc id registerProperty(new PropertyMetaInformation(Const.XML_ALBUM_DISC_ID, false, true, true, false, false, Long.class, -1l)); // Register events ObservationManager.register(this); } /* * (non-Javadoc) * * @see org.jajuk.events.Observer#getRegistrationKeys() */ @Override public Set getRegistrationKeys() { Set eventSubjectSet = new HashSet(); eventSubjectSet.add(JajukEvents.FILE_LAUNCHED); return eventSubjectSet; } /** * Gets the instance. * * @return singleton */ public static AlbumManager getInstance() { return singleton; } /** * Return hashcode for this item. * * @param sName item name * @param discId DOCUMENT_ME * * @return ItemManager ID */ protected static String createID(String sName, long discId) { return MD5Processor.hash(sName + discId); } /** * Register an Album with a known id. * * @param sId DOCUMENT_ME * @param sName DOCUMENT_ME * @param discID DOCUMENT_ME * @return the album */ public Album registerAlbum(String sId, String sName, long discID) { Album album = getAlbumByID(sId); if (album != null) { return album; } album = new Album(sId, sName, discID); registerItem(album); return album; } /** * Register an Album. * * @param sName DOCUMENT_ME * @param discID DOCUMENT_ME * * @return the album */ public Album registerAlbum(String sName, long discID) { String sId = createID(sName, discID); return registerAlbum(sId, sName, discID); } /** * Change the item. * * @param old DOCUMENT_ME * @param sNewName DOCUMENT_ME * * @return new album * * @throws JajukException the jajuk exception */ public Album changeAlbumName(Album old, String sNewName) throws JajukException { // check there is actually a change if (old.getName2().equals(sNewName)) { return old; } // check up front as later the state of the track is already changed boolean bQueueUpdateRequired = false; if (QueueModel.getPlayingFile() != null && QueueModel.getPlayingFile().getTrack().getAlbum().equals(old)) { bQueueUpdateRequired = true; } Album newItem = registerAlbum(sNewName, old.getDiscID()); // re apply old properties from old item newItem.cloneProperties(old); // update tracks for (Track track : TrackManager.getInstance().getTracks()) { if (track.getAlbum().equals(old)) { TrackManager.getInstance().changeTrackAlbum(track, sNewName, null); } } // if current track album name is changed, notify it if (bQueueUpdateRequired) { ObservationManager.notify(new JajukEvent(JajukEvents.ALBUM_CHANGED)); } // remove old item removeItem(old); return newItem; } /** * Format the album name to be normalized : *

    * -no underscores or other non-ASCII characters *

    * -no spaces at the begin and the end *

    * -All in lower case expect first letter of first word *

    * example: "My album title". * * @param sName The name to format. * * @return The formatted string. */ public static String format(String sName) { String sOut = sName.trim(); // suppress spaces at the begin and the end sOut = sOut.replace('-', ' '); // move - to space sOut = sOut.replace('_', ' '); // move _ to space char c = sOut.charAt(0); StringBuilder sb = new StringBuilder(sOut); sb.setCharAt(0, Character.toUpperCase(c)); return sb.toString(); } /* * (non-Javadoc) * * @see org.jajuk.base.ItemManager#getIdentifier() */ @Override public String getLabel() { return Const.XML_ALBUMS; } /** * Gets the album by id. * * @param sID Item ID * * @return Element */ public Album getAlbumByID(String sID) { return (Album) getItemByID(sID); } /** * Gets the albums. * * @return ordered albums list */ @SuppressWarnings("unchecked") public List getAlbums() { return (List) getItems(); } /** * Gets the albums iterator. * * @return albums iterator */ @SuppressWarnings("unchecked") public ReadOnlyIterator getAlbumsIterator() { return new ReadOnlyIterator((Iterator) getItemsIterator()); } /** * Get sorted list of albums associated with this item. * * @param item the item * * @return a list of item, void list if no result */ public List getAssociatedAlbums(Item item) { List out; // [Perf] If item is a track, just return its album if (item instanceof Track) { out = new ArrayList(1); out.add(((Track) item).getAlbum()); } else { try { lock.readLock().lock(); ReadOnlyIterator albums = getAlbumsIterator(); // Use a set to avoid dups Set albumSet = new HashSet(); while (albums.hasNext()) { Album album = albums.next(); List cache = album.getTracksCache(); synchronized (cache) { for (Track track : cache) { if (item instanceof Artist && track.getArtist().equals(item)) { albumSet.add(album); } else if (item instanceof Genre && track.getGenre().equals(item)) { albumSet.add(album); } else if (item instanceof Year && track.getYear().equals(item)) { albumSet.add(album); } else { throw new JajukRuntimeException("Association not implemented " + item); } } } } out = new ArrayList(albumSet); Collections.sort(out); } finally { lock.readLock().unlock(); } } return out; } /** * Return sorted top albums based on the average of each album rating. * * @param bHideUnmounted if true, unmounted albums are not chosen * @param iNbBestofAlbums nb of items to return * * @return top albums, can be less items than required according to nb of * available albums */ public List getBestOfAlbums(boolean bHideUnmounted, int iNbBestofAlbums) { lock.readLock().lock(); try { // Create a temporary table to remove unmounted albums // We consider an album as mounted if a least one track is mounted // This hashmap contains album-> album rates final Map cacheRate = new HashMap(AlbumManager.getInstance() .getElementCount()); ReadOnlyIterator it = AlbumManager.getInstance().getAlbumsIterator(); while (it.hasNext()) { Album album = it.next(); if (!bHideUnmounted || album.containsReadyFiles()) { cacheRate.put(album, (float) album.getRate()); } } // Now sort albums by rating List sortedAlbums = new ArrayList(cacheRate.keySet()); Collections.sort(sortedAlbums, new Comparator() { @Override public int compare(Album o1, Album o2) { // lowest first return (int) (cacheRate.get(o1) - cacheRate.get(o2)); } }); return getTopAlbums(sortedAlbums, iNbBestofAlbums); } finally { lock.readLock().unlock(); } } /** * Return ordered list of newest albums. * * @param bHideUnmounted if true, unmounted albums are not chosen * @param iNb nb of items to return * * @return newest albums */ public List getNewestAlbums(boolean bHideUnmounted, int iNb) { lock.readLock().lock(); try { // create a temporary table to remove unmounted albums // We consider an album as mounted if a least one track is mounted // This hashmap contains album-> discovery date final Map cache = new HashMap(AlbumManager.getInstance() .getElementCount()); ReadOnlyIterator it = TrackManager.getInstance().getTracksIterator(); while (it.hasNext()) { Track track = it.next(); if (track.getBestFile(bHideUnmounted) != null) { cache.put(track.getAlbum(), track.getDiscoveryDate()); } } // Now sort albums by discovery date List sortedAlbums = new ArrayList(cache.keySet()); Collections.sort(sortedAlbums, new Comparator() { @Override public int compare(Album o1, Album o2) { return cache.get(o1).compareTo(cache.get(o2)); } }); return getTopAlbums(sortedAlbums, iNb); } finally { lock.readLock().unlock(); } } /** * Return ordered rarely listen albums list. * * @param bHideUnmounted if true, unmounted albums are not chosen * @param iNb nb of items to return * * @return top albums, can be less items than required according to nb of * available albums */ public List getRarelyListenAlbums(boolean bHideUnmounted, int iNb) { lock.readLock().lock(); try { // create a temporary table to remove unmounted albums // We consider an album as mounted if a least one track is mounted // This hashmap contains album-> album hits (each track hit average) final Map cache = new HashMap(AlbumManager.getInstance() .getElementCount()); // This hashmap contains album-> nb of tracks already taken into account // for average Map cacheNb = new HashMap(AlbumManager.getInstance() .getElementCount()); ReadOnlyIterator it = TrackManager.getInstance().getTracksIterator(); while (it.hasNext()) { Track track = it.next(); if (track.getBestFile(bHideUnmounted) != null) { float newHits = 0f; Integer nb = cacheNb.get(track.getAlbum()); if (nb == null) { nb = 0; } Float previousRate = cache.get(track.getAlbum()); if (previousRate == null) { newHits = track.getHits(); } else { newHits = ((previousRate * nb) + track.getHits()) / (nb + 1); } cacheNb.put(track.getAlbum(), nb + 1); cache.put(track.getAlbum(), newHits); } } // Now sort albums by rating List sortedAlbums = new ArrayList(cache.keySet()); Collections.sort(sortedAlbums, new Comparator() { @Override public int compare(Album o1, Album o2) { // We inverse comparison as we want lowest scores return (int) (cache.get(o2) - cache.get(o1)); } }); return getTopAlbums(sortedAlbums, iNb); } finally { lock.readLock().unlock(); } } /** * Convenient method to keep top albums (used by getBestof, newest... albums) * * @param sortedAlbums sorted albums according desired criteria, size >= iNb * @param iNb Number of albums to return * * @return a nicely sorted / shuffled list of albums or a void list of none * available albums */ private List getTopAlbums(List sortedAlbums, int iNb) { // Keep only 3 * desired size or less if not enough available albums int size = 2 * iNb; if (sortedAlbums.size() <= size) { size = sortedAlbums.size() - 1; } // Leave if none album so far if (sortedAlbums.size() == 0) { return new ArrayList(); } List sublist = sortedAlbums.subList(sortedAlbums.size() - (1 + size), sortedAlbums.size() - 1); // Shuffle the result Collections.shuffle(sublist); // The result is a sublist of shuffled albums, if we have less // albums than required, take max size possible return sublist.subList(0, (size >= iNb) ? iNb : size); } /** * Gets the max rate. * * @return max rating for an album */ public long getMaxRate() { return this.maxRate; } /** * Force to refresh the album max rating, it is not done soon as it is pretty * CPU consuming and we don't need a track by track rating precision. */ public void refreshMaxRating() { // create a temporary table to remove unmounted albums // We consider an album as mounted if a least one track is mounted // This hashmap contains album-> album rates final Map cacheRate = new HashMap(AlbumManager.getInstance() .getElementCount()); for (Album album : AlbumManager.getInstance().getAlbums()) { cacheRate.put(album, (float) album.getRate()); } // OK, now keep only the highest score for (Map.Entry album : cacheRate.entrySet()) { long value = Math.round(album.getValue()); if (value > maxRate) { maxRate = value; } } } /* * (non-Javadoc) * * @see org.jajuk.base.Observer#update(org.jajuk.base.Event) */ @Override public void update(JajukEvent event) { if (event.getSubject() == JajukEvents.FILE_LAUNCHED) { // Compute album max rating every 10 tracks launches if (comp % 10 == 0) { refreshMaxRating(); } comp++; } } /** * Gets the album by name. * * @param name DOCUMENT_ME * * @return associated album (case insensitive) or null if no match */ public Album getAlbumByName(String name) { lock.readLock().lock(); try { Album out = null; for (ReadOnlyIterator it = getAlbumsIterator(); it.hasNext();) { Album album = it.next(); if (album.getName().equalsIgnoreCase(name)) { out = album; break; } } return out; } finally { lock.readLock().unlock(); } } /** * Specialize switchToOrderState, here we sort the album cache in addition. */ public void orderCache() { // read lock, not write lock because we need a write lock only when performing // structural changes to items collection for (Album album : getAlbums()) { List cache = album.getTracksCache(); synchronized (cache) { Collections.sort(cache, new TrackComparator(TrackComparatorType.ALBUM)); } } } /** * Reset cached cover url for every album. * Note that we reset only cached/discovered covers, not user-selected covers. */ public void resetCoverCache() { for (Album album : getAlbums()) { album.setProperty(Const.XML_ALBUM_DISCOVERED_COVER, ""); } } } jajuk-1.9.6.orig/src/main/java/org/jajuk/base/Year.java0000644000175000017500000000566211720500104022471 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.base; import javax.swing.ImageIcon; import org.jajuk.util.Const; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; import org.jajuk.util.UtilString; /** * Year object. *
    Logical item */ public class Year extends LogicalItem implements Comparable { /** The year that is stored in this object. */ private final long value; /** * Year constructor. * * @param sId The generated id (usually a md5hash) * @param sValue The Year-Value as string. Only a simple parsing is done, things * like AC, BC, ... are not supported. */ Year(String sId, String sValue) { super(sId, sValue); if (sValue != null) this.value = UtilString.fastLongParser(sValue); else this.value = 0; } /* * (non-Javadoc) * * @see org.jajuk.base.Item#getIdentifier() */ @Override public final String getLabel() { return XML_YEAR; } /** * Gets the value. * * @return year as a long */ public long getValue() { return value; } /** * Alphabetical comparator used to display ordered lists. * * @param other item to be compared * * @return comparison result */ @Override public int compareTo(Year other) { if (other == null) { return -1; } return (int) (getValue() - other.getValue()); } /** * Get item description. * * @return the desc */ @Override public String getDesc() { return Messages.getHumanPropertyName(Const.XML_YEAR) + " : " + getName(); } /** * Gets the name2. * * @return a human-readable year format */ public String getName2() { String s = getName(); if ("0".equals(s)) { return Messages.getString(UNKNOWN_YEAR); } return s; } /* * (non-Javadoc) * * @see org.jajuk.base.Item#getIconRepresentation() */ @Override public ImageIcon getIconRepresentation() { return IconLoader.getIcon(JajukIcons.YEAR); } /** * Return whether this year looks valid or not. * * @return true, if looks valid */ public boolean looksValid() { return value > 1000 && value < 3000; } } jajuk-1.9.6.orig/src/main/java/org/jajuk/base/TrackComparator.java0000644000175000017500000001640511720500104024662 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.base; import java.io.Serializable; import java.text.DateFormat; import java.util.Comparator; import org.jajuk.util.UtilString; /** * Multi-method track comparator. */ public class TrackComparator implements Comparator, Serializable { /** Generated serialVersionUID. */ private static final long serialVersionUID = -4735723947400147134L; /** Sorting method. */ private final TrackComparatorType comparatorType; /** * Sorting methods constants. */ public enum TrackComparatorType { /** Compare first based on the genre, then on artist and then on album. */ GENRE_ARTIST_ALBUM, /** Compare based on artist and then album. */ ARTIST_ALBUM, /** Compare only on album. */ ALBUM, /** Compare only on year. */ YEAR_ALBUM, /** Compare only on the discovery date of the album. */ DISCOVERY_ALBUM, /** Compare on the rate and then the album. */ RATE_ALBUM, /** Compare on the number of hits and then on the album. */ HITS_ALBUM, /** Compare on disc number and order of the track in the album. */ ORDER, /** Compare to find identifical tracks. */ ALMOST_IDENTICAL } /** The Constant FORMATTER. Used to correctly compare dates. */ private static final DateFormat FORMATTER = UtilString.getAdditionDateFormatter(); /** * Constructor. * * @param comparatorType Specifies the type of comparison that should be done. */ public TrackComparator(TrackComparatorType comparatorType) { this.comparatorType = comparatorType; } /** * Gets the compare string based on the input-track and the type of comparison * that is selected when constructing the comparator. * * @param track The track that should be used for constructing the string. * * @return Hashcode string used to compare two tracks in accordance with the * sorting method */ private String getCompareString(Track track) { String sHashCompare = null; // comparison based on genre, artist, album, name and year to // differentiate 2 tracks with all the same attributes // note we need to use year because in sorted set, we must differentiate // 2 tracks with different years // Genre/artist/album if (comparatorType == TrackComparatorType.GENRE_ARTIST_ALBUM) { sHashCompare = new StringBuilder().append(track.getGenre().getName2()).append( track.getArtist().getName2()).append(track.getAlbum().getName2()).append( UtilString.padNumber(track.getOrder(), 5)).append(track.getName()).toString(); }// Artist/album else if (comparatorType == TrackComparatorType.ARTIST_ALBUM) { sHashCompare = new StringBuilder().append(track.getArtist().getName2()).append( track.getAlbum().getName2()).append(UtilString.padNumber(track.getOrder(), 5)).append( track.getName()).toString(); } // Album else if (comparatorType == TrackComparatorType.ALBUM) { sHashCompare = new StringBuilder().append(track.getAlbum().getName2()).append( UtilString.padNumber(track.getOrder(), 5)).append(track.getName()).toString(); } // Year / album if (comparatorType == TrackComparatorType.YEAR_ALBUM) { sHashCompare = new StringBuilder().append( UtilString.padNumber(999999999 - track.getYear().getValue(), 10)).append( UtilString.padNumber(track.getOrder(), 5)).append(track.getName()).toString(); } // discovery date / album else if (comparatorType == TrackComparatorType.DISCOVERY_ALBUM) { sHashCompare = new StringBuilder().append(FORMATTER.format(track.getDiscoveryDate())).append( track.getAlbum().getName2()).append(UtilString.padNumber(track.getOrder(), 5)).append( track.getName()).toString(); } // Rate / album else if (comparatorType == TrackComparatorType.RATE_ALBUM) { sHashCompare = new StringBuilder().append( UtilString.padNumber(999999999 - track.getRate(), 10)).append( UtilString.padNumber(track.getOrder(), 5)).append(track.getName()).toString(); } // Hits / album else if (comparatorType == TrackComparatorType.HITS_ALBUM) { sHashCompare = new StringBuilder().append( UtilString.padNumber(999999999 - track.getHits(), 10)).append(track.getName()).toString(); } // Disc number / Order / track name else if (comparatorType == TrackComparatorType.ORDER) { sHashCompare = new StringBuilder().append( UtilString.padNumber(track.getDiscNumber(), 5) + UtilString.padNumber(track.getOrder(), 5) + track.getName()).toString(); } // We want to find identical tracks but using album name, not album id. // We only use set tags, not unknown ones else if (comparatorType == TrackComparatorType.ALMOST_IDENTICAL) { sHashCompare = buildIdenticalTestFootprint(track); } return sHashCompare; } /** * Return a footprint used to find almost-identical track. * * @param track DOCUMENT_ME * * @return a footprint used to find almost-identical track */ public String buildIdenticalTestFootprint(Track track) { StringBuilder sb = new StringBuilder(); if (!track.getGenre().seemsUnknown()) { sb.append(track.getGenre().getID()); } if (!track.getArtist().seemsUnknown()) { sb.append(track.getArtist().getID()); } if (!track.getAlbum().seemsUnknown()) { sb.append(track.getAlbum().getName()); } sb.append(track.getName()); if (track.getYear().looksValid()) { sb.append(track.getYear().getValue()); } sb.append(track.getDuration()); sb.append(track.getOrder()); sb.append(track.getType().getID()); sb.append(track.getDiscNumber()); if (!track.getAlbumArtist().seemsUnknown()) { sb.append(track.getAlbumArtist().getName()); } return sb.toString(); } /** * Compares two tracks according to the type selected during constructing of * the comparator.. * * @param track1 The first track for comparison. * @param track2 The second track for comparison. * * @return the value 0 if track1 is equal to track2; a value less * than 0 if track1 is less than track2; and a value * greater than 0 if track1 is greater than track2. */ @Override public int compare(Track track1, Track track2) { String sHashCompare = getCompareString(track1); String sHashCompareOther = getCompareString(track2); return sHashCompare.compareToIgnoreCase(sHashCompareOther); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/base/Genre.java0000644000175000017500000000657611720500104022636 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.base; import javax.swing.ImageIcon; import org.jajuk.util.Const; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; /** * A music genre ( jazz, rock...) *

    * Logical item */ public class Genre extends LogicalItem implements Comparable { /** * Genre constructor. * * @param sId DOCUMENT_ME * @param sName DOCUMENT_ME */ Genre(String sId, String sName) { super(sId, sName); } /* * (non-Javadoc) * * @see org.jajuk.base.Item#getIdentifier() */ @Override public String getLabel() { return XML_GENRE; } /** * Return genre name, dealing with unknown for any language. * * @return artist name */ public String getName2() { String sOut = getName(); if (sOut.equals(UNKNOWN_GENRE)) { sOut = Messages.getString(UNKNOWN_GENRE); } return sOut; } /** * Alphabetical comparator used to display ordered lists. * * @param otherItem DOCUMENT_ME * * @return comparison result */ @Override public int compareTo(Genre otherItem) { // compare using name and id to differentiate unknown items StringBuilder current = new StringBuilder(getName2()); current.append(getID()); StringBuilder other = new StringBuilder(otherItem.getName2()); other.append(otherItem.getID()); return current.toString().compareToIgnoreCase(other.toString()); } /** * Return whether this item is strictly unknown : contains no tag. * * @return whether this item is Unknown or not */ public boolean isUnknown() { return this.getName().equals(UNKNOWN_GENRE); } /** * Return whether this item seems unknown (fuzzy search). * * @return whether this item seems unknown */ public boolean seemsUnknown() { return isUnknown() || "unknown".equalsIgnoreCase(getName()) || Messages.getString(UNKNOWN_GENRE).equalsIgnoreCase(getName()); } /** * Get item description. * * @return the desc */ @Override public String getDesc() { return Messages.getString("Item_Genre") + " : " + getName2(); } /* * (non-Javadoc) * * @see org.jajuk.base.Item#getHumanValue(java.lang.String) */ @Override public final String getHumanValue(String sKey) { if (Const.XML_NAME.equals(sKey)) { return getName2(); } else {// default return super.getHumanValue(sKey); } } /* * (non-Javadoc) * * @see org.jajuk.base.Item#getIconRepresentation() */ @Override public ImageIcon getIconRepresentation() { return IconLoader.getIcon(JajukIcons.GENRE); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/base/PhysicalItem.java0000644000175000017500000000213111720500104024150 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.base; /** * A physical Item (file, directory, device...) */ public abstract class PhysicalItem extends Item { /** * The Constructor. * * @param sId DOCUMENT_ME * @param sName DOCUMENT_ME */ PhysicalItem(String sId, String sName) { super(sId, sName); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/base/Directory.java0000644000175000017500000006517111720500104023536 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.base; import java.io.File; import java.util.ArrayList; import java.util.Date; import java.util.HashSet; import java.util.LinkedHashSet; import java.util.List; import java.util.Set; import javax.swing.ImageIcon; import org.jajuk.services.bookmark.History; import org.jajuk.services.core.ExitService; import org.jajuk.services.tags.Tag; import org.jajuk.ui.helpers.RefreshReporter; import org.jajuk.util.Conf; import org.jajuk.util.Const; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; import org.jajuk.util.UtilFeatures; import org.jajuk.util.UtilSystem; import org.jajuk.util.error.JajukException; import org.jajuk.util.error.JajukRuntimeException; import org.jajuk.util.log.Log; /** * A physical directory *

    * Physical item. */ public class Directory extends PhysicalItem implements Comparable { /** Parent directory ID*. */ private final Directory dParent; /** Directory device. */ private final Device device; /** IO file for optimizations*. */ private java.io.File fio; /** DOCUMENT_ME. */ private long discID = -1l; /** * Directory constructor. * * @param sName DOCUMENT_ME * @param sId DOCUMENT_ME * @param dParent DOCUMENT_ME * @param device DOCUMENT_ME */ Directory(String sId, String sName, Directory dParent, Device device) { super(sId, sName); // check that top directories name is void if (dParent == null && !"".equals(sName)) { throw new JajukRuntimeException("Top directory name should be a void string"); } this.dParent = dParent; setProperty(Const.XML_DIRECTORY_PARENT, (dParent == null ? "-1" : dParent.getID())); this.device = device; setProperty(Const.XML_DEVICE, device.getID()); this.fio = new File(device.getUrl() + getRelativePath()); } /* * (non-Javadoc) * * @see org.jajuk.base.Item#getIdentifier() */ @Override public final String getLabel() { return XML_DIRECTORY; } /** * toString method. * * @return the string */ @Override public String toString() { return "Directory[ID=" + getID() + " Relative path={{" + getRelativePath() + "}} ParentID=" + (dParent == null ? "null" : dParent.getID()) + " Device={{" + device.getName() + "}}]"; } /** * Gets the absolute path. * * @return the absolute path */ public String getAbsolutePath() { StringBuilder sbOut = new StringBuilder(getDevice().getUrl()).append(getRelativePath()); return sbOut.toString(); } /** * Gets the device. * * @return the device */ public Device getDevice() { return device; } /** * Gets the parent directory (null if this directory is a top directory). * * @return the parent directory */ public Directory getParentDirectory() { return dParent; } /** * Gets the sub-directories. * * @return all sub directories */ public Set getDirectories() { Set out = new LinkedHashSet(2); // Iterate against a copy of directories, not a ReadOnlyIterator to avoid handling // synchronization issues, this method is not in a critical sequence List dirs = DirectoryManager.getInstance().getDirectories(); for (Directory directory : dirs) { if (directory.getFio().getParentFile() != null && directory.getFio().getParentFile().equals(this.getFio()) // check the device of the tested directory to handle directories // from cdroms for ie && directory.getDevice().equals(getDevice())) { out.add(directory); } } return out; } /** * return child files. * * @return child files */ public Set getFiles() { Set out = new LinkedHashSet(2); for (org.jajuk.base.File file : FileManager.getInstance().getFiles()) { if (file.getFIO().getParentFile().equals(this.getFio())) { out.add(file); } } return out; } /** * return playlists. * * @return playlists */ public Set getPlaylistFiles() { Set out = new LinkedHashSet(2); for (Playlist plf : PlaylistManager.getInstance().getPlaylists()) { if (plf.getFIO().getParentFile().equals(this.getFio())) { out.add(plf); } } return out; } /** * return ordered sibling files from the given file index. * * @param fileStart DOCUMENT_ME * * @return files or null if the given file is unknown */ public List getFilesFromFile(org.jajuk.base.File fileStart) { Set files = getFiles(); List alOut = new ArrayList(files); int indexOfStartingItem = alOut.indexOf(fileStart); if (indexOfStartingItem < 0) { return null; } return alOut.subList(indexOfStartingItem + 1, alOut.size()); } /** * return ordered child files recursively. * * @return child files recursively */ public List getFilesRecursively() { List alFiles = new ArrayList(100); for (Item item : FileManager.getInstance().getFiles()) { org.jajuk.base.File file = (org.jajuk.base.File) item; if (file.hasAncestor(this)) { alFiles.add(file); } } return alFiles; } /** * return ordered child directories recursively. * * @return child directories recursively */ public List getDirectoriesRecursively() { List alDirs = new ArrayList(10); for (Item item : DirectoryManager.getInstance().getDirectories()) { Directory dir = (Directory) item; if (dir.hasAncestor(this)) { alDirs.add(dir); } } return alDirs; } /** * Return true is the specified directory is an ancestor for this directory. * * @param directory directory to check * * @return true, if given directory is a parent directory of this directory */ public boolean hasAncestor(Directory directory) { Directory dirTested = this; while (true) { if (!dirTested.equals(this) && dirTested.equals(directory)) { return true; } else { dirTested = dirTested.getParentDirectory(); if (dirTested == null) { return false; } } } } /** * return ordered child playlists recursively. * * @return child playlists recursively */ public List getPlaylistsRecursively() { List alPlaylists = new ArrayList(100); for (Item item : PlaylistManager.getInstance().getPlaylists()) { Playlist playlist = (Playlist) item; if (playlist.hasAncestor(this)) { alPlaylists.add(playlist); } } return alPlaylists; } /** * Scan all files in a directory. * * @param bDeepScan : * force files tag read * @param reporter Refresh handler */ public void scan(boolean bDeepScan, RefreshReporter reporter) { // Wait a given delay (Bug #1793 : some NAS crash due to overload) try { Thread.sleep(Conf.getInt(CONF_REFRESHING_DELAY_MS)); } catch (Exception e) { Log.error(e); } // Make sure to reset the disc ID this.discID = -1; java.io.File[] filelist = getFio().listFiles(UtilSystem.getFileFilter()); if (filelist == null || filelist.length == 0) { // none file, leave return; } // Create a list of music files and playlist files to consider List musicFiles = new ArrayList(filelist.length); List playlistFiles = new ArrayList(filelist.length); List durations = new ArrayList(filelist.length); for (int i = 0; i < filelist.length; i++) { // Leave ASAP if exit request if (ExitService.isExiting()) { return; } // Check file name is correct (useful to fix name encoding // issues) if (!new File(filelist[i].getAbsolutePath()).exists()) { Log.warn("Cannot read file name (please rename it): {{" + filelist[i].getAbsolutePath() + "}}"); continue; } // Ignore iTunes files if (filelist[i].getName().startsWith("._")) { continue; } // check if we recognize the file as music file String extension = UtilSystem.getExtension(filelist[i]); Type type = TypeManager.getInstance().getTypeByExtension(extension); // Now, compute disc ID and cache tags (only in deep mode because we don't // want to read tags in fast modes) if (bDeepScan && type.getTagImpl() != null) { try { Tag tag = Tag.getTagForFio(filelist[i], false); durations.add(tag.getLength()); } catch (JajukException je) { Log.error(je); } } boolean bIsMusic = (Boolean) type.getValue(Const.XML_TYPE_IS_MUSIC); if (bIsMusic) { musicFiles.add(filelist[i]); } else { // playlist playlistFiles.add(filelist[i]); } } // Compute the disc id (deep mode only) if (bDeepScan) { this.discID = UtilFeatures.computeDiscID(durations); } // Perform actual scan and check errors for each file for (File musicfile : musicFiles) { try { scanMusic(musicfile, bDeepScan, reporter); } catch (Exception e) { Log.error(103, filelist.length > 0 ? "{{" + musicfile.toString() + "}}" : "", e); } } for (File playlistFile : playlistFiles) { try { scanPlaylist(playlistFile, bDeepScan, reporter); } catch (Exception e) { Log.error(103, filelist.length > 0 ? "{{" + playlistFile.toString() + "}}" : "", e); } } // Clear the tag cache so tags are actually read at next deep refresh Tag.clearCache(); // Force cover detection (after done once, the cover file is cached as album property) // We need this to avoid bug #1550 : if the device is created, then unplugged, catalog // view cover/no-cover filter is messed-up because the findCover() method always return null. Set albumsToCheck = getAlbums(); for (Album album : albumsToCheck) { album.findCover(); } } /** * Return list of albums for current directory. * * @param * * @return list of albums for current directory */ public Set getAlbums() { Set out = new HashSet(1); Set files = this.getFiles(); for (org.jajuk.base.File file : files) { out.add(file.getTrack().getAlbum()); } return out; } /** * Scan music. * * @param bDeepScan DOCUMENT_ME * @param reporter DOCUMENT_ME * @param music DOCUMENT_ME * * @throws JajukException the jajuk exception */ private void scanMusic(java.io.File music, boolean bDeepScan, RefreshReporter reporter) throws JajukException { String lName = music.getName(); String sId = FileManager.createID(lName, this); // check the file is not already known in database org.jajuk.base.File fileRef = FileManager.getInstance().getFileByID(sId); // Set name again to make sure Windows users will see actual // name with right case if (UtilSystem.isUnderWindows() && fileRef != null) { fileRef.setName(lName); } // if known file and no deep scan, just leave if (fileRef != null && !bDeepScan) { return; } // Is this format tag readable ? Type type = TypeManager.getInstance().getTypeByExtension(UtilSystem.getExtension(music)); boolean tagSupported = (type.getTaggerClass() != null); // Deep refresh : if the audio file format doesn't support tagging (like wav) and the file // is already known, continue, no need to try to read tags if (!tagSupported && fileRef != null) { return; } // Ignore tag error to make sure to get a // tag object in all cases. Tag tag = Tag.getTagForFio(music, true); // We need a tag instance even for unsupported formats but it that // case, we don't notify tag reading errors if (tag.isCorrupted() && tagSupported) { if (reporter != null) { reporter.notifyCorruptedFile(); } // if an error occurs, just display a message but keep the track Log.error(103, "{{" + music.getAbsolutePath() + "}}", null); } String sTrackName = tag.getTrackName(); String sAlbumName = tag.getAlbumName(); String sArtistName = tag.getArtistName(); String sGenre = tag.getGenreName(); long length = tag.getLength(); // length in sec String sYear = tag.getYear(); long lQuality = tag.getQuality(); String sComment = tag.getComment(); long lOrder = tag.getOrder(); String sAlbumArtist = tag.getAlbumArtist(); long discNumber = tag.getDiscNumber(); if (fileRef == null && reporter != null) { // stats, do it here and not // before because we ignore the // file if we cannot read it reporter.notifyNewFile(); } // Store oldDiscID, it is used to clone album and track // properties when album disc ID was unset to avoid loosing ratings or custom properties long oldDiscID = 0; if (fileRef != null) { oldDiscID = fileRef.getTrack().getAlbum().getDiscID(); } Track track = registerFile(music, sId, sTrackName, sAlbumName, sArtistName, sGenre, length, sYear, lQuality, sComment, lOrder, sAlbumArtist, oldDiscID, discID, discNumber); for (String s : Tag.getActivatedExtraTags()) { track.setProperty(s, tag.getTagField(s)); } } /** * Register file. * * @param music DOCUMENT_ME * @param sTrackName DOCUMENT_ME * @param sAlbumName DOCUMENT_ME * @param sArtistName DOCUMENT_ME * @param sGenre DOCUMENT_ME * @param length DOCUMENT_ME * @param sYear DOCUMENT_ME * @param lQuality DOCUMENT_ME * @param sComment DOCUMENT_ME * @param lOrder DOCUMENT_ME * @param sAlbumArtist DOCUMENT_ME * @param discID DOCUMENT_ME * @param discNumber DOCUMENT_ME * @param sFileId DOCUMENT_ME * @param oldDiskID DOCUMENT_ME * * @return the track */ private Track registerFile(java.io.File music, String sFileId, String sTrackName, String sAlbumName, String sArtistName, String sGenre, long length, String sYear, long lQuality, String sComment, long lOrder, String sAlbumArtist, long oldDiskID, long discID, long discNumber) { Album album = AlbumManager.getInstance().registerAlbum(sAlbumName, discID); Genre genre = GenreManager.getInstance().registerGenre(sGenre); Year year = YearManager.getInstance().registerYear(sYear); Artist artist = ArtistManager.getInstance().registerArtist(sArtistName); AlbumArtist albumArtist = AlbumArtistManager.getInstance().registerAlbumArtist(sAlbumArtist); Type type = TypeManager.getInstance().getTypeByExtension(UtilSystem.getExtension(music)); // Store number of tracks in collection long trackNumber = TrackManager.getInstance().getElementCount(); Track track = TrackManager.getInstance().registerTrack(sTrackName, album, genre, artist, length, year, lOrder, type, discNumber); // Fix for #1630 : if a album discID = 0 or -1 (when upgrading from older releases), we // clone the properties from the old track mapped with the old album id so we keep rating // (among other data) if (oldDiskID == -1 || oldDiskID == 0) { String oldAlbumID = AlbumManager.createID(sAlbumName, oldDiskID); Album oldAlbum = AlbumManager.getInstance().getAlbumByID(oldAlbumID); if (oldAlbum != null) { // Also clone album properties (useful to keep custom tags) album.cloneProperties(oldAlbum); String oldTrackID = TrackManager.createID(sTrackName, oldAlbum, genre, artist, length, year, lOrder, type, discNumber); Track oldTrack = TrackManager.getInstance().getTrackByID(oldTrackID); if (oldTrack != null) { track.cloneProperties(oldTrack); } } } // Note date for file date property. CAUTION: do not try to // check current date to accelerate refreshing if file has not // been modified since last refresh as user can rename a parent // directory and the files times under it are not modified long lastModified = music.lastModified(); // Use file date if the "force file date" option is used if (Conf.getBoolean(Const.CONF_FORCE_FILE_DATE)) { track.setDiscoveryDate(new Date(lastModified)); } else if (TrackManager.getInstance().getElementCount() > trackNumber) { // Update discovery date only if it is a new track // A new track has been created, we can safely update // the track date // We don't want to update date if the track is already // known, even if // it is a new file because a track can map several // files and discovery date // is a track attribute, not file one track.setDiscoveryDate(new Date()); } org.jajuk.base.File file = FileManager.getInstance().registerFile(sFileId, music.getName(), this, track, music.length(), lQuality); // Set file date file.setProperty(Const.XML_FILE_DATE, new Date(lastModified)); // Comment is at the track level, note that we take last // found file comment but we changing a comment, we will // apply to all files for a track track.setComment(sComment); // Apply the album artist track.setAlbumArtist(albumArtist); // Make sure to refresh file size file.setProperty(Const.XML_SIZE, music.length()); return track; } /** * Scan playlist. * DOCUMENT_ME * * @param file DOCUMENT_ME * @param bDeepScan DOCUMENT_ME * @param reporter DOCUMENT_ME * * @throws JajukException the jajuk exception */ private void scanPlaylist(final java.io.File file, final boolean bDeepScan, final RefreshReporter reporter) throws JajukException { String sId = PlaylistManager.createID(file.getName(), this); Playlist plfRef = PlaylistManager.getInstance().getPlaylistByID(sId); // if known playlist and no deep scan, just leave if (plfRef != null && !bDeepScan) { return; } Playlist plFile = PlaylistManager.getInstance().registerPlaylistFile(file, this); plFile.forceRefresh(); // force refresh if (plfRef == null && reporter != null) { // stats, do it here and not // before because we ignore the // file if we cannot read it reporter.notifyNewFile(); } } /** * Reset pre-calculated paths*. */ protected void reset() { fio = null; } /** * Return full directory path name relative to device url. * * @return String */ public final String getRelativePath() { if (getName().equals("")) { // if this directory is a root device // directory return ""; } StringBuilder sbOut = new StringBuilder().append(java.io.File.separatorChar).append(getName()); boolean bTop = false; Directory dCurrent = this; while (!bTop && dCurrent != null) { dCurrent = dCurrent.getParentDirectory(); if (dCurrent != null && !dCurrent.getName().equals("")) { // if it is the root directory, no parent sbOut.insert(0, java.io.File.separatorChar).insert(1, dCurrent.getName()); } else { bTop = true; } } return sbOut.toString(); } /** * Gets the fio. * * @return Returns the IO file reference to this directory. */ public File getFio() { if (fio == null) { fio = new java.io.File(getAbsolutePath()); } return fio; } /** * Alphabetical comparator used to display ordered lists of directories *

    * Sort ignoring cases *

    . * * @param otherDirectory DOCUMENT_ME * * @return comparison result */ @Override public int compareTo(Directory otherDirectory) { if (otherDirectory == null) { return -1; } // Perf: leave if directories are equals if (otherDirectory.equals(this)) { return 0; } String abs = new StringBuilder(getDevice().getName()).append(getAbsolutePath()).toString(); String otherAbs = new StringBuilder(otherDirectory.getDevice().getName()).append( otherDirectory.getAbsolutePath()).toString(); // should ignore case to get a B c ... and not Bac // We must be consistent with equals, see // http://java.sun.com/javase/6/docs/api/java/lang/Comparable.html int comp = abs.compareToIgnoreCase(otherAbs); if (comp == 0) { return abs.compareTo(otherAbs); } else { return comp; } } /** * Return whether this item should be hidden with hide option. * * @return whether this item should be hidden with hide option */ public boolean shouldBeHidden() { if (getDevice().isMounted() || !Conf.getBoolean(Const.CONF_OPTIONS_HIDE_UNMOUNTED)) { return false; } return true; } /** * Get item description. * * @return the desc */ @Override public String getDesc() { String sName = null; if (getParentDirectory() == null) { sName = getDevice().getUrl(); } else { sName = getFio().getAbsolutePath(); } return Messages.getString("Item_Directory") + " : " + sName; } /* * (non-Javadoc) * * @see org.jajuk.base.Item#getHumanValue(java.lang.String) */ @Override public String getHumanValue(String sKey) { if (Const.XML_DIRECTORY_PARENT.equals(sKey)) { Directory parentdir = DirectoryManager.getInstance() .getDirectoryByID((String) getValue(sKey)); if (parentdir == null) { return ""; // no parent directory } else { return parentdir.getFio().getAbsolutePath(); } } else if (Const.XML_DEVICE.equals(sKey)) { Device dev = DeviceManager.getInstance().getDeviceByID((String) getValue(sKey)); if (dev == null) { return ""; } return dev.getName(); } if (Const.XML_NAME.equals(sKey)) { if (dParent == null) { // if no parent, take device name return getDevice().getUrl(); } else { return getName(); } } else { // default return super.getHumanValue(sKey); } } /* * (non-Javadoc) * * @see org.jajuk.base.Item#getIconRepresentation() */ @Override public ImageIcon getIconRepresentation() { ImageIcon icon = null; // is this device synchronized? if (getBooleanValue(Const.XML_DIRECTORY_SYNCHRONIZED)) { icon = IconLoader.getIcon(JajukIcons.DIRECTORY_SYNCHRO); } else { icon = IconLoader.getIcon(JajukIcons.DIRECTORY_DESYNCHRO); } return icon; } /** * Set name (useful for Windows because same object can have different cases). * * @param name Item name */ protected void setName(String name) { setProperty(Const.XML_NAME, name); this.name = name; } /** * Refresh the directory synchronously, no dialog.
    * This method is only a wrapper to Device.refreshCommand() method * * @param bDeepScan whether it is a deep refresh request or only fast * * @return true if some changes occurred in device */ public synchronized boolean refresh(final boolean bDeepScan) { List dirsToRefresh = new ArrayList(1); dirsToRefresh.add(this); return getDevice().refreshCommand(bDeepScan, false, dirsToRefresh); } /** * Scan directory to cleanup removed files and playlists. * * @return whether some items have been removed */ public boolean cleanRemovedFiles() { boolean bChanges = false; // need to use a shallow copy to avoid concurrent exceptions final List dirs = DirectoryManager.getInstance().getDirectories(); // directories cleanup for (final Item item : dirs) { final Directory dir = (Directory) item; if (!ExitService.isExiting() && dir.getDevice().isMounted() && dir.isChildOf(this) && !dir.getFio().exists()) { // note that associated files are removed too DirectoryManager.getInstance().removeDirectory(dir.getID()); Log.debug("Removed: " + dir); bChanges = true; } } // files cleanup final List lFiles = FileManager.getInstance().getFiles(); for (final org.jajuk.base.File file : lFiles) { if (!ExitService.isExiting() // Only take into consideration files from this directory or // from // sub-directories && (file.getDirectory().equals(this) || file.getDirectory().isChildOf(this)) && file.isReady() && // Remove file if it doesn't exist any more or if it is a iTunes // file (useful for jajuk < 1.4) !file.getFIO().exists() || file.getName().startsWith("._")) { FileManager.getInstance().removeFile(file); Log.debug("Removed: " + file); bChanges = true; } } // Playlist cleanup final List plfiles = PlaylistManager.getInstance().getPlaylists(); for (final Playlist plf : plfiles) { if (!ExitService.isExiting() // Only take into consideration files from this directory or // from // sub-directories && (plf.getDirectory().equals(this) || plf.getDirectory().isChildOf(this)) && plf.isReady() && !plf.getFIO().exists()) { PlaylistManager.getInstance().removeItem(plf); Log.debug("Removed: " + plf); bChanges = true; } } // clear history to remove old files referenced in it if (Conf.getString(Const.CONF_HISTORY) != null) { History.getInstance().clear(Integer.parseInt(Conf.getString(Const.CONF_HISTORY))); } return bChanges; } /** * Return true is this is a child directory of the specified directory. * * @param directory ancestor directory * * @return true, if checks if is child of */ public boolean isChildOf(Directory directory) { Directory dirTested = getParentDirectory(); if (dirTested == null) { return false; } while (true) { if (dirTested.equals(directory)) { return true; } else { dirTested = dirTested.getParentDirectory(); if (dirTested == null) { return false; } } } } } jajuk-1.9.6.orig/src/main/java/org/jajuk/base/LogicalItem.java0000644000175000017500000000256411720500104023760 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.base; /** * A logical Item (genre, artist, year, album...) */ public abstract class LogicalItem extends Item { /** * The Constructor. * * @param sId DOCUMENT_ME * @param sName DOCUMENT_ME */ LogicalItem(String sId, String sName) { super(sId, sName); } /** * toString method. * * @return the string */ @Override public String toString() { // Use class metadata because this method is used by several logical items return getClass().getCanonicalName() + "[ID=" + getID() + " Name={{" + getName() + "}}]"; } } jajuk-1.9.6.orig/src/main/java/org/jajuk/base/Artist.java0000644000175000017500000000662611720500104023040 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.base; import javax.swing.ImageIcon; import org.jajuk.util.Const; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; /** * An artist * *

    * Logical item. */ public class Artist extends LogicalItem implements Comparable { /** * Artist constructor. * * @param sId DOCUMENT_ME * @param sName DOCUMENT_ME */ Artist(String sId, String sName) { super(sId, sName); } /* * (non-Javadoc) * * @see org.jajuk.base.Item#getIdentifier() */ @Override public String getLabel() { return XML_ARTIST; } /** * Return artist name, dealing with unknown for any language. * * @return artist name */ public String getName2() { if (isUnknown()) { return Messages.getString(UNKNOWN_ARTIST); } return getName(); } /** * Alphabetical comparator used to display ordered lists. * * @param otherItem DOCUMENT_ME * * @return comparison result */ @Override public int compareTo(Artist otherItem) { // not equal if other is null if (otherItem == null) { return 1; } // compare using name and id to differentiate unknown items StringBuilder current = new StringBuilder(getName2()); current.append(getID()); StringBuilder other = new StringBuilder(otherItem.getName2()); other.append(otherItem.getID()); return current.toString().compareToIgnoreCase(other.toString()); } /** * Return whether this item is strictly unknown : contains no tag. * * @return whether this item is Unknown or not */ public boolean isUnknown() { return this.getName().equals(UNKNOWN_ARTIST); } /** * Return whether this item seems unknown (fuzzy search). * * @return whether this item seems unknown */ public boolean seemsUnknown() { return isUnknown() || "unknown".equalsIgnoreCase(getName()) || Messages.getString(UNKNOWN_ARTIST).equalsIgnoreCase(getName()); } /** * Get item description. * * @return the desc */ @Override public String getDesc() { return Messages.getString("Item_Artist") + " : " + getName2(); } /* * (non-Javadoc) * * @see org.jajuk.base.Item#getHumanValue(java.lang.String) */ @Override public String getHumanValue(String sKey) { if (Const.XML_NAME.equals(sKey)) { return getName2(); } // default return super.getHumanValue(sKey); } /* * (non-Javadoc) * * @see org.jajuk.base.Item#getIconRepresentation() */ @Override public ImageIcon getIconRepresentation() { return IconLoader.getIcon(JajukIcons.ARTIST); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/base/AlbumComparator.java0000644000175000017500000001076211720500104024656 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.base; import java.io.Serializable; import java.util.Comparator; /** * Compares albums. * * @TODO Convert criteria from int to an enum */ public class AlbumComparator implements Comparator, Serializable { /** Generated serialVersionUID. */ private static final long serialVersionUID = -5927167916548652076L; /* * This needs to be kept in-sync with what we use in * CatalogView.initMetaInformation()! * * 0 .. genre 1 .. artist 2 .. album 3 .. year 4 .. discovery date 5 .. rate 6 .. * hits */ /** DOCUMENT_ME. */ private int criteria = 0; /** * Instantiates a new album comparator. * * @param criteria DOCUMENT_ME */ public AlbumComparator(int criteria) { this.criteria = criteria; } /* (non-Javadoc) * @see java.util.Comparator#compare(java.lang.Object, java.lang.Object) */ @Override public int compare(Album album1, Album album2) { // for albums, perform a fast compare if (criteria == 2) { return album1.compareTo(album2); } // get a track for each album Track track1 = album1.getAnyTrack(); Track track2 = album2.getAnyTrack(); // check tracks (normally useless) if (track1 == null || track2 == null) { return 0; } // @TODO // beware, this code is not consistent with equals. This should be ok as // result is used by a List but it could be a drama if we used a Set // See : http: // java.sun.com/j2se/1.4.2/docs/api/java/lang/Comparable.html switch (criteria) { case 0: // genre // Sort on Genre/Artist/Year/Title if (track1.getGenre() == track2.getGenre()) { // [Perf] We can make this '==' comparison because all these strings are // internalized if (track1.getArtist() == track2.getArtist()) { if (track1.getYear() == track2.getYear()) { return album1.compareTo(album2); } else { return track1.getYear().compareTo(track2.getYear()); } } else { return track1.getArtist().compareTo(track2.getArtist()); } } else { return track1.getGenre().compareTo(track2.getGenre()); } case 1: // artist // Sort on Artist/Year/Title // we use now the album artist if (track1.getArtist() == track2.getArtist()) { if (track1.getYear() == track2.getYear()) { return album1.compareTo(album2); } else { return track1.getYear().compareTo(track2.getYear()); } } else { return track1.getArtist().compareTo(track2.getArtist()); } case 3: // year // Sort on: Year/Artist/Title if (track1.getYear() == track2.getYear()) { if (track1.getArtist() == track2.getArtist()) { return album1.compareTo(album2); } else { return track1.getArtist().compareTo(track2.getArtist()); } } else { return track1.getYear().compareTo(track2.getYear()); } case 4: // Discovery date // Sort on: Discovery date/title if (track1.getDiscoveryDate().equals(track2.getDiscoveryDate())) { return album1.compareTo(album2); } else { return track2.getDiscoveryDate().compareTo(track1.getDiscoveryDate()); } case 5: // Rate // Sort on: Rate/title if (album1.getRate() == album2.getRate()) { return album1.compareTo(album2); } else if (album1.getRate() < album2.getRate()) { return -1; } else { return 1; } case 6: // Hits if (album1.getHits() == album2.getHits()) { return album1.compareTo(album2); } else if (album1.getHits() < album2.getHits()) { return -1; } else { return 1; } } return 0; } } jajuk-1.9.6.orig/src/main/java/org/jajuk/base/GenreManager.java0000644000175000017500000001517411720500104024123 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.base; import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.Iterator; import java.util.List; import java.util.Locale; import java.util.Properties; import java.util.Vector; import org.jajuk.events.JajukEvent; import org.jajuk.events.JajukEvents; import org.jajuk.events.ObservationManager; import org.jajuk.util.Const; import org.jajuk.util.ReadOnlyIterator; import org.jajuk.util.UtilFeatures; import org.jajuk.util.error.JajukException; /** * Convenient class to manage genres. */ public final class GenreManager extends ItemManager { /** Self instance. */ private static GenreManager singleton = new GenreManager(); /* List of all known genres */ /** DOCUMENT_ME. */ private Vector genresList; // NOPMD /** * No constructor available, only static access. */ private GenreManager() { super(); // register properties // ID registerProperty(new PropertyMetaInformation(Const.XML_ID, false, true, false, false, false, String.class, null)); // Name registerProperty(new PropertyMetaInformation(Const.XML_NAME, false, true, true, true, false, String.class, null)); // Expand registerProperty(new PropertyMetaInformation(Const.XML_EXPANDED, false, false, false, false, true, Boolean.class, false)); // Add preset genres registerPresetGenres(); } /** * Gets the instance. * * @return singleton */ public static GenreManager getInstance() { return singleton; } /** * Register a genre. * * @param sName DOCUMENT_ME * * @return the genre */ public Genre registerGenre(String sName) { String sId = createID(sName); return registerGenre(sId, sName); } /** * Register a genre with a known id. * * @param sId DOCUMENT_ME * @param sName DOCUMENT_ME * @return the genre */ public Genre registerGenre(String sId, String sName) { Genre genre = getGenreByID(sId); if (genre != null) { return genre; } genre = new Genre(sId, sName); registerItem(genre); // add it in genres list if new if (!genresList.contains(sName)) { genresList.add(genre.getName2()); // Sort items ignoring case Collections.sort(genresList, new Comparator() { @Override public int compare(String o1, String o2) { return o1.compareToIgnoreCase(o2); } }); } return genre; } /** * Register preset genres. * DOCUMENT_ME */ public void registerPresetGenres() { // create default genre list genresList = new Vector(Arrays.asList(UtilFeatures.GENRES)); Collections.sort(genresList); for (String genre : genresList) { registerGenre(genre.intern()); } } /** * Return genre by name. * * @param name DOCUMENT_ME * * @return the genre by name */ public Genre getGenreByName(String name) { Genre out = null; for (Genre genre : getGenres()) { if (genre.getName().equals(name)) { out = genre; break; } } return out; } /** * Change the item name. * * @param old DOCUMENT_ME * @param sNewName DOCUMENT_ME * * @return new item * * @throws JajukException the jajuk exception */ public Genre changeGenreName(Genre old, String sNewName) throws JajukException { // check there is actually a change if (old.getName2().equals(sNewName)) { return old; } Genre newItem = registerGenre(sNewName); // re apply old properties from old item newItem.cloneProperties(old); // update tracks List alTracks = TrackManager.getInstance().getTracks(); // we need to create a new list to avoid concurrent exceptions Iterator it = alTracks.iterator(); while (it.hasNext()) { Track track = it.next(); if (track.getGenre().equals(old)) { TrackManager.getInstance().changeTrackGenre(track, sNewName, null); } } // notify everybody for the file change Properties properties = new Properties(); properties.put(Const.DETAIL_OLD, old); properties.put(Const.DETAIL_NEW, newItem); // Notify interested items (like ambience manager) ObservationManager.notifySync(new JajukEvent(JajukEvents.GENRE_NAME_CHANGED, properties)); return newItem; } /** * Format the Genre name to be normalized : *

    * -no underscores or other non-ascii characters *

    * -no spaces at the begin and the end *

    * -All in upper case *

    * example: "ROCK". * * @param sName DOCUMENT_ME * * @return the string */ public static String format(String sName) { String sOut; sOut = sName.trim(); // supress spaces at the begin and the end sOut = sOut.replace('-', ' '); // move - to space sOut = sOut.replace('_', ' '); // move _ to space sOut = sOut.toUpperCase(Locale.getDefault()); return sOut; } /* * (non-Javadoc) * * @see org.jajuk.base.ItemManager#getIdentifier() */ @Override public String getLabel() { return Const.XML_GENRES; } /** * Gets the genres list. * * @return Human readable list of registrated genres
    * ordered (alphabeticaly) */ public Vector getGenresList() { return genresList; } /** * Gets the genre by id. * * @param sID Item ID * * @return item */ public Genre getGenreByID(String sID) { return (Genre) getItemByID(sID); } /** * Gets the genres. * * @return ordered genres list */ @SuppressWarnings("unchecked") public List getGenres() { return (List) getItems(); } /** * Gets the genres iterator. * * @return genres iterator */ @SuppressWarnings("unchecked") public ReadOnlyIterator getGenresIterator() { return new ReadOnlyIterator((Iterator) getItemsIterator()); } }jajuk-1.9.6.orig/src/main/java/org/jajuk/base/FileManager.java0000644000175000017500000006137611720500104023747 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.base; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.Date; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Properties; import org.apache.commons.collections.CollectionUtils; import org.jajuk.events.JajukEvent; import org.jajuk.events.JajukEvents; import org.jajuk.events.ObservationManager; import org.jajuk.services.players.QueueModel; import org.jajuk.util.Conf; import org.jajuk.util.Const; import org.jajuk.util.MD5Processor; import org.jajuk.util.Messages; import org.jajuk.util.ReadOnlyIterator; import org.jajuk.util.UtilSystem; import org.jajuk.util.error.CannotRenameException; import org.jajuk.util.error.JajukException; import org.jajuk.util.filters.JajukPredicates; import org.jajuk.util.log.Log; /** * Convenient class to manage files. */ public final class FileManager extends ItemManager { /** Best of files. */ private final List alBestofFiles = new ArrayList(20); /** Self instance. */ private static FileManager singleton = new FileManager(); /** File comparator based on rate. */ private final Comparator rateComparator = new Comparator() { @Override public int compare(File file1, File file2) { long lRate1 = file1.getTrack().getRate(); long lRate2 = file2.getTrack().getRate(); if (lRate1 == lRate2) { return 0; } else if (lRate1 < lRate2) { return 1; } else { return -1; } } }; /** * No constructor available, only static access. */ private FileManager() { super(); // ---register properties--- // ID registerProperty(new PropertyMetaInformation(Const.XML_ID, false, true, false, false, false, String.class, null)); // Name registerProperty(new PropertyMetaInformation(Const.XML_NAME, false, true, true, true, false, String.class, null)); // Directory registerProperty(new PropertyMetaInformation(Const.XML_DIRECTORY, false, true, true, false, true, String.class, null)); // Track registerProperty(new PropertyMetaInformation(Const.XML_TRACK, false, true, true, false, false, String.class, null)); // Size registerProperty(new PropertyMetaInformation(Const.XML_SIZE, false, true, true, false, false, Long.class, null)); // Quality registerProperty(new PropertyMetaInformation(Const.XML_QUALITY, false, true, true, false, false, Long.class, 0)); // Date registerProperty(new PropertyMetaInformation(Const.XML_FILE_DATE, false, false, true, false, false, Date.class, new Date())); } /** * Gets the instance. * * @return singleton */ public static FileManager getInstance() { return singleton; } /** * Register an File with a known id. * * @param sId DOCUMENT_ME * @param sName DOCUMENT_ME * @param directory DOCUMENT_ME * @param track DOCUMENT_ME * @param lSize DOCUMENT_ME * @param lQuality DOCUMENT_ME * * @return the file */ public File registerFile(String sId, String sName, Directory directory, Track track, long lSize, long lQuality) { lock.writeLock().lock(); try { File file = getFileByID(sId); if (file == null) { file = new File(sId, sName, directory, track, lSize, lQuality); registerItem(file); if (directory.getDevice().isRefreshing() && Log.isDebugEnabled()) { Log.debug("registrated new file: " + file); } } else { // If file already exist and the track has changed, make changes // Set name again because under Windows, the file name case // could have changed but we keep the same file object file.setName(sName); } // add this file to track file.setTrack(track); // Add file to track track.addFile(file); return file; } finally { lock.writeLock().unlock(); } } /** * Register an File without known id. * * @param sName DOCUMENT_ME * @param directory DOCUMENT_ME * @param track DOCUMENT_ME * @param lSize DOCUMENT_ME * @param lQuality DOCUMENT_ME * * @return the file */ public File registerFile(String sName, Directory directory, Track track, long lSize, long lQuality) { String sId = createID(sName); return registerFile(sId, sName, directory, track, lSize, lQuality); } /** * Get file hashcode (ID). * * @param sName DOCUMENT_ME * @param dir DOCUMENT_ME * * @return file ID */ protected static String createID(String sName, Directory dir) { String id = null; // Under windows, all files/directories with different cases should get // the same ID if (UtilSystem.isUnderWindows()) { id = MD5Processor.hash(new StringBuilder(dir.getDevice().getName()) .append(dir.getRelativePath().toLowerCase(Locale.getDefault())) .append(sName.toLowerCase(Locale.getDefault())).toString()); } else { id = MD5Processor.hash(new StringBuilder(dir.getDevice().getName()) .append(dir.getRelativePath()).append(sName).toString()); } return id; } /** * Change a file name. * * @param fileOld DOCUMENT_ME * @param sNewName DOCUMENT_ME * * @return new file * * @throws JajukException the jajuk exception */ public File changeFileName(org.jajuk.base.File fileOld, String sNewName) throws JajukException { lock.writeLock().lock(); try { // check given name is different if (fileOld.getName().equals(sNewName)) { return fileOld; } // check if this file still exists if (!fileOld.getFIO().exists()) { throw new CannotRenameException(135); } // check that the file is not currently played if (QueueModel.getCurrentItem() != null && QueueModel.getCurrentItem().getFile().equals(fileOld) && QueueModel.isPlayingTrack()) { throw new CannotRenameException(172); } java.io.File fileNew = new java.io.File(fileOld.getFIO().getParentFile().getAbsolutePath() + java.io.File.separator + sNewName); // check file name and extension if (!(UtilSystem.getExtension(fileNew).equals(UtilSystem.getExtension(fileOld.getFIO())))) { // no extension change throw new CannotRenameException(134); } // check if destination file already exists (under windows, file.exists // return true even with different case so we test file name is different) if (!fileNew.getName().equalsIgnoreCase(fileOld.getName()) && fileNew.exists()) { throw new CannotRenameException(134); } // try to rename file on disk try { if (!fileOld.getFIO().renameTo(fileNew)) { throw new CannotRenameException(134); } } catch (Exception e) { throw new CannotRenameException(134, e); } // OK, remove old file and register this new file // Compute file ID Directory dir = fileOld.getDirectory(); String sNewId = createID(sNewName, dir); // create a new file (with own fio and sAbs) Track track = fileOld.getTrack(); // Remove old file from associated track track.removeFile(fileOld); org.jajuk.base.File fNew = new File(sNewId, sNewName, fileOld.getDirectory(), track, fileOld.getSize(), fileOld.getQuality()); // transfer all properties and reset id and name // We use a shallow copy of properties to avoid any properties share between // two items fNew.setProperties(fileOld.getShallowProperties()); fNew.setProperty(Const.XML_ID, sNewId); // reset new id and name fNew.setProperty(Const.XML_NAME, sNewName); // reset new id and name removeFile(fileOld); registerItem(fNew); track.addFile(fNew); // notify everybody for the file change Properties properties = new Properties(); properties.put(Const.DETAIL_OLD, fileOld); properties.put(Const.DETAIL_NEW, fNew); // Notify interested items (like history manager) ObservationManager.notifySync(new JajukEvent(JajukEvents.FILE_NAME_CHANGED, properties)); return fNew; } finally { lock.writeLock().unlock(); } } /** * Change a file directory and actually move the old file to the new directory. * * @param old old file * @param newDir new dir * * @return new file or null if an error occurs * @throws JajukException the jajuk exception */ public File changeFileDirectory(File old, Directory newDir) throws JajukException { lock.writeLock().lock(); try { // recalculate file ID String sNewId = FileManager.createID(old.getName(), newDir); Track track = old.getTrack(); // create a new file (with own fio and sAbs) File fNew = new File(sNewId, old.getName(), newDir, track, old.getSize(), old.getQuality()); // Transfer all properties (including id), then set right id and directory // We use a shallow copy of properties to avoid any properties share between // two items fNew.setProperties(old.getShallowProperties()); fNew.setProperty(Const.XML_ID, sNewId); fNew.setProperty(Const.XML_DIRECTORY, newDir.getID()); // Real IO move try { if (!old.getFIO().renameTo(fNew.getFIO())) { throw new CannotRenameException(134); } } catch (Exception e) { throw new CannotRenameException(134, e); } // OK, remove old file and register this new file removeFile(old); registerItem(fNew); track.addFile(fNew); return fNew; } finally { lock.writeLock().unlock(); } } /** * Clean all references for the given device. * * @param sId : * Device id */ public void cleanDevice(String sId) { lock.writeLock().lock(); try { for (File file : getFiles()) { if (file.getDirectory() == null || file.getDirectory().getDevice().getID().equals(sId)) { removeItem(file); } } } finally { lock.writeLock().unlock(); } } /** * Remove a file reference. * * @param file DOCUMENT_ME */ public void removeFile(File file) { lock.writeLock().lock(); try { // We need to remove the file from the track ! TrackManager.getInstance().removeFile(file); removeItem(file); } finally { lock.writeLock().unlock(); } } /** * Return file by full path. * * @param sPath : * full path * * @return file or null if given path is not known */ public File getFileByPath(String sPath) { lock.readLock().lock(); try { File fOut = null; java.io.File fToCompare = new java.io.File(sPath); ReadOnlyIterator it = getFilesIterator(); while (it.hasNext()) { File file = it.next(); // we compare io files and not paths // to avoid dealing with path name issues if (file.getFIO().equals(fToCompare)) { fOut = file; break; } } // Fix #1717 (Cannot load some playlists) : if the file is not found, second chance ignoring the case // This can happen under Unix when using an SMB drive if (fOut == null) { it = getFilesIterator(); while (it.hasNext()) { File file = it.next(); if (file.getFIO().getAbsolutePath().equalsIgnoreCase(fToCompare.getAbsolutePath())) { fOut = file; break; } } } return fOut; } finally { lock.readLock().unlock(); } } /** * Gets the ready files. * * @return All accessible files of the collection */ public List getReadyFiles() { List files = FileManager.getInstance().getFiles(); CollectionUtils.filter(files, new JajukPredicates.ReadyFilePredicate()); return files; } /** * Return a shuffle mounted and unbaned file from the entire collection or * null if none available using these criterias. * * @return the file */ public File getShuffleFile() { List alEligibleFiles = getReadyFiles(); // filter banned files CollectionUtils.filter(alEligibleFiles, new JajukPredicates.BannedFilePredicate()); if (alEligibleFiles.size() > 0) { int index = UtilSystem.getRandom().nextInt(alEligibleFiles.size() - 1); return alEligibleFiles.get(index); } else { return null; } } /** * Return an ordered playlist with the entire accessible shuffle collection. * * @return The entire accessible shuffle collection (can return a void * collection) */ public List getGlobalShufflePlaylist() { List alEligibleFiles = getReadyFiles(); // filter banned files CollectionUtils.filter(alEligibleFiles, new JajukPredicates.BannedFilePredicate()); // shuffle Collections.shuffle(alEligibleFiles, UtilSystem.getRandom()); // song level, just shuffle full collection if (Conf.getString(Const.CONF_GLOBAL_RANDOM_MODE).equals(Const.MODE_TRACK)) { return alEligibleFiles; } // (not shuffle) Album / album else if (Conf.getString(Const.CONF_GLOBAL_RANDOM_MODE).equals(Const.MODE_ALBUM2)) { final List albums = AlbumManager.getInstance().getAlbums(); Collections.shuffle(albums, UtilSystem.getRandom()); // We need an index (bench: 45* faster) final Map index = new HashMap(); for (Album album : albums) { index.put(album, albums.indexOf(album)); } Collections.sort(alEligibleFiles, new Comparator() { @Override public int compare(File f1, File f2) { if (f1.getTrack().getAlbum().equals(f2.getTrack().getAlbum())) { int comp = (int) (f1.getTrack().getOrder() - f2.getTrack().getOrder()); if (comp == 0) { // If no track number is given, try to sort by // filename than can contain the track return f1.getName().compareTo(f2.getName()); } return comp; } return index.get(f1.getTrack().getAlbum()) - index.get(f2.getTrack().getAlbum()); } }); return alEligibleFiles; // else return shuffle albums } else { return getShuffledFilesByAlbum(alEligibleFiles); } } /** * Return a shuffle mounted file from the novelties. * * @return the novelty file */ public File getNoveltyFile() { List alEligibleFiles = getGlobalNoveltiesPlaylist(); return alEligibleFiles.get((int) (Math.random() * alEligibleFiles.size())); } /** * Return a shuffled playlist with the entire accessible novelties collection. * * @return The entire accessible novelties collection (can return a void * collection) */ public List getGlobalNoveltiesPlaylist() { return getGlobalNoveltiesPlaylist(true); } /** * Return an ordered playlist with the accessible novelties collection The * number of returned items is limited to NB_TRACKS_ON_ACTION for performance * reasons. * * @param bHideUnmounted DOCUMENT_ME * * @return The entire accessible novelties collection */ public List getGlobalNoveltiesPlaylist(boolean bHideUnmounted) { List alEligibleFiles = new ArrayList(1000); List tracks = TrackManager.getInstance().getTracks(); // Filter by age CollectionUtils.filter(tracks, new JajukPredicates.AgePredicate(Conf.getInt(Const.CONF_OPTIONS_NOVELTIES_AGE))); // filter banned tracks CollectionUtils.filter(tracks, new JajukPredicates.BannedTrackPredicate()); for (Track track : tracks) { if (alEligibleFiles.size() > Const.NB_TRACKS_ON_ACTION) { break; } File file = track.getBestFile(bHideUnmounted); // try to get a mounted file // (can return null) if (file == null) {// none mounted file, take first file we find continue; } alEligibleFiles.add(file); } // sort alphabetically and by date, newest first Collections.sort(alEligibleFiles, new Comparator() { @Override public int compare(File file1, File file2) { String sCompared1 = file1.getTrack().getDiscoveryDate().getTime() + file1.getAbsolutePath(); String sCompared2 = file2.getTrack().getDiscoveryDate().getTime() + file2.getAbsolutePath(); return sCompared2.compareTo(sCompared1); } }); return alEligibleFiles; } /** * Return a shuffled playlist with the entire accessible novelties collection. * * @return The entire accessible novelties collection */ public List getShuffleNoveltiesPlaylist() { List alEligibleFiles = getGlobalNoveltiesPlaylist(true); // song level, just shuffle full collection if (Conf.getString(Const.CONF_NOVELTIES_MODE).equals(Const.MODE_TRACK)) { Collections.shuffle(alEligibleFiles); return alEligibleFiles; } // else return shuffle albums else { return getShuffledFilesByAlbum(alEligibleFiles); } } /** * Convenient method used to return shuffled files by album. * * @param alEligibleFiles DOCUMENT_ME * * @return Shuffled tracks by album */ private List getShuffledFilesByAlbum(List alEligibleFiles) { // start with filling a set of albums containing // at least one ready file Map> albumsFiles = new HashMap>(alEligibleFiles.size() / 10); for (File file : alEligibleFiles) { // maintain a map between each albums and // eligible files Album album = file.getTrack().getAlbum(); List files = albumsFiles.get(album); if (files == null) { files = new ArrayList(10); } files.add(file); albumsFiles.put(album, files); } // build output List out = new ArrayList(alEligibleFiles.size()); List albums = new ArrayList(albumsFiles.keySet()); // we need to force a new shuffle as internal hashmap arrange items Collections.shuffle(albums, UtilSystem.getRandom()); for (Album album : albums) { List files = albumsFiles.get(album); Collections.shuffle(files, UtilSystem.getRandom()); out.addAll(files); } return out; } /** * Gets the sorted by rate. * * @return a sorted set of the collection by rate, highest first */ private List getSortedByRate() { // use only mounted files List alEligibleFiles = getReadyFiles(); // now sort by rate Collections.sort(alEligibleFiles, rateComparator); return alEligibleFiles; } /** * Return a shuffled playlist with the entire accessible bestof collection, * best first. * * @return Shuffled best tracks (n% of favorite) */ public List getGlobalBestofPlaylist() { List al = getSortedByRate(); // Filter banned files CollectionUtils.filter(al, new JajukPredicates.BannedFilePredicate()); List alBest = null; if (al.size() > 0) { // find superior interval value int sup = (int) ((Const.BESTOF_PROPORTION) * al.size()); if (sup < 2) { sup = al.size(); } alBest = al.subList(0, sup - 1); Collections.shuffle(alBest, UtilSystem.getRandom()); } return alBest; } /** * Return ordered (by rate) bestof files. * * @return top files */ public List getBestOfFiles() { // Don't refresh best of files at each call because it makes the playlist view // unusable for bestof files : each time a file is played, the view is changed if (alBestofFiles.size() == 0) { refreshBestOfFiles(); } return alBestofFiles; } /** * Refresh best of files. */ public void refreshBestOfFiles() { Log.debug("Invoking Refresh of BestOf-Files"); // clear data alBestofFiles.clear(); // create a temporary table to remove unmounted files int iNbBestofFiles = Integer.parseInt(Conf.getString(Const.CONF_BESTOF_TRACKS_SIZE)); List alEligibleFiles = new ArrayList(iNbBestofFiles); List tracks = TrackManager.getInstance().getTracks(); // filter banned tracks CollectionUtils.filter(tracks, new JajukPredicates.BannedTrackPredicate()); for (Track track : tracks) { File file = track.getBestFile(Conf.getBoolean(Const.CONF_OPTIONS_HIDE_UNMOUNTED)); if (file != null) { alEligibleFiles.add(file); } } Collections.sort(alEligibleFiles, rateComparator); // Keep as much items as we can int i = 0; while (i < alEligibleFiles.size() && i < iNbBestofFiles) { File file = alEligibleFiles.get(i); alBestofFiles.add(file); i++; } } /** * Return next mounted file ( used in continue mode ). * * @param file : * a file * * @return next file from entire collection */ public File getNextFile(File file) { List files = getFiles(); if (file == null) { return null; } // look for a correct file from index to collection end boolean bStarted = false; for (File fileNext : files) { if (bStarted) { if (fileNext.isReady()) { return fileNext; } } else { if (fileNext.equals(file)) { bStarted = true; // Begin to consider files // from this one } } } // Restart from collection from beginning for (File fileNext : files) { if (fileNext.isReady()) { // file must be on a mounted // device not refreshing return fileNext; } } // none ready file return null; } /** * Return next mounted file from a different album than the provided file. * * @param file : * a file * * @return next file from entire collection */ public File getNextAlbumFile(File file) { File testedFile = file; if (DirectoryManager.getInstance().getDirectories().size() > 1) { while (testedFile.getDirectory().equals(file.getDirectory())) { testedFile = getNextFile(testedFile); } } if (!testedFile.getDirectory().equals(file.getDirectory())) { return testedFile; } // Should not happen else { return null; } } /** * Return previous mounted file. * * @param file : * a file * * @return previous file from entire collection */ public File getPreviousFile(File file) { List files = getFiles(); if (file == null) { return null; } File filePrevious = null; int i = files.indexOf(file); // test if this file is the very first one if (i == 0) { Messages.showErrorMessage(128); return null; } // look for a correct file from index to collection begin boolean bOk = false; for (int index = i - 1; index >= 0; index--) { filePrevious = files.get(index); if (filePrevious.isReady()) { // file must be on a mounted // device not refreshing bOk = true; break; } } if (bOk) { return filePrevious; } return null; } /** * Return whether the given file is the very first file from collection. * * @param file DOCUMENT_ME * * @return true, if checks if is very first file */ public boolean isVeryfirstFile(File file) { List files = getFiles(); if (file == null || files.size() == 0) { return false; } return file.equals(files.get(0)); } /* * (non-Javadoc) * * @see org.jajuk.base.ItemManager#getIdentifier() */ @Override public String getLabel() { return Const.XML_FILES; } /** * Gets the file by id. * * @param sID Item ID * * @return File matching the id */ public File getFileByID(String sID) { return (File) getItemByID(sID); } /** * Gets the files. * * @return ordered files list */ @SuppressWarnings("unchecked") public List getFiles() { return (List) getItems(); } /** * Gets the files iterator. * * @return files iterator */ @SuppressWarnings("unchecked") public ReadOnlyIterator getFilesIterator() { return new ReadOnlyIterator((Iterator) getItemsIterator()); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/base/Album.java0000644000175000017500000005140311720500104022623 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.base; import java.awt.MediaTracker; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.Collections; import java.util.Date; import java.util.HashSet; import java.util.List; import java.util.Locale; import java.util.Set; import javax.imageio.ImageIO; import javax.swing.ImageIcon; import org.apache.commons.lang.StringUtils; import org.jajuk.base.TrackComparator.TrackComparatorType; import org.jajuk.services.covers.Cover; import org.jajuk.services.tags.Tag; import org.jajuk.ui.thumbnails.ThumbnailManager; import org.jajuk.util.Const; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukFileFilter; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; import org.jajuk.util.UtilFeatures; import org.jajuk.util.UtilString; import org.jajuk.util.error.JajukException; import org.jajuk.util.filters.ImageFilter; import org.jajuk.util.log.Log; /** * An Album * *

    * Logical item. */ public class Album extends LogicalItem implements Comparable { /** For perfs, we cache the associated tracks. This cache is filled by the TrackManager using the getTracksCache() method */ private final List cache = new ArrayList(15); /** This array stores thumbnail presence for all the available size (performance) By default all booleans are false. */ private boolean[] availableTumbs; /** * Album constructor. * * @param sName DOCUMENT_ME * @param sId DOCUMENT_ME * @param discID DOCUMENT_ME */ Album(String sId, String sName, long discID) { super(sId, sName); setProperty(Const.XML_ALBUM_DISC_ID, discID); } /** * Gets the disc id. * * @return the discID */ public long getDiscID() { return getLongValue(Const.XML_ALBUM_DISC_ID); } /** * Return album name, dealing with unknown for any language. * * @return album name */ public String getName2() { String sOut = getName(); if (sOut.equals(UNKNOWN_ALBUM)) { sOut = Messages.getString(UNKNOWN_ALBUM); } return sOut; } /** * toString method. * * @return the string */ @Override public String toString() { return "Album[ID=" + getID() + " Name={{" + getName() + "}}" + " disk ID={{" + getDiscID() + "}}]"; } /** * Alphabetical comparator on the name *

    * Used to display ordered lists. * * @param otherAlbum DOCUMENT_ME * * @return comparison result */ @Override public int compareTo(Album otherAlbum) { if (otherAlbum == null) { return -1; } // compare using name and id to differentiate unknown items StringBuilder current = new StringBuilder(getName2()); current.append(getID()); StringBuilder other = new StringBuilder(otherAlbum.getName2()); other.append(otherAlbum.getID()); return current.toString().compareToIgnoreCase(other.toString()); } /** * Return whether this item is strictly unknown : contains no tag * * @return whether this item is Unknown or not */ public boolean isUnknown() { return this.getName().equals(UNKNOWN_ALBUM); } /** * Return whether this item seems unknown (fuzzy search) * * @return whether this item seems unknown */ public boolean seemsUnknown() { return isUnknown() || "unknown".equalsIgnoreCase(getName()) || Messages.getString(UNKNOWN_ALBUM).equalsIgnoreCase(getName()); } /* * (non-Javadoc) * * @see org.jajuk.base.Item#getIdentifier() */ @Override public final String getLabel() { return XML_ALBUM; } /* (non-Javadoc) * @see org.jajuk.base.Item#getTitle() */ @Override public String getDesc() { return Messages.getString("Item_Album") + " : " + getName2(); } /* * (non-Javadoc) * * @see org.jajuk.base.Item#getHumanValue(java.lang.String) */ @Override public String getHumanValue(String sKey) { // We compute here all pseudo keys (non album real attributes) that can be // required on an album if (Const.XML_ARTIST.equals(sKey)) { return handleArtist(); } else if (Const.XML_ALBUM.equals(sKey)) { return getName2(); } else if (Const.XML_GENRE.equals(sKey)) { return handleGenre(); } else if (Const.XML_YEAR.equals(sKey)) { return handleYear(); } else if (Const.XML_TRACK_RATE.equals(sKey)) { return Long.toString(getRate()); } else if (Const.XML_TRACK_LENGTH.equals(sKey)) { return Long.toString(getDuration()); } else if (Const.XML_TRACKS.equals(sKey)) { return Integer.toString(getNbOfTracks()); } else if (Const.XML_TRACK_DISCOVERY_DATE.equals(sKey)) { return UtilString.getLocaleDateFormatter().format(getDiscoveryDate()); } else if (Const.XML_TRACK_HITS.equals(sKey)) { return Long.toString(getHits()); } else if (Const.XML_ANY.equals(sKey)) { return getAny(); } // default return super.getHumanValue(sKey); } /** * Handle artist. * DOCUMENT_ME * * @return the string */ private String handleArtist() { Artist artist = getArtist(); if (artist != null) { return artist.getName2(); } else { // More than one artist, display void string return ""; } } /** * Handle genre. * DOCUMENT_ME * * @return the string */ private String handleGenre() { Genre genre = getGenre(); if (genre != null) { return genre.getName2(); } else { // More than one genre, display void string return ""; } } /** * Handle year. * DOCUMENT_ME * * @return the string */ private String handleYear() { Year year = getYear(); if (year != null) { return Long.toString(year.getValue()); } else { return ""; } } /** * Gets the any. * * @return a human representation of all concatenated properties */ @Override public String getAny() { // rebuild any StringBuilder sb = new StringBuilder(100); sb.append(super.getAny()); // add all album-based properties // now add others properties Artist artist = getArtist(); if (artist != null) { sb.append(artist.getName2()); } // Try to add album artist Track first = null; List cache = getTracksCache(); synchronized (cache) { first = cache.get(0); } // (every track maps at minimum an "unknown artist" album artist if (first.getAlbumArtist() != null) { sb.append(first.getAlbumArtist().getName2()); } Genre genre = getGenre(); if (genre != null) { sb.append(genre.getName2()); } Year year = getYear(); if (year != null) { sb.append(getHumanValue(Const.XML_YEAR)); } sb.append(getHumanValue(Const.XML_TRACK_RATE)); sb.append(getHumanValue(Const.XML_TRACK_LENGTH)); sb.append(getHumanValue(Const.XML_TRACKS)); sb.append(getHumanValue(Const.XML_TRACK_DISCOVERY_DATE)); sb.append(getHumanValue(Const.XML_TRACK_HITS)); return sb.toString(); } /** * Gets the best associated cover as a file. *

    Can be a long action

    * * @return Associated best cover file available or null if none. The returned * file is not guarantee to exist, so use a try/catch around a future access to this method. */ public File findCover() { String discoveredCoverPath = getStringValue(XML_ALBUM_DISCOVERED_COVER); String selectedCoverPath = getStringValue(XML_ALBUM_SELECTED_COVER); if (StringUtils.isNotBlank(selectedCoverPath) && new File(selectedCoverPath).exists()) { // If user-selected cover is available, just return its path return new File(selectedCoverPath); } else if (StringUtils.isNotBlank(discoveredCoverPath) && COVER_NONE.equals(discoveredCoverPath)) { return null; } else if (StringUtils.isNotBlank(discoveredCoverPath)) { // Check if discovered cover still exist. There is an overhead // drawback but otherwise, the album's cover // property may be stuck to an old device's cover url. // Moreover, cover tags are extracted to cache directory so they are // Regularly dropped. Device device = DeviceManager.getInstance().getDeviceByPath(new File(discoveredCoverPath)); // If the device is not mounted, do not perform this existence check up if (device != null && device.isMounted()) { if (new File(discoveredCoverPath).exists()) { return new File(discoveredCoverPath); } } else { return new File(discoveredCoverPath); } } // None cover yet set or it is no more accessible. // Search for local covers in all directories mapping the current track // to reach other devices covers and display them together List lTracks = cache; if (lTracks.size() == 0) { setProperty(XML_ALBUM_DISCOVERED_COVER, COVER_NONE); return null; } // List at directories we have to look in Set dirs = new HashSet(2); for (Track track : lTracks) { for (org.jajuk.base.File file : track.getReadyFiles()) { // note that hashset ensures directory unicity dirs.add(file.getDirectory()); } } // If none available dir, we can't search for cover for now (may be better // next time when at least one device will be mounted) if (dirs.size() == 0) { return null; } // look for tag cover if tag supported for this type File cover = findTagCover(); // none ? look for standard cover in collection if (cover == null) { cover = findCoverFile(dirs, true); } // none ? OK, return first cover file we find if (cover == null) { cover = findCoverFile(dirs, false); } // [PERF] Still nothing ? ok, set no cover to avoid further searches if (cover == null) { setProperty(XML_ALBUM_DISCOVERED_COVER, COVER_NONE); } else { //[PERF] if we found a cover, we store it to avoid further covers // searches including a full tags picture extraction setProperty(XML_ALBUM_DISCOVERED_COVER, cover.getAbsolutePath()); } return cover; } /** * Return whether this album owns a cover (this method doesn't check * cover file existence). * @return whether this album owns a cover. */ public boolean containsCover() { String discoveredCoverPath = getStringValue(XML_ALBUM_DISCOVERED_COVER); return !StringUtils.isBlank(discoveredCoverPath) && !discoveredCoverPath.equals(COVER_NONE); } /** * Return a tag cover file from given directories. If a cover tags are found, * they are extracted to the cache directory. * * @return a tag cover file or null if none. */ private File findTagCover() { //Make sure to sort the cache List sortedTracks = new ArrayList(cache); Collections.sort(sortedTracks, new TrackComparator(TrackComparatorType.ALBUM)); for (Track track : sortedTracks) { for (org.jajuk.base.File file : track.getReadyFiles()) { try { if (file != null && file.getType() != null && file.getType().getTagImpl() != null) { Tag tag = new Tag(file.getFIO(), false); List covers = tag.getCovers(); if (covers.size() > 0) { return covers.get(0).getFile(); } } } catch (JajukException e1) { Log.error(e1); } } } return null; } /** * Return a cover file matching criteria or null. * * @param dirs : list of directories to search in * @param onlyStandardCovers to we consider only standard covers ? * * @return a cover file matching criteria or null */ private File findCoverFile(Set dirs, boolean onlyStandardCovers) { JajukFileFilter filter = new JajukFileFilter(ImageFilter.getInstance()); for (Directory dir : dirs) { File fDir = dir.getFio(); // store this dir java.io.File[] files = fDir.listFiles();// null if none file // found for (int i = 0; files != null && i < files.length; i++) { if (files[i].exists() // check size to avoid out of memory errors && files[i].length() < MAX_COVER_SIZE * 1024 // Is it an image ? && filter.accept(files[i])) { // Filter standard view if required if (onlyStandardCovers && !UtilFeatures.isStandardCover(files[i])) { continue; } // Test the image is not corrupted try { ImageIcon ii = new ImageIcon(files[i].getAbsolutePath()); // Note that at this point, the image is fully loaded (done in the ImageIcon // constructor) if (ii.getImageLoadStatus() == MediaTracker.COMPLETE) { return files[i]; } else { Log.debug("Problem loading: " + files[i].getAbsolutePath()); } } catch (Exception e) { Log.error(e); } } } } return null; } /* * (non-Javadoc) * * @see org.jajuk.base.Item#getIconRepresentation() */ @Override public ImageIcon getIconRepresentation() { return IconLoader.getIcon(JajukIcons.ALBUM); } /** * Gets the rate. * * @return album rating */ @Override public long getRate() { long rate = 0; for (Track track : cache) { rate += track.getRate(); } return rate; } /** * Gets the thumbnail. * * @param size size using format width x height * * @return album thumb for given size */ public ImageIcon getThumbnail(int size) { File fCover = ThumbnailManager.getThumbBySize(this, size); // Check if thumb already exists if (!fCover.exists() || fCover.length() == 0) { return IconLoader.getNoCoverIcon(size); } BufferedImage img = null; try { img = ImageIO.read(new File(fCover.getAbsolutePath())); } catch (IOException e) { Log.error(e); } // can be null now if an error occurred, we reported a error to the log // already... if (img == null) { return null; } ImageIcon icon = new ImageIcon(img); // Free thumb memory (DO IT AFTER FULL ImageIcon loading) img.flush(); return icon; } /** * Gets the genre. * * @return genre for the album. Return null if the album contains tracks with * different genres */ public Genre getGenre() { Set genres = new HashSet(1); for (Track track : cache) { genres.add(track.getGenre()); } // If different genres, the album genre is null if (genres.size() == 1) { return genres.iterator().next(); } else { return null; } } /** * Gets the artist. * * @return artist for the album.
    * Return null if the album contains tracks with different artists */ public Artist getArtist() { if (cache.size() == 0) { return null; } Artist first = cache.get(0).getArtist(); for (Track track : cache) { if (!track.getArtist().equals(first)) { return null; } } return first; } /** * Gets the artist or the album artist if not available * * Used algorithm is following : *
  • If none available tags : return "unknown artist"
  • *
  • If the album contains tracks with different artists, display the first album artist found if any
  • *
  • In this case, if no album artist is available, display the first artist found
  • *
    . * * @return artist for the album.
    * Return Always an artist, eventually a "Unknown Artist" one */ public String getArtistOrALbumArtist() { // no track => no artist if (cache.size() == 0) { return Const.UNKNOWN_ARTIST; } Artist artist = getArtist(); if (artist != null && !artist.isUnknown()) { return artist.getName(); } else { Track first = cache.get(0); AlbumArtist albumArtist = first.getAlbumArtist(); if (!albumArtist.isUnknown()) { return albumArtist.getName(); } else { return first.getArtist().getName(); } } } /** * Gets the year. * * @return year for the album. Return null if the album contains tracks with * different years */ public Year getYear() { Set years = new HashSet(1); for (Track track : cache) { years.add(track.getYear()); } // If different Artists, the album Artist is null if (years.size() == 1) { return years.iterator().next(); } else { return null; } } /** * Return full album length in secs. * * @return the duration */ public long getDuration() { long length = 0; for (Track track : cache) { length += track.getDuration(); } return length; } /** * Gets the nb of tracks. * * @return album nb of tracks */ public int getNbOfTracks() { return cache.size(); } /** * Gets the hits. * * @return album total nb of hits */ public long getHits() { int hits = 0; for (Track track : cache) { hits += track.getHits(); } return hits; } /** * Contains ready files. * * @return whether the album contains a least one available track */ public boolean containsReadyFiles() { for (Track track : cache) { if (track.getReadyFiles().size() > 0) { return true; } } return false; } /** * Gets the discovery date. * * @return First found track discovery date */ public Date getDiscoveryDate() { if (cache.size() > 0) { return cache.get(0).getDiscoveryDate(); } else { return null; } } /** * Returns true, if the pattern matches the specified property. * * Currently only Const.XML_ALBUM and Const.XML_GENRE are supported * properties. The pattern is used for a case-insensitive sub-string match, * no regular expression is used! * * @param property The property to use for the match, currently either Cosnt.XML_ALBUM * or Const.XML_GENRE * @param pattern The string to search for as case-insensitive sub-string * * @return true if either parameter is null or if the pattern matches, false otherwise. */ public boolean matches(String property, String pattern) { if (StringUtils.isBlank(property) || StringUtils.isBlank(pattern)) { return true; } String sValue = null; if (Const.XML_ALBUM.equals(property)) { sValue = getName2(); } else if (Const.XML_GENRE.equals(property)) { Genre genre = getGenre(); if (genre == null) { return false; } sValue = genre.getName2(); } if (sValue == null) { return false; } // do not use regexp matches() because the string may contain // characters to be escaped return (sValue.toLowerCase(Locale.getDefault()).indexOf( pattern.toLowerCase(Locale.getDefault())) != -1); } /** * Reset tracks cache. */ protected void resetTracks() { cache.clear(); } /** * Gets the tracks cache. * * @return ordered tracks cache for this album (perf) */ public List getTracksCache() { return this.cache; } /** * Gets the any track. * * @return a track from this album */ public Track getAnyTrack() { if (cache.size() == 0) { return null; } else { return cache.get(0); } } /** * Set that the thumb for given size is available. * * @param size (thumb size like 50) * @param available DOCUMENT_ME */ public void setAvailableThumb(int size, boolean available) { if (availableTumbs == null) { availableTumbs = new boolean[6]; } availableTumbs[size / 50 - 1] = available; } /** * Return whether a thumb is available for given size. * * @param size (thumb size like 50) * * @return whether a thumb is available for given size */ public boolean isThumbAvailable(int size) { // Lazy loading of thumb availability (for all sizes) if (availableTumbs == null) { availableTumbs = new boolean[6]; for (int i = 50; i <= 300; i += 50) { File fThumb = ThumbnailManager.getThumbBySize(this, i); setAvailableThumb(i, fThumb.exists() && fThumb.length() > 0); } } return availableTumbs[size / 50 - 1]; } } jajuk-1.9.6.orig/src/main/java/org/jajuk/base/File.java0000644000175000017500000003071011720500104022440 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.base; import java.net.MalformedURLException; import java.net.URL; import javax.swing.ImageIcon; import org.jajuk.ui.thumbnails.ThumbnailManager; import org.jajuk.util.Conf; import org.jajuk.util.Const; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; import org.jajuk.util.UtilString; import org.jajuk.util.UtilSystem; import org.jajuk.util.log.Log; /** * A music file to be played *

    * Physical item. */ public class File extends PhysicalItem implements Comparable, Const { /** Parent directory. */ protected final Directory directory; /** Associated track. */ protected Track track; /** IO file associated with this file. */ private java.io.File fio; /** * File instanciation. * * @param sId DOCUMENT_ME * @param sName DOCUMENT_ME * @param directory DOCUMENT_ME * @param track DOCUMENT_ME * @param lSize DOCUMENT_ME * @param lQuality DOCUMENT_ME */ File(String sId, String sName, Directory directory, Track track, long lSize, long lQuality) { super(sId, sName); this.directory = directory; setProperty(Const.XML_DIRECTORY, directory.getID()); this.track = track; setProperty(Const.XML_TRACK, track.getID()); setProperty(Const.XML_SIZE, lSize); setProperty(Const.XML_QUALITY, lQuality); } /* * (non-Javadoc) * * @see org.jajuk.base.Item#getIdentifier() */ @Override public final String getLabel() { return XML_FILE; } /** * toString method. * * @return the string */ @Override public String toString() { return "File[ID=" + getID() + " Name={{" + getName() + "}} Dir=" + directory + " Size=" + getSize() + " Quality=" + getQuality() + "]"; } /** * String representation as displayed in a search result. * * @return the string */ public String toStringSearch() { StringBuilder sb = new StringBuilder(track.getGenre().getName2()).append('/') .append(track.getArtist().getName2()).append('/').append(track.getAlbum().getName2()) .append('/').append(track.getName()).append(" [").append(directory.getName()).append('/') .append(getName()).append(']'); return sb.toString(); } /** * Return true is the specified directory is an ancestor for this file. * * @param directory DOCUMENT_ME * * @return true, if checks for ancestor */ public boolean hasAncestor(Directory directory) { Directory dirTested = getDirectory(); while (true) { if (dirTested.equals(directory)) { return true; } else { dirTested = dirTested.getParentDirectory(); if (dirTested == null) { return false; } } } } /** * Gets the size. * * @return the size */ public long getSize() { return getLongValue(Const.XML_SIZE); } /** * Gets the directory. * * @return the directory */ public Directory getDirectory() { return directory; } /** * Gets the device. * * @return associated device */ public Device getDevice() { return directory.getDevice(); } /** * Gets the type. * * @return associated type */ public Type getType() { String extension = UtilSystem.getExtension(this.getName()); if (extension != null) { return TypeManager.getInstance().getTypeByExtension(extension); } return null; } /** * Gets the quality. * * @return the quality */ public long getQuality() { return getLongValue(Const.XML_QUALITY); } /** * Gets the track. * * @return the track */ public Track getTrack() { return track; } /** * Return absolute file path name. * * @return String */ public String getAbsolutePath() { StringBuilder sbOut = new StringBuilder(getDevice().getUrl()) .append(getDirectory().getRelativePath()).append(java.io.File.separatorChar) .append(this.getName()); return sbOut.toString(); } /** * Alphabetical comparator used to display ordered lists of files *

    * Sort ignoring cases *

    * . * * @param otherFile DOCUMENT_ME * * @return comparison result */ @Override public int compareTo(File otherFile) { // Begin by comparing file parent directory for performances if (directory.equals(otherFile.getDirectory())) { // If both files are in the same directory, sort by track order int iOrder = (int) getTrack().getOrder(); int iOrderOther = (int) otherFile.getTrack().getOrder(); if (iOrder != iOrderOther) { return iOrder - iOrderOther; } // if same order too, simply compare file names String abs = getName(); String otherAbs = otherFile.getName(); // We must be consistent with equals, see // http://java.sun.com/javase/6/docs/api/java/lang/Comparable.html int comp = abs.compareToIgnoreCase(otherAbs); if (comp == 0) { return abs.compareTo(otherAbs); } else { return comp; } } else { // Files are in different directories, sort by parent directory return this.getDirectory().compareTo(otherFile.getDirectory()); } } /** * Return true if the file can be accessed right now. * * @return true the file can be accessed right now */ public boolean isReady() { return getDirectory().getDevice().isMounted(); } /** * Return true if the file is currently refreshed or synchronized. * * @return true if the file is currently refreshed or synchronized */ public boolean isScanned() { if (getDirectory().getDevice().isRefreshing() || getDirectory().getDevice().isSynchronizing()) { return true; } return false; } /** * Return Io file associated with this file. * * @return the FIO */ public java.io.File getFIO() { if (fio == null) { fio = new java.io.File(getAbsolutePath()); } return fio; } /** * Return whether this item should be hidden with hide option. * * @return whether this item should be hidden with hide option */ public boolean shouldBeHidden() { if (getDirectory().getDevice().isMounted() || !Conf.getBoolean(Const.CONF_OPTIONS_HIDE_UNMOUNTED)) { return false; } return true; } /** * Sets the track. * * @param track The track to set. */ public void setTrack(Track track) { // We remove previous track so it will be cleanup (if it maps no more // files). This allow cleaning old tracks after a change of tags from others // programs than jajuk if (!this.track.equals(track)) { TrackManager.getInstance().removeFile(this); this.track = track; setProperty(Const.XML_TRACK, track.getID()); track.addFile(this); } } /** * Get item description. * * @return the desc */ @Override public String getDesc() { return Messages.getString("Item_File") + " : " + getName(); } /* * (non-Javadoc) * * @see org.jajuk.base.Item#getHumanValue(java.lang.String) */ @Override public String getHumanValue(String sKey) { if (Const.XML_DIRECTORY.equals(sKey)) { Directory dParent = DirectoryManager.getInstance().getDirectoryByID(getStringValue(sKey)); return dParent.getFio().getAbsolutePath(); } else if (Const.XML_TRACK.equals(sKey)) { return getTrack().getName(); } else if (Const.XML_SIZE.equals(sKey)) { return (Math.round(getSize() / 10485.76) / 100f) + Messages.getString("FilesTreeView.54"); } else if (Const.XML_QUALITY.equals(sKey)) { return getQuality() + Messages.getString("FIFO.13"); } else if (Const.XML_ALBUM.equals(sKey)) { return getTrack().getAlbum().getName2(); } else if (Const.XML_GENRE.equals(sKey)) { return getTrack().getGenre().getName2(); } else if (Const.XML_ARTIST.equals(sKey)) { return getTrack().getArtist().getName2(); } else if (Const.XML_TRACK_LENGTH.equals(sKey)) { return UtilString.formatTimeBySec(getTrack().getDuration()); } else if (Const.XML_TRACK_RATE.equals(sKey)) { return Long.toString(getTrack().getRate()); } else if (Const.XML_DEVICE.equals(sKey)) { return getDirectory().getDevice().getName(); } else if (Const.XML_ANY.equals(sKey)) { return getAny(); } else {// default // check if this key is known if (getMeta(sKey) != null) { return super.getHumanValue(sKey); } // Unknown ? check if it is a track custom property else if (getTrack().getMeta(sKey) != null) { return getTrack().getHumanValue(sKey); } else { return null; } } } /** * Gets the any. * * @return a human representation of all concatenated properties */ @Override public String getAny() { // rebuild any StringBuilder sb = new StringBuilder(100); File file = this; Track lTrack = file.getTrack(); sb.append(super.getAny()); // add all files-based properties // now add others properties sb.append(file.getDirectory().getDevice().getName()); sb.append(lTrack.getName()); sb.append(lTrack.getGenre().getName2()); sb.append(lTrack.getArtist().getName2()); sb.append(lTrack.getAlbum().getName2()); sb.append(lTrack.getDuration()); sb.append(lTrack.getRate()); sb.append(lTrack.getValue(Const.XML_TRACK_COMMENT)); sb.append(lTrack.getAlbumArtist().getName2()); AlbumArtist albumArtist = lTrack.getAlbumArtist(); if (albumArtist != null) { sb.append(albumArtist.getName2()); } return sb.toString(); } /** * Reset pre-calculated paths*. */ protected void reset() { // sAbs = null; fio = null; } /* * (non-Javadoc) * * @see org.jajuk.base.Item#getIconRepresentation() */ @Override public ImageIcon getIconRepresentation() { ImageIcon icon = null; String ext = UtilSystem.getExtension(getName()); // getName() is better // here as // it will do less and not // create java.io.File in File Type type = TypeManager.getInstance().getTypeByExtension(ext); // Find associated icon with this type URL iconUrl = null; String sIcon; if (type != null) { sIcon = (String) type.getProperties().get(Const.XML_TYPE_ICON); try { iconUrl = new URL(sIcon); } catch (MalformedURLException e) { Log.error(e); } } if (iconUrl == null) { icon = IconLoader.getIcon(JajukIcons.TYPE_WAV); } else { icon = new ImageIcon(iconUrl); } return icon; } /** * Set name (useful for Windows because same object can have different cases). * * @param name Item name */ protected void setName(String name) { setProperty(Const.XML_NAME, name); this.name = name; } /** * Gets the html format text. * * @return text to be displayed in the tray balloon and tooltip with HTML * formating that is used correctly under Linux */ public String getHTMLFormatText() { String sOut = ""; sOut += ""; int size = 100; int maxSize = 30; ThumbnailManager.refreshThumbnail(getTrack().getAlbum(), size); java.io.File cover = ThumbnailManager.getThumbBySize(getTrack().getAlbum(), size); if (cover.canRead()) { sOut += "

    "; } sOut += "" + UtilString.getLimitedString(getTrack().getName(), maxSize) + "
    "; String sArtist = UtilString.getLimitedString(getTrack().getArtist().getName(), maxSize); if (!sArtist.equals(UNKNOWN_ARTIST)) { sOut += sArtist + "
    "; } String sAlbum = UtilString.getLimitedString(getTrack().getAlbum().getName(), maxSize); if (!sAlbum.equals(UNKNOWN_ALBUM)) { sOut += sAlbum + "
    "; } sOut += ""; return sOut; } } jajuk-1.9.6.orig/src/main/java/org/jajuk/base/PropertyMetaInformation.java0000644000175000017500000001645611720500104026435 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.base; import java.net.MalformedURLException; import java.net.URL; import java.util.Date; import org.jajuk.services.core.SessionService; import org.jajuk.util.Const; import org.jajuk.util.Messages; import org.jajuk.util.UtilString; import org.jajuk.util.UtilSystem; import org.jajuk.util.log.Log; /** * A Jajuk property meta information. */ public class PropertyMetaInformation { /** Property name. */ private final String sName; /** Is property a custom property?. */ private boolean bCustom = false; /** Is property element of associated item constructor? (and so used in the checksum ID hash). */ private boolean bConstructor = false; /** Property Type (java.lang.String for ie) */ private final Class cType; /** Default value (null: no default). */ Object oDefaultValue; /** This property should be displayed to UI?. */ boolean bShouldBeDisplayed = true; /** Editable?. */ boolean bEditable = true; /** Unique?. */ boolean bMergeable = false; /** Human Type. */ private String sHumanType; /** Today. */ public static final Date TODAY = new Date(); /** * constructor. * * @param sName Property name * @param bCustom Is custom property * @param bConstructor Is constructor property * @param bShouldBeDisplayed Does this standard property must be displayed (exp for ie is not) * @param bEditable Is this property editable * @param bMergeable Is this property mergeable if we display several items together * @param cType Property type * @param oDefaultValue Default value */ public PropertyMetaInformation(String sName, boolean bCustom, boolean bConstructor, boolean bShouldBeDisplayed, boolean bEditable, boolean bMergeable, Class cType, Object oDefaultValue) { this.sName = sName; this.bCustom = bCustom; this.bConstructor = bConstructor; this.bShouldBeDisplayed = bShouldBeDisplayed; this.bEditable = bEditable; this.bMergeable = bMergeable; this.cType = cType; this.oDefaultValue = oDefaultValue; if (cType.equals(Boolean.class)) { if (oDefaultValue == null) { this.oDefaultValue = Boolean.FALSE; // if no default is // given, false for // booleans } this.sHumanType = Messages.getString("Property_Format_Boolean"); } else if (cType.equals(String.class)) { if (oDefaultValue == null) { this.oDefaultValue = ""; // if no default is given, "" } this.sHumanType = Messages.getString("Property_Format_String"); } else if (cType.equals(Long.class)) { if (oDefaultValue == null) { this.oDefaultValue = 0l; // if no default is given, 0 } this.sHumanType = Messages.getString("Property_Format_Number"); } else if (cType.equals(Double.class)) { if (oDefaultValue == null) { this.oDefaultValue = 0.0d; // if no default is given, 0.0 } this.sHumanType = Messages.getString("Property_Format_Float"); } else if (cType.equals(Date.class)) { // date default if (oDefaultValue == null) { this.oDefaultValue = UtilSystem.TODAY; } else { this.oDefaultValue = oDefaultValue; } this.sHumanType = Messages.getString("Property_Format_Date"); } else if (cType.equals(URL.class)) { // URL default if (oDefaultValue == null) { try { this.oDefaultValue = SessionService.getConfFileByPath("").toURI().toURL(); } catch (MalformedURLException e) { Log.error(e); } } else { this.oDefaultValue = oDefaultValue; } this.sHumanType = Messages.getString("Property_Format_URL"); } else if (cType.equals(Class.class)) { this.oDefaultValue = Object.class; } else { // class not supported Log.debug("Class not supported !!!"); } } /** * Checks if is constructor. * * @return true, if is constructor */ public boolean isConstructor() { return bConstructor; } /** * Checks if is custom. * * @return true, if is custom */ public boolean isCustom() { return bCustom; } /** * Gets the type. * * @return the type */ public Class getType() { return cType; } /** * Gets the name. * * @return the name */ public String getName() { return sName; } /** * . * * @return property meta information XML description */ public String toXML() { String sDefault = ""; try { if (oDefaultValue != null) { sDefault = UtilString.format(oDefaultValue, this, false); } } catch (Exception e) { // should to occur at this point Log.error(e); } return '<' + Const.XML_PROPERTY + " " + Const.XML_NAME + "='" + UtilString.formatXML(sName) + "' " + Const.XML_CUSTOM + "='" + bCustom + "' " + Const.XML_CONSTRUCTOR + "='" + bConstructor + "' " + Const.XML_VISIBLE + "='" + bShouldBeDisplayed + "' " + Const.XML_EDITABLE + "='" + bEditable + "' " + Const.XML_UNIQUE + "='" + bMergeable + "' " + Const.XML_TYPE + "='" + cType.getName() + "' " + Const.XML_DEFAULT_VALUE + "='" + UtilString.formatXML(sDefault) + "'/>"; } /** * Gets the default value. * * @return the default value */ public Object getDefaultValue() { return oDefaultValue; } /* * public void setDefaultValue(String defaultValue) { oDefaultValue = * defaultValue; } */ /* (non-Javadoc) * @see java.lang.Object#toString() */ @Override public String toString() { return "Name=" + sName + " Custom=" + bCustom + " Constructor=" + bConstructor + " Type=" + cType + " Default=" + oDefaultValue + " Editable=" + isEditable() + " Visible=" + isVisible() + " Mergeable=" + isMergeable(); } /** * Checks if is visible. * * @return true, if is visible */ public boolean isVisible() { return bShouldBeDisplayed; } /** * Checks if is editable. * * @return true, if is editable */ public boolean isEditable() { return bEditable; } /** * Checks if is mergeable. * * @return true, if is mergeable */ public boolean isMergeable() { return bMergeable; } /** * Gets the human type. * * @return a human representation for a property type */ public String getHumanType() { return sHumanType; } /** * Gets the human name. * * @return the human name */ public String getHumanName() { return Messages.getHumanPropertyName(getName()); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/base/Collection.java0000644000175000017500000011533011720500104023656 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.base; import java.io.BufferedWriter; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStreamWriter; import java.text.DateFormat; import java.text.ParseException; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.zip.ZipInputStream; import java.util.zip.ZipOutputStream; import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; import org.apache.commons.lang.StringUtils; import org.jajuk.services.core.SessionService; import org.jajuk.util.Conf; import org.jajuk.util.Const; import org.jajuk.util.Messages; import org.jajuk.util.ReadOnlyIterator; import org.jajuk.util.UpgradeManager; import org.jajuk.util.UtilString; import org.jajuk.util.UtilSystem; import org.jajuk.util.error.JajukException; import org.jajuk.util.log.Log; import org.xml.sax.Attributes; import org.xml.sax.ErrorHandler; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import org.xml.sax.SAXParseException; import org.xml.sax.helpers.DefaultHandler; /** * Items root container. */ public final class Collection extends DefaultHandler implements ErrorHandler { /** The Constant TAG_CLOSE_NEWLINE. DOCUMENT_ME */ private static final String TAG_CLOSE_NEWLINE = ">\n"; /** The Constant TAB_CLOSE_TAG_START. DOCUMENT_ME */ private static final String TAB_CLOSE_TAG_START = " hmWrongRightTrackID = new HashMap(); /** upgrade for album IDs. */ private final Map hmWrongRightAlbumID = new HashMap(); /** upgrade for artist IDs. */ private final Map hmWrongRightArtistID = new HashMap(); /** upgrade for album-artists IDs. */ private final Map hmWrongRightAlbumArtistID = new HashMap(); /** upgrade for genre IDs. */ private final Map hmWrongRightGenreID = new HashMap(); /** upgrade for device IDs. */ private final Map hmWrongRightDeviceID = new HashMap(); /** upgrade for directory IDs. */ private final Map hmWrongRightDirectoryID = new HashMap(); /** upgrade for file IDs. */ private final Map hmWrongRightFileID = new HashMap(); /** upgrade for playlist IDs. */ private final Map hmWrongRightPlaylistFileID = new HashMap(); /** Conversion of types from Jajuk < 1.4 */ private final static Map CONVERSION; static { CONVERSION = new HashMap(12); CONVERSION.put("0", "mp3"); CONVERSION.put("1", "m3u"); CONVERSION.put("2", "ogg"); CONVERSION.put("3", "wav"); CONVERSION.put("4", "au"); CONVERSION.put("5", "flac"); CONVERSION.put("6", "wma"); CONVERSION.put("7", "aac"); CONVERSION.put("8", "m4a"); CONVERSION.put("9", "ram"); CONVERSION.put("10", "mp2"); } /** [Perf] flag used to accelerate conversion. */ private boolean needCheckConversions = true; /** [PERF] Does the type has been checked once for ID computation change ? Indeed, we check only one element of each type to check if this computation changed for perfs. */ private boolean needCheckID = false; // Constants value, use lower value for mist numerous items to parse /** * DOCUMENT_ME. */ private enum Stage { /** DOCUMENT_ME. */ STAGE_NONE, /** The Constant STAGE_FILES. DOCUMENT_ME */ STAGE_FILES, /** The Constant STAGE_DIRECTORIES. DOCUMENT_ME */ STAGE_DIRECTORIES, /** The Constant STAGE_TRACKS. DOCUMENT_ME */ STAGE_TRACKS, /** The Constant STAGE_ALBUMS. DOCUMENT_ME */ STAGE_ALBUMS, /** The Constant STAGE_ARTISTS. DOCUMENT_ME */ STAGE_ARTISTS, /** The Constant STAGE_GENRES. DOCUMENT_ME */ STAGE_GENRES, /** The Constant STAGE_PLAYLIST_FILES. DOCUMENT_ME */ STAGE_PLAYLIST_FILES, /** The Constant STAGE_PLAYLISTS. DOCUMENT_ME */ STAGE_PLAYLISTS, /** The Constant STAGE_TYPES. DOCUMENT_ME */ STAGE_TYPES, /** The Constant STAGE_DEVICES. DOCUMENT_ME */ STAGE_DEVICES, /** The Constant STAGE_YEARS. DOCUMENT_ME */ STAGE_YEARS, /** STAGE_ALBUM_ARTIST. */ STAGE_ALBUM_ARTIST } /** *************************************************************************** [PERF] provide current stage (files, tracks...) used to optimize switch when parsing the collection ************************************************************************** */ private Stage stage = Stage.STAGE_NONE; /** The Constant ADDITION_FORMATTER. DOCUMENT_ME */ private static final DateFormat ADDITION_FORMATTER = UtilString.getAdditionDateFormatter(); /** * Instance getter. * * @return the instance */ public static Collection getInstance() { return coll; } /** * Hidden constructor. */ private Collection() { super(); } /** * Write current collection to collection file for persistence between * sessions. * * @param collectionFile DOCUMENT_ME * * @throws IOException Signals that an I/O exception has occurred. */ public static synchronized void commit(File collectionFile) throws IOException { long time = System.currentTimeMillis(); String sCharset = Conf.getString(Const.CONF_COLLECTION_CHARSET); final BufferedWriter bw; if (collectionFile.getAbsolutePath().endsWith(".zip")) { bw = new BufferedWriter(new OutputStreamWriter(new ZipOutputStream(new FileOutputStream( collectionFile)), sCharset), 1000000); } else { bw = new BufferedWriter( new OutputStreamWriter(new FileOutputStream(collectionFile), sCharset), 1000000); } try { bw.write("\n"); bw.write("<" + Const.XML_COLLECTION + " " + Const.XML_VERSION + "='" + Const.JAJUK_VERSION + "'>\n"); // Devices writeItemList(bw, DeviceManager.getInstance().toXML(), DeviceManager.getInstance() .getDevices(), DeviceManager.getInstance().getLabel(), 40); Log.debug("Devices committed."); // Genres writeItemList(bw, GenreManager.getInstance().toXML(), GenreManager.getInstance().getGenres(), GenreManager.getInstance().getLabel(), 40); Log.debug("Genres committed."); // Artists writeItemList(bw, ArtistManager.getInstance().toXML(), ArtistManager.getInstance() .getArtists(), ArtistManager.getInstance().getLabel(), 40); Log.debug("Artists committed."); // Album artists writeItemList(bw, AlbumArtistManager.getInstance().toXML(), AlbumArtistManager.getInstance() .getAlbumArtists(), AlbumArtistManager.getInstance().getLabel(), 40); Log.debug("Album-artists committed."); // Albums writeItemList(bw, AlbumManager.getInstance().toXML(), AlbumManager.getInstance().getAlbums(), AlbumManager.getInstance().getLabel(), 40); Log.debug("Albums committed."); // Years writeItemList(bw, YearManager.getInstance().toXML(), YearManager.getInstance().getYears(), YearManager.getInstance().getLabel(), 40); Log.debug("Years committed."); // Tracks // Cannot use writeItemList() method as we have a bit of special handling inside the loop here TrackManager.getInstance().getLock().readLock().lock(); try { ReadOnlyIterator tracks = TrackManager.getInstance().getTracksIterator(); bw.write(TrackManager.getInstance().toXML()); while (tracks.hasNext()) { Track track = tracks.next(); // We clean up all orphan tracks if (track.getFiles().size() > 0) { bw.write(track.toXml()); } } } finally { TrackManager.getInstance().getLock().readLock().unlock(); } writeString(bw, TrackManager.getInstance().getLabel(), 200); Log.debug("Tracks committed."); // Directories writeItemList(bw, DirectoryManager.getInstance().toXML(), DirectoryManager.getInstance() .getDirectories(), DirectoryManager.getInstance().getLabel(), 100); Log.debug("Directories committed."); // Files writeItemList(bw, FileManager.getInstance().toXML(), FileManager.getInstance().getFiles(), FileManager.getInstance().getLabel(), 200); Log.debug("Files committed."); // Playlists writeItemList(bw, PlaylistManager.getInstance().toXML(), PlaylistManager.getInstance() .getPlaylists(), PlaylistManager.getInstance().getLabel(), 200); Log.debug("Playlists committed."); // end of collection bw.write(" items, String footer, int buffer) throws IOException { bw.write(header); for (Item item : items) { bw.write(item.toXml()); } writeString(bw, footer, buffer); } /** * Write string. DOCUMENT_ME * * @param bw DOCUMENT_ME * @param toWrite DOCUMENT_ME * @param buffer DOCUMENT_ME * * @throws IOException Signals that an I/O exception has occurred. */ private static void writeString(BufferedWriter bw, String toWrite, int buffer) throws IOException { StringBuilder sb = new StringBuilder(buffer); sb.append(TAB_CLOSE_TAG_START); sb.append(toWrite); sb.append(TAG_CLOSE_NEWLINE); bw.write(sb.toString()); } /** * Parse collection.xml file and put all collection information into memory * * @param file DOCUMENT_ME * * @throws SAXException the SAX exception * @throws ParserConfigurationException the parser configuration exception * @throws JajukException the jajuk exception * @throws IOException Signals that an I/O exception has occurred. */ public static void load(File file) throws SAXException, ParserConfigurationException, JajukException, IOException { Log.debug("Loading: " + file.getName()); lTime = System.currentTimeMillis(); SAXParserFactory spf = SAXParserFactory.newInstance(); spf.setValidating(false); spf.setNamespaceAware(false); // See http://xerces.apache.org/xerces-j/features.html for details spf.setFeature("http://xml.org/sax/features/external-general-entities", false); spf.setFeature("http://xml.org/sax/features/string-interning", true); SAXParser saxParser = spf.newSAXParser(); if (!file.exists()) { throw new JajukException(5, file.toString()); } if (file.getAbsolutePath().endsWith(".zip")) { InputSource input = new InputSource(new ZipInputStream(new FileInputStream(file))); saxParser.parse(input, getInstance()); } else { saxParser.parse(file.toURI().toURL().toString(), getInstance()); } } /** * Perform a collection clean up for logical items ( delete orphan data ) Note * that we don't cleanup genres up because we want to keep genres even without * associated tracks for ambiences for instance. */ public static synchronized void cleanupLogical() { // Tracks cleanup TrackManager.getInstance().cleanup(); // Artists cleanup ArtistManager.getInstance().cleanup(); // Album-artist cleanup AlbumArtistManager.getInstance().cleanup(); // albums cleanup AlbumManager.getInstance().cleanup(); // years cleanup YearManager.getInstance().cleanup(); } /** * Clear the full collection Note that we don't clear TypeManager as it is not * read from a file but filled programmatically. */ public static synchronized void clearCollection() { TrackManager.getInstance().clear(); GenreManager.getInstance().clear(); ArtistManager.getInstance().clear(); AlbumArtistManager.getInstance().clear(); AlbumManager.getInstance().clear(); YearManager.getInstance().clear(); FileManager.getInstance().clear(); DirectoryManager.getInstance().clear(); PlaylistManager.getInstance().clear(); DeviceManager.getInstance().clear(); } /** * parsing warning. * * @param spe DOCUMENT_ME * * @throws SAXException the SAX exception * * @exception SAXException */ @Override public void warning(SAXParseException spe) throws SAXException { throw new SAXException(Messages.getErrorMessage(5) + " / " + spe.getSystemId() + "/" + spe.getLineNumber() + "/" + spe.getColumnNumber() + " : " + spe.getMessage()); } /** * parsing error. * * @param spe DOCUMENT_ME * * @throws SAXException the SAX exception * * @exception SAXException */ @Override public void error(SAXParseException spe) throws SAXException { throw new SAXException(Messages.getErrorMessage(5) + " / " + spe.getSystemId() + "/" + spe.getLineNumber() + "/" + spe.getColumnNumber() + " : " + spe.getMessage()); } /** * parsing fatal error. * * @param spe DOCUMENT_ME * * @throws SAXException the SAX exception * * @exception SAXException */ @Override public void fatalError(SAXParseException spe) throws SAXException { throw new SAXException(Messages.getErrorMessage(5) + " / " + spe.getSystemId() + "/" + spe.getLineNumber() + "/" + spe.getColumnNumber() + " : " + spe.getMessage()); } /** * Called at parsing start. */ @Override public void startDocument() { Log.debug("Starting collection file parsing..."); } /** * Called at parsing end. */ @Override public void endDocument() { long l = (System.currentTimeMillis() - lTime); Log.debug("Collection file parsing done : " + l + " ms"); } /** * Called when we start an element intern() method use policy : we use this * method when adding a new string into JVM that will probably be referenced * by several objects like the Genre ID that is referenced by many tracks. In * this case, all the String objects share the same char[]. On another hand, * it musn't be used for strings that have low probability to be used several * times (like raw names) as it uses a lot of CPU (equals() is called) and we * want startup to be as fast as possible. Note that the use of intern() save * around 1/4 of overall heap memory * * We use sax-interning for the main items sections ( for ie). For all * raw items, we don't perform equals on item name but we compare the string * hashcode * * @param sUri DOCUMENT_ME * @param s DOCUMENT_ME * @param sQName DOCUMENT_ME * @param attributes DOCUMENT_ME * * @throws SAXException the SAX exception */ @Override public void startElement(String sUri, String s, String sQName, Attributes attributes) throws SAXException { try { int idIndex = attributes.getIndex(Const.XML_ID); // [PERF] Manage top tags to set current stage. Manages 'properties' // tags as well if (idIndex == -1) { if (Const.XML_DEVICES == sQName) { manager = DeviceManager.getInstance(); stage = Stage.STAGE_DEVICES; needCheckID = true; } else if (Const.XML_ALBUMS == sQName) { manager = AlbumManager.getInstance(); stage = Stage.STAGE_ALBUMS; needCheckID = true; } else if (Const.XML_ARTISTS == sQName) { manager = ArtistManager.getInstance(); stage = Stage.STAGE_ARTISTS; needCheckID = true; } else if (Const.XML_ALBUM_ARTISTS == sQName) { manager = AlbumArtistManager.getInstance(); stage = Stage.STAGE_ALBUM_ARTIST; needCheckID = true; } else if (Const.XML_DIRECTORIES == sQName) { manager = DirectoryManager.getInstance(); stage = Stage.STAGE_DIRECTORIES; needCheckID = true; } else if (Const.XML_FILES == sQName) { manager = FileManager.getInstance(); stage = Stage.STAGE_FILES; needCheckID = true; } else if (Const.XML_PLAYLISTS == sQName) { // This code is here for Jajuk < 1.6 compatibility manager = PlaylistManager.getInstance(); stage = Stage.STAGE_PLAYLISTS; needCheckID = true; } else if (Const.XML_PLAYLIST_FILES == sQName) { manager = PlaylistManager.getInstance(); stage = Stage.STAGE_PLAYLIST_FILES; needCheckID = true; } else if (Const.XML_GENRES == sQName) { manager = GenreManager.getInstance(); stage = Stage.STAGE_GENRES; needCheckID = true; } else if (Const.XML_TRACKS == sQName) { manager = TrackManager.getInstance(); stage = Stage.STAGE_TRACKS; needCheckID = true; } else if (Const.XML_YEARS == sQName) { manager = YearManager.getInstance(); stage = Stage.STAGE_YEARS; needCheckID = true; } else if (Const.XML_TYPES == sQName) { // This is here for pre-1.7 collections, after we don't commit types // anymore (they are set programmatically) manager = TypeManager.getInstance(); stage = Stage.STAGE_TYPES; needCheckID = false; } else if (Const.XML_PROPERTY == sQName) { // A property description boolean bCustom = Boolean.parseBoolean(attributes.getValue(attributes .getIndex(Const.XML_CUSTOM))); boolean bConstructor = Boolean.parseBoolean(attributes.getValue(attributes .getIndex(Const.XML_CONSTRUCTOR))); boolean bShouldBeDisplayed = Boolean.parseBoolean(attributes.getValue(attributes .getIndex(Const.XML_VISIBLE))); boolean bEditable = Boolean.parseBoolean(attributes.getValue(attributes .getIndex(Const.XML_EDITABLE))); boolean bUnique = Boolean.parseBoolean(attributes.getValue(attributes .getIndex(Const.XML_UNIQUE))); Class cType = Class.forName(attributes.getValue(Const.XML_TYPE)); String sDefaultValue = attributes.getValue(Const.XML_DEFAULT_VALUE).intern(); Object oDefaultValue = null; if (sDefaultValue != null && sDefaultValue.length() > 0) { try { // Date format has changed from 1.3 (only yyyyMMdd // addition format is used) // so an exception will be thrown when upgrading // from 1.2 // we reset default value to "today" oDefaultValue = UtilString.parse(sDefaultValue, cType); } catch (Exception e) { oDefaultValue = new Date(); } } String sPropertyName = attributes.getValue(Const.XML_NAME).intern(); if (manager.getMetaInformation(sPropertyName) == null) { PropertyMetaInformation meta = new PropertyMetaInformation(sPropertyName, bCustom, bConstructor, bShouldBeDisplayed, bEditable, bUnique, cType, oDefaultValue); // standard properties are already loaded manager.registerProperty(meta); } } if (Const.XML_PROPERTY == sQName) { Log.debug("Found property: " + attributes.getValue(Const.XML_NAME)); } else { Log.debug("Starting stage: '" + stage + "' with property: '" + sQName + "' manager: " + (manager != null ? manager.getLabel() : "")); } } else { // Manage elements themselves using a switch for performances switch (stage) { case STAGE_FILES: handleFiles(attributes, idIndex); break; case STAGE_DIRECTORIES: handleDirectories(attributes, idIndex); break; case STAGE_TRACKS: handleTracks(attributes, idIndex); break; case STAGE_ALBUMS: handleAlbums(attributes, idIndex); break; case STAGE_ARTISTS: handleArtists(attributes, idIndex); break; case STAGE_ALBUM_ARTIST: handleAlbumArtists(attributes, idIndex); break; case STAGE_GENRES: handleGenres(attributes, idIndex); break; case STAGE_PLAYLIST_FILES: handlePlaylistFiles(attributes, idIndex); break; case STAGE_DEVICES: handleDevices(attributes, idIndex); break; case STAGE_YEARS: handleYears(attributes, idIndex); break; case STAGE_TYPES: Log.warn("Unexpected Stage: STAGE_TYPES"); break; default: Log.warn("Unexpected Stage: " + stage); } } } catch (Throwable e) { // Make sure to catch every issue here (including runtime exceptions) so we make sure to start // jajuk StringBuilder sAttributes = new StringBuilder(); for (int i = 0; i < attributes.getLength(); i++) { sAttributes.append('\n').append(attributes.getQName(i)).append('=').append( attributes.getValue(i)); } Log.error(5, sAttributes.toString(), e); } } /** * Handle files. DOCUMENT_ME * * @param attributes DOCUMENT_ME * @param idIndex DOCUMENT_ME */ private void handleFiles(Attributes attributes, int idIndex) { String sItemName = attributes.getValue(Const.XML_NAME); // Check file type is still registered, it can be // useful for ie if mplayer is no more available String ext = UtilSystem.getExtension(sItemName); Type type = TypeManager.getInstance().getTypeByExtension(ext); if (type == null) { return; } String sTrackId = attributes.getValue(Const.XML_TRACK).intern(); // UPGRADE check if track Id is right if ((hmWrongRightTrackID.size() > 0) && // replace wrong by right ID (hmWrongRightTrackID.containsKey(sTrackId))) { sTrackId = hmWrongRightTrackID.get(sTrackId); } Track track = TrackManager.getInstance().getTrackByID(sTrackId); String sParentID = attributes.getValue(Const.XML_DIRECTORY).intern(); // UPGRADE check parent ID is right if ((hmWrongRightDirectoryID.size() > 0) && // replace wrong by right ID (hmWrongRightDirectoryID.containsKey(sParentID))) { sParentID = hmWrongRightDirectoryID.get(sParentID); } Directory dParent = DirectoryManager.getInstance().getDirectoryByID(sParentID); if (dParent == null || track == null) { // more checkups return; } String size = attributes.getValue(Const.XML_SIZE); long lSize = 0; if (size != null) { lSize = Long.parseLong(size); } // Quality analyze, handle format problems (mainly for // upgrades) long lQuality = 0; try { String sQuality = attributes.getValue(Const.XML_QUALITY); if (sQuality != null) { lQuality = UtilString.fastLongParser(sQuality); } } catch (Exception e) { if (Log.isDebugEnabled()) { // wrong format Log.debug(Messages.getString("Error.137") + ":" + sItemName + " Value: " + attributes.getValue(Const.XML_QUALITY) + " Error:" + e.getMessage()); } } String sID = attributes.getValue(idIndex).intern(); /* * UPGRADE test : if first element we check has the right ID, we avoid wasting time checking * others item one. If is is an upgrade, we force the check.We always check id in debug mode. */ String sRightID = sID; if (needCheckID) { sRightID = FileManager.createID(sItemName, dParent).intern(); if (sRightID == sID) { needCheckID = UpgradeManager.isUpgradeDetected() || SessionService.isTestMode(); } else { Log.debug("** Wrong file Id, upgraded: " + sItemName); hmWrongRightFileID.put(sID, sRightID); } } org.jajuk.base.File file = FileManager.getInstance().registerFile(sRightID, sItemName, dParent, track, lSize, lQuality); file.populateProperties(attributes); } /** * Handle directories. DOCUMENT_ME * * @param attributes DOCUMENT_ME * @param idIndex DOCUMENT_ME */ private void handleDirectories(Attributes attributes, int idIndex) { Directory dParent = null; // dParent = null; String sParentID = attributes.getValue(Const.XML_DIRECTORY_PARENT).intern(); // UPGRADE if ((hmWrongRightDirectoryID.size() > 0) && (hmWrongRightDirectoryID.containsKey(sParentID))) { sParentID = hmWrongRightDirectoryID.get(sParentID); } // We use intern() here for performances if (sParentID != "-1") { // Parent directory should be already referenced // because of order conservation dParent = DirectoryManager.getInstance().getDirectoryByID(sParentID); // check parent directory exists if (dParent == null) { return; } } String sDeviceID = attributes.getValue(Const.XML_DEVICE).intern(); // take upgraded device ID if needed if ((hmWrongRightDeviceID.size() > 0) && (hmWrongRightDeviceID.containsKey(sDeviceID))) { sDeviceID = hmWrongRightDeviceID.get(sDeviceID); } Device device = DeviceManager.getInstance().getDeviceByID(sDeviceID); if (device == null) { // check device exists return; } String sItemName = attributes.getValue(Const.XML_NAME); String sID = attributes.getValue(idIndex).intern(); // UPGRADE test String sRightID = sID; if (needCheckID) { sRightID = DirectoryManager.createID(sItemName, device, dParent).intern(); if (sRightID == sID) { needCheckID = UpgradeManager.isUpgradeDetected() || SessionService.isTestMode(); } else { Log.debug("** Wrong directory Id, upgraded: " + sItemName); hmWrongRightDirectoryID.put(sID, sRightID); } } Directory directory = DirectoryManager.getInstance().registerDirectory(sRightID, sItemName, dParent, device); directory.populateProperties(attributes); // also remember top-level directories at the device if (dParent == null) { device.addDirectory(directory); } } /** * Handle tracks. DOCUMENT_ME * * @param attributes DOCUMENT_ME * @param idIndex DOCUMENT_ME * * @throws ParseException the parse exception */ private void handleTracks(Attributes attributes, int idIndex) throws ParseException { String sID = attributes.getValue(idIndex).intern(); String sTrackName = attributes.getValue(Const.XML_TRACK_NAME); // album String sAlbumID = attributes.getValue(Const.XML_TRACK_ALBUM).intern(); if ((hmWrongRightAlbumID.size() > 0) && (hmWrongRightAlbumID.containsKey(sAlbumID))) { sAlbumID = hmWrongRightAlbumID.get(sAlbumID); } Album album = AlbumManager.getInstance().getAlbumByID(sAlbumID); // Genre String sGenreID = attributes.getValue(Const.XML_TRACK_GENRE).intern(); if ((hmWrongRightGenreID.size() > 0) && (hmWrongRightGenreID.containsKey(sGenreID))) { sGenreID = hmWrongRightGenreID.get(sGenreID); } Genre genre = GenreManager.getInstance().getGenreByID(sGenreID); // Year String sYearID = attributes.getValue(Const.XML_TRACK_YEAR).intern(); Year year = YearManager.getInstance().getYearByID(sYearID); // For jajuk < 1.4 if (year == null) { year = YearManager.getInstance().registerYear(sYearID, sYearID); } // Artist String sArtistID = attributes.getValue(Const.XML_TRACK_ARTIST).intern(); if ((hmWrongRightArtistID.size() > 0) && (hmWrongRightArtistID.containsKey(sArtistID))) { sArtistID = hmWrongRightArtistID.get(sArtistID); } Artist artist = ArtistManager.getInstance().getArtistByID(sArtistID); // Album-artist (not a constructor level property) String sAlbumArtist = attributes.getValue(Const.XML_ALBUM_ARTIST); if (StringUtils.isNotBlank(sAlbumArtist)) { sAlbumArtist = sAlbumArtist.intern(); } if ((hmWrongRightAlbumArtistID.size() > 0) && (hmWrongRightAlbumArtistID.containsKey(sAlbumArtist))) { sAlbumArtist = hmWrongRightAlbumArtistID.get(sAlbumArtist); } // Note that when upgrading from jajuk < 1.9, album artists field is alway null, call on the // next line always return null AlbumArtist albumArtist = AlbumArtistManager.getInstance().getAlbumArtistByID(sAlbumArtist); if (albumArtist == null) { // we force album artist to this default, a deep scan will be required to get actual values albumArtist = AlbumArtistManager.getInstance().registerAlbumArtist(Const.UNKNOWN_ARTIST); } // Length long length = UtilString.fastLongParser(attributes.getValue(Const.XML_TRACK_LENGTH)); // Type String typeID = attributes.getValue(Const.XML_TYPE).intern(); if (needCheckConversions) { if (CONVERSION.containsKey(typeID)) { typeID = CONVERSION.get(typeID); } else { needCheckConversions = false; } } Type type = TypeManager.getInstance().getTypeByID(typeID); // more checkups if (album == null || artist == null) { return; } if (genre == null || type == null) { return; } // Idem for order long lOrder = 0l; try { lOrder = UtilString.fastLongParser(attributes.getValue(Const.XML_TRACK_ORDER)); } catch (Exception e) { if (Log.isDebugEnabled()) { // wrong format Log.debug(Messages.getString("Error.137") + ":" + sTrackName); // wrong } } // Idem for disc number long lDiscNumber = 0l; if (attributes.getValue(Const.XML_TRACK_DISC_NUMBER) != null) { try { lDiscNumber = UtilString.fastLongParser(attributes.getValue(Const.XML_TRACK_DISC_NUMBER)); } catch (Exception e) { if (Log.isDebugEnabled()) { // wrong format Log.debug(Messages.getString("Error.137") + ":" + sTrackName); } } } // UPGRADE test String sRightID = sID; if (needCheckID) { sRightID = TrackManager.createID(sTrackName, album, genre, artist, length, year, lOrder, type, lDiscNumber).intern(); if (sRightID == sID) { needCheckID = UpgradeManager.isUpgradeDetected() || SessionService.isTestMode(); } else { Log.debug("** Wrong Track Id, upgraded: " + sTrackName); hmWrongRightTrackID.put(sID, sRightID); } } Track track = TrackManager.getInstance().registerTrack(sRightID, sTrackName, album, genre, artist, length, year, lOrder, type, lDiscNumber); TrackManager.getInstance().changeTrackRate(track, UtilString.fastLongParser(attributes.getValue(Const.XML_TRACK_RATE))); track.setHits(UtilString.fastLongParser(attributes.getValue(Const.XML_TRACK_HITS))); // only set discovery date if it is available in the file if (attributes.getValue(Const.XML_TRACK_DISCOVERY_DATE) != null) { // Date format should be OK Date dAdditionDate = ADDITION_FORMATTER.parse(attributes .getValue(Const.XML_TRACK_DISCOVERY_DATE)); track.setDiscoveryDate(dAdditionDate); } String sComment = attributes.getValue(Const.XML_TRACK_COMMENT); if (sComment == null) { sComment = ""; } track.setComment(sComment.intern()); track.setAlbumArtist(albumArtist); track.populateProperties(attributes); } /** * Handle albums. DOCUMENT_ME * * @param attributes DOCUMENT_ME * @param idIndex DOCUMENT_ME */ private void handleAlbums(Attributes attributes, int idIndex) { String sID = attributes.getValue(idIndex).intern(); String sItemName = attributes.getValue(Const.XML_NAME).intern(); String sAttributeAlbumArtist = attributes.getValue(Const.XML_ALBUM_ARTIST); if (sAttributeAlbumArtist != null) { sAttributeAlbumArtist = sAttributeAlbumArtist.intern(); } long lItemDiscID = 0; String sAttributeDiskId = attributes.getValue(Const.XML_ALBUM_DISC_ID); if (sAttributeDiskId != null) { lItemDiscID = Long.parseLong(sAttributeDiskId); } // UPGRADE test String sRightID = sID; if (needCheckID) { sRightID = AlbumManager.createID(sItemName, lItemDiscID).intern(); if (sRightID == sID) { needCheckID = UpgradeManager.isUpgradeDetected() || SessionService.isTestMode(); } else { Log.debug("** Wrong album Id, upgraded: " + sItemName); hmWrongRightAlbumID.put(sID, sRightID); } } Album album = AlbumManager.getInstance().registerAlbum(sRightID, sItemName, lItemDiscID); if (album != null) { album.populateProperties(attributes); } } /** * Handle artists. DOCUMENT_ME * * @param attributes DOCUMENT_ME * @param idIndex DOCUMENT_ME */ private void handleArtists(Attributes attributes, int idIndex) { String sID = attributes.getValue(idIndex).intern(); String sItemName = attributes.getValue(Const.XML_NAME).intern(); // UPGRADE test String sRightID = sID; if (needCheckID) { sRightID = ItemManager.createID(sItemName).intern(); if (sRightID == sID) { needCheckID = UpgradeManager.isUpgradeDetected() || SessionService.isTestMode(); } else { Log.debug("** Wrong artist Id, upgraded: " + sItemName); hmWrongRightArtistID.put(sID, sRightID); } } Artist artist = ArtistManager.getInstance().registerArtist(sRightID, sItemName); if (artist != null) { artist.populateProperties(attributes); } } /** * Handle genres. DOCUMENT_ME * * @param attributes DOCUMENT_ME * @param idIndex DOCUMENT_ME */ private void handleGenres(Attributes attributes, int idIndex) { String sID = attributes.getValue(idIndex).intern(); String sItemName = attributes.getValue(Const.XML_NAME).intern(); // UPGRADE test String sRightID = sID; if (needCheckID) { sRightID = ItemManager.createID(sItemName).intern(); if (sRightID == sID) { needCheckID = UpgradeManager.isUpgradeDetected() || SessionService.isTestMode(); } else { Log.debug("** Wrong genre Id, upgraded: " + sItemName); hmWrongRightGenreID.put(sID, sRightID); } } Genre genre = GenreManager.getInstance().registerGenre(sRightID, sItemName); if (genre != null) { genre.populateProperties(attributes); } } /** * Handle playlist files. DOCUMENT_ME * * @param attributes DOCUMENT_ME * @param idIndex DOCUMENT_ME */ private void handlePlaylistFiles(Attributes attributes, int idIndex) { String sParentID = attributes.getValue(Const.XML_DIRECTORY).intern(); // UPGRADE check parent ID is right if ((hmWrongRightDirectoryID.size() > 0) && // replace wrong by right ID (hmWrongRightDirectoryID.containsKey(sParentID))) { sParentID = hmWrongRightDirectoryID.get(sParentID); } Directory dParent = DirectoryManager.getInstance().getDirectoryByID(sParentID); if (dParent == null) { // check directory is exists return; } String sID = attributes.getValue(idIndex).intern(); String sItemName = attributes.getValue(Const.XML_NAME); // UPGRADE test String sRightID = sID; if (needCheckID) { sRightID = PlaylistManager.createID(sItemName, dParent).intern(); if (sRightID == sID) { needCheckID = UpgradeManager.isUpgradeDetected() || SessionService.isTestMode(); } else { Log.debug("** Wrong playlist Id, upgraded: " + sItemName); hmWrongRightPlaylistFileID.put(sID, sRightID); } } Playlist plf = PlaylistManager.getInstance().registerPlaylistFile(sRightID, sItemName, dParent); if (plf != null) { plf.populateProperties(attributes); } } /** * Handle devices. DOCUMENT_ME * * @param attributes DOCUMENT_ME * @param idIndex DOCUMENT_ME */ private void handleDevices(Attributes attributes, int idIndex) { String sID = attributes.getValue(idIndex).intern(); String sItemName = attributes.getValue(Const.XML_NAME); long lType = UtilString.fastLongParser(attributes.getValue(Const.XML_TYPE)); // UPGRADE test String sRightID = sID; if (needCheckID) { sRightID = ItemManager.createID(sItemName).intern(); if (sRightID == sID) { needCheckID = UpgradeManager.isUpgradeDetected() || SessionService.isTestMode(); } else { Log.debug("** Wrong device Id, upgraded: " + sItemName); hmWrongRightDeviceID.put(sID, sRightID); } } String sURL = attributes.getValue(Const.XML_URL); Device device = DeviceManager.getInstance().registerDevice(sRightID, sItemName, lType, sURL); if (device != null) { device.populateProperties(attributes); } } /** * Handle years. DOCUMENT_ME * * @param attributes DOCUMENT_ME * @param idIndex DOCUMENT_ME */ private void handleYears(Attributes attributes, int idIndex) { String sID = attributes.getValue(idIndex).intern(); String sItemName = attributes.getValue(Const.XML_NAME).intern(); Year year = YearManager.getInstance().registerYear(sID, sItemName); if (year != null) { year.populateProperties(attributes); } } /** * Handle album artists. * * @param attributes DOCUMENT_ME * @param idIndex DOCUMENT_ME */ private void handleAlbumArtists(Attributes attributes, int idIndex) { String sID = attributes.getValue(idIndex).intern(); String sItemName = attributes.getValue(Const.XML_NAME).intern(); AlbumArtist albumArtist = AlbumArtistManager.getInstance().registerAlbumArtist(sID, sItemName); if (albumArtist != null) { albumArtist.populateProperties(attributes); } } /** * Gets the hm wrong right file id. * * @return list of wrong file id (used by history) */ public Map getHmWrongRightFileID() { return hmWrongRightFileID; } /** * Gets the wrong right album i ds. * * @return the wrong right album i ds */ public Map getWrongRightAlbumIDs() { return this.hmWrongRightAlbumID; } } jajuk-1.9.6.orig/src/main/java/org/jajuk/base/AlbumArtist.java0000644000175000017500000000412611720500104024012 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.base; import javax.swing.ImageIcon; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; /** * An Album-Artist *
    * Logical item. *

    * Album artist objects are not widely used in jajuk (mainly in tracks tree view), * so we leverage the Artist and ArtistManager classes to limit complexity and * code duplication. The drawback is the need for casts from Artist to AlbumArtist. *

    */ public class AlbumArtist extends Artist { /** * Builds an album-artist. * * @param sId album-artist guid * @param sName album-artist string */ AlbumArtist(String sId, String sName) { super(sId, sName); } /* * (non-Javadoc) * * @see org.jajuk.base.Item#getIdentifier() */ @Override public String getLabel() { return XML_ALBUM_ARTIST; } /** * Get item description. * * @return the desc */ @Override public String getDesc() { return Messages.getString("Item_AlbumArtist") + " : " + getName2(); } /* * (non-Javadoc) * * @see org.jajuk.base.Item#getIconRepresentation() */ @Override public ImageIcon getIconRepresentation() { return IconLoader.getIcon(JajukIcons.ARTIST); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/base/TrackManager.java0000644000175000017500000010661311720500104024126 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.base; import java.util.ArrayList; import java.util.Collections; import java.util.Date; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Locale; import java.util.Set; import org.jajuk.base.TrackComparator.TrackComparatorType; import org.jajuk.events.JajukEvent; import org.jajuk.events.JajukEvents; import org.jajuk.events.ObservationManager; import org.jajuk.services.players.QueueModel; import org.jajuk.services.tags.Tag; import org.jajuk.util.Conf; import org.jajuk.util.Const; import org.jajuk.util.MD5Processor; import org.jajuk.util.ReadOnlyIterator; import org.jajuk.util.UtilString; import org.jajuk.util.error.JajukException; import org.jajuk.util.error.NoneAccessibleFileException; import org.jajuk.util.log.Log; /** * Convenient class to manage Tracks. */ public final class TrackManager extends ItemManager { /** Self instance. */ private static TrackManager singleton = new TrackManager(); /** Autocommit flag for tags *. */ private volatile boolean bAutocommit = true; /** Set of tags to commit. */ private final Set tagsToCommit = new HashSet(10); /** * No constructor available, only static access. */ private TrackManager() { super(); // ---register properties--- // ID registerProperty(new PropertyMetaInformation(Const.XML_ID, false, true, false, false, false, String.class, null)); // Name registerProperty(new PropertyMetaInformation(Const.XML_NAME, false, true, true, true, false, String.class, null)); // Album registerProperty(new PropertyMetaInformation(Const.XML_ALBUM, false, true, true, true, true, String.class, null)); // Genre registerProperty(new PropertyMetaInformation(Const.XML_GENRE, false, true, true, true, true, String.class, null)); // Artist registerProperty(new PropertyMetaInformation(Const.XML_ARTIST, false, true, true, true, true, String.class, null)); // Album-artist registerProperty(new PropertyMetaInformation(Const.XML_ALBUM_ARTIST, false, false, true, true, true, String.class, null)); // Length registerProperty(new PropertyMetaInformation(Const.XML_TRACK_LENGTH, false, true, true, false, false, Long.class, null)); // Type registerProperty(new PropertyMetaInformation(Const.XML_TRACK_TYPE, false, true, true, false, false, Long.class, null)); // Year registerProperty(new PropertyMetaInformation(Const.XML_YEAR, false, true, true, true, true, Long.class, 0)); // Rate : this is a property computed from preference and total played time, // not editable registerProperty(new PropertyMetaInformation(Const.XML_TRACK_RATE, false, false, true, false, true, Long.class, 0)); // Files registerProperty(new PropertyMetaInformation(Const.XML_FILES, false, false, true, false, false, String.class, null)); // Hits registerProperty(new PropertyMetaInformation(Const.XML_TRACK_HITS, false, false, true, false, false, Long.class, 0)); // Addition date registerProperty(new PropertyMetaInformation(Const.XML_TRACK_DISCOVERY_DATE, false, false, true, false, true, Date.class, null)); // Comment registerProperty(new PropertyMetaInformation(Const.XML_TRACK_COMMENT, false, false, true, true, true, String.class, null)); // Track order registerProperty(new PropertyMetaInformation(Const.XML_TRACK_ORDER, false, true, true, true, false, Long.class, null)); // Track disc number registerProperty(new PropertyMetaInformation(Const.XML_TRACK_DISC_NUMBER, false, true, true, true, true, Long.class, null)); // Track preference factor. This is not editable because when changing // preference, others // actions must be done (updateRate() and we want user to use contextual // menus and commands instead of the properties wizard to set preference) registerProperty(new PropertyMetaInformation(Const.XML_TRACK_PREFERENCE, false, false, true, false, true, Long.class, 0l)); // Track total playtime registerProperty(new PropertyMetaInformation(Const.XML_TRACK_TOTAL_PLAYTIME, false, false, true, false, false, Long.class, 0l)); // Track ban status registerProperty(new PropertyMetaInformation(Const.XML_TRACK_BANNED, false, false, true, true, false, Boolean.class, false)); } /** * Gets the instance. * * @return singleton */ public static TrackManager getInstance() { return singleton; } /** * Register an Track. * * @param sName DOCUMENT_ME * @param album DOCUMENT_ME * @param genre DOCUMENT_ME * @param artist DOCUMENT_ME * @param length DOCUMENT_ME * @param year DOCUMENT_ME * @param lOrder DOCUMENT_ME * @param type DOCUMENT_ME * @param lDiscNumber DOCUMENT_ME * * @return the track */ public Track registerTrack(String sName, Album album, Genre genre, Artist artist, long length, Year year, long lOrder, Type type, long lDiscNumber) { String sId = createID(sName, album, genre, artist, length, year, lOrder, type, lDiscNumber); return registerTrack(sId, sName, album, genre, artist, length, year, lOrder, type, lDiscNumber); } /** * Return hashcode for a track. * * @param sName DOCUMENT_ME * @param album DOCUMENT_ME * @param genre DOCUMENT_ME * @param artist DOCUMENT_ME * @param length DOCUMENT_ME * @param year DOCUMENT_ME * @param lOrder DOCUMENT_ME * @param type DOCUMENT_ME * @param lDiscNumber DOCUMENT_ME * * @return the string */ protected static String createID(String sName, Album album, Genre genre, Artist artist, long length, Year year, long lOrder, Type type, long lDiscNumber) { StringBuilder sb = new StringBuilder(100); sb.append(genre.getID()).append(artist.getID()).append(album.getID()).append(sName) .append(year.getValue()).append(length).append(lOrder).append(type.getID()) .append(lDiscNumber); // distinguish tracks by type because we can't find best file // on different quality levels by format return MD5Processor.hash(sb.toString()); } /** * Register an Track with a known id. * * @param sName DOCUMENT_ME * @param sId DOCUMENT_ME * @param album DOCUMENT_ME * @param genre DOCUMENT_ME * @param artist DOCUMENT_ME * @param length DOCUMENT_ME * @param year DOCUMENT_ME * @param lOrder DOCUMENT_ME * @param type DOCUMENT_ME * @param lDiscNumber DOCUMENT_ME * * @return the track */ public Track registerTrack(String sId, String sName, Album album, Genre genre, Artist artist, long length, Year year, long lOrder, Type type, long lDiscNumber) { lock.writeLock().lock(); try { // We absolutely need to return the same track if already registrated to // avoid duplicates and properties lost Track track = getTrackByID(sId); if (track != null) { return track; } track = new Track(sId, sName, album, genre, artist, length, year, lOrder, type, lDiscNumber); registerItem(track); // For performances, add the track to the album cache List cache = track.getAlbum().getTracksCache(); synchronized (cache) { cache.add(track); } return track; } finally { lock.writeLock().unlock(); } } /** * Commit tags. * * @throws JajukException the jajuk exception * * @throw an exception if a tag cannot be commited */ public void commit() throws JajukException { lock.writeLock().lock(); try { // Iterate over a shallow copy to avoid concurrent issues (note also that // several threads can commit at the same time). We synchronize the copy and // we drop tags to commit. List toCommit = null; synchronized (tagsToCommit) { toCommit = new ArrayList(tagsToCommit); tagsToCommit.clear(); } for (Tag tag : toCommit) { try { tag.commit(); } catch (Exception e) { Log.error(e); try { // If actual tag commit fails, we have to undo changes made in memory for current track // The best solution for this complex issue is to force a deep refresh of the directory // and to clear the tag cache to force tags reload Tag.clearCache(); Directory dir = null; File file = FileManager.getInstance().getFileByPath(tag.getFio().getAbsolutePath()); if (file != null) { dir = file.getDirectory(); } dir.refresh(true); // refresh views ObservationManager.notify(new JajukEvent(JajukEvents.DEVICE_REFRESH)); } catch (Exception e2) { Log.error(e2); } throw new JajukException(104, e); } } // Clear the tag cache after a transaction to // avoid memory leaks Tag.clearCache(); } finally { lock.writeLock().unlock(); } } /** * Change a track album. * * @param filter files we want to deal with * @param track DOCUMENT_ME * @param sNewAlbum DOCUMENT_ME * * @return new track * * @throws JajukException the jajuk exception */ public Track changeTrackAlbum(Track track, String sNewAlbum, Set filter) throws JajukException { lock.writeLock().lock(); try { // check there is actually a change if (track.getAlbum().getName2().equals(sNewAlbum)) { return track; } List alReady = null; // check if files are accessible alReady = track.getReadyFiles(filter); if (alReady.size() == 0) { throw new NoneAccessibleFileException(10); } // change tag in files for (File file : alReady) { Tag tag = Tag.getTagForFio(file.getFIO(), false); tag.setAlbumName(sNewAlbum); if (bAutocommit) { tag.commit(); } else { tagsToCommit.add(tag); } } // Remove the track from the old album List cache = track.getAlbum().getTracksCache(); synchronized (cache) { cache.remove(track); } // if current track album name is changed, notify it if (QueueModel.getPlayingFile() != null && QueueModel.getPlayingFile().getTrack().getAlbum().equals(track.getAlbum())) { ObservationManager.notify(new JajukEvent(JajukEvents.ALBUM_CHANGED)); } // register the new album Album newAlbum = AlbumManager.getInstance().registerAlbum(sNewAlbum, track.getAlbum().getDiscID()); Track newTrack = registerTrack(track.getName(), newAlbum, track.getGenre(), track.getArtist(), track.getDuration(), track.getYear(), track.getOrder(), track.getType(), track.getDiscNumber()); postChange(track, newTrack, filter); // remove this album if no more references AlbumManager.getInstance().cleanOrphanTracks(track.getAlbum()); return newTrack; } finally { lock.writeLock().unlock(); } } /** * Change a track artist. * * @param filter files we want to deal with * @param track DOCUMENT_ME * @param sNewArtist DOCUMENT_ME * * @return new track * * @throws JajukException the jajuk exception */ public Track changeTrackArtist(Track track, String sNewArtist, Set filter) throws JajukException { lock.writeLock().lock(); try { // check there is actually a change if (track.getArtist().getName2().equals(sNewArtist)) { return track; } List alReady = null; // check if files are accessible alReady = track.getReadyFiles(filter); if (alReady.size() == 0) { throw new NoneAccessibleFileException(10); } // change tag in files for (final File file : alReady) { final Tag tag = Tag.getTagForFio(file.getFIO(), false); tag.setArtistName(sNewArtist); if (bAutocommit) { tag.commit(); } else { tagsToCommit.add(tag); } } // Remove the track from the old album List cache = track.getAlbum().getTracksCache(); synchronized (cache) { cache.remove(track); } // if current track artist name is changed, notify it if (QueueModel.getPlayingFile() != null && QueueModel.getPlayingFile().getTrack().getArtist().equals(track.getArtist())) { ObservationManager.notify(new JajukEvent(JajukEvents.ARTIST_CHANGED)); } // register the new item Artist newArtist = ArtistManager.getInstance().registerArtist(sNewArtist); Track newTrack = registerTrack(track.getName(), track.getAlbum(), track.getGenre(), newArtist, track.getDuration(), track.getYear(), track.getOrder(), track.getType(), track.getDiscNumber()); postChange(track, newTrack, filter); // remove this item if no more references ArtistManager.getInstance().cleanOrphanTracks(track.getArtist()); return newTrack; } finally { lock.writeLock().unlock(); } } /** * Change a track genre. * * @param filter files we want to deal with * @param track DOCUMENT_ME * @param sNewGenre DOCUMENT_ME * * @return new track * * @throws JajukException the jajuk exception */ public Track changeTrackGenre(Track track, String sNewGenre, Set filter) throws JajukException { lock.writeLock().lock(); try { // check there is actually a change if (track.getGenre().getName2().equals(sNewGenre)) { return track; } List alReady = null; // check if files are accessible alReady = track.getReadyFiles(filter); if (alReady.size() == 0) { throw new NoneAccessibleFileException(10); } // change tag in files for (final File file : alReady) { Tag tag = Tag.getTagForFio(file.getFIO(), false); tag.setGenreName(sNewGenre); if (bAutocommit) { tag.commit(); } else { tagsToCommit.add(tag); } } // Remove the track from the old album List cache = track.getAlbum().getTracksCache(); synchronized (cache) { cache.remove(track); } // register the new item Genre newGenre = GenreManager.getInstance().registerGenre(sNewGenre); Track newTrack = registerTrack(track.getName(), track.getAlbum(), newGenre, track.getArtist(), track.getDuration(), track.getYear(), track.getOrder(), track.getType(), track.getDiscNumber()); postChange(track, newTrack, filter); // remove this item if no more references GenreManager.getInstance().cleanOrphanTracks(track.getGenre()); return newTrack; } finally { lock.writeLock().unlock(); } } /** * Change a track year. * * @param filter files we want to deal with * @param track DOCUMENT_ME * @param newItem DOCUMENT_ME * * @return new track or null if wrong format * * @throws JajukException the jajuk exception */ public Track changeTrackYear(Track track, String newItem, Set filter) throws JajukException { lock.writeLock().lock(); try { // check there is actually a change if (track.getYear().getName().equals(newItem)) { return track; } long lNewItem = UtilString.fastLongParser(newItem); if (lNewItem < 0 || lNewItem > 10000) { throw new JajukException(137); } List alReady = null; // check if files are accessible alReady = track.getReadyFiles(filter); if (alReady.size() == 0) { throw new NoneAccessibleFileException(10); } // change tag in files for (final File file : alReady) { Tag tag = Tag.getTagForFio(file.getFIO(), false); tag.setYear(newItem); if (bAutocommit) { tag.commit(); } else { tagsToCommit.add(tag); } } // Remove the track from the old album List cache = track.getAlbum().getTracksCache(); synchronized (cache) { cache.remove(track); } // Register new item Year newYear = YearManager.getInstance().registerYear(newItem); Track newTrack = registerTrack(track.getName(), track.getAlbum(), track.getGenre(), track.getArtist(), track.getDuration(), newYear, track.getOrder(), track.getType(), track.getDiscNumber()); postChange(track, newTrack, filter); return newTrack; } finally { lock.writeLock().unlock(); } } /** * Change a track comment. * * @param filter files we want to deal with * @param track DOCUMENT_ME * @param sNewItem DOCUMENT_ME * * @return new track or null if wronf format * * @throws JajukException the jajuk exception */ public Track changeTrackComment(Track track, String sNewItem, Set filter) throws JajukException { lock.writeLock().lock(); try { // check there is actually a change if (track.getComment().equals(sNewItem)) { return track; } List alReady = null; // check if files are accessible alReady = track.getReadyFiles(filter); if (alReady.size() == 0) { throw new NoneAccessibleFileException(10); } // change tag in files for (File file : alReady) { Tag tag = Tag.getTagForFio(file.getFIO(), false); tag.setComment(sNewItem); if (bAutocommit) { tag.commit(); // Force files resorting to ensure the sorting consistency // Do it here only because the sorting is a long operation already done // by the TrackManager.commit() method caller (PropertiesDialog for ie). // When called for a table change for ie, the sorting must be done for // each change. FileManager.getInstance().forceSorting(); } else { tagsToCommit.add(tag); } } track.setComment(sNewItem); return track; } finally { lock.writeLock().unlock(); } } /** * Change a track rate. * * @param track DOCUMENT_ME * @param lNew DOCUMENT_ME * * @return new track or null if wrong format */ public Track changeTrackRate(Track track, long lNew) { lock.writeLock().lock(); try { // check there is actually a change if (track.getRate() == lNew) { return track; } // check format, rate in [0,100] if (lNew < 0 || lNew > 100) { track.setRate(0l); Log.error(137); } else { track.setRate(lNew); } return track; } finally { lock.writeLock().unlock(); } } /** * Change a track order. * * @param filter files we want to deal with * @param track DOCUMENT_ME * @param lNewOrder DOCUMENT_ME * * @return new track or null if wrong format * * @throws JajukException the jajuk exception */ public Track changeTrackOrder(Track track, long lNewOrder, Set filter) throws JajukException { lock.writeLock().lock(); try { // check there is actually a change if (track.getOrder() == lNewOrder) { return track; } // check format if (lNewOrder < 0) { throw new JajukException(137); } List alReady = null; // check if files are accessible alReady = track.getReadyFiles(filter); if (alReady.size() == 0) { throw new NoneAccessibleFileException(10); } // change tag in files for (File file : alReady) { Tag tag = Tag.getTagForFio(file.getFIO(), false); tag.setOrder(lNewOrder); if (bAutocommit) { tag.commit(); } else { tagsToCommit.add(tag); } } // Remove the track from the old album List cache = track.getAlbum().getTracksCache(); synchronized (cache) { cache.remove(track); } Track newTrack = registerTrack(track.getName(), track.getAlbum(), track.getGenre(), track.getArtist(), track.getDuration(), track.getYear(), lNewOrder, track.getType(), track.getDiscNumber()); postChange(track, newTrack, filter); return newTrack; } finally { lock.writeLock().unlock(); } } /** * Change a track name. * * @param filter files we want to deal with * @param track DOCUMENT_ME * @param sNewItem DOCUMENT_ME * * @return new track * * @throws JajukException the jajuk exception */ public Track changeTrackName(Track track, String sNewItem, Set filter) throws JajukException { lock.writeLock().lock(); try { // check there is actually a change if (track.getName().equals(sNewItem)) { return track; } List alReady = null; // check if files are accessible alReady = track.getReadyFiles(filter); if (alReady.size() == 0) { throw new NoneAccessibleFileException(10); } // change tag in files for (File file : alReady) { Tag tag = Tag.getTagForFio(file.getFIO(), false); tag.setTrackName(sNewItem); if (bAutocommit) { tag.commit(); } else { tagsToCommit.add(tag); } } // Remove old track from the album List cache = track.getAlbum().getTracksCache(); synchronized (cache) { cache.remove(track); } Track newTrack = registerTrack(sNewItem, track.getAlbum(), track.getGenre(), track.getArtist(), track.getDuration(), track.getYear(), track.getOrder(), track.getType(), track.getDiscNumber()); postChange(track, newTrack, filter); // if current track name is changed, notify it if (QueueModel.getPlayingFile() != null && QueueModel.getPlayingFile().getTrack().equals(track)) { ObservationManager.notify(new JajukEvent(JajukEvents.TRACK_CHANGED)); } return newTrack; } finally { lock.writeLock().unlock(); } } /** * Change track album artist. * * @param track DOCUMENT_ME * @param filter DOCUMENT_ME * @param sNewItem DOCUMENT_ME * * @return the item * * @throws JajukException the jajuk exception */ public Item changeTrackAlbumArtist(Track track, String sNewItem, Set filter) throws JajukException { lock.writeLock().lock(); try { // check there is actually a change if (track.getAlbumArtist() != null && track.getAlbumArtist().getName2().equals(sNewItem)) { return track; } List alReady = null; // check if files are accessible alReady = track.getReadyFiles(filter); if (alReady.size() == 0) { throw new NoneAccessibleFileException(10); } // change tag in files for (File file : alReady) { Tag tag = Tag.getTagForFio(file.getFIO(), false); tag.setAlbumArtist(sNewItem); if (bAutocommit) { tag.commit(); // Force files resorting to ensure the sorting consistency // Do it here only because the sorting is a long operation already done // by the TrackManager.commit() method caller (PropertiesDialog for ie). // When called for a table change for ie, the sorting must be done for // each change. FileManager.getInstance().forceSorting(); } else { tagsToCommit.add(tag); } } // register the new item AlbumArtist newAlbumArtist = AlbumArtistManager.getInstance().registerAlbumArtist(sNewItem); track.setAlbumArtist(newAlbumArtist); return track; } finally { lock.writeLock().unlock(); } } /** * Change track disc number. * * @param track DOCUMENT_ME * @param filter DOCUMENT_ME * @param lNewDiscNumber DOCUMENT_ME * * @return the item * * @throws JajukException the jajuk exception */ public Item changeTrackDiscNumber(Track track, long lNewDiscNumber, Set filter) throws JajukException { lock.writeLock().lock(); try { // check there is actually a change if (track.getDiscNumber() == lNewDiscNumber) { return track; } // check format if (lNewDiscNumber < 0) { throw new JajukException(137); } List alReady = null; // check if files are accessible alReady = track.getReadyFiles(filter); if (alReady.size() == 0) { throw new NoneAccessibleFileException(10); } // change tag in files for (File file : alReady) { Tag tag = Tag.getTagForFio(file.getFIO(), false); tag.setDiscNumber(lNewDiscNumber); if (bAutocommit) { tag.commit(); } else { tagsToCommit.add(tag); } } // Remove the track from the old album List cache = track.getAlbum().getTracksCache(); synchronized (cache) { cache.remove(track); } // if current track album name is changed, notify it if (QueueModel.getPlayingFile() != null && QueueModel.getPlayingFile().getTrack().getAlbum().equals(track.getAlbum())) { ObservationManager.notify(new JajukEvent(JajukEvents.ALBUM_CHANGED)); } Track newTrack = registerTrack(track.getName(), track.getAlbum(), track.getGenre(), track.getArtist(), track.getDuration(), track.getYear(), track.getDiscNumber(), track.getType(), lNewDiscNumber); postChange(track, newTrack, filter); return newTrack; } finally { lock.writeLock().unlock(); } } /** * Update files references. * * @param oldTrack DOCUMENT_ME * @param newTrack DOCUMENT_ME * @param filter DOCUMENT_ME */ private void updateFilesReferences(Track oldTrack, Track newTrack, Set filter) { lock.writeLock().lock(); try { // Reset files property before adding new files for (File file : oldTrack.getReadyFiles(filter)) { file.setTrack(newTrack);// set new track for the changed file } } finally { lock.writeLock().unlock(); } } /** * Post change. DOCUMENT_ME * * @param track DOCUMENT_ME * @param newTrack DOCUMENT_ME * @param filter DOCUMENT_ME */ private void postChange(Track track, Track newTrack, Set filter) { lock.writeLock().lock(); try { // re apply old properties from old item newTrack.cloneProperties(track); // update files references updateFilesReferences(track, newTrack, filter); if (track.getFiles().size() == 0) { // normal case: old track has no // more associated // tracks, remove it removeItem(track);// remove old track } } finally { lock.writeLock().unlock(); } } /** * Perform a track cleanup : delete useless items. */ @Override public void cleanup() { // No need to lock or synchronize, getTracks() is a shallow copy of tracks for (Track track : getTracks()) { if (track.getFiles().size() == 0) { // no associated file removeItem(track); continue; } // Cleanup all files no more attached to a track for (File file : track.getFiles()) { if (FileManager.getInstance().getFileByID(file.getID()) == null) { FileManager.getInstance().removeFile(file); } } if (track.getFiles().size() == 0) { // the track don't map // anymore to any physical item, just remove it removeItem(track); } } } /** * Remove a file mapping from a track. * * @param file DOCUMENT_ME */ public void removeFile(File file) { Track track = file.getTrack(); lock.writeLock().lock(); try { // Remove file reference track.removeFile(file); // If the track contained a single file, drop it if (track.getFiles().size() == 0) { // the track don't map // anymore to any physical item, just remove it removeItem(track); } } finally { lock.writeLock().unlock(); } } /* * (non-Javadoc) * * @see org.jajuk.base.ItemManager#getIdentifier() */ @Override public String getLabel() { return Const.XML_TRACKS; } /** * Get ordered tracks list associated with this item *

    * This is a shallow copy only *

    * . * * @param item DOCUMENT_ME * @param sorted Whether the output should be sorted on it (actually applied on * artists,years and genres because others items are already sorted) * * @return the associated tracks */ public List getAssociatedTracks(Item item, boolean sorted) { List items = new ArrayList(1); items.add(item); return getAssociatedTracks(items, sorted); } /** * Get ordered tracks list associated with a list of items (of the same type) *

    * This is a shallow copy only *

    * . * * @param sorted Whether the output should be sorted on it (actually applied on * artists,years and genres because others items are already sorted) * @param items DOCUMENT_ME * * @return the associated tracks */ @SuppressWarnings("unchecked") public List getAssociatedTracks(List items, boolean sorted) { if (items == null || items.size() == 0) { return new ArrayList(0); } List out = new ArrayList(items.size()); if (items.get(0) instanceof Album) { // check the album cache for (Item item : items) { List tracks = ((Album) item).getTracksCache(); synchronized (tracks) { if (tracks.size() > 0) { out.addAll(tracks); } } } // cache is not sorted correct for albums with more than 1 disc if (sorted) { // sort Tracks Collections.sort(out, new TrackComparator(TrackComparatorType.ORDER)); } } // If the item is itself a track, simply return it else if (items.get(0) instanceof Track) { for (Item item : items) { out.add((Track) item); } if (sorted) { Collections.sort(out, new TrackComparator(TrackComparatorType.ALBUM)); } } else if (items.get(0) instanceof File) { for (Item item : items) { out.add(((File) item).getTrack()); } if (sorted) { Collections.sort(out, new TrackComparator(TrackComparatorType.ALBUM)); } } else if (items.get(0) instanceof Directory) { for (Item item : items) { Directory dir = (Directory) item; for (File file : dir.getFilesRecursively()) { Track track = file.getTrack(); // Caution, do not add dups if (!out.contains(track)) { out.add(file.getTrack()); } } } if (sorted) { Collections.sort(out, new TrackComparator(TrackComparatorType.ORDER)); } } else if (items.get(0) instanceof Playlist) { for (Item item : items) { Playlist pl = (Playlist) item; List files; try { files = pl.getFiles(); } catch (JajukException e) { Log.warn("Cannot parse playlist : " + pl.getAbsolutePath()); return out; } for (File file : files) { Track track = file.getTrack(); // Caution, do not add dups if (!out.contains(track)) { out.add(file.getTrack()); } } } if (sorted) { Collections.sort(out, new TrackComparator(TrackComparatorType.ALBUM)); } } else if (items.get(0) instanceof Artist) { Iterator tracks = (Iterator) getItemsIterator(); while (tracks.hasNext()) { Track track = (Track) tracks.next(); if (items.contains(track.getArtist())) { out.add(track); } // Sort by album if (sorted) { Collections.sort(out, new TrackComparator(TrackComparatorType.ARTIST_ALBUM)); } } return out; } else if (items.get(0) instanceof Genre) { Iterator tracks = (Iterator) getItemsIterator(); while (tracks.hasNext()) { Track track = (Track) tracks.next(); if (items.contains(track.getGenre())) { out.add(track); } // Sort by genre if (sorted) { Collections.sort(out, new TrackComparator(TrackComparatorType.GENRE_ARTIST_ALBUM)); } } } else if (items.get(0) instanceof Year) { Iterator tracks = (Iterator) getItemsIterator(); while (tracks.hasNext()) { Track track = (Track) tracks.next(); if (items.contains(track.getYear())) { out.add(track); } // Sort by year if (sorted) { Collections.sort(out, new TrackComparator(TrackComparatorType.YEAR_ALBUM)); } } } return out; } /** * Gets the comparator. * * @return the comparator */ public TrackComparator getComparator() { return new TrackComparator( TrackComparatorType.values()[Conf.getInt(Const.CONF_LOGICAL_TREE_SORT_ORDER)]); } /** * Gets the track by id. * * @param sID Item ID * * @return item */ public Track getTrackByID(String sID) { return (Track) getItemByID(sID); } /** * Gets the tracks. * * @return ordered tracks list */ @SuppressWarnings("unchecked") public List getTracks() { return (List) getItems(); } /** * Gets the tracks iterator. * * @return tracks iterator */ @SuppressWarnings("unchecked") public ReadOnlyIterator getTracksIterator() { return new ReadOnlyIterator((Iterator) getItemsIterator()); } /** * Perform a search in all files names with given criteria. * * @param criteria DOCUMENT_ME * * @return an ordered list of available files */ public List search(String criteria) { lock.readLock().lock(); try { boolean hide = Conf.getBoolean(Const.CONF_OPTIONS_HIDE_UNMOUNTED); List resu = new ArrayList(); ReadOnlyIterator tracks = getTracksIterator(); while (tracks.hasNext()) { Track track = tracks.next(); File playable = track.getBestFile(hide); if (playable != null) { String sResu = track.getAny(); if (sResu.toLowerCase(Locale.getDefault()).indexOf( criteria.toLowerCase(Locale.getDefault())) != -1) { resu.add(new SearchResult(playable, playable.toStringSearch())); } } } return resu; } finally { lock.readLock().unlock(); } } /** * Checks if is autocommit. * * @return autocommit behavior for tags */ public boolean isAutocommit() { return this.bAutocommit; } /** * Set autocommit behavior for tags. * * @param autocommit should tag changes be commited at each change or on demand ? */ public void setAutocommit(boolean autocommit) { this.bAutocommit = autocommit; } } jajuk-1.9.6.orig/src/main/java/org/jajuk/base/SmartPlaylist.java0000644000175000017500000000364011720500104024373 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.base; /** * A smart playlist a special "logical" playlist built automatically by Jajuk *

    Example of smart playlists includes : bestof, novelties, new and bookmarks

    * This class is only a wrapper to Playlist object. It brings a better way to identify * smart playlist from regular ones and it provides a public constructor required * because we can't store this kind of playlist in the collection itself so * we call the constructor directly without performing any item registration. */ public class SmartPlaylist extends Playlist { /** * The Constructor. * * @param sId DOCUMENT_ME * @param sName DOCUMENT_ME * @param dParentDirectory DOCUMENT_ME */ public SmartPlaylist(String sId, String sName, Directory dParentDirectory) { super(sId, sName, dParentDirectory); } /** * The Constructor. * * @param type DOCUMENT_ME * @param sId DOCUMENT_ME * @param sName DOCUMENT_ME * @param dParentDirectory DOCUMENT_ME */ public SmartPlaylist(Type type, String sId, String sName, Directory dParentDirectory) { super(type, sId, sName, dParentDirectory); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/base/Playlist.java0000644000175000017500000006625211720500104023374 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.base; import com.google.common.io.Files; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.Collections; import java.util.Date; import java.util.Iterator; import java.util.List; import javax.swing.ImageIcon; import javax.swing.JFileChooser; import javax.swing.JOptionPane; import javax.swing.SwingUtilities; import org.jajuk.services.bookmark.Bookmarks; import org.jajuk.services.players.QueueModel; import org.jajuk.services.players.StackItem; import org.jajuk.ui.widgets.JajukFileChooser; import org.jajuk.ui.windows.JajukMainWindow; import org.jajuk.util.Conf; import org.jajuk.util.Const; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukFileFilter; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; import org.jajuk.util.UtilFeatures; import org.jajuk.util.UtilString; import org.jajuk.util.UtilSystem; import org.jajuk.util.error.JajukException; import org.jajuk.util.filters.PlaylistFilter; import org.jajuk.util.log.Log; /** * A playlist *

    * Physical item * * * TODO: refactoring items for this class: * - split up the code into separate implementations for the different types * - create a base abstract playlist class that is used in the various places and * have separate implementations for each of the types to separate the code better. */ public class Playlist extends PhysicalItem implements Comparable { /** * playlist type. */ public enum Type { /** DOCUMENT_ME. */ NORMAL, /** DOCUMENT_ME. */ QUEUE, /** DOCUMENT_ME. */ NEW, /** DOCUMENT_ME. */ BOOKMARK, /** DOCUMENT_ME. */ BESTOF, /** DOCUMENT_ME. */ NOVELTIES } /** Playlist parent directory. */ private Directory dParentDirectory; /** Files list, singleton. */ private List alFiles; /** Associated physical file. */ private java.io.File fio; /** Playlist type. */ private final Type type; /** pre-calculated absolute path for perf. */ private String sAbs = null; /** Contains files outside device flag. */ private boolean bContainsExtFiles = false; /** Whether we ask for device mounting if required. */ private boolean askForMounting = true; /** * playlist constructor. * * @param type playlist type * @param sId DOCUMENT_ME * @param sName DOCUMENT_ME * @param dParentDirectory DOCUMENT_ME */ Playlist(final Type type, final String sId, final String sName, final Directory dParentDirectory) { super(sId, sName); this.dParentDirectory = dParentDirectory; setProperty(Const.XML_DIRECTORY, dParentDirectory == null ? "-1" : dParentDirectory.getID()); this.type = type; } /** * playlist constructor. * * @param sId DOCUMENT_ME * @param sName DOCUMENT_ME * @param dParentDirectory DOCUMENT_ME */ public Playlist(final String sId, final String sName, final Directory dParentDirectory) { this(Playlist.Type.NORMAL, sId, sName, dParentDirectory); } /** * Add a file to this playlist. * * @param file DOCUMENT_ME * * @throws JajukException the jajuk exception */ public void addFile(final File file) throws JajukException { final List al = getFiles(); final int index = al.size(); addFile(index, file); } /** * Gets the type. * * @return Returns the Type. */ public Type getType() { return type; } /** * Add a file to this playlist. * * @param index DOCUMENT_ME * @param file DOCUMENT_ME * * @throws JajukException the jajuk exception */ public void addFile(final int index, final File file) throws JajukException { if (type == Playlist.Type.BOOKMARK) { Bookmarks.getInstance().addFile(index, file); } else if (type == Type.QUEUE) { final StackItem item = new StackItem(file); item.setUserLaunch(false); // set repeat mode : if previous item is repeated, repeat as // well if (index > 0) { final StackItem itemPrevious = QueueModel.getItem(index - 1); if ((itemPrevious != null) && itemPrevious.isRepeat()) { item.setRepeat(true); } else { item.setRepeat(false); } // insert this track in the fifo QueueModel.insert(item, index); } else { // start immediately playing QueueModel.push(item, false); } // we don't need to adjust the alFiles here because for playlist type QUEUE // the contents is taken directly from the QueueModel in case of } else { getFiles().add(index, file); } } /** * Add some files to this playlist. * * @param alFilesToAdd : List of Files * @param position DOCUMENT_ME */ public void addFiles(final List alFilesToAdd, int position) { try { int offset = 0; for (File file : alFilesToAdd) { addFile(position + offset, file); offset++; } } catch (final Exception e) { Log.error(e); } } /** * Clear playlist. */ public void clear() { if (type == Type.BOOKMARK) { // bookmark // playlist Bookmarks.getInstance().clear(); } else if (getType() == Type.QUEUE) { QueueModel.clear(); } else { if (alFiles == null) { return; } alFiles.clear(); } } /** * Update playlist on disk if needed. * * @throws JajukException the jajuk exception */ public void commit() throws JajukException { java.io.File temp = null; try { /* * Due to bug #1046, we use a temporary file In some special cases (reproduced under Linux, * JRE SUN 1.6.0_04, CIFS mount, 777 rights file), probably due to a JRE bug, files cannot be * opened (FileNotFound? Exception, permission denied) and the file is voided (0 bytes) and is * closed (checked with lsof). */ temp = new java.io.File(getAbsolutePath() + '~'); BufferedWriter bw = new BufferedWriter(new FileWriter(temp)); try { bw.write(Const.PLAYLIST_NOTE); bw.newLine(); final Iterator it = getFiles().iterator(); while (it.hasNext()) { final File file = it.next(); if (file.getFIO().getParent().equals(getFIO().getParent())) { bw.write(file.getName()); } else { bw.write(file.getAbsolutePath()); } bw.newLine(); } bw.flush(); } finally { bw.close(); } } catch (final IOException e) { throw new JajukException(28, getName(), e); } // Now move the temp file to final one if everything seems ok moveTempPlaylistFile(temp); } /** * Move temp playlist file. * * @param temp DOCUMENT_ME * * @throws JajukException the jajuk exception */ private void moveTempPlaylistFile(java.io.File temp) throws JajukException { if (temp.exists() && temp.length() > 0) { try { UtilSystem.copy(temp, getFIO()); UtilSystem.deleteFile(temp); } catch (final Exception e1) { throw new JajukException(28, getName(), e1); } } else { try { // Try to remove the temp file UtilSystem.deleteFile(temp); } catch (final Exception e1) { Log.error(e1); } throw new JajukException(28, getName()); } } /** * Alphabetical comparator used to display ordered lists of playlists *

    * Sort ignoring cases *

    . * * @param o DOCUMENT_ME * * @return comparison result */ @Override public int compareTo(final Playlist o) { // not equal if other is null if (o == null) { return -1; } // Perf: leave if items are equals if (o.equals(this)) { return 0; } final Playlist otherPlaylistFile = o; final String abs = getName() + (getDirectory() != null ? getAbsolutePath() : ""); final String sOtherAbs = otherPlaylistFile.getName() + (otherPlaylistFile.getDirectory() != null ? otherPlaylistFile.getAbsolutePath() : ""); // We must be consistent with equals, see // http://java.sun.com/javase/6/docs/api/java/lang/Comparable.html int comp = abs.compareToIgnoreCase(sOtherAbs); if (comp == 0) { return abs.compareTo(sOtherAbs); } else { return comp; } } /** * Contains ext files. * * @return whether this playlist contains files located out of known devices */ public boolean containsExtFiles() { return bContainsExtFiles; } /** * Down a track in the playlist. * * @param index DOCUMENT_ME */ public void down(final int index) { if (type == Type.BOOKMARK) { Bookmarks.getInstance().down(index); } else if (type == Type.QUEUE) { QueueModel.down(index); } else if ((alFiles != null) && (index < alFiles.size() - 1)) { // the last track cannot go deeper // n+1 file becomes nth file Collections.swap(alFiles, index, index + 1); } } /** * Equal method to check two playlists are identical. * * @param otherPlaylistFile DOCUMENT_ME * * @return true, if equals */ @Override public boolean equals(final Object otherPlaylistFile) { // also catches null by definition if (!(otherPlaylistFile instanceof Playlist)) { return false; } final Playlist plfOther = (Playlist) otherPlaylistFile; return getID().equals(plfOther.getID()) && plfOther.getType() == type; } /** * Force playlist re-read (don't use the cache). Can be used after a forced * refresh * * @throws JajukException the jajuk exception */ public void forceRefresh() throws JajukException { alFiles = load(); // populate playlist } /** * Return absolute file path name. * * @return String */ public String getAbsolutePath() { if (type == Type.NORMAL) { if (sAbs != null) { return sAbs; } final Directory dCurrent = getDirectory(); final StringBuilder sbOut = new StringBuilder(dCurrent.getDevice().getUrl()).append( dCurrent.getRelativePath()).append(java.io.File.separatorChar).append(getName()); sAbs = sbOut.toString(); } else { // smart playlist path depends on the user selected from the save as // file chooser and has been set using the setFio() method just before // that don't use "getFIO()" here, as otherwise we can cause an endless // loop as getFIO() calls this method as well if (fio == null) { return ""; } sAbs = fio.getAbsolutePath(); } return sAbs; } /** * Get item description. * * @return the desc */ @Override public String getDesc() { return Messages.getString("Item_Playlist_File") + " : " + getName(); } /** * Gets the directory. * * @return the directory */ public Directory getDirectory() { return dParentDirectory; } /** * Gets the files. * * @return Returns the list of files this playlist maps to * * @throws JajukException if the playlist cannot be mounted or cannot be read */ public List getFiles() throws JajukException { // if normal playlist, propose to mount device if unmounted if ((getType() == Type.NORMAL) && !isReady()) { // We already asked but user didn't want to mount the device -> leave if (!askForMounting) { throw new JajukException(141, getFIO().getAbsolutePath()); } // No more ask for mounting askForMounting = false; final String sMessage = Messages.getString("Error.025") + " (" + getDirectory().getDevice().getName() + Messages.getString("FIFO.4"); final int i = Messages.getChoice(sMessage, JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.INFORMATION_MESSAGE); if (i == JOptionPane.YES_OPTION) { try { // mount the device is required getDirectory().getDevice().mount(true); } catch (final Exception e) { throw new JajukException(141, getFIO().getAbsolutePath(), e); } } else { throw new JajukException(141, getFIO().getAbsolutePath()); } } if ((type == Type.NORMAL) && (alFiles == null)) { // normal playlist, test if list is null for performances (avoid // reading the m3u file twice) if (getFIO().exists() && getFIO().canRead()) { // check device is mounted alFiles = load(); // populate playlist } else { // error accessing playlist throw new JajukException(9, getFIO().getAbsolutePath()); } } else if (type.equals(Type.BESTOF)) { alFiles = FileManager.getInstance().getBestOfFiles(); } else if (type.equals(Type.NOVELTIES)) { alFiles = FileManager.getInstance().getGlobalNoveltiesPlaylist( Conf.getBoolean(Const.CONF_OPTIONS_HIDE_UNMOUNTED)); } else if (type.equals(Type.BOOKMARK)) { alFiles = Bookmarks.getInstance().getFiles(); } else if (type.equals(Type.QUEUE)) { List items = QueueModel.getQueue(); List files = new ArrayList(items.size()); for (StackItem si : items) { files.add(si.getFile()); } alFiles = files; } else if (type.equals(Type.NEW) && alFiles == null) { alFiles = new ArrayList(10); } return alFiles; } /** * Gets the fio. * * @return Returns the fio. */ public java.io.File getFIO() { if (fio == null) { fio = new java.io.File(getAbsolutePath()); } return fio; } /* * (non-Javadoc) * * @see org.jajuk.base.Item#getHumanValue(java.lang.String) */ @Override public String getHumanValue(final String sKey) { if (Const.XML_DIRECTORY.equals(sKey)) { final Directory dParent = DirectoryManager.getInstance().getDirectoryByID( getStringValue(sKey)); return dParent.getFio().getAbsolutePath(); } else {// default return super.getHumanValue(sKey); } } /* * (non-Javadoc) * * @see org.jajuk.base.Item#getIconRepresentation() */ @Override public ImageIcon getIconRepresentation() { return IconLoader.getIcon(JajukIcons.PLAYLIST_FILE); } /* * (non-Javadoc) * * @see org.jajuk.base.Item#getIdentifier() */ @Override public final String getLabel() { return Const.XML_PLAYLIST_FILE; } /** * Return true the file can be accessed right now. * * @return true the file can be accessed right now */ public boolean isReady() { if (getDirectory() != null && getDirectory().getDevice() != null && getDirectory().getDevice().isMounted()) { return true; } return false; } /** * Parse a playlist. * * @return the list< file> * * @throws JajukException the jajuk exception */ public List load() throws JajukException { final List files = new ArrayList(10); try { BufferedReader br = new BufferedReader(new FileReader(getFIO())); try { String sLine = null; boolean bUnknownDevicesMessage = false; while ((sLine = br.readLine()) != null) { if (sLine.length() == 0) { // void line continue; } // replace '\' by '/' sLine = sLine.replace('\\', '/'); // deal with url beginning by "./something" if (sLine.startsWith("./")) { sLine = sLine.substring(1, sLine.length()); } // comment if (sLine.charAt(0) == '#') { continue; } else { java.io.File fio = null; final StringBuilder sbFileDir = new StringBuilder(getDirectory().getAbsolutePath()); // Add a trailing / at the end of the url if required if (sLine.charAt(0) != '/') { sbFileDir.append("/"); } // take a look relatively to playlist directory to check if the file exists fio = new java.io.File(sbFileDir.append(sLine).toString()); String fioAbsPath = fio.getAbsolutePath(); // Check for file existence in jajuk collection using Guava Files.simplyPath // Don't use File.getAbsolutePath() because its result can contain ./ or ../ // Don't use File.getCanonicalPath() because it resolves symlinks under unix. File jajukFile = FileManager.getInstance().getFileByPath(Files.simplifyPath(fioAbsPath)); if (jajukFile == null) { // check if this file is known in collection fio = new java.io.File(sLine); // check if given url is not absolute jajukFile = FileManager.getInstance().getFileByPath(fio.getAbsolutePath()); if (jajukFile == null) { // no more ? leave bUnknownDevicesMessage = true; continue; } } files.add(jajukFile); } } // display a warning message if the playlist contains unknown // items if (bUnknownDevicesMessage) { bContainsExtFiles = true; } } finally { br.close(); } } catch (final IOException e) { Log.error(17, "{{" + getName() + "}}", e); throw new JajukException(17, (getDirectory() != null && getFIO() != null ? getFIO() .getAbsolutePath() : ""), e); } return files; } /** * Play a playlist. * * @throws JajukException the jajuk exception */ public void play() throws JajukException { alFiles = getFiles(); if ((alFiles == null) || (alFiles.size() == 0)) { Messages.showErrorMessage(18); } else { QueueModel.push(UtilFeatures.createStackItems(UtilFeatures.applyPlayOption(alFiles), Conf .getBoolean(Const.CONF_STATE_REPEAT_ALL), true), false); } } /** * Remove a track from the playlist. * * @param index DOCUMENT_ME */ public void remove(final int index) { if (type == Type.BOOKMARK) { Bookmarks.getInstance().remove(index); } else if (type == Type.QUEUE) { QueueModel.remove(index, index); } else { alFiles.remove(index); } } /** * Replace a file inside a playlist. * * @param fOld DOCUMENT_ME * @param fNew DOCUMENT_ME * * @throws JajukException the jajuk exception */ public void replaceFile(final File fOld, final File fNew) throws JajukException { if (type == Type.BOOKMARK) { List files = Bookmarks.getInstance().getFiles(); final Iterator it = files.iterator(); for (int i = 0; it.hasNext(); i++) { final File fileToTest = it.next(); if (fileToTest.equals(fOld)) { files.set(i, fNew); /* * this leads to ConcurrentModificationException: Bookmarks.getInstance().remove(i); * Bookmarks.getInstance().addFile(i, fNew); */ } } } else if (type == Type.QUEUE) { final Iterator it = QueueModel.getQueue().iterator(); for (int i = 0; it.hasNext(); i++) { final File fileToTest = it.next().getFile(); if (fileToTest.equals(fOld)) { QueueModel.remove(i, i); // just remove final List al = new ArrayList(1); al.add(new StackItem(fNew)); QueueModel.insert(al, i); } } } else { final Iterator it = alFiles.iterator(); for (int i = 0; it.hasNext(); i++) { final File fileToTest = it.next(); if (fileToTest.equals(fOld)) { alFiles.set(i, fNew); try { commit();// save changed playlist } catch (final JajukException e) { Log.error(e); } } } } } /** * Reset pre-calculated paths*. */ protected void reset() { sAbs = null; fio = null; } /** * Save as... the playlist * * @throws JajukException the jajuk exception * @throws InterruptedException the interrupted exception * @throws InvocationTargetException the invocation target exception */ public void saveAs() throws JajukException, InterruptedException, InvocationTargetException { FileChooserRunnable runnable = new FileChooserRunnable(); SwingUtilities.invokeLater(runnable); if (runnable.getException() != null) { throw runnable.getException(); } } /** * Sets the files. * * @param alFiles The alFiles to set. */ public void setFiles(final List alFiles) { this.alFiles = alFiles; } /** * Sets the fio. * * @param fio The fio to set. */ public void setFIO(final java.io.File fio) { this.fio = fio; } /** * Sets the parent directory. * * @param parentDirectory The dParentDirectory to set. */ protected void setParentDirectory(final Directory parentDirectory) { dParentDirectory = parentDirectory; setProperty(Const.XML_DIRECTORY, parentDirectory == null ? "-1" : parentDirectory.getID()); } /** * Return whether this item should be hidden with hide option. * * @return whether this item should be hidden with hide option */ public boolean shouldBeHidden() { if (getDirectory().getDevice().isMounted() || (!Conf.getBoolean(Const.CONF_OPTIONS_HIDE_UNMOUNTED))) { // option "only display mounted devices" return false; } return true; } /** * toString method. * * @return the string */ @Override public String toString() { if (dParentDirectory == null) { return "playlist[ID=" + getID() + " Name={{" + getName() + "}} " + " Dir=]"; } else { return "playlist[ID=" + getID() + " Name={{" + getName() + "}} " + " Dir=" + dParentDirectory.getID() + "]"; } } /** * Up a track in the playlist. * * @param index DOCUMENT_ME */ public void up(final int index) { if (type == Type.BOOKMARK) { Bookmarks.getInstance().up(index); } else if (type == Playlist.Type.QUEUE) { QueueModel.up(index); } else if ((alFiles != null) && (index > 0)) { // the first track // cannot go further // n-1 file becomes nth file Collections.swap(alFiles, index, index - 1); } } /** * Gets the playlist average rating. * * @return playlist average rating */ @Override public long getRate() { if (alFiles == null) { return 0; } float rate = 0f; int nb = 0; for (File file : alFiles) { rate += file.getTrack().getRate(); nb++; } return Math.round(rate / nb); } /** * Gets the hits. * * @return total nb of hits */ public long getHits() { if (alFiles == null) { return 0; } int hits = 0; for (File file : alFiles) { hits += file.getTrack().getHits(); } return hits; } /** * Return full playlist length in secs. * * @return the duration */ public long getDuration() { if (alFiles == null) { return 0; } long length = 0; for (File file : alFiles) { length += file.getTrack().getDuration(); } return length; } /** * Gets the nb of tracks. * * @return playlist nb of tracks */ public int getNbOfTracks() { if (alFiles == null) { return 0; } return alFiles.size(); } /** * Return true is the specified directory is an ancestor for this playlist. * * @param directory DOCUMENT_ME * * @return true, if checks for ancestor */ public boolean hasAncestor(Directory directory) { Directory dirTested = getDirectory(); while (true) { if (dirTested.equals(directory)) { return true; } else { dirTested = dirTested.getParentDirectory(); if (dirTested == null) { return false; } } } } /** * Small helper class to be able to run * the FileChoose inside the EDT thread of Swing. */ private final class FileChooserRunnable implements Runnable { // records if there are exceptions during doing the call /** DOCUMENT_ME. */ JajukException ex = null; /* * (non-Javadoc) * * @see java.lang.Runnable#run() */ @Override public void run() { try { final JajukFileChooser jfchooser = new JajukFileChooser(new JajukFileFilter(PlaylistFilter .getInstance())); jfchooser.setDialogType(JFileChooser.SAVE_DIALOG); jfchooser.setAcceptDirectories(true); String sPlaylist = Const.DEFAULT_PLAYLIST_FILE; // computes new playlist alFiles = getFiles(); if (alFiles.size() > 0) { final File file = alFiles.get(0); if (getType() == Type.BESTOF) { sPlaylist = file.getDevice().getUrl() + java.io.File.separatorChar + Const.FILE_DEFAULT_BESTOF_PLAYLIST; } else if (getType() == Type.BOOKMARK) { sPlaylist = file.getDevice().getUrl() + java.io.File.separatorChar + Const.FILE_DEFAULT_BOOKMARKS_PLAYLIST; } else if (getType() == Type.NOVELTIES) { sPlaylist = file.getDevice().getUrl() + java.io.File.separatorChar + Const.FILE_DEFAULT_NOVELTIES_PLAYLIST; } else if (getType() == Type.QUEUE) { sPlaylist = file.getDevice().getUrl() + java.io.File.separatorChar + Const.FILE_DEFAULT_QUEUE_PLAYLIST + UtilString.getAdditionDateFormatter().format(new Date()); } else { sPlaylist = file.getDirectory().getAbsolutePath() + java.io.File.separatorChar + file.getTrack().getHumanValue(Const.XML_ALBUM); } } else { return; } jfchooser.setSelectedFile(new java.io.File(sPlaylist + "." + Const.EXT_PLAYLIST)); final int returnVal = jfchooser.showSaveDialog(JajukMainWindow.getInstance()); if (returnVal == JFileChooser.APPROVE_OPTION) { java.io.File file = jfchooser.getSelectedFile(); // add automatically the extension if required if (file.getAbsolutePath().endsWith(Const.EXT_PLAYLIST)) { file = new java.io.File(file.getAbsolutePath()); } else { file = new java.io.File(file.getAbsolutePath() + "." + Const.EXT_PLAYLIST); } // set new file path ( this playlist is a special playlist, just in // memory ) setFIO(file); commit(); // write it on the disk } } catch (JajukException e) { ex = e; } } /** * Returns any exception caught during running the file chooser. * * @return null if no exception was caught, the actual exception otherwise. */ public JajukException getException() { return ex; } } } jajuk-1.9.6.orig/src/main/java/org/jajuk/base/Type.java0000644000175000017500000001077511720500104022513 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.base; import java.util.List; import javax.swing.ImageIcon; import org.jajuk.services.players.IPlayerImpl; import org.jajuk.services.tags.ITagImpl; import org.jajuk.util.Const; import org.jajuk.util.Messages; import org.jajuk.util.log.Log; /** * Music type. */ public class Type extends PhysicalItem implements Comparable { /** Type extension ex:mp3,ogg. */ private final String sExtension; /** Player impl. */ private final Class cTagImpl; /** Player class. */ private final Class cPlayerImpl; /** * Constructor. * * @param sId type id if given * @param sName type name * @param sExtension type file extension (.mp3...) * @param cPlayerImpl DOCUMENT_ME * @param cTagImpl DOCUMENT_ME */ Type(final String sId, final String sName, final String sExtension, final Class cPlayerImpl, final Class cTagImpl) { super(sId, sName); this.cPlayerImpl = cPlayerImpl; this.sExtension = sExtension; setProperty(Const.XML_TYPE_EXTENSION, sExtension); setProperty(Const.XML_TYPE_PLAYER_IMPL, cPlayerImpl); this.cTagImpl = cTagImpl; if (cTagImpl != null) { // can be null for playlists setProperty(Const.XML_TYPE_TAG_IMPL, cTagImpl); } } /** * Alphabetical comparator used to display ordered lists. * * @param other item to be compared * * @return comparison result */ @Override public int compareTo(final Type other) { return toString().compareTo(other.toString()); } /** * Get item description. * * @return the desc */ @Override public String getDesc() { return Messages.getString("Type") + " : " + getName(); } /** * Gets the extension. * * @return the extension */ public String getExtension() { return sExtension; } /* * (non-Javadoc) * * @see org.jajuk.base.Item#getIconRepresentation() */ @Override public ImageIcon getIconRepresentation() { return null; } /* * (non-Javadoc) * * @see org.jajuk.base.Item#getIdentifier() */ @Override public final String getLabel() { return XML_TYPE; } /** * Gets the player class. * * @return Player class for this type */ public Class getPlayerClass() { return cPlayerImpl; } /** * Gets the tagger class. * * @return Tagger class for this type */ public Class getTaggerClass() { return cTagImpl; } /** * Gets the tag impl. * * @return Returns the tagImpl. */ public ITagImpl getTagImpl() { try { if (cTagImpl == null) { return null; } return cTagImpl.newInstance(); } catch (final Exception e) { Log.error(e); } return null; } /** * toString method. * * @return the string */ @Override public String toString() { return "Type[ID=" + getID() + " Name=" + getName() + " ; Extension=" + sExtension + "]"; } /** * Return an array of supported file extensions for given types. * * @param types the types * * @return Return an array of supported file extensions */ public static String[] getExtensionsFromTypes(final List types) { String[] extensions = {}; if (types != null) { final int typesSize = types.size(); final Type[] typesArray = types.toArray(new Type[typesSize]); extensions = new String[typesSize]; for (int i = 0; i < typesSize; i++) { extensions[i] = typesArray[i].getExtension(); } } return extensions; } /** * Return whether this type is video. * * @return whether this type is video */ public boolean isVideo() { return Messages.getString(Const.TYPE_VIDEO).equals(getName()); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/base/DeviceManager.java0000644000175000017500000003517411720500104024264 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.base; import java.io.File; import java.util.ArrayList; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; import javax.swing.JOptionPane; import org.jajuk.events.JajukEvent; import org.jajuk.events.JajukEvents; import org.jajuk.events.ObservationManager; import org.jajuk.services.core.ExitService; import org.jajuk.services.players.QueueModel; import org.jajuk.util.Conf; import org.jajuk.util.Const; import org.jajuk.util.Messages; import org.jajuk.util.ReadOnlyIterator; import org.jajuk.util.UpgradeManager; import org.jajuk.util.UtilSystem; import org.jajuk.util.log.Log; /** * Convenient class to manage devices. */ public final class DeviceManager extends ItemManager { /** Supported device types names. */ private final List alDevicesTypes = new ArrayList(10); /** Self instance. */ private static DeviceManager singleton = new DeviceManager(); /** Date last global refresh. */ private long lDateLastGlobalRefresh = 0; /** List of deep-refresh devices after an upgrade. */ private final Set devicesDeepRefreshed = new HashSet(); /** DeviceTypes Identification strings Note: this needs to correspond with the constants in @see org.jajuk.base.Device !! */ public static final String[] DEVICE_TYPES = { "Device_type.directory", "Device_type.file_cd", "Device_type.network_drive", "Device_type.extdd", "Device_type.player" }; /** Auto-refresh thread. */ private final Thread tAutoRefresh = new Thread("Device Auto Refresh Thread") { @Override public void run() { while (!ExitService.isExiting()) { try { Thread.sleep(Const.AUTO_REFRESH_DELAY); refreshAllDevices(); } catch (Exception e) { Log.error(e); } } } }; /** DOCUMENT_ME. */ private volatile boolean bGlobalRefreshing = false; /** * No constructor available, only static access. */ private DeviceManager() { super(); // register properties // ID registerProperty(new PropertyMetaInformation(Const.XML_ID, false, true, false, false, false, String.class, null)); // Name registerProperty(new PropertyMetaInformation(Const.XML_NAME, false, true, true, false, false, String.class, null)); // Type registerProperty(new PropertyMetaInformation(Const.XML_TYPE, false, true, true, false, false, Long.class, null)); // URL registerProperty(new PropertyMetaInformation(Const.XML_URL, false, true, true, false, false, Long.class, null)); // Auto-mount registerProperty(new PropertyMetaInformation(Const.XML_DEVICE_AUTO_MOUNT, false, true, true, false, false, Boolean.class, null)); // Auto-refresh registerProperty(new PropertyMetaInformation(Const.XML_DEVICE_AUTO_REFRESH, false, true, true, false, false, Double.class, 0d)); // Expand registerProperty(new PropertyMetaInformation(Const.XML_EXPANDED, false, false, false, false, true, Boolean.class, false)); // Synchro source registerProperty(new PropertyMetaInformation(Const.XML_DEVICE_SYNCHRO_SOURCE, false, false, true, false, false, String.class, null)); // Synchro mode registerProperty(new PropertyMetaInformation(Const.XML_DEVICE_SYNCHRO_MODE, false, false, true, false, false, String.class, null)); } /** * Start auto refresh thread. * DOCUMENT_ME */ public void startAutoRefreshThread() { if (!tAutoRefresh.isAlive()) { tAutoRefresh.setPriority(Thread.MIN_PRIORITY); tAutoRefresh.start(); } } /** * Gets the instance. * * @return singleton */ public static DeviceManager getInstance() { return singleton; } /** * Register a device. * * @param sName DOCUMENT_ME * @param lDeviceType DOCUMENT_ME * @param sUrl DOCUMENT_ME * * @return device */ public Device registerDevice(String sName, long lDeviceType, String sUrl) { String sId = createID(sName); return registerDevice(sId, sName, lDeviceType, sUrl); } /** * Register a device with a known id. * * @param sId DOCUMENT_ME * @param sName DOCUMENT_ME * @param lDeviceType DOCUMENT_ME * @param sUrl DOCUMENT_ME * @return device */ public Device registerDevice(String sId, String sName, long lDeviceType, String sUrl) { Device device = getDeviceByID(sId); if (device != null) { return device; } device = new Device(sId, sName); device.setProperty(Const.XML_TYPE, lDeviceType); device.setUrl(sUrl); registerItem(device); return device; } /** * Check none device already has this name or is a parent directory. * * @param sName DOCUMENT_ME * @param iDeviceType DOCUMENT_ME * @param sUrl DOCUMENT_ME * @param bNew DOCUMENT_ME * * @return 0:ok or error code */ public int checkDeviceAvailablity(String sName, int iDeviceType, String sUrl, boolean bNew) { // don't check if it is a CD as all CDs may use the same mount point if (iDeviceType == Device.TYPE_CD) { return 0; } // check name and path for (Device deviceToCheck : DeviceManager.getInstance().getDevices()) { // If we check an existing device unchanged, just leave if (!bNew && sUrl.equals(deviceToCheck.getUrl())) { continue; } // check for a new device with an existing name if (bNew && (sName.equalsIgnoreCase(deviceToCheck.getName()))) { return 19; } String sUrlChecked = deviceToCheck.getUrl(); // check it is not a sub-directory of an existing device File fNew = new File(sUrl); File fChecked = new File(sUrlChecked); if (fNew.equals(fChecked) || UtilSystem.isDescendant(fNew, fChecked) || UtilSystem.isAncestor(fNew, fChecked)) { return 29; } } // check availability if (iDeviceType != Device.TYPE_EXT_DD) { // not a remote device, TBI for remote // test directory is available File file = new File(sUrl); // check if the url exists and is readable if (!file.exists() || !file.canRead()) { return 143; } } return 0; } /** * Register a device type. * * @param sDeviceType DOCUMENT_ME */ public void registerDeviceType(String sDeviceType) { alDevicesTypes.add(sDeviceType); } /** * Gets the device types number. * * @return number of registered devices */ public int getDeviceTypesNumber() { return alDevicesTypes.size(); } /** * Return first device found being parent of the provided path. * * @param path DOCUMENT_ME * * @return first device found being parent of the provided path */ public Device getDeviceByPath(File path) { for (Device device : getDevices()) { if (UtilSystem.isAncestor(device.getFio(), path)) { return device; } } return null; } /** * Gets the device types. * * @return Device types iteration */ public Iterator getDeviceTypes() { return alDevicesTypes.iterator(); } /** * Get a device type name for a given index. * * @param index DOCUMENT_ME * * @return device name for a given index */ public String getDeviceType(long index) { return alDevicesTypes.get((int) index); } /** * Remove a device. * * @param device DOCUMENT_ME */ public void removeDevice(Device device) { lock.writeLock().lock(); try { // show confirmation message if required if (Conf.getBoolean(Const.CONF_CONFIRMATIONS_REMOVE_DEVICE)) { int iResu = Messages.getChoice(Messages.getString("Confirmation_remove_device"), JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE); if (iResu != JOptionPane.YES_OPTION) { return; } } // if device is refreshing or synchronizing, just leave if (device.isSynchronizing() || device.isRefreshing()) { Messages.showErrorMessage(13); return; } // check if device can be unmounted if (!QueueModel.canUnmount(device)) { Messages.showErrorMessage(121); return; } // if it is mounted, try to unmount it if (device.isMounted()) { try { device.unmount(); } catch (Exception e) { Messages.showErrorMessage(13); return; } } removeItem(device); DirectoryManager.getInstance().cleanDevice(device.getID()); FileManager.getInstance().cleanDevice(device.getID()); PlaylistManager.getInstance().cleanDevice(device.getID()); // Clean the collection up org.jajuk.base.Collection.cleanupLogical(); // remove synchronization if another device was synchronized // with this device for (Device deviceToCheck : getDevices()) { if (deviceToCheck.containsProperty(Const.XML_DEVICE_SYNCHRO_SOURCE)) { String sSyncSource = deviceToCheck.getStringValue(Const.XML_DEVICE_SYNCHRO_SOURCE); if (sSyncSource.equals(device.getID())) { deviceToCheck.removeProperty(Const.XML_DEVICE_SYNCHRO_SOURCE); } } } // Force suggestion view refresh to avoid showing removed albums ObservationManager.notify(new JajukEvent(JajukEvents.SUGGESTIONS_REFRESH)); } finally { lock.writeLock().unlock(); } } /** * Checks if is any device refreshing. * * @return whether any device is currently refreshing */ public boolean isAnyDeviceRefreshing() { boolean bOut = false; for (Device device : DeviceManager.getInstance().getDevices()) { if (device.isRefreshing()) { bOut = true; break; } } return bOut; } /** * Clean all devices. */ public void cleanAllDevices() { lock.writeLock().lock(); try { for (Device device : getDevices()) { // Do not auto-refresh CD as several CD may share the same mount // point if (device.getType() == Device.TYPE_CD) { continue; } FileManager.getInstance().cleanDevice(device.getName()); DirectoryManager.getInstance().cleanDevice(device.getName()); PlaylistManager.getInstance().cleanDevice(device.getName()); } clear(); } finally { lock.writeLock().unlock(); } } /* * (non-Javadoc) * * @see org.jajuk.base.ItemManager#getIdentifier() */ @Override public String getLabel() { return Const.XML_DEVICES; } /** * Gets the date last global refresh. * * @return the date last global refresh */ public long getDateLastGlobalRefresh() { return lDateLastGlobalRefresh; } /** * Refresh of all devices with auto-refresh enabled (used in automatic mode) * Must be the shortest possible. */ public void refreshAllDevices() { try { // check thread is not already refreshing if (bGlobalRefreshing) { return; } bGlobalRefreshing = true; lDateLastGlobalRefresh = System.currentTimeMillis(); boolean bNeedUIRefresh = false; for (Device device : getDevices()) { // Do not auto-refresh CD as several CD may share the same mount // point if (device.getType() == Device.TYPE_CD) { continue; } double frequency = 60000 * device.getDoubleValue(Const.XML_DEVICE_AUTO_REFRESH); // check if this device needs auto-refresh if (frequency == 0d || device.getDateLastRefresh() > (System.currentTimeMillis() - frequency)) { continue; } /* * Check if devices contains files, otherwise it is not mounted we have to check this * because of the automatic cleaner thread musn't remove all references */ File[] files = new File(device.getUrl()).listFiles(); if (!device.isRefreshing() && files != null && files.length > 0) { /* * Check if this device should be deep-refresh after an upgrade */ boolean bNeedDeepAfterUpgrade = UpgradeManager.isMajorMigration() && !devicesDeepRefreshed.contains(device); if (bNeedDeepAfterUpgrade) { // Store this device to avoid duplicate deep refreshes devicesDeepRefreshed.add(device); } // cleanup device bNeedUIRefresh = bNeedUIRefresh | device.cleanRemovedFiles(null); // refresh the device (deep refresh forced after an upgrade) bNeedUIRefresh = bNeedUIRefresh | device.refreshCommand(bNeedDeepAfterUpgrade, false, null); // UI refresh if required if (bNeedUIRefresh) { /* * Notify views to refresh once the device is refreshed, do not wait all devices * refreshing as it may be tool long */ ObservationManager.notify(new JajukEvent(JajukEvents.DEVICE_REFRESH)); } } } // Display end of refresh message with stats } catch (Exception e) { Log.error(e); } finally { bGlobalRefreshing = false; } } /** * Gets the device by id. * * @param sID Item ID * * @return Element */ public Device getDeviceByID(String sID) { return (Device) getItemByID(sID); } /** * Gets the device by name. * * @param sName device name * * @return device by given name or null if no match */ public Device getDeviceByName(String sName) { for (Device device : getDevices()) { if (device.getName().equals(sName)) { return device; } } return null; } /** * Gets the devices. * * @return ordered devices list */ @SuppressWarnings("unchecked") public List getDevices() { return (List) getItems(); } /** * Gets the devices iterator. * * @return devices iterator */ @SuppressWarnings("unchecked") public ReadOnlyIterator getDevicesIterator() { return new ReadOnlyIterator((Iterator) getItemsIterator()); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/base/Track.java0000644000175000017500000004514311720500104022633 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.base; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.Date; import java.util.List; import java.util.Set; import javax.swing.ImageIcon; import org.apache.commons.lang.StringUtils; import org.jajuk.services.core.RatingManager; import org.jajuk.util.Conf; import org.jajuk.util.Const; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; import org.jajuk.util.UtilString; import org.jajuk.util.log.Log; /** * A track *

    * Logical item. */ public class Track extends LogicalItem implements Comparable { /** Track album*. */ private final Album album; /** Track genre. */ private final Genre genre; /** Track artist. */ private final Artist artist; /** Track length. */ private final long length; /** Track year. */ private final Year year; /** Track type. */ private final Type type; /** Album Artist. */ private AlbumArtist albumArtist; /** Track associated files. */ private final List alFiles = new ArrayList(1); /** * Track constructor. * * @param sId DOCUMENT_ME * @param sName DOCUMENT_ME * @param album DOCUMENT_ME * @param genre DOCUMENT_ME * @param artist DOCUMENT_ME * @param length DOCUMENT_ME * @param year DOCUMENT_ME * @param lOrder DOCUMENT_ME * @param type DOCUMENT_ME * @param lDiscNumber DOCUMENT_ME */ Track(String sId, String sName, Album album, Genre genre, Artist artist, long length, Year year, long lOrder, Type type, long lDiscNumber) { super(sId, sName); // album this.album = album; setProperty(Const.XML_ALBUM, album.getID()); // genre this.genre = genre; setProperty(Const.XML_GENRE, genre.getID()); // artist this.artist = artist; setProperty(Const.XML_ARTIST, artist.getID()); // Length this.length = length; setProperty(Const.XML_TRACK_LENGTH, length); // Type this.type = type; setProperty(Const.XML_TYPE, type.getID()); // Year this.year = year; setProperty(Const.XML_YEAR, year.getID()); // Order setProperty(Const.XML_TRACK_ORDER, lOrder); // Order setProperty(Const.XML_TRACK_DISC_NUMBER, lDiscNumber); // Rate setProperty(Const.XML_TRACK_RATE, 0l); // Hits setProperty(Const.XML_TRACK_HITS, 0l); } /** * toString method. * * @return the string */ @Override public String toString() { StringBuilder sOut = new StringBuilder(); sOut.append("Track[ID=").append(getID()).append(" Name={{").append(getName()).append("}} ") .append(album).append(" ").append(genre).append(" ").append(artist).append(" Length=") .append(length).append(" Year=").append(year.getValue()).append(" Rate=").append(getRate()) .append(" ").append(type).append(" Hits=").append(getHits()).append(" Addition date=") .append(getDiscoveryDate()).append(" Comment=").append(getComment()).append(" order=") .append(getOrder()).append(" Nb of files=").append(alFiles.size()).append(" Album artist=") .append(getAlbumArtist()).append(" Disc=").append(getDiscNumber()).append("]"); for (int i = 0; i < alFiles.size(); i++) { sOut.append('\n').append(alFiles.get(i).toString()); } return sOut.toString(); } /** * Gets the any. * * @return a human representation of all concatenated properties */ @Override public String getAny() { // rebuild any StringBuilder sb = new StringBuilder(100); sb.append(super.getAny()); // add all track-based properties // Add all files absolute paths for (File file : getFiles()) { sb.append(file.getAbsolutePath()); } return sb.toString(); } /** * Default comparator for tracks, not used for sorting (use TrackComparator * for that) But only for storage. * * @param otherTrack DOCUMENT_ME * * @return comparison result */ @Override public int compareTo(Track otherTrack) { return getID().compareTo(otherTrack.getID()); } /** * Gets the album. * * @return the album */ public Album getAlbum() { return album; } /** * Gets a copy of associated files. * * @return a copy of associated files */ public List getFiles() { return new ArrayList(alFiles); } /** * Remove specified file from associated files. * * @param file : the file to remove */ public void removeFile(File file) { alFiles.remove(file); } /** * Gets the files. * * @param filter files we want to deal with, null means no filter * * @return all associated files */ public List getFiles(Set filter) { List out = new ArrayList(alFiles.size()); for (File file : alFiles) { if (filter == null || filter.contains(file)) { out.add(file); } } return out; } /** * Gets the ready files. * * @return ready files */ public List getReadyFiles() { List alReadyFiles = new ArrayList(alFiles.size()); for (File file : alFiles) { if (file.isReady()) { alReadyFiles.add(file); } } return alReadyFiles; } /** * Gets the ready files. * * @param filter files we want to deal with, null means no filter * * @return ready files with given filter */ public List getReadyFiles(Set filter) { List alReadyFiles = new ArrayList(alFiles.size()); for (File file : alFiles) { if (file.isReady() && (filter == null || filter.contains(file))) { alReadyFiles.add(file); } } return alReadyFiles; } /** * Get sum size of all files this track map to. * * @return the total size */ public long getTotalSize() { long l = 0; for (final File file : alFiles) { l += file.getSize(); } return l; } /** * Gets the playable file. * * @param bIgnoreUnmounted Do we return unmounted files * * @return best file to play for this track or null if none available */ public File getBestFile(boolean bIgnoreUnmounted) { File fileOut = null; final List alMountedFiles = new ArrayList(2); // firstly, filter mounted files if needed for (final File file : alFiles) { if (!bIgnoreUnmounted || file.isReady()) { alMountedFiles.add(file); } } if (alMountedFiles.size() == 1) { fileOut = alMountedFiles.get(0); } else if (alMountedFiles.size() > 0) { // then keep best quality and mounted first Collections.sort(alMountedFiles, new Comparator() { @Override public int compare(File file1, File file2) { long lQuality1 = file1.getQuality(); boolean bMounted1 = file1.isReady(); long lQuality2 = file2.getQuality(); // quality for // out file boolean bMounted2 = file2.isReady(); if (bMounted1 && !bMounted2) {// first item mounted, // not second return 1; } else if (!bMounted1 && bMounted2) { // second // mounted, not // the first return -1; } else { // both mounted or unmounted, compare quality return (int) (lQuality1 - lQuality2); } } }); fileOut = alMountedFiles.get(alMountedFiles.size() - 1); } return fileOut; } /** * Gets the hits. * * @return the hits */ public long getHits() { return getLongValue(Const.XML_TRACK_HITS); } /** * Gets the comment. * * @return the comment */ public String getComment() { return getStringValue(Const.XML_TRACK_COMMENT); } /** * Get track number. * * @return the order */ public long getOrder() { return getLongValue(Const.XML_TRACK_ORDER); } /** * Get disc number. * * @return the disc number */ public long getDiscNumber() { return getLongValue(Const.XML_TRACK_DISC_NUMBER); } /** * Get album artist. * * @return the album artist */ public AlbumArtist getAlbumArtist() { return albumArtist; } /** * Gets the album artist or artist if album-artist is not available. * * @return the albumArtist or artist if album artist not available *

    * If this is various, the album artist is tried to be defined by the * track artists of this album *

    */ public String getAlbumArtistOrArtist() { // If the album artist tag is provided, perfect, let's use it ! String albumArtist = getAlbumArtist().getName(); if (StringUtils.isNotBlank(albumArtist) && !(Const.UNKNOWN_ARTIST.equals(albumArtist))) { return albumArtist; } // various artist? check if all artists are the same Artist artist = getArtist(); if (artist == null) { // Several different artist, return translated "various" return Messages.getString(Const.VARIOUS_ARTIST); } else { // single artist, return it return artist.getName2(); } } /** * Gets the year. * * @return the year */ public Year getYear() { return year; } /** * Gets the duration. * * @return length in sec */ public long getDuration() { return length; } /* (non-Javadoc) * @see org.jajuk.base.Item#getRate() */ @Override public long getRate() { return getLongValue(Const.XML_TRACK_RATE); } /** * Gets the discovery date. * * @return the date where the track has been discovered (added into the * collection) */ public Date getDiscoveryDate() { return getDateValue(Const.XML_TRACK_DISCOVERY_DATE); } /** * Gets the type. * * @return the type */ public Type getType() { return type; } /** * Gets the artist. * * @return the artist */ public Artist getArtist() { return artist; } /** * Gets the genre. * * @return the genre */ public Genre getGenre() { return genre; } /** * Add an associated file. * * @param file DOCUMENT_ME */ public void addFile(File file) { // make sure a file will be referenced by only one track (first found) if (!alFiles.contains(file) && file.getTrack().equals(this)) { alFiles.add(file); } } /** * Sets the hits. * * @param hits The iHits to set. */ public void setHits(long hits) { setProperty(Const.XML_TRACK_HITS, hits); // Store max playcount if (hits > RatingManager.getMaxPlaycount()) { RatingManager.setMaxPlaycount(hits); } } /** * Increase playcount number. */ public void incHits() { long value = getHits() + 1; setHits(value); } /** * Set track preference (from -3 to 3: -3: hate, -2=dislike, -1=poor, +1=like, * +2=love +3=crazy). The preference is a factor given by the user to increase * or decrease a track rate. * * @param preference from -3 to 3 */ public void setPreference(long preference) { Log.debug("Changed preference of " + getID() + "=" + preference); if (preference >= -3l && preference <= 3l) { setProperty(Const.XML_TRACK_PREFERENCE, preference); } else { setProperty(Const.XML_TRACK_PREFERENCE, 0l); Log.debug("Out of bounds preference for : " + getID()); } updateRate(); } /** * Compute final track rate. * * @see http://trac.jajuk.info/ticket/1179 */ public void updateRate() { try { // rate contains final rate [0,100] long rate = 0; // Normalize values to avoid division by zero long duration = getDuration(); long playcount = getHits(); // Playcount must be > 0 to avoid divisions by zero and log(0) operations if (playcount <= 0) { playcount = 1; } float playtimeRate = 0.5f; if (duration == 0) { // If duration = 0, always set playtimeRate to 0.5 Log.info("Duration = 0 for: {{" + getName() + "}}. Playtime forced to 0.5"); } else { // Compute playtime rate = total play time / (play count * track length) playtimeRate = (float) getLongValue(Const.XML_TRACK_TOTAL_PLAYTIME) / (playcount * duration); } // playtimeRate can be > 1 because of player impl duration computation // precision issue or if user seeks back into the track // set =1. if (playtimeRate > 1) { Log.warn("Playtime rate > 1 for: {{" + getName() + "}} value=" + playtimeRate); // We reset tpt and hits to // make things clear and to avoid increasing the error with time setProperty(Const.XML_TRACK_TOTAL_PLAYTIME, duration * playcount); playtimeRate = 1f; } // compute the playcount rate (logarithmic scale to take number of plays // into account) // playcountRate = ln(track playcount)/ln(max playcount) long maxPlayCount = RatingManager.getMaxPlaycount(); if (maxPlayCount <= 0) { maxPlayCount = 1; } float playcountRate = (float) (Math.log(playcount) / Math.log(maxPlayCount)); // Intermediate rate is a mix between playtime and playcount rates with // factor 0.75 for the first one and 0.25 for the second float intermediateRate = (0.75f * playtimeRate) + (0.25f * playcountRate); // Final rate is intermediateRate in whish we apply the user preference // from // -3 (hate) to 3 (adore) long preference = getLongValue(Const.XML_TRACK_PREFERENCE); long absPreference = Math.abs(preference); rate = Math.round(100 * (intermediateRate + (preference + absPreference) / 2) / (absPreference + 1)); // Apply new rate setRate(rate); } catch (Exception e) { // We catch any arithmetic issue here to avoid preventing next track // startup Log.error(e); } } /** * Sets the rate. * * @param rate The lRate to set. */ protected void setRate(long rate) { setProperty(Const.XML_TRACK_RATE, rate); RatingManager.setRateHasChanged(true); } /** * Sets the comment. * * @param sComment DOCUMENT_ME */ public void setComment(String sComment) { setProperty(Const.XML_TRACK_COMMENT, sComment); } /** * Sets the album artist. * * @param albumArtist : the album artist */ public void setAlbumArtist(AlbumArtist albumArtist) { this.albumArtist = albumArtist; // We store the album-artist ID string, not the album-artist itself setProperty(Const.XML_ALBUM_ARTIST, albumArtist.getID()); } /** * Sets the discovery date. * * @param additionDate The sAdditionDate to set. */ public void setDiscoveryDate(Date additionDate) { setProperty(Const.XML_TRACK_DISCOVERY_DATE, additionDate); } /** * Return whether this item should be hidden with hide option. * * @return whether this item should be hidden with hide option */ public boolean shouldBeHidden() { if (getBestFile(true) != null || !Conf.getBoolean(Const.CONF_OPTIONS_HIDE_UNMOUNTED)) { return false; } return true; } /* * (non-Javadoc) * * @see org.jajuk.base.Item#getIdentifier() */ @Override public final String getLabel() { return XML_TRACK; } /** * Get item description. * * @return the desc */ @Override public String getDesc() { return Messages.getString("Item_Track") + " : " + getName(); } /* * (non-Javadoc) * * @see org.jajuk.base.Item#getHumanValue(java.lang.String) */ @Override public String getHumanValue(String sKey) { if (Const.XML_ALBUM.equals(sKey)) { Album lAlbum = AlbumManager.getInstance().getAlbumByID(getStringValue(sKey)); if (lAlbum != null) { // can be null after a fresh change return lAlbum.getName2(); } return null; } else if (Const.XML_ARTIST.equals(sKey)) { Artist artist = ArtistManager.getInstance().getArtistByID(getStringValue(sKey)); if (artist != null) { // can be null after a fresh change return artist.getName2(); } return null; } else if (Const.XML_ALBUM_ARTIST.equals(sKey)) { AlbumArtist albumArtist = AlbumArtistManager.getInstance().getAlbumArtistByID( getStringValue(sKey)); if (albumArtist != null) { // can be null after a fresh change return albumArtist.getName2(); } return null; } else if (Const.XML_GENRE.equals(sKey)) { Genre genre = GenreManager.getInstance().getGenreByID(getStringValue(sKey)); if (genre != null) { // can be null after a fresh change return genre.getName2(); } return null; } else if (Const.XML_TRACK_LENGTH.equals(sKey)) { return UtilString.formatTimeBySec(length); } else if (Const.XML_TYPE.equals(sKey)) { return TypeManager.getInstance().getTypeByID(getStringValue(sKey)).getName(); } else if (Const.XML_YEAR.equals(sKey)) { return getStringValue(sKey); } else if (Const.XML_FILES.equals(sKey)) { final StringBuilder sbOut = new StringBuilder(); for (final File file : alFiles) { sbOut.append(file.getAbsolutePath()); sbOut.append(','); } return sbOut.substring(0, sbOut.length() - 1); // remove trailing coma } else if (Const.XML_TRACK_DISCOVERY_DATE.equals(sKey)) { return UtilString.getLocaleDateFormatter().format(getDiscoveryDate()); } else if (Const.XML_ANY.equals(sKey)) { return getAny(); } else {// default return super.getHumanValue(sKey); } } /* * (non-Javadoc) * * @see org.jajuk.base.Item#getIconRepresentation() */ @Override public ImageIcon getIconRepresentation() { return IconLoader.getIcon(JajukIcons.TRACK); } /** * Gets the files string. * * @return a list of associated files in format : file1,file2... */ public String getFilesString() { StringBuilder sb = new StringBuilder(100); for (File file : alFiles) { sb.append(file.getName()); sb.append(','); } // Remove trailing ',' sb.deleteCharAt(sb.length() - 1); return sb.toString(); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/base/ItemManager.java0000644000175000017500000005313511720500104023760 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.base; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Set; import java.util.TreeSet; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.Predicate; import org.jajuk.services.tags.Tag; import org.jajuk.util.Const; import org.jajuk.util.MD5Processor; import org.jajuk.util.error.JajukException; import org.jajuk.util.log.Log; /** * Managers parent class. */ public abstract class ItemManager { /** Maps item classes -> instance, must be a linked map for ordering (mandatory in commited collection). */ private static Map, ItemManager> hmItemManagers = new LinkedHashMap, ItemManager>( 10); /** Maps properties meta information name and object. */ private final Map hmPropertiesMetaInformation = new LinkedHashMap( 10); /** The Lock. */ ReadWriteLock lock = new ReentrantReadWriteLock(); /** Use an array list during startup which is faster during loading the collection. */ private List startupItems = new ArrayList(100); /** Stores the items by ID to have quick access if necessary. */ private final Map internalMap = new HashMap(100); /** Collection pointer : at the beginning point to the ArrayList, later this is replaced by a TreeSet to have correct ordering. */ private Collection items = startupItems; /** * Item manager default constructor. */ ItemManager() { } /** * Switch all item managers to ordered mode See * ItemManager.switchToOrderState() for more details */ public static void switchAllManagersToOrderState() { Log.debug("Switching to sorted mode"); for (ItemManager manager : hmItemManagers.values()) { manager.switchToOrderState(); } } /** * Switch this item manager to order mode This feature allows faster * collection loading As collection.xml contains ordered elements, we simply a * use an ArrayList to store items first, then few seconds after startup and * before user could make changes to the collection, we populate a TreeSet * from the ArrayList and begin to use it. */ public void switchToOrderState() { lock.writeLock().lock(); try { // populate a new TreeSet with the startup-items if (startupItems != null) { items = new TreeSet(startupItems); // Free startup memory startupItems = null; } } finally { lock.writeLock().unlock(); } } /** * Registers a new item manager. * * @param c Managed item class * @param itemManager DOCUMENT_ME */ public static void registerItemManager(Class c, ItemManager itemManager) { hmItemManagers.put(c, itemManager); } /** * Gets the label. * * @return identifier used for XML generation */ public abstract String getLabel(); /** * Gets the meta information. * * @param sPropertyName DOCUMENT_ME * * @return meta data for given property */ public PropertyMetaInformation getMetaInformation(String sPropertyName) { return hmPropertiesMetaInformation.get(sPropertyName); } /** * Remove a property *. * * @param sProperty DOCUMENT_ME */ public void removeProperty(String sProperty) { PropertyMetaInformation meta = getMetaInformation(sProperty); hmPropertiesMetaInformation.remove(sProperty); applyRemoveProperty(meta); // remove this property from all items } /** * Remove a custom property from all items for the given manager. * * @param meta DOCUMENT_ME */ public void applyRemoveProperty(PropertyMetaInformation meta) { lock.readLock().lock(); try { for (Item item : items) { item.removeProperty(meta.getName()); } } finally { lock.readLock().unlock(); } } /** * Generic method to access to a parameterized list of items. * * @param meta DOCUMENT_ME * * @return the item-parameterized list * * protected abstract HashMap getItemsMap(); */ /** Add a custom property to all items for the given manager */ public void applyNewProperty(PropertyMetaInformation meta) { lock.readLock().lock(); try { for (Item item : items) { item.setProperty(meta.getName(), meta.getDefaultValue()); } } finally { lock.readLock().unlock(); } } /** * Attention, this method does not return a full XML, but rather an excerpt * that is then completed in Collection.commit()! * * @return (partial) XML representation of this manager */ public String toXML() { StringBuilder sb = new StringBuilder("<").append(getLabel() + ">"); Iterator it = hmPropertiesMetaInformation.keySet().iterator(); while (it.hasNext()) { String sProperty = it.next(); PropertyMetaInformation meta = hmPropertiesMetaInformation.get(sProperty); sb.append('\n' + meta.toXML()); } return sb.append('\n').toString(); } /** * Return the associated read write lock. * * @return the associated read write lock */ public ReadWriteLock getLock() { return lock; } /** * Format the item name to be normalized : *

    * -no underscores or other non-ascii characters *

    * -no spaces at the begin and the end *

    * -All in lower case expect first letter of first word *

    * example: "My artist". * * @param sName The name to format. * * @return the string * * TODO: the "all lowercase" part is not done currently, should this be changed?? */ public static String format(String sName) { String sOut; sOut = sName.trim(); // suppress spaces at the begin and the end sOut = sOut.replace('-', ' '); // move - to space sOut = sOut.replace('_', ' '); // move _ to space char c = sOut.charAt(0); StringBuilder sb = new StringBuilder(sOut); sb.setCharAt(0, Character.toUpperCase(c)); return sb.toString(); } /** * Gets the properties. * * @return properties Meta informations */ public Collection getProperties() { return hmPropertiesMetaInformation.values(); } /** * Gets the custom properties including activated extra tags. * * @return custom properties Meta informations */ public Collection getCustomProperties() { List col = new ArrayList(); Iterator it = hmPropertiesMetaInformation.values().iterator(); while (it.hasNext()) { PropertyMetaInformation meta = it.next(); if (meta.isCustom()) { col.add(meta); } } return col; } /** * Gets the custom properties without the activated extra tags. * * @return custom properties Meta informations */ public Collection getUserCustomProperties() { List col = new ArrayList(); Iterator it = hmPropertiesMetaInformation.values().iterator(); while (it.hasNext()) { PropertyMetaInformation meta = it.next(); if (meta.isCustom() && !Tag.getActivatedExtraTags().contains(meta.getName())) { col.add(meta); } } return col; } /** * Gets the visible properties. * * @return visible properties Meta informations */ public Collection getVisibleProperties() { List col = new ArrayList(); Iterator it = hmPropertiesMetaInformation.values().iterator(); while (it.hasNext()) { PropertyMetaInformation meta = it.next(); if (meta.isVisible()) { col.add(meta); } } return col; } /** * Get the manager from a given attribute name. * * @param sProperty The property to compare. * * @return an ItemManager if one is found for the property or null if none * found. */ public static ItemManager getItemManager(String sProperty) { if (Const.XML_DEVICE.equals(sProperty)) { return DeviceManager.getInstance(); } else if (Const.XML_TRACK.equals(sProperty)) { return TrackManager.getInstance(); } else if (Const.XML_ALBUM.equals(sProperty)) { return AlbumManager.getInstance(); } else if (Const.XML_ARTIST.equals(sProperty)) { return ArtistManager.getInstance(); } else if (Const.XML_ALBUM_ARTIST.equals(sProperty)) { return AlbumArtistManager.getInstance(); } else if (Const.XML_GENRE.equals(sProperty)) { return GenreManager.getInstance(); } else if (Const.XML_DIRECTORY.equals(sProperty)) { return DirectoryManager.getInstance(); } else if (Const.XML_FILE.equals(sProperty)) { return FileManager.getInstance(); } else if (Const.XML_PLAYLIST_FILE.equals(sProperty)) { return PlaylistManager.getInstance(); } else if (Const.XML_TYPE.equals(sProperty)) { return TypeManager.getInstance(); } else { return null; } } /** * Get ItemManager manager for given item class. * * @param c DOCUMENT_ME * * @return associated item manager or null if none was found */ public static ItemManager getItemManager(Class c) { return hmItemManagers.get(c); } /** * Return an iteration over item managers. * * @return the item managers */ public static Iterator getItemManagers() { return hmItemManagers.values().iterator(); } /** * Perform cleanup : delete useless items. */ @SuppressWarnings("unchecked") public void cleanup() { lock.writeLock().lock(); try { // Prefetch item manager type for performances short managerType = 0; // Album if (this instanceof ArtistManager) { managerType = 1; } else if (this instanceof GenreManager) { Log.debug("Genre cleanup not allowed"); return; } else if (this instanceof YearManager) { managerType = 2; } else if (this instanceof AlbumArtistManager) { managerType = 3; } // build used items set List lItems = new ArrayList(100); List tracks = TrackManager.getInstance().getTracks(); for (Track track : tracks) { switch (managerType) { case 0: lItems.add(track.getAlbum()); break; case 1: lItems.add(track.getArtist()); break; case 2: lItems.add(track.getYear()); break; case 3: lItems.add(track.getAlbumArtist()); break; } } // Now iterate over this manager items to check if it is present in the // items list Iterator it = (Iterator) getItemsIterator(); while (it.hasNext()) { Item item = it.next(); // check if this item still maps some tracks if (!lItems.contains(item)) { it.remove(); internalMap.remove(item.getID()); } } } finally { lock.writeLock().unlock(); } } /** * Perform a cleanup of all orphan tracks associated with given item. * * @param item item whose associated tracks should be checked for cleanup */ protected void cleanOrphanTracks(Item item) { if (TrackManager.getInstance().getAssociatedTracks(item, false).isEmpty()) { removeItem(item); } } /** * Remove a given item. * * @param item DOCUMENT_ME */ protected void removeItem(Item item) { lock.writeLock().lock(); try { if (item != null) { items.remove(item); internalMap.remove(item.getID()); } } finally { lock.writeLock().unlock(); } } /** * Register a given item. * * @param item : the item to add */ protected void registerItem(Item item) { lock.writeLock().lock(); try { items.add(item); internalMap.put(item.getID(), item); } finally { lock.writeLock().unlock(); } } /** * Register a new property. * * @param meta DOCUMENT_ME */ public void registerProperty(PropertyMetaInformation meta) { hmPropertiesMetaInformation.put(meta.getName(), meta); } /** * Change any item. * * @param itemToChange DOCUMENT_ME * @param sKey DOCUMENT_ME * @param oValue DOCUMENT_ME * @param filter : files we want to deal with * * @return the changed item * * @throws JajukException the jajuk exception */ public static Item changeItem(Item itemToChange, String sKey, Object oValue, Set filter) throws JajukException { if (Log.isDebugEnabled()) { Log.debug("Set " + sKey + "=" + oValue.toString() + " to " + itemToChange); } Item newItem = itemToChange; if (itemToChange instanceof File) { File file = (File) itemToChange; if (Const.XML_NAME.equals(sKey)) { // file name newItem = FileManager.getInstance().changeFileName((File) itemToChange, (String) oValue); } else if (Const.XML_TRACK.equals(sKey)) { // track name newItem = TrackManager.getInstance().changeTrackName(file.getTrack(), (String) oValue, filter); } else if (Const.XML_GENRE.equals(sKey)) { newItem = TrackManager.getInstance().changeTrackGenre(file.getTrack(), (String) oValue, filter); } else if (Const.XML_ALBUM.equals(sKey)) { newItem = TrackManager.getInstance().changeTrackAlbum(file.getTrack(), (String) oValue, filter); } else if (Const.XML_ARTIST.equals(sKey)) { newItem = TrackManager.getInstance().changeTrackArtist(file.getTrack(), (String) oValue, filter); } else if (Const.XML_TRACK_COMMENT.equals(sKey)) { newItem = TrackManager.getInstance().changeTrackComment(file.getTrack(), (String) oValue, filter); } else if (Const.XML_TRACK_ORDER.equals(sKey)) { newItem = TrackManager.getInstance().changeTrackOrder(file.getTrack(), (Long) oValue, filter); } else if (Const.XML_ALBUM_ARTIST.equals(sKey)) { newItem = TrackManager.getInstance().changeTrackAlbumArtist(file.getTrack(), (String) oValue, filter); } else if (Const.XML_YEAR.equals(sKey)) { newItem = TrackManager.getInstance().changeTrackYear(file.getTrack(), String.valueOf(oValue), filter); } else if (Const.XML_TRACK_RATE.equals(sKey)) { newItem = TrackManager.getInstance().changeTrackRate(file.getTrack(), (Long) oValue); } else { // others properties // check if this key is known for files if (file.getMeta(sKey) != null) { itemToChange.setProperty(sKey, oValue); } // Unknown ? check if it is a track custom property else if (file.getTrack().getMeta(sKey) != null) { file.getTrack().setProperty(sKey, oValue); } } // Get associated track file if (newItem instanceof Track) { file.setTrack((Track) newItem); newItem = file; } } else if (itemToChange instanceof Playlist) { if (Const.XML_NAME.equals(sKey)) { // playlistfile name newItem = PlaylistManager.getInstance().changePlaylistFileName((Playlist) itemToChange, (String) oValue); } } else if (itemToChange instanceof Directory) { if (!Const.XML_NAME.equals(sKey)) { // file name // TBI newItem = // DirectoryManager.getInstance().changeDirectoryName((Directory)itemToChange,(String)oValue); // } else { // others properties itemToChange.setProperty(sKey, oValue); } } else if (itemToChange instanceof Device) { itemToChange.setProperty(sKey, oValue); } else if (itemToChange instanceof Track) { if (Const.XML_NAME.equals(sKey)) { newItem = TrackManager.getInstance().changeTrackName((Track) itemToChange, (String) oValue, filter); } else if (Const.XML_GENRE.equals(sKey)) { newItem = TrackManager.getInstance().changeTrackGenre((Track) itemToChange, (String) oValue, filter); } else if (Const.XML_ALBUM.equals(sKey)) { newItem = TrackManager.getInstance().changeTrackAlbum((Track) itemToChange, (String) oValue, filter); } else if (Const.XML_ARTIST.equals(sKey)) { newItem = TrackManager.getInstance().changeTrackArtist((Track) itemToChange, (String) oValue, filter); } else if (Const.XML_ALBUM_ARTIST.equals(sKey)) { newItem = TrackManager.getInstance().changeTrackAlbumArtist((Track) itemToChange, (String) oValue, filter); } else if (Const.XML_TRACK_COMMENT.equals(sKey)) { newItem = TrackManager.getInstance().changeTrackComment((Track) itemToChange, (String) oValue, filter); } else if (Const.XML_TRACK_ORDER.equals(sKey)) { newItem = TrackManager.getInstance().changeTrackOrder((Track) itemToChange, (Long) oValue, filter); } else if (Const.XML_YEAR.equals(sKey)) { newItem = TrackManager.getInstance().changeTrackYear((Track) itemToChange, String.valueOf(oValue), filter); } else if (Const.XML_TRACK_RATE.equals(sKey)) { newItem = TrackManager.getInstance().changeTrackRate((Track) itemToChange, (Long) oValue); } else { // others properties itemToChange.setProperty(sKey, oValue); } } else if (itemToChange instanceof Album) { if (Const.XML_NAME.equals(sKey)) { newItem = AlbumManager.getInstance().changeAlbumName((Album) itemToChange, (String) oValue); } else { // others properties itemToChange.setProperty(sKey, oValue); } } else if (itemToChange instanceof Artist) { if (Const.XML_NAME.equals(sKey)) { newItem = ArtistManager.getInstance().changeArtistName((Artist) itemToChange, (String) oValue); } else { // others properties itemToChange.setProperty(sKey, oValue); } } else if (itemToChange instanceof Genre) { if (Const.XML_NAME.equals(sKey)) { newItem = GenreManager.getInstance().changeGenreName((Genre) itemToChange, (String) oValue); } else { // others properties itemToChange.setProperty(sKey, oValue); } } else if (itemToChange instanceof Year) { itemToChange.setProperty(sKey, oValue); } return newItem; } /** * Gets the element count. * * @return number of item */ public int getElementCount() { return items.size(); } /** * Gets the item by id. * * @param sID Item ID * * @return Item */ public Item getItemByID(String sID) { return internalMap.get(sID); } /** * Return a copy of all registered items. * * @return a copy of all registered items */ public List getItems() { return new ArrayList(items); } /** * Return a shallow copy of all registered items filtered using the provided * predicate*. * * @param predicate DOCUMENT_ME * * @return a shallow copy of all registered items filtered using the provided * * @arg predicate : the predicate */ public List getFilteredItems(Predicate predicate) { ArrayList itemsCopy = new ArrayList(items); CollectionUtils.filter(itemsCopy, predicate); return itemsCopy; } /** * *************************************************************************** * Return all registered enumeration CAUTION : do not call remove() on this * iterator, you would effectively remove items instead of using regular * removeItem() primitive * **************************************************************************. * * @return the items iterator */ protected Iterator getItemsIterator() { return items.iterator(); } /** * Clear any entries from this manager. */ public void clear() { lock.writeLock().lock(); try { items.clear(); internalMap.clear(); } finally { lock.writeLock().unlock(); } } /** * Force files sorting after an order change, i.e. Called to ensure Set * sorting contract
    * We remove all items and add them all again to force sorting */ public void forceSorting() { lock.writeLock().lock(); try { // first create a copy ArrayList itemsCopy = new ArrayList(items); // then remove all elements clear(); // and then re-add all items again to make them correctly sorted again for (Item item : itemsCopy) { registerItem(item); } } finally { lock.writeLock().unlock(); } } /** * Basic implementation for item hashcode computation. * * @param sName item name * * @return ItemManager ID */ protected static String createID(String sName) { return MD5Processor.hash(sName); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/base/SearchResult.java0000644000175000017500000000560211720500104024167 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.base; import org.jajuk.services.webradio.WebRadio; /** * A search result, contains a file and a search description. */ public class SearchResult implements Comparable { /** * Result type *. */ public enum SearchResultType { /** DOCUMENT_ME. */ FILE, /** DOCUMENT_ME. */ WEBRADIO } /** The associated file. */ File file; /** The associated web radio. */ WebRadio radio; /** Pre-calculated search string. */ String sResu; /** * Instantiates a new search result. * * @param file DOCUMENT_ME */ public SearchResult(File file) { this(file, file.toStringSearch()); } /** * Instantiates a new search result. * * @param file DOCUMENT_ME * @param sResu DOCUMENT_ME */ public SearchResult(File file, String sResu) { this.file = file; this.sResu = sResu; } /** * Instantiates a new search result. * * @param radio DOCUMENT_ME * @param sResu DOCUMENT_ME */ public SearchResult(WebRadio radio, String sResu) { this.radio = radio; this.sResu = sResu; } /** * Return hashcode, used during sorting. * * @return the int */ @Override public int hashCode() { return sResu.hashCode(); } /* * (non-Javadoc) * * @see java.lang.Comparable#compareTo(java.lang.Object) */ @Override public int compareTo(SearchResult sr) { if (sr == null) { return -1; } return sResu.compareToIgnoreCase(sr.getResu()); } /** * Gets the file. * * @return Returns the file. */ public File getFile() { return file; } /** * Gets the type. * * @return result type: file or web radio */ public SearchResultType getType() { if (file != null) { return SearchResultType.FILE; } else { return SearchResultType.WEBRADIO; } } /** * Gets the webradio. * * @return Returns the webradio. */ public WebRadio getWebradio() { return radio; } /** * Gets the resu. * * @return Returns the sResu. */ public String getResu() { return sResu; } } jajuk-1.9.6.orig/src/main/java/org/jajuk/base/PlaylistManager.java0000644000175000017500000002414211720500104024657 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.base; import java.io.IOException; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Properties; import java.util.Set; import org.jajuk.events.JajukEvent; import org.jajuk.events.JajukEvents; import org.jajuk.events.Observer; import org.jajuk.util.Const; import org.jajuk.util.MD5Processor; import org.jajuk.util.Messages; import org.jajuk.util.ReadOnlyIterator; import org.jajuk.util.UtilSystem; import org.jajuk.util.error.JajukException; import org.jajuk.util.log.Log; /** * Convenient class to manage playlists. */ public final class PlaylistManager extends ItemManager implements Observer { /** Self instance. */ private static PlaylistManager singleton = new PlaylistManager(); /** * No constructor available, only static access. */ private PlaylistManager() { super(); // ---register properties--- // ID registerProperty(new PropertyMetaInformation(Const.XML_ID, false, true, false, false, false, String.class, null)); // Name registerProperty(new PropertyMetaInformation(Const.XML_NAME, false, true, true, true, false, String.class, null)); // Directory registerProperty(new PropertyMetaInformation(Const.XML_DIRECTORY, false, true, true, false, false, String.class, null)); } /** * Gets the instance. * * @return singleton */ public static PlaylistManager getInstance() { return singleton; } /** * Register an Playlist with a known id. * * @param fio DOCUMENT_ME * @param dParentDirectory DOCUMENT_ME * * @return the playlist */ public Playlist registerPlaylistFile(java.io.File fio, Directory dParentDirectory) { String sId = createID(fio.getName(), dParentDirectory); return registerPlaylistFile(sId, fio.getName(), dParentDirectory); } /** * Creates the id. * * @param sName DOCUMENT_ME * @param dParentDirectory DOCUMENT_ME * * @return ItemManager ID */ protected static String createID(String sName, Directory dParentDirectory) { return MD5Processor.hash(new StringBuilder(dParentDirectory.getDevice().getName()).append( dParentDirectory.getRelativePath()).append(sName).toString()); } /** * Remove a playlist. * * @param plf the playlist * * @throws IOException Signals that an I/O exception has occurred. */ public void removePlaylistFile(Playlist plf) throws IOException { String sFileToDelete = plf.getDirectory().getFio().getAbsoluteFile().toString() + java.io.File.separatorChar + plf.getName(); lock.writeLock().lock(); try { java.io.File fileToDelete = new java.io.File(sFileToDelete); if (fileToDelete.exists()) { UtilSystem.deleteFile(fileToDelete); } // remove playlist removeItem(plf); } finally { lock.writeLock().unlock(); } } /** * Delete physically a playlist. * * @param plf the playlist * * @throws IOException Signals that an I/O exception has occurred. */ public void deletePlaylistFile(Playlist plf) throws IOException { lock.writeLock().lock(); try { String sFileToDelete = plf.getDirectory().getFio().getAbsoluteFile().toString() + java.io.File.separatorChar + plf.getName(); java.io.File fileToDelete = new java.io.File(sFileToDelete); if (fileToDelete.exists()) { UtilSystem.deleteFile(fileToDelete); } // remove playlist removePlaylistFile(plf); } finally { lock.writeLock().unlock(); } } /** * Register an Playlist with a known id. * * @param sId DOCUMENT_ME * @param sName DOCUMENT_ME * @param dParentDirectory DOCUMENT_ME * @return the playlist */ public Playlist registerPlaylistFile(String sId, String sName, Directory dParentDirectory) { Playlist playlistFile = getPlaylistByID(sId); if (playlistFile != null) { return playlistFile; } playlistFile = new Playlist(sId, sName, dParentDirectory); registerItem(playlistFile); return playlistFile; } /** * Clean all references for the given device. * * @param sId : * Device id */ public void cleanDevice(String sId) { for (Playlist plf : getPlaylists()) { if (plf.getDirectory() == null || plf.getDirectory().getDevice().getID().equals(sId)) { removeItem(plf); } } } /* * (non-Javadoc) * * @see org.jajuk.base.ItemManager#getIdentifier() */ @Override public String getLabel() { return Const.XML_PLAYLIST_FILES; } /** * Change a playlist name. * * @param plfOld DOCUMENT_ME * @param sNewName DOCUMENT_ME * * @return new playlist * * @throws JajukException the jajuk exception */ public Playlist changePlaylistFileName(Playlist plfOld, String sNewName) throws JajukException { lock.writeLock().lock(); try { // check given name is different if (plfOld.getName().equals(sNewName)) { return plfOld; } // check if this file still exists if (!plfOld.getFIO().exists()) { throw new JajukException(135); } java.io.File ioNew = new java.io.File(plfOld.getFIO().getParentFile().getAbsolutePath() + java.io.File.separator + sNewName); // recalculate file ID plfOld.getDirectory(); String sNewId = PlaylistManager.createID(sNewName, plfOld.getDirectory()); // create a new playlist (with own fio and sAbs) Playlist plfNew = new Playlist(sNewId, sNewName, plfOld.getDirectory()); // Transfer all properties (id and name) // We use a shallow copy of properties to avoid any properties share between // two items plfNew.setProperties(plfOld.getShallowProperties()); plfNew.setProperty(Const.XML_ID, sNewId); // reset new id and name plfNew.setProperty(Const.XML_NAME, sNewName); // reset new id and name // check file name and extension if (plfNew.getName().lastIndexOf('.') != plfNew.getName().indexOf('.')// just // one // '.' || !(UtilSystem.getExtension(ioNew).equals(Const.EXT_PLAYLIST))) { // check // extension Messages.showErrorMessage(134); throw new JajukException(134); } // check if future file exists (under windows, file.exists // return true even with different case so we test file name is // different) if (!ioNew.getName().equalsIgnoreCase(plfOld.getName()) && ioNew.exists()) { throw new JajukException(134); } // try to rename file on disk try { boolean result = plfOld.getFIO().renameTo(ioNew); if (!result) { throw new IOException(); } } catch (Exception e) { throw new JajukException(134, e); } // OK, remove old file and register this new file removeItem(plfOld); registerItem(plfNew); return plfNew; } finally { lock.writeLock().unlock(); } } /* * (non-Javadoc) * * @see org.jajuk.base.Observer#update(org.jajuk.base.Event) */ @Override public void update(JajukEvent event) { JajukEvents subject = event.getSubject(); if (JajukEvents.FILE_NAME_CHANGED.equals(subject)) { lock.writeLock().lock(); try { Properties properties = event.getDetails(); File fNew = (File) properties.get(Const.DETAIL_NEW); File fileOld = (File) properties.get(Const.DETAIL_OLD); // search references in playlists ReadOnlyIterator it = getPlaylistsIterator(); while (it.hasNext()) { Playlist plf = it.next(); if (plf.isReady()) { // check only in mounted // playlists, note that we can't // change unmounted playlists try { if (plf.getFiles().contains(fileOld)) { plf.replaceFile(fileOld, fNew); } } catch (Exception e) { Log.error(17, e); } } } } finally { lock.writeLock().unlock(); } } } /* * (non-Javadoc) * * @see org.jajuk.events.Observer#getRegistrationKeys() */ @Override public Set getRegistrationKeys() { Set eventSubjectSet = new HashSet(); eventSubjectSet.add(JajukEvents.FILE_NAME_CHANGED); return eventSubjectSet; } /** * Gets the playlist by id. * * @param sID Item ID * * @return item */ public Playlist getPlaylistByID(String sID) { return (Playlist) getItemByID(sID); } /** * Gets the playlists. * * @return ordered playlists list */ @SuppressWarnings("unchecked") public List getPlaylists() { return (List) getItems(); } /** * Gets the playlists iterator. * * @return playlists iterator */ @SuppressWarnings("unchecked") public ReadOnlyIterator getPlaylistsIterator() { return new ReadOnlyIterator((Iterator) getItemsIterator()); } /** * Returns the first playlist with the given name. * * @param name The name of the Playlist to search * * @return The playlist if found, null otherwise. */ public Playlist getPlaylistByName(String name) { for (Playlist pl : getPlaylists()) { // if this is the correct playlist, return it if (pl.getName().equals(name)) { return pl; } } // none found return null; } } jajuk-1.9.6.orig/src/main/java/org/jajuk/base/Item.java0000644000175000017500000003155611720500104022470 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.base; import java.util.Date; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import javax.swing.ImageIcon; import org.jajuk.util.Const; import org.jajuk.util.UtilString; import org.jajuk.util.log.Log; import org.xml.sax.Attributes; /** * Generic property handler, parent class for all items *

    * Note that some properties can be omitted (not in properties object), in this * case, we take default value given in meta infos, this can decrease collection * file size *

    . */ public abstract class Item implements Const { /** We cache the ID to avoid getting it from properties for CPU performance reasons. */ String sID; /** We cache the name to avoid getting it from properties for CPU performance reasons. */ String name; /** Item properties, singleton use very high load factor as this size will not change often. */ private Map properties = new HashMap(2, 1f); /** * Constructor. * * @param sId element ID * @param sName element name */ Item(final String sId, final String sName) { this.sID = sId; setProperty(Const.XML_ID, sId); this.name = sName; setProperty(Const.XML_NAME, sName); } /** * Gets the iD. * * @return the iD */ public String getID() { return this.sID; } /** * Gets the name. * * @return the name */ public String getName() { return name; } /** * Item hashcode (used by the equals method) See * http://www.geocities.com/technofundo/tech/java/equalhash.html * * @return the int */ @Override public int hashCode() { return getID().hashCode(); } /** * Get item description (HTML). * * @return item description */ public abstract String getDesc(); /** * Equal method to check two items are identical. * * @param otherItem DOCUMENT_ME * * @return true, if equals */ @Override public boolean equals(Object otherItem) { // this also catches null if (!(otherItem instanceof Item)) { return false; } // [Perf] We can compare with an == operator here because // all ID are stored into String intern() buffer return getID() == ((Item) otherItem).getID(); } /* * (non-Javadoc) * * @see org.jajuk.base.Item#getProperties() */ /** * Gets the properties. * * @return the properties */ public Map getProperties() { return properties; } /** * Return a shallow copy of the item properties. * * @return a shallow copy of the item properties */ public Map getShallowProperties() { HashMap out = new HashMap(properties.size()); for (String key : properties.keySet()) { out.put(key, properties.get(key)); } return out; } /* * (non-Javadoc) * * @see org.jajuk.base.Item#getProperty(java.lang.String) */ /** * Gets the value. * * @param sKey DOCUMENT_ME * * @return the value */ public Object getValue(String sKey) { Object out = getProperties().get(sKey); // look at properties to check the given property is known if (out == null) { // no? take property default return getDefaultValue(sKey); } return out; } /** * Gets the long value. * * @param sKey DOCUMENT_ME * * @return the long value */ public long getLongValue(String sKey) { Long out = (Long) getProperties().get(sKey); // look at properties to check the given property is known if (out == null) { // no? take property default return (Long) getDefaultValue(sKey); } return out; } /** * Gets the double value. * * @param sKey DOCUMENT_ME * * @return the double value */ public double getDoubleValue(String sKey) { Double out = (Double) getProperties().get(sKey); // look at properties to check the given property is known if (out == null) { // no? take property default return (Double) getDefaultValue(sKey); } return out; } /** * Return String value for String type values. We assume that given property * is a String. * * @param sKey DOCUMENT_ME * * @return the string value */ public String getStringValue(String sKey) { String out = (String) getProperties().get(sKey); // look at properties to check the given property is known if (out == null) { // no? take property default return (String) getDefaultValue(sKey); } return out; } /** * Gets the boolean value. * * @param sKey DOCUMENT_ME * * @return the boolean value */ public boolean getBooleanValue(String sKey) { Boolean out = (Boolean) getProperties().get(sKey); // look at properties to check the given property is known if (out == null) { // no? take property default return (Boolean) getDefaultValue(sKey); } return out; } /** * Gets the date value. * * @param sKey DOCUMENT_ME * * @return the date value */ public Date getDateValue(String sKey) { Date out = (Date) getProperties().get(sKey); // look at properties to check the given property is known if (out == null) { // no? take property default return (Date) getDefaultValue(sKey); } return out; } /** * Gets the default value. * * @param sKey DOCUMENT_ME * * @return the default value */ public Object getDefaultValue(String sKey) { PropertyMetaInformation meta = getMeta(sKey); return meta.getDefaultValue(); } /* * (non-Javadoc) * * @see org.jajuk.base.Item#containsKey(java.lang.String) */ /** * Contains property. * DOCUMENT_ME * * @param sKey DOCUMENT_ME * * @return true if... */ public boolean containsProperty(String sKey) { return properties.containsKey(sKey) && properties.get(sKey) != null && !properties.get(sKey).equals(""); } /* * (non-Javadoc) * * @see org.jajuk.base.Item#setProperty(java.lang.String, java.lang.String) */ /** * Sets the property. * DOCUMENT_ME * * @param sKey DOCUMENT_ME * @param oValue DOCUMENT_ME */ public final void setProperty(String sKey, Object oValue) { getProperties().put(sKey, oValue); } /* * (non-Javadoc) * * @see org.jajuk.base.Item#getAny() */ /** * Gets the any. * * @return the any */ public String getAny() { StringBuilder sb = new StringBuilder(100); Iterator it = properties.keySet().iterator(); while (it.hasNext()) { String sKey = it.next(); String sValue = getHumanValue(sKey); if (sValue != null) { PropertyMetaInformation meta = getMeta(sKey); if (!meta.isVisible()) { // computes "any" only on // visible items continue; } sb.append(sValue); } } return sb.toString(); } /* * (non-Javadoc) * * @see org.jajuk.base.Item#setDefaultProperty(java.lang.String, * java.lang.String) */ /** * Populate default property. * DOCUMENT_ME * * @param meta DOCUMENT_ME */ public void populateDefaultProperty(PropertyMetaInformation meta) { properties.put(meta.getName(), meta.getDefaultValue()); } /** * Return an XML representation of this item. * * @return the string */ public String toXml() { try { StringBuilder sb = new StringBuilder("<").append(getLabel()); sb.append(getPropertiesXml()); sb.append("/>\n"); return sb.toString(); } catch (Exception e) { // catch any error here because it can prevent // collection to commit Log.error(e); return ""; } } /** * Gets the label. * * @return an identifier used to generate XML representation of this item */ abstract String getLabel(); /** * Gets the properties xml. * * @return XML representation for item properties */ private String getPropertiesXml() { StringBuilder sb = new StringBuilder(); for (String sKey : properties.keySet()) { String sValue = null; Object oValue = properties.get(sKey); if (oValue != null) { PropertyMetaInformation meta = getMeta(sKey); // The meta can be null for unknown reason, see #1226 if (meta == null) { Log.warn("Null meta for: " + sKey); continue; } try { sValue = UtilString.format(oValue, meta, false); // make sure to remove // non-XML characters sValue = UtilString.formatXML(sValue); sb.append(' '); sb.append(UtilString.formatXML(sKey)); sb.append("='"); sb.append(sValue); sb.append("'"); } catch (Exception e) { // should not occur Log.debug("Key=" + sKey + " Meta=" + meta); Log.error(e); } } } return sb.toString(); } /** * Set all personal properties of an XML file for an item (doesn't overwrite * existing properties for perfs). * * @param attributes : * list of attributes for this XML item */ public void populateProperties(Attributes attributes) { for (int i = 0; i < attributes.getLength(); i++) { String sProperty = attributes.getQName(i); if (!properties.containsKey(sProperty)) { String sValue = attributes.getValue(i); PropertyMetaInformation meta = getMeta(sProperty); try { if (meta != null) { // small memory optimization: there are some properties that we do not automatically intern during collection loading, // therefore do it manually here to not have the strings duplicated. // This is currently useful for "ALBUM_ARTIST" and for Const.NONE Cover in Albums // measured gain: aprox. 1MB for 25k tracks if (Const.XML_ALBUM_ARTIST.equals(sProperty) || Const.COVER_NONE.equals(sValue)) { setProperty(sProperty, UtilString.parse(sValue.intern(), meta.getType())); } else { setProperty(sProperty, UtilString.parse(sValue, meta.getType())); } } } catch (Exception e) { Log.error(137, sProperty, e); } } } } /** * Sets the properties. * * @param properties The properties to set. */ public void setProperties(Map properties) { this.properties = properties; } /* * (non-Javadoc) * * @see org.jajuk.base.Item#removeProperty(java.lang.String) */ /** * Removes the property. * DOCUMENT_ME * * @param sKey DOCUMENT_ME */ public void removeProperty(String sKey) { properties.remove(sKey); } /** * Default implementation for this method, simply return standard value. * * @param sKey DOCUMENT_ME * * @return the human value */ public String getHumanValue(String sKey) { try { return UtilString.format(getValue(sKey), getMeta(sKey), true); } catch (Exception e) { Log.error(e); return ""; } } /** * Gets the meta. * * @param sProperty Property name * * @return Meta information for current item and given property name */ public PropertyMetaInformation getMeta(String sProperty) { return ItemManager.getItemManager(this.getClass()).getMetaInformation(sProperty); } /** * Clone all properties from a given properties list but not overwrite * constructor properties. * * @param propertiesSource DOCUMENT_ME */ public void cloneProperties(Item propertiesSource) { Iterator it = propertiesSource.getProperties().keySet().iterator(); while (it.hasNext()) { String sProperty = it.next(); if (!getMeta(sProperty).isConstructor()) { this.properties.put(sProperty, propertiesSource.getValue(sProperty)); } } } /** * Gets the icon representation. * * @return an icon representation for this item or null if none available */ public abstract ImageIcon getIconRepresentation(); /** * Item rate. Should be overwritten by sub classes * * @return item rate if item supports rating or -1 otherwise */ public long getRate() { return -1; } } jajuk-1.9.6.orig/src/main/java/org/jajuk/base/TypeManager.java0000644000175000017500000005756111720500104024012 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.base; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Locale; import java.util.Map; import org.jajuk.services.players.IPlayerImpl; import org.jajuk.services.tags.ITagImpl; import org.jajuk.util.Const; import org.jajuk.util.Messages; import org.jajuk.util.ReadOnlyIterator; import org.jajuk.util.UtilSystem; /** * Manages types ( mp3, ogg...) supported by jajuk *

    */ public final class TypeManager extends ItemManager { /** The Constant ICON_16X16_VIDEO for the supported media types. */ private static final String ICON_16X16_VIDEO = "icons/16x16/type_video_16x16.png"; /** The Constant ICONS_16X16_TYPE_APE for the supported media types. */ private static final String ICONS_16X16_TYPE_APE = "icons/16x16/type_ape_16x16.png"; /** The Constant ICONS_16X16_TYPE_MP2 for the supported media types. */ private static final String ICONS_16X16_TYPE_MP2 = "icons/16x16/type_mp2_16x16.png"; /** The Constant ICONS_16X16_TYPE_AAC for the supported media types. */ private static final String ICONS_16X16_TYPE_AAC = "icons/16x16/type_aac_16x16.png"; /** The Constant ICONS_16X16_TYPE_WMA for the supported media types. */ private static final String ICONS_16X16_TYPE_WMA = "icons/16x16/type_wma_16x16.png"; /** The Constant ICONS_16X16_TYPE_FLAC for the supported media types. */ private static final String ICONS_16X16_TYPE_FLAC = "icons/16x16/type_flac_16x16.png"; /** The Constant ICONS_16X16_TYPE_RAM for the supported media types. */ private static final String ICONS_16X16_TYPE_RAM = "icons/16x16/type_ram_16x16.png"; /** The Constant ICONS_16X16_TYPE_OGG for the supported media types. */ private static final String ICONS_16X16_TYPE_OGG = "icons/16x16/type_ogg_16x16.png"; /** The Constant ICONS_16X16_TYPE_WAV for the supported media types. */ private static final String ICONS_16X16_TYPE_WAV = "icons/16x16/type_wav_16x16.png"; /** The Constant ICONS_16X16_TYPE_MP3 for the supported media types. */ private static final String ICONS_16X16_TYPE_MP3 = "icons/16x16/type_mp3_16x16.png"; /** extensions->types. */ private final Map hmSupportedTypes = new HashMap(10); /** Self instance. */ private static TypeManager singleton = new TypeManager(); /** * No constructor available, only static access. */ private TypeManager() { super(); // ---register properties--- // ID registerProperty(new PropertyMetaInformation(Const.XML_ID, false, true, false, false, false, String.class, null)); // Name registerProperty(new PropertyMetaInformation(Const.XML_NAME, false, true, true, false, false, String.class, null)); // Extension registerProperty(new PropertyMetaInformation(Const.XML_TYPE_EXTENSION, false, true, true, false, false, String.class, null)); // Player impl registerProperty(new PropertyMetaInformation(Const.XML_TYPE_PLAYER_IMPL, false, true, true, false, false, Class.class, null)); // Tag impl registerProperty(new PropertyMetaInformation(Const.XML_TYPE_TAG_IMPL, false, true, true, false, false, Class.class, null)); // Music registerProperty(new PropertyMetaInformation(Const.XML_TYPE_IS_MUSIC, false, false, true, false, false, Boolean.class, null)); // Seek registerProperty(new PropertyMetaInformation(Const.XML_TYPE_SEEK_SUPPORTED, false, false, true, false, false, Boolean.class, null)); // Icon registerProperty(new PropertyMetaInformation(Const.XML_TYPE_ICON, false, false, false, false, false, String.class, null)); } /** * Gets the instance. * * @return singleton */ public static TypeManager getInstance() { return singleton; } /** * Register a type jajuk can read. * * @param sName The human readable name of the type. * @param sExtension The extension for the type, without a dot. * @param cPlayerImpl The class used to play files of this type. Needs to implement the * interface IPlayerImpl, @see IPlayerImpl * @param cTagImpl The class used to retrieve and write tags for this file type. * Needs to implement the interface ITagImpl, @see ITagImpl * * @return the type */ @SuppressWarnings("unchecked") public Type registerType(String sName, String sExtension, Class cPlayerImpl, Class cTagImpl) { String sId = sExtension.toLowerCase(Locale.getDefault()); Type type = getTypeByID(sId); if (type != null) { return type; } // TODO: can this happen at all?? I think the previous "if" already covers // this case... if (hmSupportedTypes.containsKey(sExtension)) { // if the type is already in memory, use it return hmSupportedTypes.get(sExtension); } type = new Type(sId, sName, sExtension, (Class) cPlayerImpl, (Class) cTagImpl); registerItem(type); hmSupportedTypes.put(type.getExtension(), type); return type; } /** * Tells if the type is supported. * * @param sExt The extension to check (without leading dot) * * @return true, if checks if is extension supported */ public boolean isExtensionSupported(String sExt) { return hmSupportedTypes.containsKey(sExt.toLowerCase(Locale.getDefault())); } /** * Return type for a given extension. * * @param sExtension The extension to retrieve (without leading dot) * * @return the type by extension */ public Type getTypeByExtension(String sExtension) { return hmSupportedTypes.get(sExtension.toLowerCase(Locale.getDefault())); } /** * Return all music types. * * @return the all music types */ public List getAllMusicTypes() { List alResu = new ArrayList(5); Iterator it = hmSupportedTypes.values().iterator(); while (it.hasNext()) { Type type = it.next(); if (type.getBooleanValue(Const.XML_TYPE_IS_MUSIC)) { alResu.add(type); } } return alResu; } /** * Return a list "a,b,c" of registered extensions, used by FileChooser. * * @return the types as one string. */ public String getTypeListString() { if (hmSupportedTypes.isEmpty()) { return ""; } StringBuilder sb = new StringBuilder(); Iterator it = hmSupportedTypes.keySet().iterator(); while (it.hasNext()) { sb.append(it.next()); sb.append(','); } sb.deleteCharAt(sb.length() - 1); // remove last ',' return sb.toString(); } /* * (non-Javadoc) * * @see org.jajuk.base.ItemManager#getIdentifier() */ @Override public String getLabel() { return Const.XML_TYPES; } /** * Gets the type by id. * * @param sID Item ID * * @return item */ public Type getTypeByID(String sID) { return (Type) getItemByID(sID); } /** * Gets the types. * * @return types list */ @SuppressWarnings("unchecked") public List getTypes() { return (List) getItems(); } /** * Gets the types iterator. * * @return types iterator */ @SuppressWarnings("unchecked") public ReadOnlyIterator getTypesIterator() { return new ReadOnlyIterator((Iterator) getItemsIterator()); } /** * Convenient method to register all types when mplayer is not available *

    * Note that we use explicite strings for icon location. It's to avoid loading * all icons at startup, we do it asynchronously to accelerate startup *

    * * @throws ClassNotFoundException the class not found exception */ public static void registerTypesNoMplayer() throws ClassNotFoundException { // mp3 Type type = TypeManager.getInstance().registerType(Messages.getString("Type.mp3"), Const.EXT_MP3, Class.forName(Const.PLAYER_IMPL_JAVALAYER), Class.forName(Const.TAG_IMPL_JAUDIOTAGGER)); type.setProperty(Const.XML_TYPE_IS_MUSIC, true); type.setProperty(Const.XML_TYPE_SEEK_SUPPORTED, true); // Do not use IconLoader to get icon, it takes too much time to // load all icons type.setProperty(Const.XML_TYPE_ICON, UtilSystem.getResource(ICONS_16X16_TYPE_MP3) .toExternalForm()); // playlists type = TypeManager.getInstance().registerType(Messages.getString("Type.playlist"), Const.EXT_PLAYLIST, Class.forName(Const.PLAYER_IMPL_JAVALAYER), null); type.setProperty(Const.XML_TYPE_IS_MUSIC, false); type.setProperty(Const.XML_TYPE_SEEK_SUPPORTED, false); // Ogg vorbis type = TypeManager.getInstance().registerType(Messages.getString("Type.ogg"), Const.EXT_OGG, Class.forName(Const.PLAYER_IMPL_JAVALAYER), Class.forName(Const.TAG_IMPL_JAUDIOTAGGER)); type.setProperty(Const.XML_TYPE_IS_MUSIC, true); type.setProperty(Const.XML_TYPE_SEEK_SUPPORTED, false); type.setProperty(Const.XML_TYPE_ICON, UtilSystem.getResource(ICONS_16X16_TYPE_OGG) .toExternalForm()); // Wave type = TypeManager.getInstance().registerType(Messages.getString("Type.wav"), Const.EXT_WAV, Class.forName(Const.PLAYER_IMPL_JAVALAYER), Class.forName(Const.TAG_IMPL_NO_TAGS)); type.setProperty(Const.XML_TYPE_IS_MUSIC, true); type.setProperty(Const.XML_TYPE_SEEK_SUPPORTED, true); type.setProperty(Const.XML_TYPE_ICON, UtilSystem.getResource(ICONS_16X16_TYPE_WAV) .toExternalForm()); // au type = TypeManager.getInstance().registerType(Messages.getString("Type.au"), Const.EXT_AU, Class.forName(Const.PLAYER_IMPL_JAVALAYER), Class.forName(Const.TAG_IMPL_NO_TAGS)); type.setProperty(Const.XML_TYPE_IS_MUSIC, true); type.setProperty(Const.XML_TYPE_SEEK_SUPPORTED, false); type.setProperty(Const.XML_TYPE_ICON, UtilSystem.getResource(ICONS_16X16_TYPE_WAV) .toExternalForm()); } /** * Convenient method to register all types when mplayer is available. *

    * Note that we use explicite strings for icon location. It's to avoid loading * all icons at startup, we do it asynchronously to accelerate startup *

    * * @throws ClassNotFoundException the class not found exception * @throws Exception */ public static void registerTypesMplayerAvailable() throws ClassNotFoundException { // mp3 Type type = TypeManager.getInstance().registerType(Messages.getString("Type.mp3"), Const.EXT_MP3, Class.forName(Const.PLAYER_IMPL_MPLAYER), Class.forName(Const.TAG_IMPL_JAUDIOTAGGER)); type.setProperty(Const.XML_TYPE_IS_MUSIC, true); type.setProperty(Const.XML_TYPE_SEEK_SUPPORTED, true); type.setProperty(Const.XML_TYPE_ICON, UtilSystem.getResource(ICONS_16X16_TYPE_MP3) .toExternalForm()); // playlists type = TypeManager.getInstance().registerType(Messages.getString("Type.playlist"), Const.EXT_PLAYLIST, Class.forName(Const.PLAYER_IMPL_JAVALAYER), null); type.setProperty(Const.XML_TYPE_IS_MUSIC, false); type.setProperty(Const.XML_TYPE_SEEK_SUPPORTED, false); // Ogg vorbis type = TypeManager.getInstance().registerType(Messages.getString("Type.ogg"), Const.EXT_OGG, Class.forName(Const.PLAYER_IMPL_MPLAYER), Class.forName(Const.TAG_IMPL_JAUDIOTAGGER)); type.setProperty(Const.XML_TYPE_IS_MUSIC, true); type.setProperty(Const.XML_TYPE_SEEK_SUPPORTED, true); type.setProperty(Const.XML_TYPE_ICON, UtilSystem.getResource(ICONS_16X16_TYPE_OGG) .toExternalForm()); // Wav type = TypeManager.getInstance().registerType(Messages.getString("Type.wav"), Const.EXT_WAV, Class.forName(Const.PLAYER_IMPL_MPLAYER), Class.forName(Const.TAG_IMPL_NO_TAGS)); type.setProperty(Const.XML_TYPE_IS_MUSIC, true); type.setProperty(Const.XML_TYPE_SEEK_SUPPORTED, true); type.setProperty(Const.XML_TYPE_ICON, UtilSystem.getResource(ICONS_16X16_TYPE_WAV) .toExternalForm()); // au type = TypeManager.getInstance().registerType(Messages.getString("Type.au"), Const.EXT_AU, Class.forName(Const.PLAYER_IMPL_MPLAYER), Class.forName(Const.TAG_IMPL_NO_TAGS)); type.setProperty(Const.XML_TYPE_IS_MUSIC, true); type.setProperty(Const.XML_TYPE_SEEK_SUPPORTED, true); type.setProperty(Const.XML_TYPE_ICON, UtilSystem.getResource(ICONS_16X16_TYPE_WAV) .toExternalForm()); // aiff type = TypeManager.getInstance().registerType(Messages.getString("Type.aiff"), Const.EXT_AIFF, Class.forName(Const.PLAYER_IMPL_MPLAYER), Class.forName(Const.TAG_IMPL_NO_TAGS)); type.setProperty(Const.XML_TYPE_IS_MUSIC, true); type.setProperty(Const.XML_TYPE_SEEK_SUPPORTED, true); type.setProperty(Const.XML_TYPE_ICON, UtilSystem.getResource(ICONS_16X16_TYPE_WAV) .toExternalForm()); // aiff type = TypeManager.getInstance().registerType(Messages.getString("Type.aiff"), Const.EXT_AIF, Class.forName(Const.PLAYER_IMPL_MPLAYER), Class.forName(Const.TAG_IMPL_NO_TAGS)); type.setProperty(Const.XML_TYPE_IS_MUSIC, true); type.setProperty(Const.XML_TYPE_SEEK_SUPPORTED, true); type.setProperty(Const.XML_TYPE_ICON, UtilSystem.getResource(ICONS_16X16_TYPE_WAV) .toExternalForm()); // flac type = TypeManager.getInstance().registerType(Messages.getString("Type.flac"), Const.EXT_FLAC, Class.forName(Const.PLAYER_IMPL_MPLAYER), Class.forName(Const.TAG_IMPL_JAUDIOTAGGER)); type.setProperty(Const.XML_TYPE_IS_MUSIC, true); type.setProperty(Const.XML_TYPE_SEEK_SUPPORTED, true); type.setProperty(Const.XML_TYPE_ICON, UtilSystem.getResource(ICONS_16X16_TYPE_FLAC) .toExternalForm()); // WMA type = TypeManager.getInstance().registerType(Messages.getString("Type.wma"), Const.EXT_WMA, Class.forName(Const.PLAYER_IMPL_MPLAYER), Class.forName(Const.TAG_IMPL_JAUDIOTAGGER)); type.setProperty(Const.XML_TYPE_IS_MUSIC, true); type.setProperty(Const.XML_TYPE_SEEK_SUPPORTED, true); type.setProperty(Const.XML_TYPE_ICON, UtilSystem.getResource(ICONS_16X16_TYPE_WMA) .toExternalForm()); // M4A type = TypeManager.getInstance().registerType(Messages.getString("Type.aac"), Const.EXT_M4A, Class.forName(Const.PLAYER_IMPL_MPLAYER), Class.forName(Const.TAG_IMPL_JAUDIOTAGGER)); type.setProperty(Const.XML_TYPE_IS_MUSIC, true); type.setProperty(Const.XML_TYPE_SEEK_SUPPORTED, true); type.setProperty(Const.XML_TYPE_ICON, UtilSystem.getResource(ICONS_16X16_TYPE_AAC) .toExternalForm()); // Real audio (.rm) type = TypeManager.getInstance().registerType(Messages.getString("Type.real"), Const.EXT_REAL_RM, Class.forName(Const.PLAYER_IMPL_MPLAYER), Class.forName(Const.TAG_IMPL_JAUDIOTAGGER)); type.setProperty(Const.XML_TYPE_IS_MUSIC, true); type.setProperty(Const.XML_TYPE_SEEK_SUPPORTED, true); type.setProperty(Const.XML_TYPE_ICON, UtilSystem.getResource(ICONS_16X16_TYPE_RAM) .toExternalForm()); // Real audio (.ra) type = TypeManager.getInstance().registerType(Messages.getString("Type.real"), Const.EXT_REAL_RA, Class.forName(Const.PLAYER_IMPL_MPLAYER), Class.forName(Const.TAG_IMPL_JAUDIOTAGGER)); type.setProperty(Const.XML_TYPE_IS_MUSIC, true); type.setProperty(Const.XML_TYPE_SEEK_SUPPORTED, true); type.setProperty(Const.XML_TYPE_ICON, UtilSystem.getResource(ICONS_16X16_TYPE_RAM) .toExternalForm()); // mp2 type = TypeManager.getInstance().registerType(Messages.getString("Type.mp2"), Const.EXT_MP2, Class.forName(Const.PLAYER_IMPL_MPLAYER), Class.forName(Const.TAG_IMPL_NO_TAGS)); type.setProperty(Const.XML_TYPE_IS_MUSIC, true); type.setProperty(Const.XML_TYPE_SEEK_SUPPORTED, true); type.setProperty(Const.XML_TYPE_ICON, UtilSystem.getResource(ICONS_16X16_TYPE_MP2) .toExternalForm()); // web radios type = TypeManager.getInstance().registerType(Messages.getString("Type.radio"), Const.EXT_RADIO, Class.forName(Const.PLAYER_IMPL_WEBRADIOS), Class.forName(Const.TAG_IMPL_NO_TAGS)); type.setProperty(Const.XML_TYPE_IS_MUSIC, true); type.setProperty(Const.XML_TYPE_SEEK_SUPPORTED, true); // APE type = TypeManager.getInstance().registerType(Messages.getString("Type.ape"), Const.EXT_APE, Class.forName(Const.PLAYER_IMPL_MPLAYER), Class.forName(Const.TAG_IMPL_NO_TAGS)); type.setProperty(Const.XML_TYPE_IS_MUSIC, true); type.setProperty(Const.XML_TYPE_SEEK_SUPPORTED, Const.TRUE); type.setProperty(Const.XML_TYPE_ICON, UtilSystem.getResource(ICONS_16X16_TYPE_APE) .toExternalForm()); // MAC = APE type = TypeManager.getInstance().registerType(Messages.getString("Type.mac"), Const.EXT_MAC, Class.forName(Const.PLAYER_IMPL_MPLAYER), Class.forName(Const.TAG_IMPL_NO_TAGS)); type.setProperty(Const.XML_TYPE_IS_MUSIC, true); type.setProperty(Const.XML_TYPE_SEEK_SUPPORTED, Const.TRUE); type.setProperty(Const.XML_TYPE_ICON, UtilSystem.getResource(ICONS_16X16_TYPE_APE) .toExternalForm()); // MPC type = TypeManager.getInstance().registerType(Messages.getString("Type.mpc"), Const.EXT_MPC, Class.forName(Const.PLAYER_IMPL_MPLAYER), Class.forName(Const.TAG_IMPL_NO_TAGS)); type.setProperty(Const.XML_TYPE_IS_MUSIC, true); type.setProperty(Const.XML_TYPE_SEEK_SUPPORTED, Const.TRUE); // Change the MPC icon here if you find one type.setProperty(Const.XML_TYPE_ICON, UtilSystem.getResource(ICONS_16X16_TYPE_MP3) .toExternalForm()); // MP+ type = TypeManager.getInstance().registerType(Messages.getString("Type.mpc"), Const.EXT_MPPLUS, Class.forName(Const.PLAYER_IMPL_MPLAYER), Class.forName(Const.TAG_IMPL_NO_TAGS)); type.setProperty(Const.XML_TYPE_IS_MUSIC, true); type.setProperty(Const.XML_TYPE_SEEK_SUPPORTED, Const.TRUE); // Change the MPC icon here if you find one type.setProperty(Const.XML_TYPE_ICON, UtilSystem.getResource(ICONS_16X16_TYPE_MP3) .toExternalForm()); // MPP type = TypeManager.getInstance().registerType(Messages.getString("Type.mpc"), Const.EXT_MPP, Class.forName(Const.PLAYER_IMPL_MPLAYER), Class.forName(Const.TAG_IMPL_NO_TAGS)); type.setProperty(Const.XML_TYPE_IS_MUSIC, true); type.setProperty(Const.XML_TYPE_SEEK_SUPPORTED, Const.TRUE); // Change the MPC icon here if you find one type.setProperty(Const.XML_TYPE_ICON, UtilSystem.getResource(ICONS_16X16_TYPE_MP3) .toExternalForm()); // WavPack type = TypeManager.getInstance().registerType(Messages.getString("Type.wavpack"), Const.EXT_WV, Class.forName(Const.PLAYER_IMPL_MPLAYER), Class.forName(Const.TAG_IMPL_NO_TAGS)); type.setProperty(Const.XML_TYPE_IS_MUSIC, true); type.setProperty(Const.XML_TYPE_SEEK_SUPPORTED, Const.TRUE); // Official logo contains text and doesn't display well in 16x16, take wav // logo type.setProperty(Const.XML_TYPE_ICON, UtilSystem.getResource(ICONS_16X16_TYPE_WAV) .toExternalForm()); // -- VIDEO -- // AVI type = TypeManager.getInstance().registerType(Messages.getString(Const.TYPE_VIDEO), Const.EXT_AVI, Class.forName(Const.PLAYER_IMPL_MPLAYER), Class.forName(Const.TAG_IMPL_NO_TAGS)); type.setProperty(Const.XML_TYPE_IS_MUSIC, true); type.setProperty(Const.XML_TYPE_SEEK_SUPPORTED, Const.TRUE); type.setProperty(Const.XML_TYPE_ICON, UtilSystem.getResource(ICON_16X16_VIDEO).toExternalForm()); // mpg type = TypeManager.getInstance().registerType(Messages.getString(Const.TYPE_VIDEO), Const.EXT_MPG, Class.forName(Const.PLAYER_IMPL_MPLAYER), Class.forName(Const.TAG_IMPL_NO_TAGS)); type.setProperty(Const.XML_TYPE_IS_MUSIC, true); type.setProperty(Const.XML_TYPE_SEEK_SUPPORTED, Const.TRUE); type.setProperty(Const.XML_TYPE_ICON, UtilSystem.getResource(ICON_16X16_VIDEO).toExternalForm()); // MP4 type = TypeManager.getInstance().registerType(Messages.getString(Const.TYPE_VIDEO), Const.EXT_MP4, Class.forName(Const.PLAYER_IMPL_MPLAYER), Class.forName(Const.TAG_IMPL_JAUDIOTAGGER)); type.setProperty(Const.XML_TYPE_IS_MUSIC, true); type.setProperty(Const.XML_TYPE_SEEK_SUPPORTED, Const.TRUE); type.setProperty(Const.XML_TYPE_ICON, UtilSystem.getResource(ICON_16X16_VIDEO).toExternalForm()); // mpeg type = TypeManager.getInstance().registerType(Messages.getString(Const.TYPE_VIDEO), Const.EXT_MPEG, Class.forName(Const.PLAYER_IMPL_MPLAYER), Class.forName(Const.TAG_IMPL_NO_TAGS)); type.setProperty(Const.XML_TYPE_IS_MUSIC, true); type.setProperty(Const.XML_TYPE_SEEK_SUPPORTED, Const.TRUE); type.setProperty(Const.XML_TYPE_ICON, UtilSystem.getResource(ICON_16X16_VIDEO).toExternalForm()); // mkv type = TypeManager.getInstance().registerType(Messages.getString(Const.TYPE_VIDEO), Const.EXT_MKV, Class.forName(Const.PLAYER_IMPL_MPLAYER), Class.forName(Const.TAG_IMPL_NO_TAGS)); type.setProperty(Const.XML_TYPE_IS_MUSIC, true); type.setProperty(Const.XML_TYPE_SEEK_SUPPORTED, Const.TRUE); type.setProperty(Const.XML_TYPE_ICON, UtilSystem.getResource(ICON_16X16_VIDEO).toExternalForm()); // asf type = TypeManager.getInstance().registerType(Messages.getString(Const.TYPE_VIDEO), Const.EXT_ASF, Class.forName(Const.PLAYER_IMPL_MPLAYER), Class.forName(Const.TAG_IMPL_NO_TAGS)); type.setProperty(Const.XML_TYPE_IS_MUSIC, true); type.setProperty(Const.XML_TYPE_SEEK_SUPPORTED, Const.TRUE); type.setProperty(Const.XML_TYPE_ICON, UtilSystem.getResource(ICON_16X16_VIDEO).toExternalForm()); // wmv type = TypeManager.getInstance().registerType(Messages.getString(Const.TYPE_VIDEO), Const.EXT_WMV, Class.forName(Const.PLAYER_IMPL_MPLAYER), Class.forName(Const.TAG_IMPL_NO_TAGS)); type.setProperty(Const.XML_TYPE_IS_MUSIC, true); type.setProperty(Const.XML_TYPE_SEEK_SUPPORTED, Const.TRUE); type.setProperty(Const.XML_TYPE_ICON, UtilSystem.getResource(ICON_16X16_VIDEO).toExternalForm()); // mov type = TypeManager.getInstance().registerType(Messages.getString(Const.TYPE_VIDEO), Const.EXT_MOV, Class.forName(Const.PLAYER_IMPL_MPLAYER), Class.forName(Const.TAG_IMPL_NO_TAGS)); type.setProperty(Const.XML_TYPE_IS_MUSIC, true); type.setProperty(Const.XML_TYPE_SEEK_SUPPORTED, Const.TRUE); type.setProperty(Const.XML_TYPE_ICON, UtilSystem.getResource(ICON_16X16_VIDEO).toExternalForm()); // ogm type = TypeManager.getInstance().registerType(Messages.getString(Const.TYPE_VIDEO), Const.EXT_OGM, Class.forName(Const.PLAYER_IMPL_MPLAYER), Class.forName(Const.TAG_IMPL_NO_TAGS)); type.setProperty(Const.XML_TYPE_IS_MUSIC, true); type.setProperty(Const.XML_TYPE_SEEK_SUPPORTED, Const.TRUE); type.setProperty(Const.XML_TYPE_ICON, UtilSystem.getResource(ICON_16X16_VIDEO).toExternalForm()); // FLV - Flash Movie type = TypeManager.getInstance().registerType(Messages.getString(Const.TYPE_VIDEO), Const.EXT_FLV, Class.forName(Const.PLAYER_IMPL_MPLAYER), Class.forName(Const.TAG_IMPL_NO_TAGS)); type.setProperty(Const.XML_TYPE_IS_MUSIC, true); type.setProperty(Const.XML_TYPE_SEEK_SUPPORTED, Const.TRUE); type.setProperty(Const.XML_TYPE_ICON, UtilSystem.getResource(ICON_16X16_VIDEO).toExternalForm()); } /* * (non-Javadoc) * * @see org.jajuk.base.ItemManager#clear() */ @Override public void clear() { lock.writeLock().lock(); try { hmSupportedTypes.clear(); super.clear(); } finally { lock.writeLock().unlock(); } } } jajuk-1.9.6.orig/src/main/java/org/jajuk/base/AlbumArtistManager.java0000644000175000017500000001546411720500104025314 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.base; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.Vector; import org.jajuk.events.JajukEvent; import org.jajuk.events.JajukEvents; import org.jajuk.events.ObservationManager; import org.jajuk.services.players.QueueModel; import org.jajuk.util.Const; import org.jajuk.util.error.JajukException; /** * Convenient class to manage album-artists. */ public final class AlbumArtistManager extends ItemManager { /** Self instance. */ private static AlbumArtistManager singleton = new AlbumArtistManager(); /** List of all known album-artists. */ private static Vector albumArtistsList = new Vector(100); // NOPMD /** * No constructor available, only static access. */ private AlbumArtistManager() { super(); // register properties // ID registerProperty(new PropertyMetaInformation(Const.XML_ID, false, true, false, false, false, String.class, null)); // Name registerProperty(new PropertyMetaInformation(Const.XML_NAME, false, true, true, true, false, String.class, null)); // Expand registerProperty(new PropertyMetaInformation(Const.XML_EXPANDED, false, false, false, false, true, Boolean.class, false)); } /** * Gets the instance. * * @return singleton */ public static AlbumArtistManager getInstance() { return singleton; } /** * Register an albumArtist. * * @param sName The name of the albumArtist to search for. * * @return the albumArtist */ public AlbumArtist registerAlbumArtist(String sName) { String sId = createID(sName); return registerAlbumArtist(sId, sName); } /** * Register an albumArtist with a known id. * * @param sId the ID of the new albumArtist. * @param sName The name of the new albumArtist. * @return the albumArtist */ public synchronized AlbumArtist registerAlbumArtist(String sId, String sName) { AlbumArtist albumArtist = getAlbumArtistByID(sId); // if we have this albumArtist already, simply return the existing one if (albumArtist != null) { return albumArtist; } albumArtist = new AlbumArtist(sId, sName); registerItem(albumArtist); // add it in genres list if new if (!albumArtistsList.contains(sName)) { albumArtistsList.add(albumArtist.getName2()); // Sort items ignoring case Collections.sort(albumArtistsList, new Comparator() { @Override public int compare(String o1, String o2) { return o1.compareToIgnoreCase(o2); } }); } return albumArtist; } /** * Change the item name. * * @param old The name of the albumArtist to update. * @param sNewName The new name of the albumArtist. * * @return The new Album-Instance. * * @throws JajukException Thrown if adjusting the name fails for some reason. */ public AlbumArtist changeAlbumArtistName(AlbumArtist old, String sNewName) throws JajukException { synchronized (TrackManager.getInstance()) { // check there is actually a change if (old.getName2().equals(sNewName)) { return old; } // find out if the QueueModel is playing this track before we change the track! boolean queueNeedsUpdate = false; if (QueueModel.getPlayingFile() != null && QueueModel.getPlayingFile().getTrack().getAlbumArtist().equals(old)) { queueNeedsUpdate = true; } AlbumArtist newItem = registerAlbumArtist(sNewName); // re apply old properties from old item newItem.cloneProperties(old); // update tracks for (Track track : TrackManager.getInstance().getTracks()) { if (track.getAlbumArtist().equals(old)) { TrackManager.getInstance().changeTrackAlbumArtist(track, sNewName, null); } } // if current track albumArtist name is changed, notify it if (queueNeedsUpdate) { // We use the same event than for artists to keep things simple ObservationManager.notify(new JajukEvent(JajukEvents.ARTIST_CHANGED)); } return newItem; } } /* * (non-Javadoc) * * @see org.jajuk.base.ItemManager#getIdentifier() */ @Override public String getLabel() { return Const.XML_ALBUM_ARTISTS; } /** * Gets the albumArtists list. * * @return albumArtists as a string list (used for albumArtists combos) */ public static Vector getAlbumArtistsList() { return albumArtistsList; } /** * Gets the albumArtist by id. * * @param sID Item ID * * @return Element */ public AlbumArtist getAlbumArtistByID(String sID) { return (AlbumArtist) getItemByID(sID); } /** * Gets the albumArtists. * * @return ordered albums list */ @SuppressWarnings("unchecked") public List getAlbumArtists() { return (List) getItems(); } /** * Get ordered list of albumArtists associated with this item. * * @param item The albumArtist-item to look for. * * @return the associated albumArtists */ public synchronized List getAssociatedAlbumArtists(Item item) { List out; if (item instanceof Track) { out = new ArrayList(1); out.add(((Track) item).getAlbumArtist()); } else { // [Perf] If item is a track, just return its album-artist // Use a set to avoid dups Set albumArtistSet = new HashSet(); List tracks = TrackManager.getInstance().getAssociatedTracks(item, true); for (Track track : tracks) { albumArtistSet.add(track.getAlbumArtist()); } out = new ArrayList(albumArtistSet); Collections.sort(out); } return out; } } jajuk-1.9.6.orig/src/main/java/org/jajuk/base/Device.java0000644000175000017500000011214511720500104022763 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.base; import java.io.File; import java.io.FileFilter; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; import javax.swing.ImageIcon; import javax.swing.JOptionPane; import javax.swing.SwingUtilities; import org.apache.commons.lang.StringUtils; import org.jajuk.events.JajukEvent; import org.jajuk.events.JajukEvents; import org.jajuk.events.ObservationManager; import org.jajuk.services.bookmark.History; import org.jajuk.services.core.ExitService; import org.jajuk.services.core.SessionService; import org.jajuk.services.players.QueueModel; import org.jajuk.ui.helpers.ManualDeviceRefreshReporter; import org.jajuk.ui.helpers.RefreshReporter; import org.jajuk.ui.widgets.InformationJPanel; import org.jajuk.util.Conf; import org.jajuk.util.Const; import org.jajuk.util.IconLoader; import org.jajuk.util.JajukFileFilter; import org.jajuk.util.JajukIcons; import org.jajuk.util.Messages; import org.jajuk.util.UtilGUI; import org.jajuk.util.UtilString; import org.jajuk.util.UtilSystem; import org.jajuk.util.error.JajukException; import org.jajuk.util.filters.ImageFilter; import org.jajuk.util.filters.KnownTypeFilter; import org.jajuk.util.log.Log; import org.xml.sax.Attributes; /** * A device ( music files repository ) *

    * Some properties of a device are immuatable : name, url and type * *

    * Physical item. */ public class Device extends PhysicalItem implements Comparable { /** The Constant OPTION_REFRESH_DEEP. DOCUMENT_ME */ protected static final int OPTION_REFRESH_DEEP = 1; /** The Constant OPTION_REFRESH_CANCEL. DOCUMENT_ME */ protected static final int OPTION_REFRESH_CANCEL = 2; // Device type constants // Note: these need to correspond with the static array in @see // org.jajuk.base.DeviceManager !! /** The Constant TYPE_DIRECTORY. DOCUMENT_ME */ public static final int TYPE_DIRECTORY = 0; /** The Constant TYPE_CD. DOCUMENT_ME */ public static final int TYPE_CD = 1; /** The Constant TYPE_NETWORK_DRIVE. DOCUMENT_ME */ public static final int TYPE_NETWORK_DRIVE = 2; /** The Constant TYPE_EXT_DD. DOCUMENT_ME */ public static final int TYPE_EXT_DD = 3; /** The Constant TYPE_PLAYER. DOCUMENT_ME */ public static final int TYPE_PLAYER = 4; /** Device URL (performances). */ private String sUrl; /** IO file for optimizations*. */ private java.io.File fio; /** Mounted device flag. */ private boolean bMounted = false; /** directories. */ private final List alDirectories = new ArrayList(20); /** Already refreshing flag. */ private volatile boolean bAlreadyRefreshing = false; /** Already synchronizing flag. */ private volatile boolean bAlreadySynchronizing = false; /** Volume of created files during synchronization. */ private long lVolume = 0; /** date last refresh. */ private long lDateLastRefresh; /** Progress reporter *. */ private RefreshReporter reporter; /** Refresh deepness choice *. */ private int choice = Device.OPTION_REFRESH_DEEP; /** [PERF] cache rootDir directory */ private Directory rootDir; /** * Device constructor. * * @param sId DOCUMENT_ME * @param sName DOCUMENT_ME */ Device(final String sId, final String sName) { super(sId, sName); } /** * Adds the directory. * * @param directory DOCUMENT_ME */ public void addDirectory(final Directory directory) { alDirectories.add(directory); } /** * Scan directories to cleanup removed files and playlists. * * @param dirsToRefresh list of the directory to refresh, null if all of them * * @return whether some items have been removed */ public boolean cleanRemovedFiles(List dirsToRefresh) { long l = System.currentTimeMillis(); // directories cleanup boolean bChanges = cleanDirectories(dirsToRefresh); // files cleanup bChanges = bChanges | cleanFiles(dirsToRefresh); // Playlist cleanup bChanges = bChanges | cleanPlaylist(dirsToRefresh); // clear history to remove old files referenced in it if (Conf.getString(Const.CONF_HISTORY) != null) { History.getInstance().clear(Integer.parseInt(Conf.getString(Const.CONF_HISTORY))); } // delete old history items l = System.currentTimeMillis() - l; Log.debug("{{" + getName() + "}} Old file references cleaned in: " + ((l < 1000) ? l + " ms" : l / 1000 + " s, changes: " + bChanges)); return bChanges; } /** * Walk through all Playlists and remove the ones for the current device. * * @param dirsToRefresh list of the directory to refresh, null if all of them * * @return true if there was any playlist removed */ private boolean cleanPlaylist(List dirsToRefresh) { boolean bChanges = false; final List plfiles = PlaylistManager.getInstance().getPlaylists(); for (final Playlist plf : plfiles) { // check if it is a playlist located inside refreshed directory if (dirsToRefresh != null) { boolean checkIt = false; for (Directory directory : dirsToRefresh) { if (plf.hasAncestor(directory)) { checkIt = true; } } // This item is not in given directories, just continue if (!checkIt) { continue; } } if (!ExitService.isExiting() && plf.getDirectory().getDevice().equals(this) && plf.isReady() && !plf.getFIO().exists()) { PlaylistManager.getInstance().removeItem(plf); Log.debug("Removed: " + plf); bChanges = true; } } return bChanges; } /** * Walk through tall Files and remove the ones for the current device. * * @param dirsToRefresh list of the directory to refresh, null if all of them * * @return true if there was any file removed. */ private boolean cleanFiles(List dirsToRefresh) { boolean bChanges = false; final List files = FileManager.getInstance().getFiles(); for (final org.jajuk.base.File file : files) { // check if it is a file located inside refreshed directory if (dirsToRefresh != null) { boolean checkIt = false; for (Directory directory : dirsToRefresh) { if (file.hasAncestor(directory)) { checkIt = true; } } // This item is not in given directories, just continue if (!checkIt) { continue; } } if (!ExitService.isExiting() && file.getDirectory().getDevice().equals(this) && file.isReady() && // Remove file if it doesn't exist any more or if it is a iTunes // file (useful for jajuk < 1.4) (!file.getFIO().exists() || file.getName().startsWith("._"))) { FileManager.getInstance().removeFile(file); Log.debug("Removed: " + file); bChanges = true; } } return bChanges; } /** * Walks through all directories and removes the ones for this device. * * @param dirsToRefresh list of the directory to refresh, null if all of them * * @return true if there was any directory removed */ private boolean cleanDirectories(List dirsToRefresh) { boolean bChanges = false; // need to use a shallow copy to avoid concurrent exceptions List dirs = null; if (dirsToRefresh == null) { dirs = DirectoryManager.getInstance().getDirectories(); } else { dirs = dirsToRefresh; } for (final Directory dir : dirs) { if (!ExitService.isExiting() && dir.getDevice().equals(this) && dir.getDevice().isMounted() && !dir.getFio().exists()) { // note that associated files are removed too DirectoryManager.getInstance().removeDirectory(dir.getID()); Log.debug("Removed: " + dir); bChanges = true; } } return bChanges; } /** * Alphabetical comparator used to display ordered lists of devices. * * @param otherDevice DOCUMENT_ME * * @return comparison result */ @Override public int compareTo(final Device otherDevice) { // should handle null if (otherDevice == null) { return -1; } // We must be consistent with equals, see // http://java.sun.com/javase/6/docs/api/java/lang/Comparable.html int comp = getName().compareToIgnoreCase(otherDevice.getName()); if (comp == 0) { return getName().compareTo(otherDevice.getName()); } else { return comp; } } /** * Gets the date last refresh. * * @return the date last refresh */ public long getDateLastRefresh() { return lDateLastRefresh; } /** * Get item description. * * @return the desc */ @Override public String getDesc() { return Messages.getString("Item_Device") + " : " + getName(); } /** * Gets the device type s. * * @return the device type s */ public String getDeviceTypeS() { return DeviceManager.getInstance().getDeviceType(getType()); } /** * Gets the directories directly under the device root (not recursive). * * @return the directories */ public List getDirectories() { return alDirectories; } /** * return ordered child files recursively. * * @return child files recursively */ public List getFilesRecursively() { // looks for the root directory for this device Directory dirRoot = getRootDirectory(); if (dirRoot != null) { return dirRoot.getFilesRecursively(); } // nothing found, return empty list return new ArrayList(); } /** * Gets the fio. * * @return Returns the IO file reference to this directory. */ public File getFio() { return fio; } /* * (non-Javadoc) * * @see org.jajuk.base.Item#getHumanValue(java.lang.String) */ @Override public String getHumanValue(final String sKey) { if (Const.XML_TYPE.equals(sKey)) { final long lType = getLongValue(sKey); return DeviceManager.getInstance().getDeviceType(lType); } else {// default return super.getHumanValue(sKey); } } /* * (non-Javadoc) * * @see org.jajuk.base.Item#getIconRepresentation() */ @Override public ImageIcon getIconRepresentation() { switch ((int) getType()) { case 0: return setIcon(IconLoader.getIcon(JajukIcons.DEVICE_DIRECTORY_MOUNTED_SMALL), IconLoader.getIcon(JajukIcons.DEVICE_DIRECTORY_UNMOUNTED_SMALL)); case 1: return setIcon(IconLoader.getIcon(JajukIcons.DEVICE_CD_MOUNTED_SMALL), IconLoader.getIcon(JajukIcons.DEVICE_CD_UNMOUNTED_SMALL)); case 2: return setIcon(IconLoader.getIcon(JajukIcons.DEVICE_NETWORK_DRIVE_MOUNTED_SMALL), IconLoader.getIcon(JajukIcons.DEVICE_NETWORK_DRIVE_UNMOUNTED_SMALL)); case 3: return setIcon(IconLoader.getIcon(JajukIcons.DEVICE_EXT_DD_MOUNTED_SMALL), IconLoader.getIcon(JajukIcons.DEVICE_EXT_DD_UNMOUNTED_SMALL)); case 4: return setIcon(IconLoader.getIcon(JajukIcons.DEVICE_PLAYER_MOUNTED_SMALL), IconLoader.getIcon(JajukIcons.DEVICE_PLAYER_UNMOUNTED_SMALL)); default: Log.warn("Unknown type of device detected: " + getType()); return null; } } /** * Sets the icon. * * @param mountedIcon The icon to return for a mounted device * @param unmountedIcon The icon to return for an unmounted device * * @return Returns either of the two provided icons depending on the state of * the device */ private ImageIcon setIcon(ImageIcon mountedIcon, ImageIcon unmountedIcon) { if (isMounted()) { return mountedIcon; } else { return unmountedIcon; } } /* * (non-Javadoc) * * @see org.jajuk.base.Item#getIdentifier() */ @Override public final String getLabel() { return Const.XML_DEVICE; } /** * Gets the root directory. * * @return Associated root directory */ public Directory getRootDirectory() { if (rootDir == null) { rootDir = DirectoryManager.getInstance().getDirectoryForIO(getFio(), this); } return rootDir; } /** * Gets the type. * * @return the type */ public long getType() { return getLongValue(Const.XML_TYPE); } /** * Gets the url. * * @return the url */ public String getUrl() { return sUrl; } /** * Checks if is mounted. * * @return true, if is mounted */ public boolean isMounted() { return bMounted; } /** * Return true if the device can be accessed right now. * * @return true the file can be accessed right now */ public boolean isReady() { if (isMounted() && !isRefreshing() && !isSynchronizing()) { return true; } return false; } /** * Tells if a device is refreshing. * * @return true, if checks if is refreshing */ public boolean isRefreshing() { return bAlreadyRefreshing; } /** * Tells if a device is synchronizing. * * @return true, if checks if is synchronizing */ public boolean isSynchronizing() { return bAlreadySynchronizing; } /** * Manual refresh, displays a dialog. * * @param bAsk ask for refreshing type (deep or fast ?) * @param bAfterMove is this refresh done after a device location change ? * @param forcedDeep : override bAsk and force a deep refresh * @param dirsToRefresh : only refresh specified dirs, or all of them if null */ public void manualRefresh(final boolean bAsk, final boolean bAfterMove, final boolean forcedDeep, List dirsToRefresh) { int i = 0; try { i = prepareRefresh(bAsk); if (i == OPTION_REFRESH_CANCEL) { return; } bAlreadyRefreshing = true; } catch (JajukException je) { Messages.showErrorMessage(je.getCode()); Log.debug(je); return; } try { reporter = new ManualDeviceRefreshReporter(this); reporter.startup(); // clean old files up (takes a while) if (!bAfterMove) { cleanRemovedFiles(dirsToRefresh); } reporter.cleanupDone(); // Actual refresh refreshCommand(((i == Device.OPTION_REFRESH_DEEP) || forcedDeep), true, dirsToRefresh); // if it is a move, clean old files *after* the refresh if (bAfterMove) { cleanRemovedFiles(dirsToRefresh); } // notify views to refresh ObservationManager.notify(new JajukEvent(JajukEvents.DEVICE_REFRESH)); // Commit collection at each refresh (can be useful if // application // is closed brutally with control-C or shutdown and that // exit hook has no time to perform commit). // But don't commit when any device is refreshing to avoid collisions. if (!DeviceManager.getInstance().isAnyDeviceRefreshing()) { try { org.jajuk.base.Collection.commit(SessionService.getConfFileByPath(Const.FILE_COLLECTION)); } catch (final IOException e) { Log.error(e); } } } finally { // Do not let current reporter as a manual reporter because it would fail // in NPE with auto-refresh reporter = null; // Make sure to unlock refreshing bAlreadyRefreshing = false; } } /** * Prepare manual refresh. * * @param bAsk DOCUMENT_ME * * @return the user choice (deep or fast) * * @throws JajukException if user canceled, device cannot be refreshed or device already * refreshing */ public int prepareRefresh(final boolean bAsk) throws JajukException { if (bAsk) { final Object[] possibleValues = { Messages.getString("FilesTreeView.60"),// fast Messages.getString("FilesTreeView.61"),// deep Messages.getString("Cancel") };// cancel try { SwingUtilities.invokeAndWait(new Runnable() { @Override public void run() { choice = JOptionPane.showOptionDialog(null, Messages.getString("FilesTreeView.59"), Messages.getString("Option"), JOptionPane.DEFAULT_OPTION, JOptionPane.QUESTION_MESSAGE, null, possibleValues, possibleValues[0]); } }); } catch (Exception e) { Log.error(e); choice = Device.OPTION_REFRESH_CANCEL; } if (choice == Device.OPTION_REFRESH_CANCEL) { // Cancel return choice; } } // JajukException are not trapped, will be thrown to the caller final Device device = this; if (!device.isMounted()) { // Leave if user canceled device mounting if (!device.mount(true)) { return Device.OPTION_REFRESH_CANCEL; } } if (bAlreadyRefreshing) { throw new JajukException(107); } return choice; } /** * Check that the device is available and not void. * * @param bManual manual or automatic refresh ? * * @return true if the device is ready for mounting, false if the device is void * * @throws JajukException if the device is not accessible */ private boolean checkDevice(boolean bManual) throws JajukException { final File file = new File(getUrl()); if (!file.exists()) { throw new JajukException(11, "\"" + getName() + "\" at URL : " + getUrl()); } /* * Cannot mount void devices because of the jajuk reference cleanup thread * ( a refresh would clear the entire device collection) */ if (file.listFiles() == null || file.listFiles().length == 0) { if (bManual) { final int answer = Messages.getChoice( "[" + getName() + "] " + Messages.getString("Confirmation_void_refresh"), JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE); // leave if user doesn't confirm to mount the void device return (answer == JOptionPane.YES_OPTION); } else { // In auto mode, never mount a void device return false; } } else { // Device is not void return true; } } /** * Mount the device. * * @param bManual set whether mount is manual or auto * * @return whether the device has been mounted * * @throws JajukException if device cannot be mounted */ public boolean mount(final boolean bManual) throws JajukException { if (bMounted) { throw new JajukException(111); } // Check if we can mount the device. It can throw a JajukException if void or unavailable // device boolean readyToMount = checkDevice(bManual); // Effective mounting if available. if (readyToMount) { bMounted = true; } // notify views to refresh if needed ObservationManager.notify(new JajukEvent(JajukEvents.DEVICE_MOUNT)); return bMounted; } /** * Set all personal properties of an XML file for an item (doesn't overwrite * existing properties for perfs). * * @param attributes : * list of attributes for this XML item */ @Override public void populateProperties(final Attributes attributes) { for (int i = 0; i < attributes.getLength(); i++) { final String sProperty = attributes.getQName(i); if (!getProperties().containsKey(sProperty)) { String sValue = attributes.getValue(i); final PropertyMetaInformation meta = getMeta(sProperty); // compatibility code for <1.1 : auto-refresh is now a double, // no more a boolean if (meta.getName().equals(Const.XML_DEVICE_AUTO_REFRESH) && (sValue.equalsIgnoreCase(Const.TRUE) || sValue.equalsIgnoreCase(Const.FALSE))) { switch ((int) getType()) { case TYPE_DIRECTORY: // directory sValue = "0.5d"; break; case TYPE_CD: // file cd sValue = "0d"; break; case TYPE_NETWORK_DRIVE: // network drive sValue = "0d"; break; case TYPE_EXT_DD: // ext dd sValue = "3d"; break; case TYPE_PLAYER: // player sValue = "3d"; break; } } try { setProperty(sProperty, UtilString.parse(sValue, meta.getType())); } catch (final Exception e) { Log.error(137, sProperty, e); } } } } /** * Refresh : scan the device to find tracks. * This method is only called from GUI. auto-refresh uses refreshCommand() directly. * * @param bAsynchronous : * set asynchronous or synchronous mode * @param bAsk whether we ask for fast/deep scan * @param bAfterMove whether this is called after a device move * @param dirsToRefresh : only refresh specified dirs, or all of them if null */ public void refresh(final boolean bAsynchronous, final boolean bAsk, final boolean bAfterMove, final List dirsToRefresh) { if (bAsynchronous) { final Thread t = new Thread("Device Refresh Thread for : " + name) { @Override public void run() { manualRefresh(bAsk, bAfterMove, false, dirsToRefresh); } }; t.setPriority(Thread.MIN_PRIORITY); t.start(); } else { manualRefresh(bAsk, bAfterMove, false, dirsToRefresh); } } /** * Deep / full Refresh with GUI. */ public void manualRefreshDeep() { final Thread t = new Thread("Device Deep Refresh Thread for : " + name) { @Override public void run() { manualRefresh(false, false, true, null); } }; t.setPriority(Thread.MIN_PRIORITY); t.start(); } /** * The refresh itself. * * @param bDeepScan whether it is a deep refresh request or only fast * @param bManual whether it is a manual refresh or auto * @param dirsToRefresh list of the directory to refresh, null if all of them * * @return true if some changes occurred in device */ public synchronized boolean refreshCommand(final boolean bDeepScan, final boolean bManual, List dirsToRefresh) { try { // Check if this device is mounted (useful when called by // automatic refresh) if (!isMounted()) { return false; } // Check that device is still available boolean readyToMount = checkDevice(bManual); if (!readyToMount) { return false; } bAlreadyRefreshing = true; // reporter is already set in case of manual refresh if (reporter == null) { reporter = new RefreshReporter(this); } // Notify the reporter of the actual refresh startup reporter.refreshStarted(); lDateLastRefresh = System.currentTimeMillis(); // check Jajuk is not exiting because a refresh cannot start in // this state if (ExitService.isExiting()) { return false; } int iNbFilesBeforeRefresh = FileManager.getInstance().getElementCount(); int iNbDirsBeforeRefresh = DirectoryManager.getInstance().getElementCount(); int iNbPlaylistsBeforeRefresh = PlaylistManager.getInstance().getElementCount(); if (bDeepScan && Log.isDebugEnabled()) { Log.debug("Starting refresh of device : " + this); } // Create a directory for device itself and scan files to allow // files at the root of the device final Directory top = DirectoryManager.getInstance().registerDirectory(this); if (!getDirectories().contains(top)) { addDirectory(top); } // Start actual scan List dirs = null; if (dirsToRefresh == null) { // No directory specified ? refresh the top directory dirs = new ArrayList(1); dirs.add(top); } else { dirs = dirsToRefresh; } for (Directory dir : dirs) { scanRecursively(dir, bDeepScan); } // Force a GUI refresh if new files or directories discovered or have been // removed if (((FileManager.getInstance().getElementCount() - iNbFilesBeforeRefresh) != 0) || ((DirectoryManager.getInstance().getElementCount() - iNbDirsBeforeRefresh) != 0) || ((PlaylistManager.getInstance().getElementCount() - iNbPlaylistsBeforeRefresh) != 0)) { return true; } return false; } catch (final Exception e) { // and regular ones logged Log.error(e); return false; } finally { // make sure to unlock refreshing even if an error occurred bAlreadyRefreshing = false; // cleanup logical items org.jajuk.base.Collection.cleanupLogical(); // reporter is null if mount is not mounted due to early return if (reporter != null) { // Notify the reporter of the actual refresh startup reporter.done(); // Reset the reporter as next time, it could be another type reporter = null; } } } /** * Scan recursively. * * @param dir top directory to scan * @param bDeepScan whether we want to perform a deep scan (read tags again) */ private void scanRecursively(final Directory dir, final boolean bDeepScan) { dir.scan(bDeepScan, reporter); if (reporter != null) { reporter.updateState(dir); } final File[] files = dir.getFio().listFiles(UtilSystem.getDirFilter()); if (files != null) { for (final File element : files) { // Leave ASAP if exit request if (ExitService.isExiting()) { return; } final Directory subDir = DirectoryManager.getInstance().registerDirectory( element.getName(), dir, this); scanRecursively(subDir, bDeepScan); } } } /** * Sets the url. * * @param url The sUrl to set. */ public void setUrl(final String url) { sUrl = url; setProperty(Const.XML_URL, url); fio = new File(url); /** Reset files */ for (final org.jajuk.base.File file : FileManager.getInstance().getFiles()) { file.reset(); } /** Reset playlists */ for (final Playlist plf : PlaylistManager.getInstance().getPlaylists()) { plf.reset(); } /** Reset directories */ for (final Directory dir : DirectoryManager.getInstance().getDirectories()) { dir.reset(); } // Reset the root dir rootDir = null; } /** * Synchronizing asynchronously. * * @param bAsynchronous : * set asynchronous or synchronous mode */ public void synchronize(final boolean bAsynchronous) { // Check a source device is defined if (StringUtils.isBlank((String) getValue(Const.XML_DEVICE_SYNCHRO_SOURCE))) { Messages.showErrorMessage(171); return; } final Device device = this; if (!device.isMounted()) { try { device.mount(true); } catch (final Exception e) { Log.error(11, getName(), e); // mount failed Messages.showErrorMessage(11, getName()); return; } } if (bAsynchronous) { final Thread t = new Thread("Device Synchronize Thread") { @Override public void run() { synchronizeCommand(); } }; t.setPriority(Thread.MIN_PRIORITY); t.start(); } else { synchronizeCommand(); } } /** * Synchronize action itself. */ public void synchronizeCommand() { try { bAlreadySynchronizing = true; long lTime = System.currentTimeMillis(); int iNbCreatedFilesDest = 0; int iNbCreatedFilesSrc = 0; lVolume = 0; final boolean bidi = getValue(Const.XML_DEVICE_SYNCHRO_MODE).equals( Const.DEVICE_SYNCHRO_MODE_BI); // check this device is synchronized final String sIdSrc = (String) getValue(Const.XML_DEVICE_SYNCHRO_SOURCE); if (StringUtils.isBlank(sIdSrc) || sIdSrc.equals(getID())) { // cannot synchro with itself return; } final Device dSrc = DeviceManager.getInstance().getDeviceByID(sIdSrc); // perform a fast refresh refreshCommand(false, true, null); // if bidi sync, refresh the other device as well (new file can // have been copied to it) if (bidi) { dSrc.refreshCommand(false, true, null); } // start message InformationJPanel.getInstance().setMessage( new StringBuilder(Messages.getString("Device.31")).append(dSrc.getName()).append(',') .append(getName()).append("]").toString(), InformationJPanel.MessageType.INFORMATIVE); // in both cases (bi or uni-directional), make an unidirectional // sync from source device to this one iNbCreatedFilesDest = synchronizeUnidirectonal(dSrc, this); // now the other one if bidi if (bidi) { iNbCreatedFilesDest += synchronizeUnidirectonal(this, dSrc); } // end message lTime = System.currentTimeMillis() - lTime; final String sOut = new StringBuilder(Messages.getString("Device.33")) .append(((lTime < 1000) ? lTime + " ms" : lTime / 1000 + " s")).append(" - ") .append(iNbCreatedFilesSrc + iNbCreatedFilesDest).append(Messages.getString("Device.35")) .append(lVolume / 1048576).append(Messages.getString("Device.36")).toString(); // perform a fast refresh refreshCommand(false, true, null); // if bidi sync, refresh the other device as well (new file can // have been copied to it) if (bidi) { dSrc.refreshCommand(false, true, null); } InformationJPanel.getInstance().setMessage(sOut, InformationJPanel.MessageType.INFORMATIVE); Log.debug(sOut); } catch (final RuntimeException e) { // runtime errors are thrown throw e; } catch (final Exception e) { // and regular ones logged Log.error(e); } finally { // make sure to unlock synchronizing even if an error occurred bAlreadySynchronizing = false; // Refresh GUI ObservationManager.notify(new JajukEvent(JajukEvents.DEVICE_REFRESH)); } } /** * Synchronize a device with another one (unidirectional). * * @param dSrc DOCUMENT_ME * @param dest DOCUMENT_ME * * @return nb of created files */ private int synchronizeUnidirectonal(final Device dSrc, final Device dest) { final Set hsSourceDirs = new HashSet(100); // contains paths ( relative to device) of desynchronized dirs final Set hsDesynchroPaths = new HashSet(10); final Set hsDestDirs = new HashSet(100); int iNbCreatedFiles = 0; List dirs = DirectoryManager.getInstance().getDirectories(); for (Directory dir : dirs) { if (dir.getDevice().equals(dSrc)) { // don't take desynchronized dirs into account if (dir.getBooleanValue(Const.XML_DIRECTORY_SYNCHRONIZED)) { hsSourceDirs.add(dir); } else { hsDesynchroPaths.add(dir.getRelativePath()); } } } for (Directory dir : dirs) { if (dir.getDevice().equals(dest)) { if (dir.getBooleanValue(Const.XML_DIRECTORY_SYNCHRONIZED)) { // don't take desynchronized dirs into account hsDestDirs.add(dir); } else { hsDesynchroPaths.add(dir.getRelativePath()); } } } // handle known extensions and image files final FileFilter filter = new JajukFileFilter(false, new JajukFileFilter[] { KnownTypeFilter.getInstance(), ImageFilter.getInstance() }); for (Directory dir : hsSourceDirs) { // give a chance to exit during sync if (ExitService.isExiting()) { return iNbCreatedFiles; } boolean bNeedCreate = true; final String sPath = dir.getRelativePath(); // check the directory on source is not desynchronized. If it // is, leave without checking files if (hsDesynchroPaths.contains(sPath)) { continue; } for (Directory dir2 : hsDestDirs) { if (dir2.getRelativePath().equals(sPath)) { // directory already exists on this device bNeedCreate = false; break; } } // create it if needed final File fileNewDir = new File(new StringBuilder(dest.getUrl()).append(sPath).toString()); if (bNeedCreate && !fileNewDir.mkdirs()) { Log.warn("Could not create directory " + fileNewDir); } // synchronize files final File fileSrc = new File(new StringBuilder(dSrc.getUrl()).append(sPath).toString()); final File[] fSrcFiles = fileSrc.listFiles(filter); if (fSrcFiles != null) { for (final File element : fSrcFiles) { File[] filesArray = fileNewDir.listFiles(filter); if (filesArray == null) { // fileNewDir is not a directory or an error occurred ( // read/write right ? ) continue; } final List files = Arrays.asList(filesArray); // Sort so files are copied in the filesystem order Collections.sort(files); boolean bNeedCopy = true; for (final File element2 : files) { if (element.getName().equalsIgnoreCase(element2.getName())) { bNeedCopy = false; } } if (bNeedCopy) { try { UtilSystem.copyToDir(element, fileNewDir); iNbCreatedFiles++; lVolume += element.length(); InformationJPanel.getInstance().setMessage( new StringBuilder(Messages.getString("Device.41")).append(dSrc.getName()) .append(',').append(dest.getName()).append(Messages.getString("Device.42")) .append(element.getAbsolutePath()).append("]").toString(), InformationJPanel.MessageType.INFORMATIVE); } catch (final JajukException je) { Messages.showErrorMessage(je.getCode(), element.getAbsolutePath()); Messages.showErrorMessage(27); Log.error(je); return iNbCreatedFiles; } catch (final Exception e) { Messages.showErrorMessage(20, element.getAbsolutePath()); Messages.showErrorMessage(27); Log.error(20, "{{" + element.getAbsolutePath() + "}}", e); return iNbCreatedFiles; } } } } } return iNbCreatedFiles; } /** * Test device accessibility. * * @return true if the device is available */ public boolean test() { UtilGUI.waiting(); // waiting cursor boolean bOK = false; boolean bWasMounted = bMounted; // store mounted state of device before // mount test try { if (!bMounted) { mount(true); } } catch (final Exception e) { UtilGUI.stopWaiting(); return false; } if (getLongValue(Const.XML_TYPE) != 5) { // not a remote device final File file = new File(sUrl); if (file.exists() && file.canRead()) { // see if the url exists // and is readable // check if this device was void boolean bVoid = true; for (org.jajuk.base.File f : FileManager.getInstance().getFiles()) { if (f.getDirectory().getDevice().equals(this)) { // at least one field in this device bVoid = false; break; } } if (!bVoid) { // if the device is not supposed to be void, // check if it is the case, if no, the device // must not be unix-mounted if (file.list().length > 0) { bOK = true; } } else { // device is void, OK we assume it is accessible bOK = true; } } } else { bOK = false; // TBI } // unmount the device if it was mounted only for the test if (!bWasMounted) { try { unmount(false, false); } catch (final Exception e1) { Log.error(e1); } } UtilGUI.stopWaiting(); return bOK; } /** * toString method. * * @return the string */ @Override public String toString() { return "Device[ID=" + getID() + " Name=" + getName() + " Type=" + DeviceManager.getInstance().getDeviceType(getLongValue(Const.XML_TYPE)) + " URL=" + sUrl + "]"; } /** * Unmount the device. */ public void unmount() { unmount(false, true); } /** * Unmount the device with ejection. * * @param bEjection set whether the device must be ejected * @param bUIRefresh set wheter the UI should be refreshed */ public void unmount(final boolean bEjection, final boolean bUIRefresh) { // look to see if the device is already mounted if (!bMounted) { Messages.showErrorMessage(125); // already unmounted return; } // ask fifo if it doens't use any track from this device if (!QueueModel.canUnmount(this)) { Messages.showErrorMessage(121); return; } bMounted = false; if (bUIRefresh) { ObservationManager.notify(new JajukEvent(JajukEvents.DEVICE_UNMOUNT)); } } } jajuk-1.9.6.orig/src/main/java/org/jajuk/base/DirectoryManager.java0000644000175000017500000001703711720500104025027 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.base; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Locale; import org.jajuk.util.Const; import org.jajuk.util.MD5Processor; import org.jajuk.util.ReadOnlyIterator; import org.jajuk.util.UtilSystem; /** * Convenient class to manage directories. */ public final class DirectoryManager extends ItemManager { /** Self instance. */ private static DirectoryManager singleton = new DirectoryManager(); /** * Return hashcode for this item. * * @param sName directory name * @param device device * @param dParent parent directory * * @return ItemManager ID */ protected static String createID(final String sName, final Device device, final Directory dParent) { final StringBuilder sbAbs = new StringBuilder(device.getName()); // Under windows, all files/directories with different cases should get // the same ID if (UtilSystem.isUnderWindows()) { if (dParent != null) { sbAbs.append(dParent.getRelativePath().toLowerCase(Locale.getDefault())); } sbAbs.append(sName.toLowerCase(Locale.getDefault())); } else { if (dParent != null) { sbAbs.append(dParent.getRelativePath()); } sbAbs.append(sName); } return MD5Processor.hash(sbAbs.toString()); } /** * Gets the instance. * * @return singleton */ public static DirectoryManager getInstance() { return DirectoryManager.singleton; } /** * No constructor available, only static access. */ private DirectoryManager() { super(); // ---register properties--- // ID registerProperty(new PropertyMetaInformation(Const.XML_ID, false, true, false, false, false, String.class, null)); // Name test with (getParentDirectory() != null); //name editable only // for standard // directories, not root registerProperty(new PropertyMetaInformation(Const.XML_NAME, false, true, true, false, false, String.class, null)); // @TODO edition // Parent registerProperty(new PropertyMetaInformation(Const.XML_DIRECTORY_PARENT, false, true, true, false, false, String.class, null)); // Device registerProperty(new PropertyMetaInformation(Const.XML_DEVICE, false, true, true, false, false, String.class, null)); // Expand registerProperty(new PropertyMetaInformation(Const.XML_EXPANDED, false, false, false, false, true, Boolean.class, false)); // Synchronized directory registerProperty(new PropertyMetaInformation(Const.XML_DIRECTORY_SYNCHRONIZED, false, false, true, false, false, Boolean.class, true)); } /** * Clean all references for the given device. * * @param sId : * Device id */ public void cleanDevice(final String sId) { lock.writeLock().lock(); try { for (Directory directory : getDirectories()) { if (directory.getDevice().getID().equals(sId)) { removeItem(directory); } } } finally { lock.writeLock().unlock(); } } /** * Gets a shallow copy of all directories. * * @return ordered directories list */ @SuppressWarnings("unchecked") public List getDirectories() { return (List) getItems(); } /** * Gets the directories iterator. * * @return directories iterator */ @SuppressWarnings("unchecked") public ReadOnlyIterator getDirectoriesIterator() { return new ReadOnlyIterator((Iterator) getItemsIterator()); } /** * Gets the directory by id. * * @param sID Item ID * * @return Directory matching the id */ public Directory getDirectoryByID(final String sID) { return (Directory) getItemByID(sID); } /** * Gets the directory for io. * * @param fio DOCUMENT_ME * @param device Associated device * @return Directory matching the io file */ public Directory getDirectoryForIO(final java.io.File fio, Device device) { for (Directory dir : getDirectories()) { // we have to test the device because of cdroms : all CD have the same IO if (dir.getFio().equals(fio) && dir.getDevice().equals(device)) { return dir; } } return null; } /* * (non-Javadoc) * * @see org.jajuk.base.ItemManager#getIdentifier() */ @Override public String getLabel() { return Const.XML_DIRECTORIES; } /** * Register a root device directory. * * @param device DOCUMENT_ME * * @return the directory */ public Directory registerDirectory(final Device device) { return registerDirectory(device.getID(), "", null, device); } /** * Register a directory. * * @param sName DOCUMENT_ME * @param dParent DOCUMENT_ME * @param device DOCUMENT_ME * * @return the directory */ public Directory registerDirectory(final String sName, final Directory dParent, final Device device) { return registerDirectory(DirectoryManager.createID(sName, device, dParent), sName, dParent, device); } /** * Register a directory with a known id. * * @param sId DOCUMENT_ME * @param sName DOCUMENT_ME * @param dParent DOCUMENT_ME * @param device DOCUMENT_ME * @return the directory */ public Directory registerDirectory(final String sId, final String sName, final Directory dParent, final Device device) { Directory directory = getDirectoryByID(sId); if (directory != null) { return directory; } directory = new Directory(sId, sName, dParent, device); registerItem(directory); return directory; } /** * Remove a directory and all subdirectories from main directory repository. * Remove reference from parent directories as well. * * @param sId DOCUMENT_ME */ public void removeDirectory(final String sId) { lock.writeLock().lock(); try { final Directory dir = getDirectoryByID(sId); if (dir == null) {// check the directory has not already been // removed return; } // remove all files // need to use a shallow copy to avoid concurrent exceptions final List alFiles = new ArrayList(dir.getFiles()); for (final File file : alFiles) { FileManager.getInstance().removeFile(file); } // remove all playlists for (final Playlist plf : dir.getPlaylistFiles()) { PlaylistManager.getInstance().removeItem(plf); } // remove all sub dirs final Iterator it = dir.getDirectories().iterator(); while (it.hasNext()) { final Directory dSub = it.next(); removeDirectory(dSub.getID()); // self call // remove it it.remove(); } // remove this dir from collection removeItem(dir); } finally { lock.writeLock().unlock(); } } }jajuk-1.9.6.orig/src/main/java/org/jajuk/services/0000755000175000017500000000000011720500104021626 5ustar drazzibdrazzibjajuk-1.9.6.orig/src/main/java/org/jajuk/services/alarm/0000755000175000017500000000000011720500104022722 5ustar drazzibdrazzibjajuk-1.9.6.orig/src/main/java/org/jajuk/services/alarm/package.html0000644000175000017500000000017111720500104025202 0ustar drazzibdrazzib DOCUMENT_ME jajuk-1.9.6.orig/src/main/java/org/jajuk/services/alarm/Alarm.java0000644000175000017500000000533211720500104024624 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.services.alarm; import java.util.Date; import java.util.List; import org.apache.commons.lang.time.DateUtils; import org.jajuk.base.File; import org.jajuk.services.players.QueueModel; import org.jajuk.services.webradio.WebRadio; import org.jajuk.util.Conf; import org.jajuk.util.Const; import org.jajuk.util.UtilFeatures; import org.jajuk.util.log.Log; /** * An Alarm. */ public class Alarm { /** The files to play. */ private List alToPlay; /** The webradio to play. */ private WebRadio radio; /** DOCUMENT_ME. */ private String alarmAction; /** DOCUMENT_ME. */ private Date aTime; /** * Instantiates a new alarm. * * @param aTime DOCUMENT_ME * @param alFiles DOCUMENT_ME * @param mode DOCUMENT_ME */ public Alarm(java.util.Date aTime, List alFiles, String mode) { this.aTime = aTime; this.alToPlay = alFiles; this.alarmAction = mode; } /** * Instantiates a new alarm. * * @param aTime DOCUMENT_ME * @param radio DOCUMENT_ME * @param mode DOCUMENT_ME */ public Alarm(java.util.Date aTime, WebRadio radio, String mode) { this.aTime = aTime; this.radio = radio; this.alarmAction = mode; } /** * Effective action to perform by the alarm. */ public void wakeUpSleeper() { Log.debug("Wake up at " + new Date()); if (alarmAction.equals(Const.ALARM_START_ACTION)) { if (alToPlay != null) { QueueModel.push(UtilFeatures.createStackItems(alToPlay, Conf .getBoolean(Const.CONF_STATE_REPEAT_ALL), false), false); } else if (radio != null) { QueueModel.launchRadio(radio); } } else { QueueModel.stopRequest(); } } /** * Gets the alarm time. * * @return the alarm time */ public Date getAlarmTime() { return this.aTime; } /** * Add 24 hours to current alarm. */ public void nextDay() { aTime = DateUtils.addDays(aTime, 1); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/services/alarm/AlarmManager.java0000644000175000017500000001560511720500104026123 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.services.alarm; import java.util.ArrayList; import java.util.Calendar; import java.util.Date; import java.util.HashSet; import java.util.List; import java.util.Set; import org.apache.commons.lang.time.DateUtils; import org.jajuk.base.File; import org.jajuk.base.FileManager; import org.jajuk.base.SearchResult.SearchResultType; import org.jajuk.events.JajukEvent; import org.jajuk.events.JajukEvents; import org.jajuk.events.ObservationManager; import org.jajuk.events.Observer; import org.jajuk.services.core.ExitService; import org.jajuk.services.dj.Ambience; import org.jajuk.services.dj.AmbienceManager; import org.jajuk.services.webradio.WebRadio; import org.jajuk.services.webradio.WebRadioManager; import org.jajuk.util.Conf; import org.jajuk.util.Const; import org.jajuk.util.UtilFeatures; import org.jajuk.util.log.Log; /** * Manages alarms * * TODO: We could use Timer instead of implementing the Timer loop ourselves here!. * TODO : multi-alarms management */ public class AlarmManager implements Observer { /** DOCUMENT_ME. */ private static AlarmManager singleton = new AlarmManager(); static { // Start the clock singleton.clock.start(); // register the instance so that it receives updates of changes to the configured Alarm ObservationManager.register(singleton); // force last event update singleton.update(new JajukEvent(JajukEvents.ALARMS_CHANGE)); } /** DOCUMENT_ME. */ private Alarm alarm; /** This thread looks alarms up and call weak up when it's time. */ private final Thread clock = new Thread("Alarm manager Thread") { @Override public void run() { Log.debug("Starting Alarm thread"); while (!ExitService.isExiting()) { try { Thread.sleep(1000); } catch (InterruptedException e) { Log.error(e); } // Wake up if the alarm is enabled and if it's time if (Conf.getBoolean(Const.CONF_ALARM_ENABLED) && alarm != null && System.currentTimeMillis() > alarm.getAlarmTime().getTime()) { alarm.wakeUpSleeper(); // Add 24 hours to current alarm alarm.nextDay(); } } } }; /** * Gets the single instance of AlarmManager. * * @return single instance of AlarmManager */ public static AlarmManager getInstance() { return singleton; } /* * (non-Javadoc) * * @see org.jajuk.events.Observer#update(org.jajuk.events.JajukEvent) */ @Override public void update(JajukEvent event) { JajukEvents subject = event.getSubject(); // Reset rate and total play time (automatic part of rating system) if (subject.equals(JajukEvents.ALARMS_CHANGE)) { if (Conf.getBoolean(Const.CONF_ALARM_ENABLED)) { // construct a Date with the configured alarm-time int hours = Conf.getInt(Const.CONF_ALARM_TIME_HOUR); int minutes = Conf.getInt(Const.CONF_ALARM_TIME_MINUTES); int seconds = Conf.getInt(Const.CONF_ALARM_TIME_SECONDS); String alarmAction = Conf.getString(Const.CONF_ALARM_ACTION); Calendar cal = Calendar.getInstance(); cal.set(Calendar.HOUR_OF_DAY, hours); cal.set(Calendar.MINUTE, minutes); cal.set(Calendar.SECOND, seconds); // If chosen date is already past, consider that user meant // tomorrow Date alarmDate = cal.getTime(); if (alarmDate.before(new Date())) { alarmDate = DateUtils.addDays(alarmDate, 1); } // Compute playlist if required List alToPlay = null; WebRadio radio = null; Ambience ambience = AmbienceManager.getInstance().getSelectedAmbience(); if (alarmAction.equals(Const.ALARM_START_ACTION)) { String mode = Conf.getString(Const.CONF_ALARM_MODE); String conf = Conf.getString(Const.CONF_ALARM_FILE); String item = conf.substring(conf.indexOf('/') + 1, conf.length()); alToPlay = new ArrayList(); if (mode.equals(Const.STARTUP_MODE_ITEM)) { if (conf.matches(SearchResultType.FILE.name() + ".*")) { File file = FileManager.getInstance().getFileByID(item); if (file != null) { alToPlay.add(file); } } else if (conf.matches(SearchResultType.WEBRADIO.name() + ".*")) { radio = WebRadioManager.getInstance().getWebRadioByName(item); } } else if (mode.equals(Const.STARTUP_MODE_SHUFFLE)) { // Filter files by ambience or if none ambience matches, perform a global shuffle // ignoring current ambience alToPlay = UtilFeatures.filterByAmbience(FileManager.getInstance() .getGlobalShufflePlaylist(), ambience); if (alToPlay.size() == 0) { alToPlay = FileManager.getInstance().getGlobalShufflePlaylist(); } } else if (mode.equals(Const.STARTUP_MODE_BESTOF)) { alToPlay = UtilFeatures.filterByAmbience(FileManager.getInstance() .getGlobalBestofPlaylist(), ambience); if (alToPlay.size() == 0) { alToPlay = FileManager.getInstance().getGlobalBestofPlaylist(); } } else if (mode.equals(Const.STARTUP_MODE_NOVELTIES)) { alToPlay = UtilFeatures.filterByAmbience(FileManager.getInstance() .getGlobalNoveltiesPlaylist(), ambience); if (alToPlay.size() == 0) { alToPlay = FileManager.getInstance().getGlobalNoveltiesPlaylist(); } } else { Log.warn("Undefined alarm mode found: " + mode); } } // Instanciate either the files list or the web radio if (radio == null) { alarm = new Alarm(alarmDate, alToPlay, alarmAction); } else { alarm = new Alarm(alarmDate, radio, alarmAction); } } } } /* * (non-Javadoc) * * @see org.jajuk.events.Observer#getRegistrationKeys() */ @Override public Set getRegistrationKeys() { Set keys = new HashSet(); keys.add(JajukEvents.ALARMS_CHANGE); return keys; } }jajuk-1.9.6.orig/src/main/java/org/jajuk/services/dj/0000755000175000017500000000000011720500104022223 5ustar drazzibdrazzibjajuk-1.9.6.orig/src/main/java/org/jajuk/services/dj/package.html0000644000175000017500000000017111720500104024503 0ustar drazzibdrazzib DOCUMENT_ME jajuk-1.9.6.orig/src/main/java/org/jajuk/services/dj/Proportion.java0000644000175000017500000000702011720500104025240 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.services.dj; import java.util.Set; import org.jajuk.base.Genre; /** * Represent a genre proportion (used by digital DJs). */ public class Proportion { /** genres. */ private Ambience ambience; /** Proportion*. */ private float proportion; /** * Constructor. * * @param ambience DOCUMENT_ME * @param proportion genre proportion in %. Ex: 0.1 */ public Proportion(Ambience ambience, float proportion) { this.ambience = ambience; this.proportion = proportion; } /** * Constructor for void proportion. */ public Proportion() { this.ambience = new Ambience(Long.toString(System.currentTimeMillis()), ""); this.proportion = 0.2f; } /** * equals method. * * @param other DOCUMENT_ME * * @return whether two object are equals */ @Override public boolean equals(Object other) { // also catches null if (!(other instanceof Proportion)) { return false; } return getProportion() == ((Proportion) other).getProportion() && getGenres().equals(((Proportion) other).getGenres()); } /* (non-Javadoc) * @see java.lang.Object#hashCode() */ @Override public int hashCode() { // for now just use ambience for the hashCode, not sure if we should include // the proportion value as well... return ambience.hashCode(); } /** * Gets the genres. * * @return Returns the genres */ public Set getGenres() { return this.ambience.getGenres(); } /** * Add a genre. * * @param genre DOCUMENT_ME */ public void addGenre(Genre genre) { ambience.addGenre(genre); } /** * To string. * * @return String representation of this proportion */ @Override public String toString() { return "" + proportion; } /** * From String, return genre1,genre2,... * * @return the genres desc */ public String getGenresDesc() { String out = ""; for (Genre s : ambience.getGenres()) { out += s.getName2() + ','; } if (out.length() > 0) { out = out.substring(0, out.length() - 1); // remove trailing ',' } return out; } /** * Gets the next genre. * * @return next genre to be played or null if no idea */ public Genre getNextGenre() { return null; } /** * Gets the proportion. * * @return the proportion */ public float getProportion() { return this.proportion; } /** * Sets the genre. * * @param ambience the new genre */ public void setGenre(Ambience ambience) { this.ambience = ambience; } /** * Sets the proportion. * * @param proportion the new proportion */ public void setProportion(float proportion) { this.proportion = proportion; } } jajuk-1.9.6.orig/src/main/java/org/jajuk/services/dj/DigitalDJ.java0000644000175000017500000001504511720500104024666 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.services.dj; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; import org.jajuk.base.File; import org.jajuk.base.Track; import org.jajuk.ui.helpers.StarsHelper; import org.jajuk.util.Const; /** * Digital DJ. */ public abstract class DigitalDJ implements Comparable { /** DJ unique ID. */ private final String sID; /** DJ name. */ protected String sName; /** Rating floor. */ protected int iRatingLevel = 0; /** Fading duration in sec. */ protected int iFadingDuration = 0; /** Track unicity. */ protected boolean bUnicity = false; /** DOCUMENT_ME. */ private int iMaxTracks = -1; /** * Constructor with ID. * * @param sID DJ ID */ DigitalDJ(String sID) { this.sID = sID; } /** * toString method. * * @return String representation of this object */ @Override public String toString() { return "DJ " + sName; } /** * Compare to method, sorted alphaticaly. * * @param other DOCUMENT_ME * * @return the int */ @Override public int compareTo(DigitalDJ other) { // if (other == null) { return -1; } return this.sName.compareTo(other.getName()); } /** * To xml. * * @return XML representation of this DJ */ public abstract String toXML(); /** * To xml general parameters. * * @return DJ common parameters */ protected String toXMLGeneralParameters() { StringBuilder sb = new StringBuilder(); sb.append("\n"); sb.append("<" + Const.XML_DJ_DJ + " " + Const.XML_VERSION + "='" + Const.JAJUK_VERSION + "' " + Const.XML_ID + "='" + sID + "' " + Const.XML_NAME + "='" + sName + "' " + Const.XML_TYPE + "='" + this.getClass().getName() + "'>\n"); sb.append("\t<" + Const.XML_DJ_GENERAL + " "); sb.append(Const.XML_DJ_RATING_LEVEL + "='" + iRatingLevel + "' "); sb.append(Const.XML_DJ_UNICITY + "='" + bUnicity + "' "); sb.append(Const.XML_DJ_FADE_DURATION + "='" + iFadingDuration + "' "); sb.append(Const.XML_DJ_MAX_TRACKS + "='" + iMaxTracks + "'/>\n"); return sb.toString(); } /** * Filter by rate and remove duplicates (unicity). * * @param files DOCUMENT_ME */ void filterFilesByRate(List files) { // this set stores already used tracks Set selectedTracks = new HashSet(files.size()); // Select by rate if needed if (iRatingLevel > 0) { Iterator it = files.iterator(); while (it.hasNext()) { File file = it.next(); if (StarsHelper.getStarsNumber(file.getTrack()) < iRatingLevel || selectedTracks.contains(file.getTrack())) { it.remove(); } else { selectedTracks.add(file.getTrack()); } } } } /** * Filter files by max track. * DOCUMENT_ME * * @param files DOCUMENT_ME */ void filterFilesByMaxTrack(List files) { // cut off some tracks if less are selected for queuing if (iMaxTracks > 0) { // return without any copying if we have less entries than max if (iMaxTracks > files.size()) { return; } // remove until we have less than max tracks while (files.size() > iMaxTracks) { files.remove(files.size() - 1); } } } /** * Gets the name. * * @return DJ name */ public String getName() { return sName; } /** * equals method. * * @param other DOCUMENT_ME * * @return whether two object are equals */ @Override public boolean equals(Object other) { if (!(other instanceof DigitalDJ)) { return false; } String sOtherName = ((DigitalDJ) other).getName(); return getName().equals(sOtherName); } /* (non-Javadoc) * @see java.lang.Object#hashCode() */ @Override public int hashCode() { // equals only compares on Name, therefore use the same for the hashcode return sName.hashCode(); } /** * Sets the name. * * @param name DOCUMENT_ME */ public void setName(String name) { this.sName = name; } /** * Gets the fading duration. * * @return DJ fade duration */ public int getFadingDuration() { return this.iFadingDuration; } /** * Sets the fading duration. * * @param fadingDuration DOCUMENT_ME */ public void setFadingDuration(int fadingDuration) { this.iFadingDuration = fadingDuration; } /** * Gets the rating level. * * @return Returns the iRatingFloor. */ public int getRatingLevel() { return this.iRatingLevel; } /** * Sets the rating level. * * @param ratingFloor The iRatingFloor to set. */ public void setRatingLevel(int ratingFloor) { this.iRatingLevel = ratingFloor; } /** * Generate playlist. * * @return Generated playlist */ public abstract List generatePlaylist(); /** * Gets the iD. * * @return the iD */ public String getID() { return this.sID; } /** * Checks if is track unicity. * * @return true, if is track unicity */ public boolean isTrackUnicity() { return this.bUnicity; } /** * Sets the track unicity. * * @param trackUnicity the new track unicity */ public void setTrackUnicity(boolean trackUnicity) { this.bUnicity = trackUnicity; } /** * Gets the max tracks. * * @return The configured number of max tracks to queue for this DJ. -1 * denotes infinity. */ public int getMaxTracks() { return this.iMaxTracks; } /** * Set the new max number of tracks to queue. * * @param iMaxTracks The new max number of tracks to queue for this DJ. -1 for infinity */ public void setMaxTracks(int iMaxTracks) { this.iMaxTracks = iMaxTracks; } } jajuk-1.9.6.orig/src/main/java/org/jajuk/services/dj/ProportionDigitalDJ.java0000644000175000017500000001225411720500104026761 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.services.dj; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import org.jajuk.base.File; import org.jajuk.base.FileManager; import org.jajuk.base.Genre; import org.jajuk.util.Const; import org.jajuk.util.UtilSystem; /** * A proportion (10% JAZZ, 20% ROCK...) digital DJ */ public class ProportionDigitalDJ extends DigitalDJ { /** Set of proportions. */ private List proportions; /** * The Constructor. * * @param sID DOCUMENT_ME */ public ProportionDigitalDJ(String sID) { super(sID); this.proportions = new ArrayList(10); } /* * (non-Javadoc) * * @see org.jajuk.base.DigitalDJ#generatePlaylist() */ @Override public List generatePlaylist() { List out = getSequence(); if (!bUnicity && out.size() > 0) { while (out.size() < Const.MIN_TRACKS_NUMBER_WITHOUT_UNICITY) { out.addAll(getSequence()); } } return out; } /** * Gets the sequence. * * @return a single loop sequence */ private List getSequence() { List out = new ArrayList(100); Map> list = new HashMap>(10); // get a global shuffle selection, we will keep only tracks with wanted // genres List global = FileManager.getInstance().getGlobalShufflePlaylist(); // Select by rate if needed filterFilesByRate(global); for (File file : global) { for (Proportion prop : proportions) { if (prop.getGenres().contains(file.getTrack().getGenre())) { List files = list.get(prop); if (files == null) { // not yet file list files = new ArrayList(100); list.put(prop, files); } files.add(file); } } } // check if all properties are represented if (list.size() < proportions.size()) { return out; // return void list } // now, keep the smallest list before applying proportion Proportion minProp = null; int iMinSize = 0; float fTotal = 0; for (Entry> prop : list.entrySet()) { fTotal += prop.getKey().getProportion(); List files = prop.getValue(); // keep proportion with smallest number of files if (minProp == null || files.size() < iMinSize) { minProp = prop.getKey(); iMinSize = files.size(); } } // apply proportions for (Entry> prop : list.entrySet()) { List files = prop.getValue(); out.addAll(files.subList(0, (int) (iMinSize * prop.getKey().getProportion()))); } // complete this shuffle files if total sum < 100% if (fTotal < 1.0) { int iNbAdditional = (int) ((1.0 - fTotal) * iMinSize); for (int i = 0; i < iNbAdditional; i++) { out.add(global.get((int) (Math.random() * global.size()))); } } // shuffle selection Collections.shuffle(out, UtilSystem.getRandom()); // finally ensure that we don't select more than the max number of tracks filterFilesByMaxTrack(out); return out; } /** * Gets the proportions. * * @return Proportions */ public List getProportions() { return this.proportions; } /** * (non-Javadoc). * * @return the string * * @see dj.DigitalDJ#toXML() */ @Override public String toXML() { StringBuilder sb = new StringBuilder(2000); sb.append(toXMLGeneralParameters()); sb.append("\t<" + Const.XML_DJ_PROPORTIONS + ">\n"); for (Proportion proportion : proportions) { String genresDesc = ""; for (Genre genre : proportion.getGenres()) { genresDesc += genre.getID() + ','; } // remove trailing coma genresDesc = genresDesc.substring(0, genresDesc.length() - 1); sb.append("\t\t<" + Const.XML_DJ_PROPORTION + " " + Const.XML_DJ_GENRES + "='" + genresDesc + "' " + Const.XML_DJ_VALUE + "='" + proportion.getProportion() + "'/>\n"); } sb.append("\t\n"); sb.append("\n"); return sb.toString(); } /** * Sets the proportions. * * @param proportions the new proportions */ public void setProportions(List proportions) { this.proportions = proportions; } } jajuk-1.9.6.orig/src/main/java/org/jajuk/services/dj/AmbienceManager.java0000644000175000017500000002645611720500104026101 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.services.dj; import java.util.ArrayList; import java.util.Collections; import java.util.Enumeration; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.Set; import java.util.StringTokenizer; import org.jajuk.base.Genre; import org.jajuk.base.GenreManager; import org.jajuk.events.JajukEvent; import org.jajuk.events.JajukEvents; import org.jajuk.events.ObservationManager; import org.jajuk.events.Observer; import org.jajuk.util.Conf; import org.jajuk.util.Const; import org.jajuk.util.Messages; import org.jajuk.util.UpgradeManager; import org.jajuk.util.log.Log; /** * Ambience manager. */ public final class AmbienceManager implements Observer { /** Ambience id-> ambience. */ private final Map ambiences = new HashMap(10); /** Self instance. */ private static AmbienceManager self = new AmbienceManager(); /** * No direct constructor. */ private AmbienceManager() { ObservationManager.register(this); } /* * (non-Javadoc) * * @see org.jajuk.events.Observer#getRegistrationKeys() */ public Set getRegistrationKeys() { Set eventSubjectSet = new HashSet(); eventSubjectSet.add(JajukEvents.GENRE_NAME_CHANGED); return eventSubjectSet; } /** * Gets the instance. * * @return singleton */ public static AmbienceManager getInstance() { return self; } /** * Load properties from in file Format: jajuk.ambience./=genre1,genre2,... */ public void load() { // if first startup, define default ambiences if (UpgradeManager.isFirstSession()) { Log.debug("First start, creating default Ambiences."); createDefaultAmbiences(); return; } Properties properties = Conf.getProperties(); Enumeration e = properties.keys(); while (e.hasMoreElements()) { String sKey = (String) e.nextElement(); if (sKey.matches(Const.AMBIENCE_PREFIX + ".*")) { Set genres = new HashSet(10); StringTokenizer st = new StringTokenizer((String) properties.get(sKey), ","); while (st.hasMoreTokens()) { Genre genre = GenreManager.getInstance().getGenreByID(st.nextToken()); if (genre != null) { genres.add(genre); } } String ambienceDesc = sKey.substring(Const.AMBIENCE_PREFIX.length()); int index = ambienceDesc.indexOf('/'); if (index == -1) { continue; } String ambienceID = ambienceDesc.substring(0, index); String ambienceName = ambienceDesc.substring(index + 1); Ambience ambience = new Ambience(ambienceID, ambienceName, genres); ambiences.put(ambienceID, ambience); } } // If none ambience, means ambience can have been reset after a genre // hashcode computation change, reset to defaults if (ambiences.size() == 0) { Log.debug("No ambiences loaded, creating default Ambiences."); createDefaultAmbiences(); } } /** * Gets the ambiences. * * @return sorted list of registered ambiences */ public List getAmbiences() { List al = new ArrayList(ambiences.values()); Collections.sort(al); return al; } /** * Gets the ambience. * * @param sID Ambience id * * @return registrated ambience */ public Ambience getAmbience(String sID) { return ambiences.get(sID); } /** * Gets the ambience by name. * * @param sName Ambience name * * @return registrated ambience or null if no matching name */ public Ambience getAmbienceByName(String sName) { for (Ambience ambience : ambiences.values()) { if (ambience.getName().equals(sName)) { return ambience; } } return null; } /** * Register a new ambience. * * @param ambience ambience to register */ public void registerAmbience(Ambience ambience) { ambiences.put(ambience.getID(), ambience); } /** * Gets the selected ambience. * * @return currently selected ambience or null if "all" ambience selected */ public Ambience getSelectedAmbience() { String sDefault = Conf.getString(Const.CONF_DEFAULT_AMBIENCE); return getAmbience(sDefault); } /* * (non-Javadoc) * * @see org.jajuk.ui.Observer#update(java.lang.String) */ public void update(JajukEvent event) { JajukEvents subject = event.getSubject(); if (JajukEvents.GENRE_NAME_CHANGED.equals(subject)) { Properties properties = event.getDetails(); Genre old = (Genre) properties.get(Const.DETAIL_OLD); Genre newGenre = (Genre) properties.get(Const.DETAIL_NEW); // replace genre into all genres for (Ambience ambience : ambiences.values()) { if (ambience.getGenres().contains(old)) { ambience.removeGenre(old); ambience.addGenre(newGenre); } } } } /** * Perform required operations before exit. */ public void commit() { // first, remove all ambiences from configuration Properties properties = Conf.getProperties(); Iterator it = properties.keySet().iterator(); while (it.hasNext()) { String sKey = (String) it.next(); if (sKey.startsWith(Const.AMBIENCE_PREFIX)) { it.remove(); } } // now create and set each ambience for (Ambience ambience : ambiences.values()) { if (ambience.getGenres().size() > 0) { StringBuilder genres = new StringBuilder(); for (Genre genre : ambience.getGenres()) { genres.append(genre.getID()).append(','); } Conf.setProperty(Const.AMBIENCE_PREFIX + ambience.getID() + '/' + ambience.getName(), genres.toString().substring(0, genres.length() - 1)); } } } /** * Remove a ambience. * * @param sAmbienceID the ambience to remove */ public void removeAmbience(String sAmbienceID) { this.ambiences.remove(sAmbienceID); // Propagate the event Properties properties = new Properties(); properties.put(Const.DETAIL_CONTENT, sAmbienceID); ObservationManager.notify(new JajukEvent(JajukEvents.AMBIENCE_REMOVED, properties)); } /** * Create out of the box ambiences. */ public void createDefaultAmbiences() { // Define default ambience by genre name String[] genresRockPop = new String[] { "Classic Rock", "Pop", "Rock", "Ska", "AlternRock", "Instrumental Pop", "Instrumental Rock", "Southern Rock", "Pop/Funk", "Folk-Rock", "Rock & Roll", "Symphonic Rock", "Ballad", "Christian Rock", "JPop", "SynthPop" }; AmbienceManager.getInstance().registerAmbience( new Ambience("0", Messages.getString("Ambience.0"), genresRockPop)); String[] genresRap = new String[] { "Hip-Hop", "R&B", "Rap", "Fusion", "Gangsta", "Christian Rap", "Porn Groove", "Rhytmic Soul", "Christian Gangsta" }; AmbienceManager.getInstance().registerAmbience( new Ambience("1", Messages.getString("Ambience.1"), genresRap)); String[] genresHardRock = new String[] { "Grunge", "Metal", "Industrial", "Death Metal", "Fusion", "Punk", "Gothic", "Darkwave", "Fast Fusion", "Hard Rock", "Gothic Rock", "Progressive Rock", "Punk Rock", "Terror", "Negerpunk", "Polsk Punk", "Heavy Metal", "Black Metal", "Thrash Metal" }; AmbienceManager.getInstance().registerAmbience( new Ambience("2", Messages.getString("Ambience.2"), genresHardRock)); String[] genresTechno = new String[] { "Dance", "New Age", "Techno", "Euro-Techno", "Ambient", "Trance", "House", "Game", "Space", "Techno-Industrial", "Eurodance", "Dream", "Jungle", "Rave", "Euro-House", "Goa", "Club-House", "Hardcore", "Beat" }; AmbienceManager.getInstance().registerAmbience( new Ambience("3", Messages.getString("Ambience.3"), genresTechno)); String[] genresElectro = new String[] { "Trip-Hop", "Acid", "Electronic", "Club" }; AmbienceManager.getInstance().registerAmbience( new Ambience("4", Messages.getString("Ambience.4"), genresElectro)); String[] genresClassical = new String[] { "Classical", "Chorus", "Opera", "Chamber Music", "Sonata", "Symphony" }; AmbienceManager.getInstance().registerAmbience( new Ambience("5", Messages.getString("Ambience.5"), genresClassical)); String[] genresSoft = new String[] { "Reggae", "Acid Jazz", "Slow Rock", "Jazz", "Easy Listening", "Acoustic", "Ballad" }; AmbienceManager.getInstance().registerAmbience( new Ambience("6", Messages.getString("Ambience.6"), genresSoft)); String[] genresParty = new String[] { "Dance", "Disco", "Funk", "Ska", "Soul", "Eurodance", "Big Band", "Club", "Rhytmic Soul", "Dance Hall", "Club-House" }; AmbienceManager.getInstance().registerAmbience( new Ambience("7", Messages.getString("Ambience.7"), genresParty)); String[] genresJazzBlues = new String[] { "Jazz", "Jazz+Funk", "Bass", "Acid Jazz" }; AmbienceManager.getInstance().registerAmbience( new Ambience("8", Messages.getString("Ambience.8"), genresJazzBlues)); String[] genresWorld = new String[] { "Ethnic", "Native American", "Tribal", "Polka", "Celtic", "Folklore", "Indie" }; AmbienceManager.getInstance().registerAmbience( new Ambience("9", Messages.getString("Ambience.9"), genresWorld)); String[] genresOthers = new String[] { "Other", "Alternative", "Soundtrack", "Vocal", "Meditative", "Comedy", "Humour", "Speech", "Anime" }; AmbienceManager.getInstance().registerAmbience( new Ambience("10", Messages.getString("Ambience.10"), genresOthers)); String[] genresFolkOldies = new String[] { "Country", "Oldies", "Gospel", "Pop-Folk", "Southern Rock", "Cabaret", "Retro", "Folk-Rock", "National Folk", "Swing", "Rock & Roll", "Folk", "Revival", "Chanson" }; AmbienceManager.getInstance().registerAmbience( new Ambience("11", Messages.getString("Ambience.11"), genresFolkOldies)); String[] genresInde = new String[] { "Noise", "AlternRock", "New Wave", "Psychedelic", "Acid Punk", "Avantgarde", "Psychedelic Rock", "Freegenre", "Drum Solo", "Drum & Bass" }; AmbienceManager.getInstance().registerAmbience( new Ambience("12", Messages.getString("Ambience.12"), genresInde)); String[] genresLatin = new String[] { "Latin", "Tango", "Samba", "Acapella", "Salsa" }; AmbienceManager.getInstance().registerAmbience( new Ambience("13", Messages.getString("Ambience.13"), genresLatin)); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/services/dj/TransitionDigitalDJ.java0000644000175000017500000001751311720500104026743 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.services.dj; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import org.apache.commons.collections.CollectionUtils; import org.jajuk.base.File; import org.jajuk.base.FileManager; import org.jajuk.base.Genre; import org.jajuk.util.Const; import org.jajuk.util.UtilFeatures; import org.jajuk.util.filters.JajukPredicates; /** * Type description. */ public class TransitionDigitalDJ extends DigitalDJ { /** List of transitions, need to be a list, not a set for offset. */ private List transitions; /** * The Constructor. * * @param sID DOCUMENT_ME */ public TransitionDigitalDJ(String sID) { super(sID); this.transitions = new ArrayList(10); } /** * Gets the transitions. * * @return DJ transitions */ public List getTransitions() { return this.transitions; } /** * Delete a transition at given offset. * * @param offset DOCUMENT_ME */ public void deleteTransition(int offset) { this.transitions.remove(offset); } /** * Add a transition. * * @param transition DOCUMENT_ME * @param offset DOCUMENT_ME */ public void addTransition(Transition transition, int offset) { this.transitions.add(offset, transition); } /** * Gets the transition. * * @param ambience DOCUMENT_ME * * @return transition mapping this FROM ambience or null if none maps it */ public Transition getTransition(Ambience ambience) { for (Transition transition : transitions) { if (CollectionUtils.containsAny(transition.getFrom().getGenres(), ambience.getGenres())) { return transition; } } return null; } /* * Generate the playlist @return the playlist */ /* (non-Javadoc) * @see org.jajuk.services.dj.DigitalDJ#generatePlaylist() */ @Override public List generatePlaylist() { List out = new ArrayList(500); // get a global shuffle selection List global = FileManager.getInstance().getGlobalShufflePlaylist(); // Select by rate if needed filterFilesByRate(global); // None element, leave if (global.size() == 0) { return out; } // Build a ambience -> files map Map> hmAmbienceFiles = getAmbienceFilesList(global); // compute number of items to add int items = Math.min(global.size(), Const.NB_TRACKS_ON_ACTION); if (!bUnicity && items < Const.MIN_TRACKS_NUMBER_WITHOUT_UNICITY) { // under a limit, if collection is too small and no unicity, use // several times the same files items = Const.MIN_TRACKS_NUMBER_WITHOUT_UNICITY; } // Get first track for (File file : global) { if (transitions.get(0).getFrom().getGenres().contains(file.getTrack().getGenre())) { out.add(file); // Unicity in selection, remove it from this ambience if (bUnicity) { List files = hmAmbienceFiles.get(getAmbience(file.getTrack().getGenre())); files.remove(file); } items--; break; } } // none matching track? return if (out.size() == 0) { return out; } // initialize current ambience with first track ambience (can be null for // unsorted tracks) Ambience currentAmbience = getAmbience(out.get(0).getTrack().getGenre()); // start transition applying while (items > 0) { // A genre can be in only one transition Transition currentTransition = getTransition(currentAmbience); List files = hmAmbienceFiles.get(currentAmbience); int nbTracks = 2; if (currentTransition != null) { nbTracks = currentTransition.getNbTracks(); } // We remove one item as it has already been added through the first track if (out.size() == 1) { nbTracks--; } if (files != null && files.size() >= nbTracks) { for (int i = 0; i < nbTracks && files.size() > 0; i++) { File file = UtilFeatures.getShuffleItem(files); out.add(file); items--; // Unicity in selection, remove it from this ambience if (bUnicity) { files.remove(file); } } } else { // no more tracks for this ambience ? leave // finally ensure that we don't select more than the max number of tracks filterFilesByMaxTrack(out); return out; } if (currentTransition != null) { currentAmbience = currentTransition.getTo(); } else { break; } } // finally ensure that we don't select more than the max number of tracks filterFilesByMaxTrack(out); return out; } /** * Returns a map ambience -> set of files. * * @param global initial set of files to consider * * @return a map ambience -> set of files */ @SuppressWarnings("unchecked") private Map> getAmbienceFilesList(List global) { // Create a map ambience -> set of files Map> hmAmbienceFiles = new HashMap>(5); // For performance, we find unique ambiences in from and to transitions Set ambiences = new HashSet(5); for (Transition tr : transitions) { ambiences.add(tr.getFrom()); ambiences.add(tr.getTo()); } // Fill null key hmAmbienceFiles.put(null, (List) ((ArrayList) global).clone()); // Fill all ambiences for (Ambience ambience : ambiences) { List all = (List) ((ArrayList) global).clone(); CollectionUtils.filter(all, new JajukPredicates.AmbiencePredicate(ambience)); hmAmbienceFiles.put(ambience, all); } return hmAmbienceFiles; } /** * Gets the ambience. * * @param genre DOCUMENT_ME * * @return ambience associated with a genre known in transitions or null if * none */ private Ambience getAmbience(Genre genre) { for (Transition transition : transitions) { if (transition.getFrom().getGenres().contains(genre)) { return transition.getFrom(); } } return null; } /** * (non-Javadoc). * * @return the string * * @see dj.DigitalDJ#toXML() */ @Override public String toXML() { StringBuilder sb = new StringBuilder(2000); sb.append(toXMLGeneralParameters()); sb.append("\t<" + Const.XML_DJ_TRANSITIONS + ">\n"); for (Transition transition : transitions) { sb.append("\t\t<" + Const.XML_DJ_TRANSITION + " " + Const.XML_DJ_FROM + "='" + transition.getFrom().toXML() + "' " + Const.XML_DJ_TO + "='" + transition.getTo().toXML() + "' " + Const.XML_DJ_NUMBER + "='" + transition.getNbTracks() + "'/>\n"); } sb.append("\t\n"); sb.append("\n"); return sb.toString(); } /** * Sets the transitions. * * @param transitions the new transitions */ public void setTransitions(List transitions) { this.transitions = transitions; } } jajuk-1.9.6.orig/src/main/java/org/jajuk/services/dj/DigitalDJManager.java0000644000175000017500000004004211720500104026154 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.services.dj; import java.io.BufferedWriter; import java.io.File; import java.io.FileFilter; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStreamWriter; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.Set; import java.util.StringTokenizer; import javax.swing.JOptionPane; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; import org.jajuk.base.Genre; import org.jajuk.base.GenreManager; import org.jajuk.events.JajukEvent; import org.jajuk.events.JajukEvents; import org.jajuk.events.ObservationManager; import org.jajuk.events.Observer; import org.jajuk.services.core.SessionService; import org.jajuk.util.Conf; import org.jajuk.util.Const; import org.jajuk.util.Messages; import org.jajuk.util.UtilSystem; import org.jajuk.util.error.JajukException; import org.jajuk.util.log.Log; import org.xml.sax.Attributes; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; /** * Manages Digital DJs *

    * Singleton *

    . */ public final class DigitalDJManager implements Observer { /** List of registrated DJs ID->DJ. */ private final Map djs; /** self instance. */ private static DigitalDJManager dj = new DigitalDJManager(); /** Currently selected DJ. */ private static DigitalDJ current; /** * no instantiation. */ private DigitalDJManager() { djs = new HashMap(); ObservationManager.register(this); } /* * (non-Javadoc) * * @see org.jajuk.events.Observer#getRegistrationKeys() */ @Override public Set getRegistrationKeys() { Set eventSubjectSet = new HashSet(); eventSubjectSet.add(JajukEvents.AMBIENCE_REMOVED); return eventSubjectSet; } /** * Gets the instance. * * @return self instance */ public static DigitalDJManager getInstance() { return dj; } /** * Gets the d js. * * @return DJs iteration */ public Collection getDJs() { return djs.values(); } /** * Returns the list of DJs sorted in ascending order according to the natural ordering. * * @return DJs iteration */ public List getDJsSorted() { List sorted = new ArrayList(djs.values()); Collections.sort(sorted); return sorted; } /** * Gets the dj names. * * @return DJs names iteration */ public Set getDJNames() { Set hsNames = new HashSet(10); for (DigitalDJ lDJ : djs.values()) { hsNames.add(lDJ.getName()); } return hsNames; } /** * Gets the dj by name. * * @param sName DOCUMENT_ME * * @return DJ by name */ public DigitalDJ getDJByName(String sName) { for (DigitalDJ lDJ : djs.values()) { if (lDJ.getName().equals(sName)) { return lDJ; } } return null; } /** * Gets the dj by id. * * @param sID DOCUMENT_ME * * @return DJ by ID */ public DigitalDJ getDJByID(String sID) { return djs.get(sID); } /** * Commit given dj on disk. * * @param dj DOCUMENT_ME */ public static void commit(DigitalDJ dj) { try { BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream( SessionService.getConfFileByPath(Const.FILE_DJ_DIR + "/" + dj.getID() + "." + Const.XML_DJ_EXTENSION)), "UTF-8")); bw.write(dj.toXML()); bw.flush(); bw.close(); } catch (Exception e) { Log.error(145, (dj != null) ? "{{" + dj.getName() + "}}" : null, e); } } /** * Remove a DJ. * * @param dj DOCUMENT_ME * * @throws IOException Signals that an I/O exception has occurred. */ public void remove(DigitalDJ dj) throws IOException { djs.remove(dj.getID()); File file = SessionService.getConfFileByPath(Const.FILE_DJ_DIR + "/" + dj.getID() + "." + Const.XML_DJ_EXTENSION); UtilSystem.deleteFile(file); // reset default DJ if this DJ was default if (Conf.getString(Const.CONF_DEFAULT_DJ).equals(dj.getID())) { Conf.setProperty(Const.CONF_DEFAULT_DJ, ""); } // alert command panel ObservationManager.notify(new JajukEvent(JajukEvents.DJS_CHANGE)); } /** * Register a DJ. * * @param dj DOCUMENT_ME */ public void register(DigitalDJ dj) { djs.put(dj.getID(), dj); // alert command panel ObservationManager.notify(new JajukEvent(JajukEvents.DJS_CHANGE)); } /* * (non-Javadoc) * * @see org.jajuk.base.Observer#update(org.jajuk.base.Event) */ @Override public void update(JajukEvent event) { if (JajukEvents.AMBIENCE_REMOVED.equals(event.getSubject())) { Properties properties = event.getDetails(); String sID = (String) properties.get(Const.DETAIL_CONTENT); for (DigitalDJ lDJ : djs.values()) { if (lDJ instanceof AmbienceDigitalDJ && ((AmbienceDigitalDJ) lDJ).getAmbience().getID().equals(sID)) { int i = Messages.getChoice(Messages.getString("DigitalDJWizard.61") + " " + lDJ.getName() + " ?", JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE); if (i == JOptionPane.YES_OPTION) { try { remove(lDJ); } catch (IOException e) { Log.error(e); } } else { return; } } } } } /** * Load all DJs (.dj files) found in jajuk home directory */ public void loadAllDJs() { try { // read all files that end with ".dj" in the configuration directory for // DJs File[] files = SessionService.getConfFileByPath(Const.FILE_DJ_DIR).listFiles( new FileFilter() { @Override public boolean accept(File file) { if (file.isFile() && file.getPath().endsWith('.' + Const.XML_DJ_EXTENSION)) { return true; } return false; } }); // read each of the files for (File element : files) { try { // try each DJ to continue others if one fails DigitalDJFactory factory = DigitalDJFactory.getFactory(element); DigitalDJ lDJ = factory.getDJ(element); djs.put(lDJ.getID(), lDJ); if (lDJ.getID().equals(Conf.getString(Const.CONF_DEFAULT_DJ))) { current = lDJ; } } catch (Exception e) { Log.error(144, "{{" + element.getAbsolutePath() + "}}", e); } } } catch (Exception e) { Log.error(e); } } /** * Gets the current dj. * * @return the current dj */ public static DigitalDJ getCurrentDJ() { return current; } /** * Sets the current dj. * * @param dj the new current dj */ public static void setCurrentDJ(DigitalDJ dj) { current = dj; } } /** * This class is responsible for creating different factories */ abstract class DigitalDJFactory extends DefaultHandler { /** Factory type (class name) */ private static String factoryType; /** DJ type (class name) */ protected String type; /** DJ name */ protected String name; /** DJ ID */ protected String id; /** DJ Fade duration */ protected int fadeDuration; /** Rating level */ protected int iRatingLevel; /** Startup genre */ protected Genre startupGenre; /** Track unicity */ protected boolean bTrackUnicity = false; protected int maxTracks; /** General parameters handlers */ abstract class GeneralDefaultHandler extends DefaultHandler { /** * Called when we start an element * */ @Override public void startElement(String sUri, String s, String sQName, Attributes attributes) throws SAXException { if (Const.XML_DJ_DJ.equals(sQName)) { id = attributes.getValue(attributes.getIndex(Const.XML_ID)); name = attributes.getValue(attributes.getIndex(Const.XML_NAME)); type = attributes.getValue(attributes.getIndex(Const.XML_TYPE)); } else if (Const.XML_DJ_GENERAL.equals(sQName)) { bTrackUnicity = Boolean.parseBoolean(attributes.getValue(attributes .getIndex(Const.XML_DJ_UNICITY))); iRatingLevel = Integer.parseInt(attributes.getValue(attributes .getIndex(Const.XML_DJ_RATING_LEVEL))); fadeDuration = Integer.parseInt(attributes.getValue(attributes .getIndex(Const.XML_DJ_FADE_DURATION))); // keep older DJs without this attribute usable if (attributes.getValue(attributes.getIndex(Const.XML_DJ_MAX_TRACKS)) != null) { maxTracks = Integer.parseInt(attributes.getValue(attributes .getIndex(Const.XML_DJ_MAX_TRACKS))); } else { maxTracks = -1; // default is infinity } } else {// others implementation dependant-operation othersTags(sQName, attributes); } } /** Non general tags operations */ abstract protected void othersTags(String sQname, Attributes attributes); } /** * * @param file * DJ configuration file (XML) * @return the right factory */ protected static DigitalDJFactory getFactory(File file) throws Exception { // Parse the file to get DJ type SAXParserFactory spf = SAXParserFactory.newInstance(); SAXParser saxParser = spf.newSAXParser(); try { saxParser.parse(file, new DefaultHandler() { /** * Called when we start an element */ @Override public void startElement(String sUri, String s, String sQName, Attributes attributes) throws SAXException { if (Const.XML_DJ_DJ.equals(sQName)) { factoryType = attributes.getValue(attributes.getIndex(Const.XML_TYPE)); } } }); if (Const.XML_DJ_PROPORTION_CLASS.equals(factoryType)) { return new DigitalDJFactoryProportionImpl(); } else if (Const.XML_DJ_TRANSITION_CLASS.equals(factoryType)) { return new DigitalDJFactoryTransitionImpl(); } else if (Const.XML_DJ_AMBIENCE_CLASS.equals(factoryType)) { return new DigitalDJFactoryAmbienceImpl(); } else { // Delete the file throw new JajukException(-1); } } // Error parsing the DJ ? delete it catch (Exception e) { Log.error(e); Log.debug("Corrupted DJ: {{" + file.getAbsolutePath() + "}} deleted"); try { UtilSystem.deleteFile(file); } catch (IOException ioe) { Log.error(ioe); } } return null; } /** * @param dj */ protected void setGeneralProperties(DigitalDJ dj) { dj.setName(name); dj.setFadingDuration(fadeDuration); dj.setRatingLevel(iRatingLevel); dj.setTrackUnicity(bTrackUnicity); dj.setMaxTracks(maxTracks); } /** * * @return DigitalDJ from associated factory * @param file * DJ file */ abstract DigitalDJ getDJ(File file) throws Exception; } /** * Proportion dj factory * */ class DigitalDJFactoryProportionImpl extends DigitalDJFactory { /** Intermediate genres variable used during parsing */ private String genres; /** Intermediate proportion variable used during parsing */ private float proportion; private final List proportions = new ArrayList(5); @Override DigitalDJ getDJ(File file) throws Exception { // Parse XML file to populate the DJ DefaultHandler handler = new GeneralDefaultHandler() { @Override protected void othersTags(String sQname, Attributes attributes) { if (Const.XML_DJ_PROPORTION.equals(sQname)) { genres = attributes.getValue(attributes.getIndex(Const.XML_DJ_GENRES)); proportion = Float.parseFloat(attributes .getValue(attributes.getIndex(Const.XML_DJ_VALUE))); StringTokenizer st = new StringTokenizer(genres, ","); Ambience ambience = new Ambience(Long.toString(System.currentTimeMillis()), ""); while (st.hasMoreTokens()) { ambience.addGenre(GenreManager.getInstance().getGenreByID(st.nextToken())); } proportions.add(new Proportion(ambience, proportion)); } } }; SAXParserFactory spf = SAXParserFactory.newInstance(); SAXParser saxParser = spf.newSAXParser(); saxParser.parse(file, handler); ProportionDigitalDJ dj = new ProportionDigitalDJ(id); setGeneralProperties(dj); dj.setProportions(proportions); return dj; } /** No direct constructor */ DigitalDJFactoryProportionImpl() { super(); } } /** * Ambience dj factory */ class DigitalDJFactoryAmbienceImpl extends DigitalDJFactory { private Ambience ambience; @Override DigitalDJ getDJ(File file) throws Exception { // Parse XML file to populate the DJ DefaultHandler handler = new GeneralDefaultHandler() { @Override protected void othersTags(String sQname, Attributes attributes) { if (Const.XML_DJ_AMBIENCE.equals(sQname)) { String sAmbienceID = attributes.getValue(attributes.getIndex(Const.XML_DJ_VALUE)); ambience = AmbienceManager.getInstance().getAmbience(sAmbienceID); } } }; SAXParserFactory spf = SAXParserFactory.newInstance(); SAXParser saxParser = spf.newSAXParser(); saxParser.parse(file, handler); AmbienceDigitalDJ dj = new AmbienceDigitalDJ(id); setGeneralProperties(dj); dj.setAmbience(ambience); return dj; } /** No direct constructor */ DigitalDJFactoryAmbienceImpl() { super(); } } /** * Transition dj factory * */ class DigitalDJFactoryTransitionImpl extends DigitalDJFactory { /** Intermediate transition list */ private final List transitions = new ArrayList(10); @Override DigitalDJ getDJ(File file) throws Exception { // Parse XML file to populate the DJ DefaultHandler handler = new GeneralDefaultHandler() { @Override protected void othersTags(String sQname, Attributes attributes) { if (Const.XML_DJ_TRANSITION.equals(sQname)) { int number = Integer.parseInt(attributes.getValue(attributes .getIndex(Const.XML_DJ_NUMBER))); String fromGenres = attributes.getValue(attributes.getIndex(Const.XML_DJ_FROM)); StringTokenizer st = new StringTokenizer(fromGenres, ","); Ambience fromAmbience = new Ambience(); while (st.hasMoreTokens()) { fromAmbience.addGenre(GenreManager.getInstance().getGenreByID(st.nextToken())); } String toGenres = attributes.getValue(attributes.getIndex(Const.XML_DJ_TO)); Ambience toAmbience = new Ambience(); st = new StringTokenizer(toGenres, ","); while (st.hasMoreTokens()) { toAmbience.addGenre(GenreManager.getInstance().getGenreByID(st.nextToken())); } transitions.add(new Transition(fromAmbience, toAmbience, number)); } } }; SAXParserFactory spf = SAXParserFactory.newInstance(); SAXParser saxParser = spf.newSAXParser(); saxParser.parse(file, handler); TransitionDigitalDJ dj = new TransitionDigitalDJ(id); setGeneralProperties(dj); dj.setTransitions(transitions); return dj; } /** No direct constructor */ DigitalDJFactoryTransitionImpl() { super(); } }jajuk-1.9.6.orig/src/main/java/org/jajuk/services/dj/AmbienceDigitalDJ.java0000644000175000017500000000616211720500104026312 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.services.dj; import java.util.ArrayList; import java.util.List; import org.jajuk.base.File; import org.jajuk.base.FileManager; import org.jajuk.util.Const; import org.jajuk.util.Messages; /** * Ambience DJ. */ public class AmbienceDigitalDJ extends DigitalDJ { /** Used ambience. */ private Ambience ambience; /** * The Constructor. * * @param sID DOCUMENT_ME */ public AmbienceDigitalDJ(String sID) { super(sID); } /* * (non-Javadoc) * * @see org.jajuk.base.DigitalDJ#generatePlaylist() */ @Override public List generatePlaylist() { if (ambience == null) { // can be null if ambience has been removed Messages.showErrorMessage(159); return new ArrayList(); } List out = getSequence(); if (!bUnicity && out.size() > 0) { while (out.size() < Const.MIN_TRACKS_NUMBER_WITHOUT_UNICITY) { out.addAll(getSequence()); } } return out; } /** * Gets the sequence. * * @return a single loop sequence */ private List getSequence() { List out = new ArrayList(100); // Get a shuffle selection List files = FileManager.getInstance().getGlobalShufflePlaylist(); // Keep only right genres and check for unicity for (File file : files) { if (ambience.getGenres().contains(file.getTrack().getGenre())) { out.add(file); } } // Select by rate if needed filterFilesByRate(out); // finally ensure that we don't select more than the max number of tracks filterFilesByMaxTrack(out); return out; } /** * Gets the ambience. * * @return Ambience */ public Ambience getAmbience() { return this.ambience; } /** * (non-Javadoc). * * @return the string * * @see dj.DigitalDJ#toXML() */ @Override public String toXML() { StringBuilder sb = new StringBuilder(2000); sb.append(toXMLGeneralParameters()); sb.append("\t<" + Const.XML_DJ_AMBIENCE + " " + Const.XML_DJ_VALUE + "='"); sb.append((ambience == null ? "" : ambience.getID()) + "'/>\n"); sb.append("\n"); return sb.toString(); } /** * Sets the ambience. * * @param ambience the new ambience */ public void setAmbience(Ambience ambience) { this.ambience = ambience; } }jajuk-1.9.6.orig/src/main/java/org/jajuk/services/dj/Transition.java0000644000175000017500000001161111720500104025220 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.services.dj; import org.jajuk.base.Genre; import org.jajuk.util.UtilFeatures; /** * Represents a transition from one genre to another (used by digital DJs). */ public class Transition { /** From genres. */ private Ambience from; /** To genres. */ private Ambience to; /** Nb of tracks. */ private int nb; /** * Constructor. * * @param from source genres * @param to destination genre * @param nb number of tracks played before changing genre */ public Transition(Ambience from, Ambience to, int nb) { this.from = from; this.to = to; this.nb = nb; } /** * Constructor for void transition. * * @param nb initial number of tracks */ public Transition(int nb) { this.from = new Ambience(Long.toString(System.currentTimeMillis()), ""); this.to = new Ambience(Long.toString(System.currentTimeMillis() - 100), ""); this.nb = nb; } /** * equals method. * * @param other DOCUMENT_ME * * @return whether two object are equals */ @Override public boolean equals(Object other) { if (!(other instanceof Transition)) { return false; } return getFrom().equals(((Transition) other).getFrom()) && getTo().equals(((Transition) other).getTo()); } /* (non-Javadoc) * @see java.lang.Object#hashCode() */ @Override public int hashCode() { // for now just combine name and id to a hashcode // idea taken from // http://www.geocities.com/technofundo/tech/java/equalhash.html int hash = 7; hash = 31 * hash + getFrom().hashCode(); hash = 31 * hash + getTo().hashCode(); return hash; } /** * Gets the from. * * @return Returns the from. */ /** * @return */ public Ambience getFrom() { return this.from; } /** * From String, return genre1,genre2,... * * @return the from string */ public String getFromString() { String out = ""; for (Genre s : from.getGenres()) { out += s.getName2() + ','; } if (out.length() > 0) { out = out.substring(0, out.length() - 1); // remove trailing , } return out; } /** * "To" String, return genre1,genre2,... * * @return the to string */ public String getToString() { String out = ""; for (Genre s : to.getGenres()) { out += s.getName2() + ','; } if (out.length() > 0) { out = out.substring(0, out.length() - 1); // remove trailing , } return out; } /** * Gets the to. * * @return Returns the to. */ /** * @return */ public Ambience getTo() { return this.to; } /** * Adds the from genre. * DOCUMENT_ME * * @param genre DOCUMENT_ME */ public void addFromGenre(Genre genre) { from.addGenre(genre); } /** * Removes the from genre. * * @param genre DOCUMENT_ME */ public void removeFromGenre(Genre genre) { from.removeGenre(genre); } /** * Adds the to genre. * DOCUMENT_ME * * @param genre DOCUMENT_ME */ public void addToGenre(Genre genre) { to.addGenre(genre); } /** * Removes the to genre. * * @param genre DOCUMENT_ME */ public void removeToGenre(Genre genre) { to.removeGenre(genre); } /** * Gets the next genre. * * @return next genre to be played or null if no idea */ public Genre getNextGenre() { if (to.getGenres().size() == 0) { return null; } else if (to.getGenres().size() == 1) { return to.getGenres().iterator().next(); } else { // several destination genres, return a shuffle one return UtilFeatures.getShuffleItem(to.getGenres()); } } /** * Gets the nb tracks. * * @return the nb tracks */ public int getNbTracks() { return this.nb; } /** * Sets the from. * * @param from the new from */ public void setFrom(Ambience from) { this.from = from; } /** * Sets the to. * * @param to the new to */ public void setTo(Ambience to) { this.to = to; } /** * Sets the nb. * * @param nb the new nb */ public void setNb(int nb) { this.nb = nb; } } jajuk-1.9.6.orig/src/main/java/org/jajuk/services/dj/Ambience.java0000644000175000017500000001316711720500104024601 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.services.dj; import java.util.HashSet; import java.util.Set; import org.jajuk.base.Genre; import org.jajuk.base.GenreManager; /** * An ambience is a set of genres
    * Note that an ambience is identified by an id and not its name Several * ambiences can eventually share the same name. This is because ambience is * translated and can change with current locale */ public class Ambience implements Comparable { /** List of genres. */ private Set genres; /** Ambience name. */ private String sName; /** Ambience ID. */ private final String sID; /** * Constructor. * * @param sID Ambience unique id * @param sName Ambience name * @param genres list of genres */ public Ambience(String sID, String sName, Set genres) { this.sID = sID; this.sName = sName; this.genres = genres; } /** * Constructor. * * @param sID Ambience unique id * @param sName Ambience name * @param genres list by name */ public Ambience(String sID, String sName, String[] genres) { Set hgenres = new HashSet(genres.length); for (String element : genres) { Genre genre = GenreManager.getInstance().getGenreByName(element); if (genre != null) { hgenres.add(genre); } } this.sID = sID; this.sName = sName; this.genres = hgenres; } /** * Constructor. * * @param sID DOCUMENT_ME * @param sName Ambience name */ public Ambience(String sID, String sName) { this(sID, sName, new HashSet(10)); } /** * Constructor. */ public Ambience() { this.sID = "" + System.currentTimeMillis(); this.sName = ""; this.genres = new HashSet(10); } /** * Adds the genre. * DOCUMENT_ME * * @param genre DOCUMENT_ME */ public void addGenre(Genre genre) { if (genre != null) { genres.add(genre); } } /** * Removes the genre. * DOCUMENT_ME * * @param genre DOCUMENT_ME */ public void removeGenre(Genre genre) { genres.remove(genre); } /** * Gets the name. * * @return the name */ public String getName() { return this.sName; } /** * Gets the iD. * * @return the iD */ public String getID() { return this.sID; } /** * Sets the name. * * @param name the new name */ public void setName(String name) { this.sName = name; } /** * Gets the genres. * * @return the genres */ public Set getGenres() { return this.genres; } /** * Sets the genres. * * @param genres the new genres */ public void setGenres(Set genres) { this.genres = genres; } /** * From String, return genre1,genre2,... * * @return the genres desc */ public String getGenresDesc() { // check if we have genres at all if (getGenres().size() == 0) { return ""; } StringBuilder out = new StringBuilder(); for (Genre s : getGenres()) { out.append(s.getName2()).append(','); } return out.substring(0, out.length() - 1); // remove trailling , } /** * toString method. * * @return String representation of this item */ @Override public String toString() { return sName + " " + genres; } /** * Equals method. * * @param o DOCUMENT_ME * * @return true if ambience have the same same and contains the same genres */ @Override public boolean equals(Object o) { // also catches null by definition if (!(o instanceof Ambience)) { return false; } Ambience ambienceOther = (Ambience) o; return this.sName.equals(ambienceOther.getName()) && this.genres.equals(ambienceOther.getGenres()); } /* (non-Javadoc) * @see java.lang.Object#hashCode() */ @Override public int hashCode() { // for now just combine name and id to a hashcode // idea token from // http://www.geocities.com/technofundo/tech/java/equalhash.html int hash = 7; hash = 31 * hash + sName.hashCode(); hash = 31 * hash + sID.hashCode(); return hash; } /** * Compare to method : alphabetical. * * @param ambience DOCUMENT_ME * * @return the int */ @Override public int compareTo(Ambience ambience) { // check for null if (ambience == null) { return -1; } // otherwise just compare on the name return this.getName().compareToIgnoreCase(ambience.getName()); } /** * return "genre1,genre2,..,genre_n" * * @return String used in DJ XML representation */ public String toXML() { // check if we have genres at all if (getGenres().size() == 0) { return ""; } StringBuilder s = new StringBuilder(); for (Genre genre : getGenres()) { s.append(genre.getID()).append(','); } return s.substring(0, s.length() - 1); // remove last coma } } jajuk-1.9.6.orig/src/main/java/org/jajuk/services/lyrics/0000755000175000017500000000000011720500104023133 5ustar drazzibdrazzibjajuk-1.9.6.orig/src/main/java/org/jajuk/services/lyrics/package.html0000644000175000017500000000017111720500104025413 0ustar drazzibdrazzib DOCUMENT_ME jajuk-1.9.6.orig/src/main/java/org/jajuk/services/lyrics/persisters/0000755000175000017500000000000011720500104025336 5ustar drazzibdrazzibjajuk-1.9.6.orig/src/main/java/org/jajuk/services/lyrics/persisters/package.html0000644000175000017500000000017111720500104027616 0ustar drazzibdrazzib DOCUMENT_ME jajuk-1.9.6.orig/src/main/java/org/jajuk/services/lyrics/persisters/ILyricsPersister.java0000644000175000017500000000341411720500104031462 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.services.lyrics.persisters; import org.jajuk.base.File; /** * Interface for lyrics persisters to be used by the modified LyricsService. */ public interface ILyricsPersister { /** * Sets the audio file to set lyrics to. * * @param file the new audio file */ void setAudioFile(File file); /** * Commit lyrics for a given filename
    * Returns true if commited correctly, false otherwise. * * @param artist DOCUMENT_ME * @param title DOCUMENT_ME * @param lyrics lyrics as a string * @return true if OK, false otherwise */ boolean commitLyrics(String artist, String title, String lyrics); /** * Deletes Lyrics that user has saved
    * in Tag or in a Txt file. * Returns true if deleted correctly, false otherwise. * * @return true, if delete lyrics */ boolean deleteLyrics(); /** * Gets the destination file. * * @return the destination file */ java.io.File getDestinationFile(); } jajuk-1.9.6.orig/src/main/java/org/jajuk/services/lyrics/persisters/TxtPersister.java0000644000175000017500000000645011720500104030666 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.services.lyrics.persisters; import java.io.FileWriter; import java.io.IOException; import java.io.Writer; import org.jajuk.util.UtilSystem; import org.jajuk.util.log.Log; /** * Class to read/write lyrics to TXT file. */ public class TxtPersister implements ILyricsPersister { /** DOCUMENT_ME. */ private java.io.File lyricsFile = null; /** DOCUMENT_ME. */ private Writer lyricsWriter = null; /** Audio file to set lyrics to. */ private org.jajuk.base.File file = null; /* (non-Javadoc) * @see org.jajuk.services.lyrics.persisters.ILyricsPersister#commitLyrics(String,String,String) */ @Override public boolean commitLyrics(String artist, String title, String lyrics) { try { lyricsWriter = getLyricsWriter(); lyricsWriter.write("# This is a Jajuk generated lyrics file\n"); lyricsWriter.write("# Artist:\t" + artist + "\n"); lyricsWriter.write("# Title:\t" + title + "\n#"); lyricsWriter.write("\n" + lyrics + "\n"); lyricsWriter.close(); lyricsWriter = null; return true; } catch (Exception e) { Log.error(e); try { if (lyricsFile.exists()) { UtilSystem.deleteFile(lyricsFile); } } catch (IOException e1) { Log.error(e1); } lyricsFile = null; return false; } } /* (non-Javadoc) * @see org.jajuk.services.lyrics.persisters.ILyricsPersister#deleteLyrics() */ @Override public boolean deleteLyrics() { lyricsFile = getDestinationFile(); try { UtilSystem.deleteFile(lyricsFile); return true; } catch (IOException e) { Log.error(e); return false; } } /** * Gets the lyrics file. * * @return the lyrics file */ @Override public java.io.File getDestinationFile() { if (lyricsFile == null) { lyricsFile = new java.io.File(UtilSystem.removeExtension(file.getAbsolutePath()) + ".txt"); } return lyricsFile; } /** * Gets the lyrics writer. * * @return the lyrics writer * * @throws IOException Signals that an I/O exception has occurred. */ private Writer getLyricsWriter() throws IOException { lyricsFile = getDestinationFile(); if (lyricsWriter == null) { lyricsWriter = new FileWriter(lyricsFile); } return lyricsWriter; } /* (non-Javadoc) * @see org.jajuk.services.lyrics.persisters.ILyricsPersister#setAudioFile(java.io.File) */ @Override public void setAudioFile(org.jajuk.base.File file) { this.file = file; } } jajuk-1.9.6.orig/src/main/java/org/jajuk/services/lyrics/persisters/TagPersister.java0000644000175000017500000000455311720500104030624 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.services.lyrics.persisters; import org.jajuk.base.File; import org.jajuk.services.tags.Tag; import org.jajuk.util.error.JajukException; import org.jajuk.util.log.Log; /** * Class to read/write lyrics to Tag of Track. */ public class TagPersister implements ILyricsPersister { /** Audio file to set lyrics to. */ private File file = null; /* (non-Javadoc) * @see org.jajuk.services.lyrics.persisters.ILyricsPersister#commitLyrics(String,String,String) */ @Override public boolean commitLyrics(String artist, String title, String lyrics) { try { Tag g = Tag.getTagForFio(file.getFIO(), true); g.setLyrics(lyrics); return true; } catch (JajukException e) { Log.error(e); Log.warn(e.getMessage()); return false; } } /* (non-Javadoc) * @see org.jajuk.services.lyrics.persisters.ILyricsPersister#deleteLyrics() */ @Override public boolean deleteLyrics() { try { Tag g = Tag.getTagForFio(file.getFIO(), true); g.deleteLyrics(); return true; } catch (JajukException e) { Log.error(e); return false; } } /* (non-Javadoc) * @see org.jajuk.services.lyrics.persisters.ILyricsPersister#getDestinationFile() */ @Override public java.io.File getDestinationFile() { // For tag persister, destination file is audio file itself return file.getFIO(); } /* (non-Javadoc) * @see org.jajuk.services.lyrics.persisters.ILyricsPersister#setAudioFile(java.io.File) */ @Override public void setAudioFile(File file) { this.file = file; } } jajuk-1.9.6.orig/src/main/java/org/jajuk/services/lyrics/LyricsService.java0000644000175000017500000001736411720500104026577 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.services.lyrics; import java.util.ArrayList; import java.util.List; import org.apache.commons.lang.StringUtils; import org.jajuk.base.File; import org.jajuk.services.lyrics.persisters.ILyricsPersister; import org.jajuk.services.lyrics.providers.ILyricsProvider; import org.jajuk.services.lyrics.providers.JajukLyricsProvider; import org.jajuk.ui.widgets.InformationJPanel; import org.jajuk.ui.widgets.InformationJPanel.MessageType; import org.jajuk.util.Messages; import org.jajuk.util.error.LyricsPersistenceException; import org.jajuk.util.log.Log; /** * Lyrics retrieval service. This service will retrieves lyrics from various * providers, querying all of them until one returns some valid input. * * TODO: user-selectable multi-input-sources. edit the LyricsService so that it will * notify about various valid sources, so we could propose various inputs to the * user. For now the lyrics providers list is static and stored directly in this class. */ public final class LyricsService { /** DOCUMENT_ME. */ private static List providers = null; /** DOCUMENT_ME. */ private static ILyricsProvider current = null; /** DOCUMENT_ME. */ private static List persisters = null; /** Providers list. */ private static String[] providersClasses = new String[] { "org.jajuk.services.lyrics.providers.TagLyricsProvider", "org.jajuk.services.lyrics.providers.TxtLyricsProvider", "org.jajuk.services.lyrics.providers.LyricWikiWebLyricsProvider", }; /** Persisters list. */ private static String[] persisterClasses = new String[] { "org.jajuk.services.lyrics.persisters.TagPersister", "org.jajuk.services.lyrics.persisters.TxtPersister" }; /** * Empty private constructor to avoid instantiating utility class. */ private LyricsService() { } /** * Loads the appropriate providers from the properties file. For now, * providers order is static and the providersClasses array reflect jajuk * artists service preferred ordering * * @TODO this behavior could eventually be switched to a shuffle provider list * for performance or better resources usage reasons */ @SuppressWarnings("unchecked") public static void loadProviders() { providers = new ArrayList(2); try { for (String providerClass : providersClasses) { if (!StringUtils.isBlank(providerClass)) { Class clazz = (Class) Class.forName(providerClass); ILyricsProvider provider = clazz.newInstance(); providers.add(provider); Log.debug("Added Lyrics provider " + providerClass); } } } catch (Exception e) { Log.error(e); } } /** * Load persisters. * DOCUMENT_ME */ @SuppressWarnings("unchecked") public static void loadPersisters() { persisters = new ArrayList(2); try { for (String persisterClass : persisterClasses) { if (!StringUtils.isBlank(persisterClass)) { Class clazz = (Class) Class.forName(persisterClass); ILyricsPersister persister = clazz.newInstance(); persisters.add(persister); Log.debug("Added Lyrics persister " + persisterClass); } } } catch (Exception e) { Log.error(e); } } /** * Cycles through lyrics providers to return the best matching lyrics. * * @param audioFile DOCUMENT_ME * * @return the song's lyrics */ public static String getLyrics(final File audioFile) { String lyrics = null; current = null; Log.debug("Retrieving lyrics for file {{" + audioFile + "}}"); for (final ILyricsProvider provider : getProviders()) { provider.setAudioFile(audioFile); lyrics = provider.getLyrics(); current = provider; if (lyrics != null) { break; } } // None provider found lyrics so reset current if (lyrics == null) { current = null; } return lyrics; } /** * Commit lyrics for a jajuk lyrics provider (jajuk GUI). * * @param provider the JajukLyricsProvider * * @throws LyricsPersistenceException if lyrics cannot be written */ public static void commitLyrics(JajukLyricsProvider provider) throws LyricsPersistenceException { boolean commitOK = false; String destinationPath = null; Log.debug("Commiting lyrics for file {{" + provider.getFile().getAbsolutePath() + "}}"); // Try each persister until we actually persist lyrics for (final ILyricsPersister persister : getPersisters()) { persister.setAudioFile(provider.getFile()); destinationPath = persister.getDestinationFile().getAbsolutePath(); commitOK = persister.commitLyrics(provider.getArtist(), provider.getTitle(), provider.getLyrics()); if (commitOK) { break; } } if (commitOK) { Log.info("Lyrics successfully commited to : " + destinationPath); InformationJPanel.getInstance().setMessage( Messages.getString("Success") + " [" + destinationPath + "]", MessageType.INFORMATIVE); } else { throw new LyricsPersistenceException("Lyrics could not be commited to " + provider.getFile().getAbsolutePath()); } } /** * Delete lyrics from any persister support. * * @param provider DOCUMENT_ME * * @throws LyricsPersistenceException if the lyrics cannot be removed */ public static void deleteLyrics(JajukLyricsProvider provider) throws LyricsPersistenceException { boolean deleteOK = false; String destinationPath = null; Log.debug("deleting lyrics for file {{" + provider.getFile().getAbsolutePath() + "}}"); for (final ILyricsPersister persister : getPersisters()) { persister.setAudioFile(provider.getFile()); destinationPath = persister.getDestinationFile().getAbsolutePath(); deleteOK = persister.deleteLyrics(); if (deleteOK) { break; } } if (deleteOK) { Log.info("Lyrics successfully deleted for file : " + provider.getFile().getAbsolutePath()); InformationJPanel.getInstance().setMessage( Messages.getString("Success") + " [" + destinationPath + "]", MessageType.INFORMATIVE); } else { throw new LyricsPersistenceException("Lyrics could not be deleted from " + provider.getFile().getName()); } } /** * Returns the lazy-instantiated providers collection. * * @return the map of loaded providers */ public static List getProviders() { if (providers == null) { loadProviders(); } return providers; } /** * Gets the current provider. * * @return the current provider */ public static ILyricsProvider getCurrentProvider() { return current; } /** * Gets the persisters. * * @return the persisters */ public static List getPersisters() { if (persisters == null) { loadPersisters(); } return persisters; } } jajuk-1.9.6.orig/src/main/java/org/jajuk/services/lyrics/providers/0000755000175000017500000000000011720500104025150 5ustar drazzibdrazzibjajuk-1.9.6.orig/src/main/java/org/jajuk/services/lyrics/providers/TxtLyricsProvider.java0000644000175000017500000000647411720500104031506 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.services.lyrics.providers; import java.io.BufferedReader; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; import org.apache.commons.lang.StringUtils; import org.jajuk.base.File; import org.jajuk.util.UtilSystem; import org.jajuk.util.log.Log; /** * DOCUMENT_ME. */ public class TxtLyricsProvider implements ILyricsProvider { /** DOCUMENT_ME. */ private BufferedReader lyricsReader = null; /** DOCUMENT_ME. */ private String readerPath = null; /** audio file we search lyrics for. */ private File audioFile = null; /* (non-Javadoc) * @see org.jajuk.services.lyrics.providers.ILyricsProvider#getLyrics() */ @Override public String getLyrics() { readerPath = UtilSystem.removeExtension(audioFile.getAbsolutePath()) + ".txt"; if (!new java.io.File(readerPath).exists()) { Log.debug("Lyrics Txt file not found, can not read lyrics for Txt-Provider"); return null; } try { String lyrics = ""; lyricsReader = getLyricsReader(); String s = null; while ((s = lyricsReader.readLine()) != null) { if (!s.startsWith("#")) { lyrics += s + "\n"; } } lyricsReader.close(); lyricsReader = null; // So it will be instanced new if (StringUtils.isBlank(lyrics)) { return null; } return lyrics; } catch (FileNotFoundException e) { Log.debug("Not found approriate lyrics Txt file"); return null; } catch (IOException e) { Log.error(e); return null; } } /* (non-Javadoc) * @see org.jajuk.services.lyrics.providers.ILyricsProvider#getResponseEncoding() */ @Override public String getResponseEncoding() { return "UTF-8"; } /** * Gets the lyrics reader. * * @return the lyrics reader * * @throws FileNotFoundException the file not found exception */ private BufferedReader getLyricsReader() throws FileNotFoundException { if (lyricsReader == null) { lyricsReader = new BufferedReader(new FileReader(readerPath)); } return lyricsReader; } /* (non-Javadoc) * @see org.jajuk.services.lyrics.providers.ILyricsProvider#setAudioFile(org.jajuk.base.File) */ @Override public void setAudioFile(File file) { this.audioFile = file; } /* (non-Javadoc) * @see org.jajuk.services.lyrics.providers.ILyricsProvider#getSourceAddress() */ @Override public String getSourceAddress() { return UtilSystem.removeExtension(audioFile.getAbsolutePath()) + ".txt"; } } jajuk-1.9.6.orig/src/main/java/org/jajuk/services/lyrics/providers/package.html0000644000175000017500000000017111720500104027430 0ustar drazzibdrazzib DOCUMENT_ME jajuk-1.9.6.orig/src/main/java/org/jajuk/services/lyrics/providers/GenericWebLyricsProvider.java0000644000175000017500000001241711720500104032733 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.services.lyrics.providers; import ext.services.network.NetworkUtils; import java.net.MalformedURLException; import java.net.URL; import org.jajuk.base.File; import org.jajuk.base.Track; import org.jajuk.util.Const; import org.jajuk.util.DownloadManager; import org.jajuk.util.log.Log; /** * GenericProvider is a basic processor for web-based lyrics providers. It * doesn't provide fine-grained processing and simply retrieves raw text data * from HTML pages. * * The GenericProvider is used as a base class by other, more fine-grained * specific providers. */ public abstract class GenericWebLyricsProvider implements ILyricsProvider { /** DOCUMENT_ME. */ private String source = null; /** DOCUMENT_ME. */ private String queryUrlTemplate = null; /** audio file we search lyrics for. */ File audioFile = null; /** * Instantiates a new generic web lyrics provider. * * @param queryUrlTemplate DOCUMENT_ME */ public GenericWebLyricsProvider(final String queryUrlTemplate) { this.queryUrlTemplate = queryUrlTemplate; } /* * Call the provider @artist non encoded artist @title non encoded title * @return query return or null if query fails */ /** * Call provider. * DOCUMENT_ME * * @param artist DOCUMENT_ME * @param title DOCUMENT_ME * * @return the string */ public String callProvider(final String artist, final String title) { String text = null; try { URL url = getActualURL(artist, title); text = DownloadManager.getTextFromCachedFile(url, getResponseEncoding()); } catch (final Exception e) { Log.warn("Could not retrieve URL {{" + getProviderHostname() + "}}", e.getMessage()); } return text; } /** * Return query URL template like http://..?artist=%artist&songname=%title * * @return query URL template like http://..?artist=%artist&songname=%title */ public String getQueryURLTemplate() { return queryUrlTemplate; } /** * Return the hostname of the lyrics provider, used as unique identifier for * the provider. * * @return the provider hostname */ public String getProviderHostname() { if (source == null) { try { source = new URL(queryUrlTemplate).getHost(); } catch (final MalformedURLException e) { Log.warn("Invalid lyrics provider [" + queryUrlTemplate + "]", e.getMessage()); } } return source; } /** * Build the actual formated and valorized URL to the provider. * * @param artist the artist * @param title the title * * @return URL the final url */ URL getActualURL(final String artist, final String title) { try { String queryString = getQueryURLTemplate(); queryString = queryString.replace(Const.PATTERN_ARTIST, (artist != null) ? NetworkUtils .encodeString(artist) : ""); queryString = queryString.replace(Const.PATTERN_TRACKNAME, (title != null) ? NetworkUtils .encodeString(title) : ""); return new URL(queryString); } catch (MalformedURLException e) { Log.error(e); return null; } } /** * Return the URL from where the lyrics can be displayed from out of Jajuk *
    * Note that this URL can be different from the jajuk used url for example if * a provider provides a web service interface (jajuk then uses the * corresponding URL) and a Web page (this is this URL that is returned from * this method). * * @param artist DOCUMENT_ME * @param title DOCUMENT_ME * * @return the Web URL or null if a problem occurred */ public abstract java.net.URL getWebURL(String artist, String title); /** * Gets the lyrics. * * @param artist DOCUMENT_ME * @param title DOCUMENT_ME * * @return the lyrics */ public abstract String getLyrics(String artist, String title); /* (non-Javadoc) * @see org.jajuk.services.lyrics.providers.ILyricsProvider#getLyrics() */ @Override public String getLyrics() { // TODO Auto-generated method stub return null; } /* (non-Javadoc) * @see org.jajuk.services.lyrics.providers.ILyricsProvider#setAudioFile(org.jajuk.base.File) */ @Override public void setAudioFile(File file) { this.audioFile = file; } /* (non-Javadoc) * @see org.jajuk.services.lyrics.providers.ILyricsProvider#getSourceAddress() */ @Override public String getSourceAddress() { Track track = audioFile.getTrack(); return getWebURL(track.getArtist().getName2(), track.getName()).toString(); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/services/lyrics/providers/LyricWikiWebLyricsProvider.java0000644000175000017500000001400111720500104033254 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.services.lyrics.providers; import ext.services.network.NetworkUtils; import java.net.MalformedURLException; import java.util.StringTokenizer; import org.apache.commons.lang.StringUtils; import org.jajuk.util.Const; import org.jajuk.util.log.Log; /** * Lyrics Provider extracting lyrics from lyricwiki.org */ public class LyricWikiWebLyricsProvider extends GenericWebLyricsProvider { /** URL pattern used by jajuk to retrieve lyrics. */ private static final String URL = "http://lyrics.wikia.com/%artist:%title"; /** URL pattern to web page (see ILyricsProvider interface for details). */ private static final String WEB_URL = "http://lyrics.wikia.com/%artist:%title"; /** * Instantiates a new lyric wiki web lyrics provider. */ public LyricWikiWebLyricsProvider() { super(URL); } /* * (non-Javadoc) * * @see ext.services.lyrics.providers.GenericProvider#getLyrics(java.lang.String, * java.lang.String) */ @Override public String getLyrics(final String artist, final String title) { try { // This provider waits for '_' instead of regular '+' for spaces in URL String formattedArtist = artist.replaceAll(" ", "_"); String formattedTitle = title.replaceAll(" ", "_"); String html = callProvider(formattedArtist, formattedTitle); if (StringUtils.isBlank(html)) { Log.debug("Empty return from callProvider()."); return null; } // Remove html part html = cleanLyrics(html); // From oct 2009, lyrics wiki returns lyrics encoded as HTML chars // like Sha ... StringBuffer sbFinalHtml = new StringBuffer(1000); StringTokenizer st = new StringTokenizer(html, "&#"); while (st.hasMoreTokens()) { String token = st.nextToken(); // Remove trailing ';' if (token.endsWith("\n")) { String trailing = token.substring(token.indexOf(';') + 1); token = token.substring(0, token.indexOf(';')); sbFinalHtml.append((char) Integer.parseInt(token, 10)); // Re-add carriage returns sbFinalHtml.append(trailing); } else { token = token.substring(0, token.length() - 1); sbFinalHtml.append((char) Integer.parseInt(token, 10)); } } return sbFinalHtml.toString(); } catch (Exception e) { Log.debug("Cannot fetch lyrics for: {{" + artist + "/" + title + "}}"); return null; } } /** * Extracts lyrics from the HTML page. The correct subsection is to be * extracted first, before being cleaned and stripped from useless HTML tags. * * @param html DOCUMENT_ME * * @return the lyrics */ private String cleanLyrics(final String html) { String ret = html; // LyricWiki uses this with and without blank sometimes, maybe we should use // a regular expression instead... if (ret.contains("
    ") || ret.contains("
    ")) { int startIndex = html.indexOf("
    "); if (startIndex == -1) { startIndex = html.indexOf("
    "); ret = html.substring(startIndex + 22); // LyricWiki added some additional div class now... if (ret.startsWith("
    ")) { startIndex = ret.indexOf("
    "); ret = ret.substring(startIndex + 6); } } else { ret = html.substring(startIndex + 23); } int stopIndex = ret.indexOf(" jajuk-1.9.6.orig/src/main/java/org/jajuk/util/log/package.html0000644000175000017500000000007011720500104024017 0ustar drazzibdrazzib

    Logging facilities

    jajuk-1.9.6.orig/src/main/java/org/jajuk/util/log/Log.java0000644000175000017500000003072311720500104023132 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.util.log; import java.util.ArrayList; import java.util.List; import org.apache.log4j.Level; import org.apache.log4j.Logger; import org.apache.log4j.xml.DOMConfigurator; import org.jajuk.services.core.SessionService; import org.jajuk.util.Const; import org.jajuk.util.Messages; import org.jajuk.util.error.JajukException; /** * Logging utility class, facade to logging system *

    * Singleton. */ public final class Log { /** The Constant FONT_END. DOCUMENT_ME */ private static final String FONT_END = ""; /** The Constant LOGGER_APACHE_HTTPCLIENT. DOCUMENT_ME */ private static final String LOGGER_APACHE_HTTPCLIENT = "org.apache.commons.httpclient"; // verbosity consts /** The Constant FATAL. DOCUMENT_ME */ public static final int FATAL = 0; /** The Constant ERROR. DOCUMENT_ME */ public static final int ERROR = 1; /** The Constant WARNING. DOCUMENT_ME */ public static final int WARNING = 2; /** The Constant INFO. DOCUMENT_ME */ public static final int INFO = 3; /** The Constant DEBUG. DOCUMENT_ME */ public static final int DEBUG = 4; /** Verbosity level of the logger( between 1 and 5 )

    Default used at statup is INFO. */ private static int verbosity = INFO; /** Jajuk logger. */ private static Logger logger; /** Debug traces spool. */ private static List alSpool; /** The Constant FULL_QUALIFIED_CLASS_NAME. DOCUMENT_ME */ private static final String FULL_QUALIFIED_CLASS_NAME = Log.class.getName(); /** * Log system initialization. */ public static void init() { try { // set env variable used in the log4j conf file System.setProperty("jajuk.log", SessionService.getConfFileByPath(Const.FILE_LOGS) .getAbsolutePath()); DOMConfigurator.configure(Const.FILE_LOG4J_CONF); } catch (Exception e) { Log.stack(e); } logger = Logger.getLogger(Log.class.getName()); alSpool = new ArrayList(Const.FEEDBACK_LINES); // message for logging system start Log.info("******************JAJUK******************"); Log.info("Version: " + Const.JAJUK_VERSION); } /** * Log a debug-level message. * * @param s DOCUMENT_ME */ public static synchronized void debug(String s) { // Just display the message if Log is not yet enabled if (logger == null) { System.out.println("[DEBUG] " + s); return; } spool("[DEBUG] " + s); logger.log(FULL_QUALIFIED_CLASS_NAME, Level.DEBUG, s, null); } /** * Debug. * DOCUMENT_ME * * @param t DOCUMENT_ME */ public static void debug(Throwable t) { debug("", t); } /** * Debug. * DOCUMENT_ME * * @param sInfosup DOCUMENT_ME * @param t DOCUMENT_ME */ public static synchronized void debug(String sInfosup, Throwable t) { // Just make a print stake trace if Log is not yet enabled (example: // collection commit problem in initialCheckups) if (logger == null) { System.out.println("[DEBUG] " + sInfosup); stack(t); return; } String sOut; if (Messages.isInitialized()) { sOut = ((sInfosup == null) ? "" : ": " + sInfosup); } else { sOut = ((sInfosup == null) ? "" : ":" + sInfosup); } spool("[DEBUG] " + sOut + FONT_END); if (t != null) { spool(t); } logger.log(FULL_QUALIFIED_CLASS_NAME, Level.DEBUG, sOut, t); } /** * Log a info-level message. * * @param s DOCUMENT_ME */ public static synchronized void info(String s) { // Just display the message if Log is not yet enabled if (logger == null) { System.out.println("[INFO] " + s); return; } spool("[INFO] " + s + FONT_END); logger.log(FULL_QUALIFIED_CLASS_NAME, Level.INFO, s, null); } /** * Log a warning-level message. * * @param s DOCUMENT_ME */ public static synchronized void warn(String s) { // Just display the message if Log is not yet enabled if (logger == null) { System.out.println("[WARN] " + s); return; } spool("[WARN] " + s + FONT_END); logger.log(FULL_QUALIFIED_CLASS_NAME, Level.WARN, s, null); } /** * Log a warning-level message with info sup. * * @param s DOCUMENT_ME * @param sInfoSup DOCUMENT_ME */ public static synchronized void warn(String s, String sInfoSup) { String sOut = s + ": " + sInfoSup; // Just display the message if Log is not yet enabled if (logger == null) { System.out.println("[WARN] " + sOut); return; } spool("[INFO] " + sOut + FONT_END); logger.log(FULL_QUALIFIED_CLASS_NAME, Level.WARN, sOut, null); } /** * Log an warning-level message. * * @param code error code * @param sInfosup : error context information * @param t the exception itself */ public static synchronized void warn(int code, String sInfosup, Throwable t) { String sOut; if (Messages.isInitialized()) { sOut = "(" + code + ") " + Messages.getErrorMessage(code) + ((sInfosup == null) ? "" : ":" + sInfosup); } else { sOut = "(" + code + ") " + ((sInfosup == null) ? "" : ":" + sInfosup); } // Just display the message if Log is not yet enabled if (logger == null) { System.out.println("[WARN] " + sOut); stack(t); return; } spool("[WARN] " + sOut + FONT_END); spool(t); logger.log(FULL_QUALIFIED_CLASS_NAME, Level.WARN, sOut, t); } /** * Log an error-level message. * * @param code error code * @param sInfosup : error context information * @param t the exception itself */ public static synchronized void error(int code, String sInfosup, Throwable t) { // Just make a print stake trace if Log is not yet enabled (example: // collection commit problem in initialCheckups) if (logger == null) { System.out.println("[ERROR] " + code + " / " + sInfosup); stack(t); return; } String sOut; if (Messages.isInitialized()) { sOut = "(" + code + ") " + Messages.getErrorMessage(code) + ((sInfosup == null) ? "" : ": " + sInfosup); } else { sOut = "(" + code + ") " + ((sInfosup == null) ? "" : ":" + sInfosup); } spool("[ERROR] " + sOut + FONT_END); if (t != null) { spool(t); } logger.log(FULL_QUALIFIED_CLASS_NAME, Level.ERROR, sOut, t); } /** * Log an error-level message. * * @param code error code */ public static synchronized void error(int code) { String sOut; if (Messages.isInitialized()) { sOut = "(" + code + ") " + Messages.getErrorMessage(code); } else { sOut = "(" + code + ") "; } // Just make a print stake trace if Log is not yet enabled (example: // collection commit problem in initialCheckups) if (logger == null) { System.out.println("[ERROR] " + sOut); return; } spool("[ERROR] " + sOut + FONT_END); logger.log(FULL_QUALIFIED_CLASS_NAME, Level.ERROR, sOut, null); } /** * Log an error-level message. * * @param t the exception itself */ public static synchronized void error(Throwable t) { // Just make a print stake trace if Log is not yet enabled (example: // collection commit problem in initialCheckups) if (logger == null) { stack(t); return; } spool(t); if (t.getCause() != null) { logger.log(FULL_QUALIFIED_CLASS_NAME, Level.ERROR, t.getMessage() + " / " + t.getCause(), t); } else { logger.log(FULL_QUALIFIED_CLASS_NAME, Level.ERROR, t.getMessage(), t); } } /** * Log an error-level message. * * @param code DOCUMENT_ME * @param t DOCUMENT_ME */ public static void error(int code, Throwable t) { error(code, null, t); } /** * Log an error-level message. * * @param sInfosup DOCUMENT_ME * @param je DOCUMENT_ME */ public static void error(String sInfosup, JajukException je) { error(je.getCode(), sInfosup, je); } /** * Log an error-level message. * * @param je DOCUMENT_ME */ public static void error(JajukException je) { error(je.getCode(), null, je); } /** * Log a fatal error message. * * @param s DOCUMENT_ME */ public static synchronized void fatal(String s) { // Just make a print stake trace if Log is not yet enabled (example: // collection commit problem in initialCheckups) if (logger == null) { System.out.println("[FATAL] " + s); return; } spool("[FATAL] " + s + ""); logger.log(FULL_QUALIFIED_CLASS_NAME, Level.FATAL, s, null); } /** * Returns the verbosity. * * @return int */ public static int getVerbosity() { return verbosity; } /** * Sets the verbosity. * * @param newVerbosity DOCUMENT_ME */ public static void setVerbosity(int newVerbosity) { verbosity = newVerbosity; switch (newVerbosity) { case DEBUG: logger.setLevel(Level.DEBUG); Logger.getLogger(LOGGER_APACHE_HTTPCLIENT).setLevel(Level.WARN); Logger.getRootLogger().setLevel(Level.WARN); break; case INFO: logger.setLevel(Level.INFO); Logger.getLogger(LOGGER_APACHE_HTTPCLIENT).setLevel(Level.WARN); Logger.getRootLogger().setLevel(Level.WARN); break; case WARNING: logger.setLevel(Level.WARN); Logger.getLogger(LOGGER_APACHE_HTTPCLIENT).setLevel(Level.WARN); Logger.getRootLogger().setLevel(Level.WARN); break; case ERROR: logger.setLevel(Level.ERROR); Logger.getLogger(LOGGER_APACHE_HTTPCLIENT).setLevel(Level.ERROR); Logger.getRootLogger().setLevel(Level.ERROR); break; case FATAL: logger.setLevel(Level.FATAL); Logger.getLogger(LOGGER_APACHE_HTTPCLIENT).setLevel(Level.FATAL); Logger.getRootLogger().setLevel(Level.FATAL); break; } } /** * Convenient method to display stacks properly. * * @param e DOCUMENT_ME */ public static void stack(Throwable e) { e.printStackTrace(); } /** * Return whether Log are in debug mode. * * @return true, if checks if is debug enabled */ public static boolean isDebugEnabled() { if (verbosity == Log.DEBUG) { return true; } return false; } /** * Add this message in the memory spool. * * @param sMessage DOCUMENT_ME */ private synchronized static void spool(String sMessage) { // we maz have to make some room if (alSpool.size() >= Const.FEEDBACK_LINES) { alSpool.remove(0); } // anonymize standard labels (with {{xxx}}) String sAnonymizedMessage = sMessage.replaceAll("\\{\\{.*\\}\\}", "***"); // additionally anonymize Basic Player logs int pos = sAnonymizedMessage.indexOf("Player state changed: OPENING"); if (pos != -1) { // cut away trailing stuff which is personal data sAnonymizedMessage = sAnonymizedMessage.substring(0, pos + 40); } alSpool.add(sAnonymizedMessage); } /** * Spool an exception with stack traces. * * @param e DOCUMENT_ME */ private static void spool(Throwable e) { if (e.getCause() != null) { spool("" + "[ERROR] " + e.getClass() + " / {{" + e.getMessage() + "}} / " + e.getCause()); } else { spool("" + "[ERROR] " + e.getClass() + " / {{" + e.getMessage() + "}}"); } StackTraceElement[] ste = e.getStackTrace(); for (StackTraceElement element : ste) { spool(element.toString()); } spool(FONT_END); } /** * Gets the spool. * * @return Spool traces */ @SuppressWarnings("unchecked") public static List getSpool() { return (List) ((ArrayList) alSpool).clone(); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/util/UtilSystem.java0000644000175000017500000012036511720500104023754 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.util; import ext.MersenneTwister; import java.awt.Desktop; import java.awt.GraphicsEnvironment; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.RandomAccessFile; import java.io.Writer; import java.net.InetAddress; import java.net.URL; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; import java.nio.channels.FileLock; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Random; import javax.swing.ImageIcon; import org.apache.commons.io.FileUtils; import org.apache.commons.lang.StringUtils; import org.jajuk.Main; import org.jajuk.services.core.SessionService; import org.jajuk.util.error.JajukException; import org.jajuk.util.error.JajukRuntimeException; import org.jajuk.util.filters.DirectoryFilter; import org.jajuk.util.filters.KnownTypeFilter; import org.jajuk.util.log.Log; /** * Set of convenient methods for system and IO. */ public final class UtilSystem { /** The Constant LOCAL_IP. DOCUMENT_ME */ private static final String LOCAL_IP = "127.0.0.1"; /** Is browser supported ?. */ private static Boolean browserSupported; /** Size of the short names converter in bytes. */ private static final int CONVERTER_FILE_SIZE = 23; /** * MPlayer status possible values *. */ public static enum MPlayerStatus { /** DOCUMENT_ME. */ MPLAYER_STATUS_OK, /** DOCUMENT_ME. */ MPLAYER_STATUS_NOT_FOUND, /** DOCUMENT_ME. */ MPLAYER_STATUS_WRONG_VERSION, /** DOCUMENT_ME. */ MPLAYER_STATUS_JNLP_DOWNLOAD_PBM } /** Current date cached (for performances) *. */ public static final Date TODAY = new Date(); /** Central random object for all Jajuk *. */ private static final Random RANDOM = new MersenneTwister(); /** Cached user home directory *. */ private static String cachedUserHomeDir; /** Are we under Linux ? *. */ private static final boolean UNDER_LINUX; /** Are we under MAC OS Intel ? *. */ private static final boolean UNDER_OSX; /** Are we under Windows ? *. */ private static final boolean UNDER_WINDOWS; /** Are we under Windows 32 bits ? *. */ private static final boolean UNDER_WINDOWS_32BIT; /** Are we under Windows 64 bits ? *. */ private static final boolean UNDER_WINDOWS_64BIT; /** Are we in JNLP mode ? *. */ private static final boolean UNDER_JNLP; /** Are we under KDE ? *. */ private static final boolean UNDER_KDE; /** Directory filter used in refresh. */ private static JajukFileFilter dirFilter; /** File filter used in refresh. */ private static JajukFileFilter fileFilter; // Computes OS detection operations for perf reasons (can be called in loop // in refresh method for ie) static { final String sOS = (String) System.getProperties().get("os.name"); // os.name can be null with JWS under MacOS UNDER_WINDOWS = ((sOS != null) && (sOS.trim().toLowerCase(Locale.getDefault()).lastIndexOf( "windows") != -1)); } static { UNDER_WINDOWS_32BIT = UtilSystem.isUnderWindows() && System.getProperties().get("sun.arch.data.model").equals("32"); } static { UNDER_WINDOWS_64BIT = UtilSystem.isUnderWindows() && !System.getProperties().get("sun.arch.data.model").equals("32"); } static { final String sOS = (String) System.getProperties().get("os.name"); // os.name can be null with JWS under MacOS UNDER_LINUX = ((sOS != null) && (sOS.trim().toLowerCase(Locale.getDefault()).lastIndexOf( "linux") != -1)); } static { final String sArch = System.getProperty("os.arch"); UNDER_OSX = org.jdesktop.swingx.util.OS.isMacOSX() // We only support Intel OSX && ((sArch != null) && sArch.matches(".*86.*")); } static { UNDER_JNLP = (System.getProperty("jnlpx.jvm") != null); } /** * Are we running in a KDE environment ? * * We check it by using ps command + a grep searching 'kdeinit' process*/ static { boolean underKDE = false; if (isUnderLinux()) { BufferedReader stdInput = null; try { ProcessBuilder pb = new ProcessBuilder("ps", "-eaf"); Process proc = pb.start(); stdInput = new BufferedReader(new InputStreamReader(proc.getInputStream())); proc.waitFor(); String s; while ((s = stdInput.readLine()) != null) { if (s.matches(".*kdeinit.*")) { underKDE = true; break; } } } catch (Throwable e) { Log.error(e); } finally { if (stdInput != null) { try { stdInput.close(); } catch (IOException e) { Log.error(e); } } } } UNDER_KDE = underKDE; } /** Icons cache. */ static Map iconCache = new HashMap(200); /** Mplayer exe path. */ private static File mplayerPath = null; /** current class loader. */ private static ClassLoader classLoader = null; /** * private constructor to avoid instantiating utility class. */ private UtilSystem() { } /** * Save a file in the same directory with name _YYYYmmddHHMM.xml and * with a given maximum Mb size for the file and its backup files * * @param file The file to back up * @param iMB DOCUMENT_ME */ public static void backupFile(final File file, final int iMB) { try { if (Integer.parseInt(Conf.getString(Const.CONF_BACKUP_SIZE)) <= 0) { // 0 or less means no backup return; } // calculates total size in MB for the file to backup and its // backup files long lUsedMB = 0; final List alFiles = new ArrayList(10); final File[] files = new File(file.getAbsolutePath()).getParentFile().listFiles(); if (files != null) { for (final File element : files) { if (element.getName().indexOf(UtilSystem.removeExtension(file.getName())) != -1) { lUsedMB += element.length(); alFiles.add(element); } } // sort found files alFiles.remove(file); Collections.sort(alFiles); // too much backup files, delete older if (((lUsedMB - file.length()) / 1048576 > iMB) && (alFiles.size() > 0)) { final File fileToDelete = alFiles.get(0); if (fileToDelete != null) { if (!fileToDelete.delete()) { Log.warn("Could not delete file " + fileToDelete); } } } } // backup itself using nio, file name is // collection-backup-yyyMMdd.xml final String sExt = new SimpleDateFormat("yyyyMMdd", Locale.getDefault()).format(new Date()); final File fileNew = new File(UtilSystem.removeExtension(file.getAbsolutePath()) + "-backup-" + sExt + "." + UtilSystem.getExtension(file)); final FileChannel fcSrc = new FileInputStream(file).getChannel(); try { final FileChannel fcDest = new FileOutputStream(fileNew).getChannel(); try { fcDest.transferFrom(fcSrc, 0, fcSrc.size()); } finally { fcDest.close(); } } finally { fcSrc.close(); } } catch (final IOException ie) { Log.error(ie); } } /** * Copy a file to another file. * * @param file : file to copy * @param fNew : destination file * * @throws JajukException the jajuk exception * @throws IOException Signals that an I/O exception has occurred. */ public static void copy(final File file, final File fNew) throws JajukException, IOException { Log.debug("Copying: {{" + file.getAbsolutePath() + "}} to : " + fNew.getAbsolutePath()); if (!file.exists() || !file.canRead()) { throw new JajukException(9, file.getAbsolutePath(), null); } FileUtils.copyFile(file, fNew); // Display a warning if copied file is void as it can happen with full // disks if (fNew.length() == 0) { Log.warn("Copied file is void: {{" + file.getAbsolutePath() + "}}"); } } /** * Move a file to another file (directories are not supported). * * Note that it may be better to use this method than java.io.File.renameTo() method that * doesn't seem to work always under windows (in special directories) and because this method * always return an exception in case of problem. * * @param file : file to move * @param fNew : destination file * * @throws JajukException the jajuk exception * @throws IOException Signals that an I/O exception has occurred. */ public static void move(final File file, final File fNew) throws JajukException, IOException { copy(file, fNew); if (!file.delete()) { throw new IOException("Cannot delete file: " + file.getAbsolutePath()); } } /** * Copy a file. * * @param file : source file * @param sNewName : dest file * * @throws JajukException the jajuk exception * @throws IOException Signals that an I/O exception has occurred. */ public static void copy(final File file, final String sNewName) throws JajukException, IOException { Log.debug("Renaming: {{" + file.getAbsolutePath() + "}} to : " + sNewName); final File fileNew = new File(new StringBuilder(file.getParentFile().getAbsolutePath()).append( '/').append(sNewName).toString()); if (!file.exists() || !file.canRead()) { throw new JajukException(9, file.getAbsolutePath(), null); } FileUtils.copyFile(file, fileNew); } /** * Copy a URL resource to a file We don't use nio but Buffered Reader / writer * because we can only get channels from a FileInputStream that can be or not * be in a Jar (production / test). * * @param src source designed by URL * @param dest destination file full path * * @throws IOException If the src or dest cannot be opened/created. */ public static void copy(final URL src, final String dest) throws IOException { final BufferedReader br = new BufferedReader(new InputStreamReader(src.openStream())); try { final BufferedWriter bw = new BufferedWriter(new FileWriter(dest)); try { String sLine = null; do { sLine = br.readLine(); if (sLine != null) { bw.write(sLine); bw.newLine(); } } while (sLine != null); bw.flush(); } finally { bw.close(); } } finally { br.close(); } } /** * Copy recursively files and directories. * * @param dst DOCUMENT_ME * @param src DOCUMENT_ME * * @throws IOException Signals that an I/O exception has occurred. * @throws JajukException the jajuk exception */ public static void copyRecursively(final File src, final File dst) throws JajukException, IOException { if (src.isDirectory()) { if (!dst.mkdirs()) { Log.warn("Could not create directory structure " + dst.toString()); } final String list[] = src.list(); for (final String element : list) { final String dest1 = dst.getAbsolutePath() + '/' + element; final String src1 = src.getAbsolutePath() + '/' + element; UtilSystem.copyRecursively(new File(src1), new File(dest1)); } } else { UtilSystem.copy(src, dst); } } /** * Copy a file to given directory. * * @param file : file to copy * @param directory : destination directory * * @return destination file * * @throws JajukException the jajuk exception * @throws IOException Signals that an I/O exception has occurred. */ public static void copyToDir(final File file, final File directory) throws JajukException, IOException { Log.debug("Copying: {{" + file.getAbsolutePath() + "}} to : " + directory.getAbsolutePath()); if (!file.exists() || !file.canRead()) { throw new JajukException(9, file.getAbsolutePath(), null); } FileUtils.copyFileToDirectory(file, directory); } /** * Create empty file. * * @param file DOCUMENT_ME * * @throws IOException Signals that an I/O exception has occurred. */ public static void createEmptyFile(final File file) throws IOException { final OutputStream fos = new FileOutputStream(file); try { fos.write(new byte[0]); } finally { fos.close(); } } /** * Delete recursively a directory (use with caution!). * * @param dir : source directory * * @throws IOException Signals that an I/O exception has occurred. */ public static void deleteDir(final File dir) throws IOException { Log.debug("Deleting: {{" + dir.getAbsolutePath() + "}}"); if (dir.isDirectory()) { for (final File file : dir.listFiles()) { if (file.isDirectory()) { UtilSystem.deleteDir(file); } else { UtilSystem.deleteFile(file); } } if (!dir.delete()) { Log.warn("Could not delete directory " + dir); } } else { UtilSystem.deleteFile(dir); } return; } /** * Delete a file. * * @param file : source file * * @throws IOException Signals that an I/O exception has occurred. */ public static void deleteFile(final File file) throws IOException { Log.debug("Deleting: {{" + file.getAbsolutePath() + "}}"); if (file.isFile() && file.exists()) { if (!file.delete()) { Log.warn("Could not delete file " + file); } // check that file has been really deleted (sometimes, // we get no exception) if (file.exists()) { throw new IOException("File" + file.getAbsolutePath() + " still exists"); } } else {// not a file, must have a problem throw new IOException("File " + file.getAbsolutePath() + " didn't exist"); } return; } /** * Get a file extension. * * @param file DOCUMENT_ME * * @return the extension */ public static String getExtension(final File file) { return UtilSystem.getExtension(file.getName()); } /** * Get a file extension (without the dot!). * * @param filename The file to examine. * * @return The actual file extension or an empty string if no extension is * found (i.e. no dot in the filename). */ public static String getExtension(final String filename) { int dotIndex = filename.lastIndexOf('.'); // File without point if (dotIndex == -1) { return ""; } if (dotIndex > 0) { return filename.substring(dotIndex + 1, filename.length()); } else { // File beginning by a point (unix hidden file) return filename; } } /** * Additional file checksum used to prevent bug #886098. Simply return some * bytes read at the middle of the file *

    * uses nio api for performances * * @param fio DOCUMENT_ME * * @return the file checksum * * @throws JajukException the jajuk exception */ public static String getFileChecksum(final File fio) throws JajukException { try { String sOut = ""; final FileChannel fc = new FileInputStream(fio).getChannel(); try { final ByteBuffer bb = ByteBuffer.allocate(500); fc.read(bb, fio.length() / 2); sOut = new String(bb.array()); } finally { fc.close(); } return MD5Processor.hash(sOut); } catch (final IOException e) { throw new JajukException(103, e); } } /** * Gets the host name. * * @return This box hostname */ public static String getHostName() { String sHostname = null; // Try to get hostname using the standard way try { sHostname = InetAddress.getLocalHost().getHostName(); } catch (final Exception e) { Log.debug("Cannot get Hostname using the standard way"); } if (sHostname == null) { // Try using IP now try { final java.net.InetAddress inetAdd = java.net.InetAddress.getByName(LOCAL_IP); sHostname = inetAdd.getHostName(); } catch (final Exception e) { Log.debug("Cannot get Hostname by IP"); } } // If still no hostname, return a default value if (sHostname == null) { sHostname = Const.DEFAULT_HOSTNAME; } return sHostname; } /** * Return url of jar we are executing. * * This code no more work with last JRE 6 under JNLP (it returns only partial URL) * * @param cClass DOCUMENT_ME * * @return URL of jar we are executing */ public static URL getJarLocation(final Class cClass) { URL url = cClass.getProtectionDomain().getCodeSource().getLocation(); if (UtilSystem.isUnderJNLP()) { Log.debug("JAR location: " + url.getFile()); } return url; } /** * Gets the mplayer windows path. * * @return MPlayer exe file */ public static File getMPlayerWindowsPath() { // Use cache if (UtilSystem.mplayerPath != null) { return UtilSystem.mplayerPath; } File file = null; // Check in ~/.jajuk directory (used by JNLP distribution // as well). Test exe size as well to detect unfinished downloads of // mplayer.exe in JNLP mode file = SessionService.getConfFileByPath(Const.FILE_MPLAYER_WINDOWS_EXE); if (file.exists() && file.length() == Const.MPLAYER_WINDOWS_EXE_SIZE) { UtilSystem.mplayerPath = file; return UtilSystem.mplayerPath; } else if (!UtilSystem.isUnderJNLP()) { // Check in the path where jajuk.jar is executed (all others // distributions). does not work under JNLP String sPATH = null; try { // Extract file name from URL. URI returns jar path, its parent // is the bin directory and the right dir is the parent of bin // dir if (SessionService.isIdeMode()) { // If under dev, take mplayer exe file from the packaging // directory sPATH = "./src/packaging"; } else { sPATH = new File(getJarLocation(Main.class).toURI()).getParentFile().getParentFile() .getAbsolutePath(); } // Add MPlayer file name file = new File(sPATH + '/' + Const.FILE_MPLAYER_WINDOWS_EXE); if (file.exists() && file.length() == Const.MPLAYER_WINDOWS_EXE_SIZE) { UtilSystem.mplayerPath = file; } else { // For bundle project, Jajuk should check if mplayer was // installed along with aTunes. In this case, mplayer is // found in sPATH\win_tools\ directory. Hence, changed sPATH // Note that we don't test mplayer.exe size in this case file = new File(sPATH + "/win_tools/" + Const.MPLAYER_WINDOWS_EXE_SIZE); if (file.exists()) { UtilSystem.mplayerPath = file; } } } catch (Exception e) { Log.error(e); } } return UtilSystem.mplayerPath; // can be null if none suitable file found } /** * Gets the mplayer OSX path. * It is mainly based upon Windows getWindowsPath() path method, see comments over there * * @return MPLayer binary MAC full path */ public static File getMPlayerOSXPath() { if (UtilSystem.mplayerPath != null) { return UtilSystem.mplayerPath; } // Search in /Applications first File file = new File("/Applications/Jajuk.app/Contents/Resources/External_Binaries/" + Const.FILE_MPLAYER_OSX_EXE); if (file.canExecute() && file.length() == Const.MPLAYER_OSX_EXE_SIZE) { UtilSystem.mplayerPath = file; return UtilSystem.mplayerPath; } // Search in collection path file = SessionService.getConfFileByPath(Const.FILE_MPLAYER_OSX_EXE); if (file.exists() && file.length() == Const.MPLAYER_OSX_EXE_SIZE) { UtilSystem.mplayerPath = file; return UtilSystem.mplayerPath; } else if (!UtilSystem.isUnderJNLP()) { // Search in jajuk installation directory, do not work under JNLP String sPATH = null; try { if (SessionService.isIdeMode()) { // If under dev, take mplayer exe file from /Applications (the mplayer osx binary is not // in SCM) sPATH = "/Applications"; } else { sPATH = new File(getJarLocation(Main.class).toURI()).getParentFile().getParentFile() .getAbsolutePath(); } file = new File(sPATH + '/' + Const.FILE_MPLAYER_OSX_EXE); if (file.exists() && file.length() == Const.MPLAYER_OSX_EXE_SIZE) { UtilSystem.mplayerPath = file; } } catch (Exception e) { Log.error(e); } } return UtilSystem.mplayerPath; // can be null if none suitable file found } /** * Gets the mplayer status. * * @param mplayerPATH DOCUMENT_ME * * @return the mplayer status */ public static UtilSystem.MPlayerStatus getMplayerStatus(final String mplayerPATH) { Process proc = null; UtilSystem.MPlayerStatus mplayerStatus = UtilSystem.MPlayerStatus.MPLAYER_STATUS_NOT_FOUND; try { String fullPath = null; if ("".equals(mplayerPATH)) { fullPath = "mplayer"; } else { fullPath = mplayerPATH; } Log.debug("Testing path: " + fullPath); // check MPlayer release : 1.0pre8 min proc = Runtime.getRuntime().exec(new String[] { fullPath, "-input", "cmdlist" }); //$NON-NLS-2$ final BufferedReader in = new BufferedReader(new InputStreamReader(proc.getInputStream())); try { String line = null; mplayerStatus = UtilSystem.MPlayerStatus.MPLAYER_STATUS_WRONG_VERSION; for (;;) { line = in.readLine(); if (line == null) { break; } if (line.matches("get_time_pos.*")) { mplayerStatus = UtilSystem.MPlayerStatus.MPLAYER_STATUS_OK; break; } } } finally { in.close(); } } catch (final IOException e) { mplayerStatus = UtilSystem.MPlayerStatus.MPLAYER_STATUS_NOT_FOUND; } return mplayerStatus; } /** * This method intends to cleanup a future filename so it can be created on * all operating systems. Windows forbids characters : /\"<>|:*? * * @param in filename * * @return filename with forbidden characters replaced at best */ public static String getNormalizedFilename(final String in) { String out = in.trim(); // Replace / : < > and \ by - out = in.replaceAll("[/:<>\\\\]", "-"); // Replace * and | by spaces out = out.replaceAll("[\\*|]", " "); // Remove " and ? characters out = out.replaceAll("[\"\\?]", ""); return out; } /** * Return only the name of a file from a complete URL. * * @param sPath DOCUMENT_ME * * @return the only file */ public static String getOnlyFile(final String sPath) { return new File(sPath).getName(); } /** * Resource loading is done this way to meet the requirements for Web Start. * http * ://java.sun.com/j2se/1.5.0/docs/guide/javaws/developersguide/faq.html#211 * * @param name DOCUMENT_ME * * @return the resource */ public static URL getResource(final String name) { return UtilSystem.getClassLoader().getResource(name); } /** * Checks if is ancestor. * * @param file1 potential ancestor * @param file2 potential child * * @return whether file1 is a file2 ancestor */ public static boolean isAncestor(final File file1, final File file2) { File fParent = file2.getParentFile(); boolean bOut = false; while (fParent != null) { if (fParent.equals(file1)) { bOut = true; break; } fParent = fParent.getParentFile(); } return bOut; } /** * Checks if is descendant. * * @param file1 DOCUMENT_ME * @param file2 DOCUMENT_ME * * @return whether file1 is a file2 descendant */ public static boolean isDescendant(final File file1, final File file2) { // a file is a descendant to another file if the other file is it's // ancestor... return isAncestor(file2, file1); } /** * Checks if is under linux. * * @return whether we are under Linux */ public static boolean isUnderLinux() { return UtilSystem.UNDER_LINUX; } /** * Checks if we are running as jnlp app. * * @return whether we are running as jnlp app */ public static boolean isUnderJNLP() { return UtilSystem.UNDER_JNLP; } /** * Checks if is under OSX (Intel or PowerPC). * * @return whether we are under OS X */ public static boolean isUnderOSX() { return UtilSystem.UNDER_OSX; } /** * Checks if is under windows. * * @return whether we are under Windows */ public static boolean isUnderWindows() { return UtilSystem.UNDER_WINDOWS; } /** * Checks if is under windows32bits. * * @return whether we are under Windows 32 bits */ public static boolean isUnderWindows32bits() { return UtilSystem.UNDER_WINDOWS_32BIT; } /** * Checks if is under windows64bits. * * @return whether we are under Windows 64 bits */ public static boolean isUnderWindows64bits() { return UtilSystem.UNDER_WINDOWS_64BIT; } /** * Checks if is valid file name. * * @param parent parent directory * @param name file name * * @return whether the file name is correct on the current filesystem */ public static boolean isValidFileName(final File parent, final String name) { // General tests if ((parent == null) || (name == null)) { return false; } // only digits or letters, OK, no need to test if (!UtilString.containsNonDigitOrLetters(name)) { return true; } final File f = new File(parent, name); if (!f.exists()) { try { // try to create the file f.createNewFile(); // test if the file is seen into the directory final File[] files = parent.listFiles(); boolean b = false; for (final File element : files) { if (element.getName().equals(name)) { b = true; break; } } // remove test file if (f.exists()) { UtilSystem.deleteFile(f); } return b; } catch (final IOException ioe) { return false; } } else { // file already exists return true; } } /** * Need full fc. * * @return whether we need a full gc or not */ public static boolean needFullFC() { final float fTotal = Runtime.getRuntime().totalMemory(); final float fFree = Runtime.getRuntime().freeMemory(); final float fLevel = (fTotal - fFree) / fTotal; return fLevel >= Const.NEED_FULL_GC_LEVEL; } /** * Open a file and return a string buffer with the file content. * * @param path -File path * * @return StringBuilder - File content. * * @throws JajukException - Throws a JajukException if a problem occurs during the file * access. */ public static StringBuilder readFile(final String path) throws JajukException { // Read File file = new File(path); FileReader fileReader; try { fileReader = new FileReader(file); } catch (final FileNotFoundException e) { throw new JajukException(9, path, e); } try { final BufferedReader input = new BufferedReader(fileReader); try { // Read final StringBuilder strColl = new StringBuilder(); String line = null; while ((line = input.readLine()) != null) { strColl.append(line); } return strColl; } finally { // Close the bufferedReader input.close(); } } catch (final IOException e) { throw new JajukException(9, path, e); } } /** * Open a file from current jar and return a string buffer with the file * content. * * @param sURL DOCUMENT_ME * * @return StringBuilder - File content. * * @throws JajukException -Throws a JajukException if a problem occurs during the file * access. */ public static StringBuilder readJarFile(final String sURL) throws JajukException { // Read InputStream is; StringBuilder sb = null; try { is = Main.class.getResourceAsStream(sURL); try { // Read final byte[] b = new byte[200]; sb = new StringBuilder(); int i = 0; do { i = is.read(b, 0, b.length); sb.append(new String(b)); } while (i > 0); } finally { // Close the bufferedReader is.close(); } } catch (final IOException e) { throw new JajukException(9, e); } return sb; } /** * Remove an extension from a file name. * * @param sFilename DOCUMENT_ME * * @return filename without extension */ public static String removeExtension(final String sFilename) { return sFilename.substring(0, sFilename.lastIndexOf('.')); } /** * Gets the class loader. * * @return the class loader */ public static ClassLoader getClassLoader() { if (UtilSystem.classLoader == null) { UtilSystem.classLoader = Thread.currentThread().getContextClassLoader(); } return UtilSystem.classLoader; } /** * Gets the dir filter. * * @return the dir filter */ public static JajukFileFilter getDirFilter() { if (dirFilter == null) { dirFilter = new JajukFileFilter(DirectoryFilter.getInstance()); } return dirFilter; } /** * Gets the file filter. * * @return the file filter */ public static JajukFileFilter getFileFilter() { if (fileFilter == null) { fileFilter = new JajukFileFilter(KnownTypeFilter.getInstance()); } return fileFilter; } /** * Replace a string inside a given file. * * @param file the file * @param oldS the string to replace * @param newS the new string * @param encoding the encoding of the file * * @return whether some replacements occurred */ public static boolean replaceInFile(File file, String oldS, String newS, String encoding) { try { String s = FileUtils.readFileToString(file); if (s.indexOf(oldS) != -1) { s = s.replaceAll(oldS, newS); Writer bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file), encoding)); try { bw.write(s); bw.flush(); } finally { bw.close(); } return true; } } catch (IOException e) { Log.error(e); } return false; } /** * This method returns a single random object that can be used anywhere in * jajuk It has to be a singleton to get a good shuffling. Indeed, Random() * object are seeded by default with current nano date but in some cases, two * random could be created at the same exact date in different threads or the * same. * * @return Jajuk singleton random object */ public static Random getRandom() { return UtilSystem.RANDOM; } /** * Opens a directory with the associated explorer program.

  • Start by trying * to open the directory with any provided explorer path
  • Then, try to * use the JDIC Desktop class if supported by the platform
  • * * Inspired from an aTunes method * * @param directory DOCUMENT_ME */ public static void openInExplorer(File directory) { final File directoryToOpen; /* * Needed for UNC filenames with spaces -> http://bugs.sun.com/view_bug.do?bug_id=6550588 */ if (isUnderWindows()) { String shortPath = getShortPathNameW(directory.getAbsolutePath()); // If shortnames conversion doesn't work, try the initial path if (shortPath == null || !new File(shortPath).exists()) { directoryToOpen = directory; } else { directoryToOpen = new File(shortPath); } } else { directoryToOpen = directory; } // Try to open the location using the forced explorer path of provided if (StringUtils.isNotBlank(Conf.getString(Const.CONF_EXPLORER_PATH))) { new Thread("Explorer Open Thread 1") { @Override public void run() { try { ProcessBuilder pb = new ProcessBuilder(Conf.getString(Const.CONF_EXPLORER_PATH), directoryToOpen.getAbsolutePath()); pb.start(); } catch (Exception e) { Log.error(e); Messages.showErrorMessage(179, directoryToOpen.getAbsolutePath()); } } }.start(); } // Try to open the location using the JDIC/JDK Desktop.open method // This is not supported on some platforms (Linux/XFCE for ie) else if (Desktop.getDesktop().isSupported(Desktop.Action.OPEN)) { new Thread("Explorer Open Thread 2") { @Override public void run() { try { Desktop.getDesktop().open(directoryToOpen); } catch (Exception e) { Log.error(e); Messages.showErrorMessage(179, directoryToOpen.getAbsolutePath()); } } }.start(); } // Else, display a warning message: we don't support this platform else { Messages.showErrorMessage(179); } } /** * Return whether a process is still running. * * @param process the process * * @return whether the process is still running */ public static boolean isRunning(Process process) { try { process.exitValue(); return false; } catch (IllegalThreadStateException itse) { return true; } } /** * Return a process exit value, -100 if the process is still running. * * @param process the process * * @return the process exit value, -100 if the process is still running */ public static int getExitValue(Process process) { try { return process.exitValue(); } catch (IllegalThreadStateException itse) { return -100; } } /** * Returns current user home directory handling Windows issues on JRE. * * @return current user home directory */ public static String getUserHome() { // User home is cached for performances if (cachedUserHomeDir != null) { return cachedUserHomeDir; } /** * We search first in USERPROFILE env directory before than user.home. * * But we give priority to user.home if it already contains a suitable jajuk * collection to maintain backward compatibility * * See https://trac.jajuk.info/ticket/1473 and * http://bugs.sun.com/view_bug.do?bug_id=4787931 **/ if (StringUtils.isNotBlank(System.getenv("USERPROFILE"))) { cachedUserHomeDir = System.getenv("USERPROFILE"); } else { cachedUserHomeDir = System.getProperty("user.home"); } return cachedUserHomeDir; } /** * Convert a full regular Windows path to 8.3 DOS format * * @param longname the regular absolute path * * @return the shortname absolute path */ public static String getShortPathNameW(String longname) { // Find the shortname .bat converter, create it if it doesn't yet exist String shortname = null; try { File fileConverter = SessionService.getConfFileByPath(Const.FILE_FILENAME_CONVERTER); if (!fileConverter.exists() // Test that the converter version has not been updated // IMPORTANT ! Don't forget to update the CONVERTER_FILE_SIZE constant if you change the // script ! || (fileConverter.exists() && fileConverter.length() != CONVERTER_FILE_SIZE)) { FileWriter fw = new FileWriter(fileConverter); fw.write("@echo off\n"); fw.write("dir /x \"%~s1\""); fw.flush(); fw.close(); } // these two quotes are required in the case where both directory and file are non-ascii ProcessBuilder pc = new ProcessBuilder(fileConverter.getAbsolutePath(), "\"" + longname + "\""); Process process = pc.start(); /* * dir /x parsing : Sample output (in French but should work with any language): * * Le volume dans le lecteur D s'appelle Données * * Le numéro de série du volume est C880-0321 * * Répertoire de D:\MESDOC~1\MAMUSI~1\FILES_~1\1F19~1 * * 07/06/2010 21:49 . * * 07/06/2010 21:49 .. * * 07/06/2010 14:41 20 108 -(_)~1.MP3 µ×ùÕ│» - µÿÄÕñ®õ╗ÑÕ¥î (µ×ùÕ│»+µ│ÕàÆÕÉêÕö▒).mp3 */ BufferedReader br = new BufferedReader(new InputStreamReader(process.getInputStream())); String line = ""; String lineDirectory = null; while ((line = br.readLine()) != null) { String ext = UtilSystem.getExtension(new File(longname)); if (StringUtils.isNotBlank(line)) { // Index of the file extension in short name int indexExtension = line.indexOf(longname.substring(0, 3).toUpperCase()); if (line.endsWith(ext)) { int indexEnd = line.indexOf(ext.toUpperCase()); int indexBegin = indexEnd; // Find the previous space while (line.charAt(indexBegin) != ' ') { indexBegin--; } shortname = line.substring(indexBegin, indexEnd + 4).trim(); break; } else if (indexExtension != -1) { // We get parent directory full path in shortname thanks the %~s1 in the script lineDirectory = line.substring(indexExtension, line.length()).trim(); } } } shortname = lineDirectory + "\\" + shortname; process.destroy(); } catch (Exception e) { throw new JajukRuntimeException("Cannot convert the filename to 8.3 format", e); } return shortname; } /** * Return whether the Desktop BROWSE action is actually supported * Note this bug : http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6486393 * under KDE : isSupported returns true but we get an exception when actually browsing * * @return true, if checks if is browser supported */ public static boolean isBrowserSupported() { // value stored for perf if (browserSupported != null) { return browserSupported; } // In server UT mode, just return false if (GraphicsEnvironment.isHeadless()) { return false; } else { if (Desktop.isDesktopSupported()) { // If under Linux, check if we're under KDE because of a sun bug, // see http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6486393 and #1612 if (isUnderLinux() && isUnderKDE()) { return false; } else { return (Desktop.getDesktop().isSupported(Desktop.Action.BROWSE)); } } else { return false; } } } /** * Are we running in a KDE environment ? * * We check it by using ps command + a grep searching 'kdeinit' process. * * @return whether we are running in a KDE environment */ public static boolean isUnderKDE() { return UtilSystem.UNDER_KDE; } /** * Attempt to acquire a file lock for given file. * * @param file the file to lock * * @return a FileLock or null if it can't be acquired */ public static FileLock tryLockFile(File file) { FileLock lock = null; try { FileChannel channel = new RandomAccessFile(file, "rw").getChannel(); // Get an exclusive lock on the whole file lock = channel.tryLock(); if (!lock.isValid()) { throw new IOException("Lock invalid for : " + file.getAbsolutePath()); } } catch (Exception e) { Log.warn("Cannot acquire lock for file : " + file.getAbsolutePath()); } return lock; } } jajuk-1.9.6.orig/src/main/java/org/jajuk/util/UtilString.java0000644000175000017500000007436411720500104023745 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.util; import java.text.DateFormat; import java.text.Normalizer; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Date; import java.util.List; import java.util.Locale; import java.util.Properties; import java.util.StringTokenizer; import org.apache.commons.io.FilenameUtils; import org.apache.commons.lang.StringUtils; import org.jajuk.base.AlbumArtistManager; import org.jajuk.base.AlbumManager; import org.jajuk.base.ArtistManager; import org.jajuk.base.File; import org.jajuk.base.GenreManager; import org.jajuk.base.ItemManager; import org.jajuk.base.PropertyMetaInformation; import org.jajuk.base.Track; import org.jajuk.util.error.JajukException; /** * Set of convenient classes for string manipulation. */ public final class UtilString { /** The list of characters that we need to escape in strings. */ private final static String ESCAPE_CHARACTERS = "\\[](){}.*+?$^|-"; /** Constant date FORMATTER, one by thread for perfs, we need an instance by thread because this class is not thread safe. */ private static final ThreadLocal FORMATTER = new ThreadLocal() { @Override protected SimpleDateFormat initialValue() { return new SimpleDateFormat(Const.ADDITION_DATE_FORMAT, Locale.getDefault()); } }; /** Character that is used to replace if filename normalization is used. */ private static final String FILLER_CHAR = "_"; /** * private constructor to avoid instantiating utility class. */ private UtilString() { } /** * Apply the Album pattern. * * @param file file to apply pattern to * @param sPattern DOCUMENT_ME * @param bMandatory are all needed tags mandatory ? * @param normalize DOCUMENT_ME * @param out DOCUMENT_ME * @param track DOCUMENT_ME * * @return the string * * @throws JajukException the jajuk exception */ private static String applyAlbumPattern(final org.jajuk.base.File file, final String sPattern, final boolean bMandatory, final boolean normalize, final String out, final Track track) throws JajukException { String ret = out; String sValue; if (sPattern.contains(Const.PATTERN_ALBUM)) { sValue = track.getAlbum().getName(); if (normalize) { sValue = UtilSystem.getNormalizedFilename(sValue); } if (!sValue.equals(Const.UNKNOWN_ALBUM)) { ret = ret.replace(Const.PATTERN_ALBUM, AlbumManager.format(sValue)); } else { if (bMandatory) { throw new JajukException(149, file.getAbsolutePath()); } else { ret = ret.replace(Const.PATTERN_ALBUM, Messages.getString(Const.UNKNOWN_ALBUM)); } } } return ret; } /** * Apply the Year pattern. * * @param file file to apply pattern to * @param sPattern DOCUMENT_ME * @param bMandatory are all needed tags mandatory ? * @param out DOCUMENT_ME * @param track DOCUMENT_ME * * @return the string * * @throws JajukException the jajuk exception */ private static String applyYearPattern(final org.jajuk.base.File file, final String sPattern, final boolean bMandatory, final String out, final Track track) throws JajukException { String ret = out; if (sPattern.contains(Const.PATTERN_YEAR)) { if (track.getYear().getValue() != 0) { ret = ret.replace(Const.PATTERN_YEAR, track.getYear().getValue() + ""); } else { if (bMandatory) { throw new JajukException(148, file.getAbsolutePath()); } else { ret = ret.replace(Const.PATTERN_YEAR, "?"); } } } return ret; } /** * Apply the Track pattern. * * @param sPattern DOCUMENT_ME * @param normalize DOCUMENT_ME * @param out DOCUMENT_ME * @param track DOCUMENT_ME * * @return the string */ private static String applyTrackPattern(final String sPattern, final boolean normalize, final String out, final Track track) { String ret = out; String sValue; if (sPattern.contains(Const.PATTERN_TRACKNAME)) { sValue = track.getName(); if (normalize) { sValue = UtilSystem.getNormalizedFilename(sValue); } ret = ret.replace(Const.PATTERN_TRACKNAME, sValue); } return ret; } /** * Apply the Track Order pattern. * * @param file file to apply pattern to * @param sPattern DOCUMENT_ME * @param bMandatory are all needed tags mandatory ? * @param out DOCUMENT_ME * @param track DOCUMENT_ME * * @return the string * * @throws JajukException the jajuk exception */ private static String applyTrackOrderPattern(final org.jajuk.base.File file, final String sPattern, final boolean bMandatory, final String out, final Track track) throws JajukException { if (sPattern.contains(Const.PATTERN_TRACKORDER)) { // override Order from filename if not set explicitly long lOrder = handleOrder(file, bMandatory, track); // prepend one digit numbers with "0" if (lOrder < 10) { return out.replace(Const.PATTERN_TRACKORDER, "0" + lOrder); } else { return out.replace(Const.PATTERN_TRACKORDER, lOrder + ""); } } return out; } /** * Handle order. * DOCUMENT_ME * * @param file DOCUMENT_ME * @param bMandatory DOCUMENT_ME * @param track DOCUMENT_ME * * @return the long * * @throws JajukException the jajuk exception */ private static long handleOrder(final org.jajuk.base.File file, final boolean bMandatory, final Track track) throws JajukException { long lOrder = track.getOrder(); if (lOrder == 0) { final String sFilename = file.getName(); if (Character.isDigit(sFilename.charAt(0))) { final String sTo = sFilename.substring(0, 3).trim().replaceAll("[^0-9]", ""); for (final char c : sTo.toCharArray()) { if (!Character.isDigit(c)) { throw new JajukException(152, file.getAbsolutePath()); } } lOrder = Long.parseLong(sTo); } else { if (bMandatory) { throw new JajukException(152, file.getAbsolutePath()); } else { lOrder = 0; } } } return lOrder; } /** * Apply the Genre pattern. * * @param file file to apply pattern to * @param sPattern DOCUMENT_ME * @param bMandatory are all needed tags mandatory ? * @param normalize DOCUMENT_ME * @param out DOCUMENT_ME * @param track DOCUMENT_ME * * @return the string * * @throws JajukException the jajuk exception */ private static String applyGenrePattern(final org.jajuk.base.File file, final String sPattern, final boolean bMandatory, final boolean normalize, final String out, final Track track) throws JajukException { String ret = out; String sValue; if (sPattern.contains(Const.PATTERN_GENRE)) { sValue = track.getGenre().getName(); if (normalize) { sValue = UtilSystem.getNormalizedFilename(sValue); } if (!sValue.equals(Const.UNKNOWN_GENRE)) { ret = ret.replace(Const.PATTERN_GENRE, GenreManager.format(sValue)); } else { if (bMandatory) { throw new JajukException(153, file.getAbsolutePath()); } else { ret = ret.replace(Const.PATTERN_GENRE, Messages.getString(Const.UNKNOWN_GENRE)); } } } return ret; } /** * Apply the Artist pattern. * * @param file file to apply pattern to * @param sPattern DOCUMENT_ME * @param bMandatory are all needed tags mandatory ? * @param normalize DOCUMENT_ME * @param out DOCUMENT_ME * @param track DOCUMENT_ME * * @return the string * * @throws JajukException the jajuk exception */ private static String applyArtistPattern(final org.jajuk.base.File file, final String sPattern, final boolean bMandatory, final boolean normalize, final String out, final Track track) throws JajukException { String ret = out; String sValue; if (sPattern.contains(Const.PATTERN_ARTIST)) { sValue = track.getArtist().getName(); if (normalize) { sValue = UtilSystem.getNormalizedFilename(sValue); } if (!sValue.equals(Const.UNKNOWN_ARTIST)) { ret = ret.replaceAll(Const.PATTERN_ARTIST, ItemManager.format(sValue)); } else { if (bMandatory) { throw new JajukException(150, file.getAbsolutePath()); } else { ret = ret.replaceAll(Const.PATTERN_ARTIST, Messages.getString(Const.UNKNOWN_ARTIST)); } } } return ret; } /** * Apply a pattern. This replaces certain patterns in the provided Pattern * with information from the file and returns the result. * * @param file file to apply pattern to * @param sPattern DOCUMENT_ME * @param bMandatory are all needed tags mandatory ? * @param normalize DOCUMENT_ME * * @return computed string * make sure the created string can be used as file name on target * file system * * @throws JajukException if some tags are missing */ public static String applyPattern(final org.jajuk.base.File file, final String sPattern, final boolean bMandatory, final boolean normalize) throws JajukException { String out = sPattern; final Track track = file.getTrack(); // Check Artist name out = UtilString.applyArtistPattern(file, sPattern, bMandatory, normalize, out, track); // Check Album artist, use artist name if no album artist out = UtilString.applyAlbumArtistPattern(sPattern, normalize, out, track); // Check Genre name out = UtilString.applyGenrePattern(file, sPattern, bMandatory, normalize, out, track); // Check Album Name out = UtilString.applyAlbumPattern(file, sPattern, bMandatory, normalize, out, track); // Check Track Order out = UtilString.applyTrackOrderPattern(file, sPattern, bMandatory, out, track); // Check Track name out = UtilString.applyTrackPattern(sPattern, normalize, out, track); // Check Year Value out = UtilString.applyYearPattern(file, sPattern, bMandatory, out, track); // Check Disc Value out = UtilString.applyDiscPattern(file, sPattern, bMandatory, out, track); return out; } /** * Apply album artist pattern. * * @param sPattern DOCUMENT_ME * @param normalize DOCUMENT_ME * @param out DOCUMENT_ME * @param track DOCUMENT_ME * @return the string */ private static String applyAlbumArtistPattern(String sPattern, boolean normalize, String out, Track track) { String ret = out; String sValue; if (sPattern.contains(Const.PATTERN_ALBUM_ARTIST)) { sValue = track.getAlbumArtistOrArtist(); if (normalize) { sValue = UtilSystem.getNormalizedFilename(sValue); } ret = ret.replaceAll(Const.PATTERN_ALBUM_ARTIST, ItemManager.format(sValue)); } return ret; } /** * Apply disc pattern. * * @param file DOCUMENT_ME * @param sPattern DOCUMENT_ME * @param bMandatory DOCUMENT_ME * @param out DOCUMENT_ME * @param track DOCUMENT_ME * @return the string * @throws JajukException the jajuk exception */ private static String applyDiscPattern(File file, String sPattern, boolean bMandatory, String out, Track track) throws JajukException { if (sPattern.contains(Const.PATTERN_DISC)) { // override Order from filename if not set explicitly long lDiscNumber = handleDiscNumber(file, bMandatory, track); // prepend one digit numbers with "0" if (lDiscNumber < 10) { return out.replace(Const.PATTERN_DISC, "0" + lDiscNumber); } else { return out.replace(Const.PATTERN_DISC, lDiscNumber + ""); } } return out; } /** * Handle disc number. * DOCUMENT_ME * * @param file DOCUMENT_ME * @param bMandatory DOCUMENT_ME * @param track DOCUMENT_ME * * @return the long * * @throws JajukException the jajuk exception */ private static long handleDiscNumber(File file, boolean bMandatory, Track track) throws JajukException { long lDiscNumber = track.getDiscNumber(); if (lDiscNumber == 0) { final String sFilename = file.getName(); if (Character.isDigit(sFilename.charAt(0))) { final String sTo = sFilename.substring(0, 3).trim().replaceAll("[^0-9]", ""); for (final char c : sTo.toCharArray()) { if (!Character.isDigit(c)) { throw new JajukException(152, file.getAbsolutePath()); } } lDiscNumber = Long.parseLong(sTo); } else { if (bMandatory) { throw new JajukException(152, file.getAbsolutePath()); } else { lDiscNumber = 0; } } } return lDiscNumber; } /** * Contains non digit or letters. * * @param s String to analyse * * @return whether the given string contains non digit or letter characters */ public static boolean containsNonDigitOrLetters(final String s) { boolean bOK = false; for (int i = 0; i < s.length(); i++) { if (!Character.isLetterOrDigit(s.charAt(i))) { bOK = true; break; } } return bOK; } /** * Encode URLS. * * @param s DOCUMENT_ME * * @return the string */ public static String encodeURL(final String s) { return s.replaceAll(" +", "+"); } /* * Escape (in the regexp sense) a string Source Search reserved: $ ( ) * + - . ? [ \ ] ^ { | } * http://mindprod.com/jgloss/regex.html */ /** * Escape string. * DOCUMENT_ME * * @param s DOCUMENT_ME * * @return the string */ public static String escapeString(String s) { int length = s.length(); StringBuffer buffer = new StringBuffer(2 * length); for (int i = 0; i != length; i++) { char c = s.charAt(i); // if we have a character that needs to be escaped, we prepend backslash // before it if (ESCAPE_CHARACTERS.indexOf(c) != -1) { buffer.append('\\'); } // now append the actual character buffer.append(c); } return buffer.toString(); } /** * Format an object to a string. * * @param oValue DOCUMENT_ME * @param meta DOCUMENT_ME * @param bHuman is this string intended to be human-readable ? * @return the string */ public static String format(final Object oValue, final PropertyMetaInformation meta, final boolean bHuman) { final Class cType = meta.getType(); // default (works for strings, long and double) String sValue = oValue.toString(); if (cType.equals(Date.class)) { if (bHuman) { sValue = getLocaleDateFormatter().format((Date) oValue); } else { sValue = UtilString.getAdditionDateFormatter().format((Date) oValue); } } else if (cType.equals(Class.class)) { sValue = oValue.getClass().getName(); } return sValue; } /** * Gets the locale date formatter. * * @return locale date FORMATTER instance */ public static DateFormat getLocaleDateFormatter() { return DateFormat.getDateInstance(DateFormat.DEFAULT, Locale.getDefault()); } /** * Formatter for properties dialog window. * * @param sDesc DOCUMENT_ME * * @return the string */ public static String formatPropertyDesc(final String sDesc) { return "
    " + sDesc + ""; } /** * format genre: first letter uppercase and others lowercase. * * @param genre DOCUMENT_ME * * @return the string */ public static String formatGenre(final String genre) { if (genre.length() == 0) { return ""; } if (genre.length() == 1) { return genre.substring(0, 1).toUpperCase(Locale.getDefault()); } // construct string with first letter uppercase and rest lowercase return genre.substring(0, 1).toUpperCase(Locale.getDefault()) + genre.toLowerCase(Locale.getDefault()).substring(1); } /** * Performs some cleanups for strings comming from tag libs. * * @param s DOCUMENT_ME * * @return the string */ public static String formatTag(final String s) { // we delete all non char characters to avoid parsing errors char c; final StringBuilder sb = new StringBuilder(s.length()); for (int i = 0; i < s.length(); i++) { c = s.charAt(i); if (UtilString.isChar(c)) { sb.append(c); } } return sb.toString().trim(); } /** * Format a time from secs to a human readable format. * * @param lTime DOCUMENT_ME * * @return the string */ public static String formatTimeBySec(final long lTime) { // Convert time to int for performance reasons int l = (int) lTime; if (l == -1) { // means we are in repeat mode return "--:--"; } else if (l < 0) { // make sure to to get negative values l = 0; } final int hours = l / 3600; final int mins = l / 60 - (hours * 60); final int secs = l - (hours * 3600) - (mins * 60); final StringBuilder sbResult = new StringBuilder(8); if (hours > 0) { sbResult.append(UtilString.padNumber(hours, 2)).append(":"); } return sbResult.append(UtilString.padNumber(mins, 2)).append(":") .append(UtilString.padNumber(secs, 2)).toString(); } /** * Format a string before XML write *

    * see http://www.w3.org/TR/2000/REC-xml-20001006 *

    * substrings *

    ' to ' *

    " to " *

    < to < *

    > to > *

    & to & * * @param s DOCUMENT_ME * * @return the string */ public static String formatXML(final String s) { String sOut = replaceReservedXMLChars(s); final StringBuilder sbOut = new StringBuilder(sOut.length()); /* * Transform String to XML-valid characters. XML 1.0 specs ; Character Range * [2] Char ::= #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | * [#x10000-#x10FFFF] any Unicode character, excluding the surrogate blocks, * FFFE, and FFFF. */ for (int i = 0; i < sOut.length(); i++) { final char c = sOut.charAt(i); if (UtilString.isChar(c)) { sbOut.append(c); } } return sbOut.toString(); } /** * Replace reserved xml chars. * * @param s DOCUMENT_ME * * @return the string */ private static String replaceReservedXMLChars(final String s) { String sOut = s; if (s.contains("&")) { sOut = sOut.replaceAll("&", "&"); } if (s.contains("\'")) { sOut = sOut.replaceAll("\'", "'"); } if (s.contains("\"")) { sOut = sOut.replaceAll("\"", """); } if (s.contains("<")) { sOut = sOut.replaceAll("<", "<"); } if (s.contains(">")) { sOut = sOut.replaceAll(">", ">"); } return sOut; } /** * Gets the addition date formatter. * * @return Thread-safe addition date simple format instance */ public static DateFormat getAdditionDateFormatter() { return FORMATTER.get(); } /** * Gets the anonymized jajuk properties. * * @return Anonymized Jajuk properties (for log or quality agent) */ public static Properties getAnonymizedJajukProperties() { final Properties properties = (Properties) Conf.getProperties().clone(); // We remove sensible data from logs properties.remove("jajuk.network.proxy_login"); properties.remove("jajuk.network.proxy_port"); properties.remove("jajuk.network.proxy_hostname"); properties.remove("jajuk.options.p2p.password"); return properties; } /** * Gets the anonymized system properties. * * @return Anonymized System properties (for log or quality agent) */ public static Properties getAnonymizedSystemProperties() { final Properties properties = (Properties) System.getProperties().clone(); // We remove sensible data from logs /* * can contain external program paths */ properties.remove("java.library.path"); properties.remove("java.class.path"); // user name is private properties.remove("user.name"); properties.remove("java.ext.dirs"); properties.remove("sun.boot.class.path"); properties.remove("deployment.user.security.trusted.certs"); properties.remove("deployment.user.security.trusted.clientauthcerts"); properties.remove("jajuk.log"); return properties; } /** * Make sure to reduce a string to the given size. * * @param sIn Input string, example: blabla * @param iSize max size, example: 3 * * @return bla... */ public static String getLimitedString(final String sIn, final int iSize) { String sOut = sIn; if (sIn.length() > iSize) { sOut = sIn.substring(0, iSize) + "..."; } return sOut; } /** * Checks if is char. * * @param ucs4char char to test * * @return whether the char is valid, code taken from Apache sax * implementation */ public static boolean isChar(final int ucs4char) { return ((ucs4char >= 32) && (ucs4char <= 55295)) || (ucs4char == 10) || (ucs4char == 9) || (ucs4char == 13) || ((ucs4char >= 57344) && (ucs4char <= 65533)) || ((ucs4char >= 0x10000) && (ucs4char <= 0x10ffff)); } /** * Checks if is xml valid. * * @param s DOCUMENT_ME * * @return whether given string is XML-valid */ public static boolean isXMLValid(final String s) { // check invalid chars for (int i = 0; i < s.length(); i++) { final char c = s.charAt(i); // check reserved chars if (-1 != "&\'\"<>".indexOf(c)) { return false; } if (!UtilString.isChar(c)) { return false; } } return true; } /** * Pad an int with zeros. * * @param l the number to be padded * @param size the targeted size * * @return the string */ public static String padNumber(final long l, final int size) { final StringBuilder sb = new StringBuilder(Long.toString(l)); while (sb.length() < size) { sb.insert(0, '0'); } return sb.toString(); } /** * Parse a string to an object. * * @param sValue DOCUMENT_ME * @param cType DOCUMENT_ME * * @return parsed item * * @throws ParseException the parse exception * @throws ClassNotFoundException the class not found exception */ public static Object parse(final String sValue, final Class cType) throws ParseException, ClassNotFoundException { Object oDefaultValue = sValue; // String by default if (cType.equals(Boolean.class)) { oDefaultValue = handleBoolean(sValue); } else if (cType.equals(Date.class)) { oDefaultValue = getAdditionDateFormatter().parseObject(sValue); } else if (cType.equals(Long.class)) { oDefaultValue = Long.parseLong(sValue); } else if (cType.equals(Double.class)) { oDefaultValue = Double.parseDouble(sValue); } else if (cType.equals(Class.class)) { oDefaultValue = Class.forName(sValue); } return oDefaultValue; } /** * Handle boolean. * DOCUMENT_ME * * @param sValue DOCUMENT_ME * * @return the boolean */ private static Boolean handleBoolean(final String sValue) { Boolean oValue; // "y" and "n" is an old boolean // attribute notation prior to 1.0 if ("y".equals(sValue)) { oValue = true; } else if ("n".equals(sValue)) { oValue = false; } else { oValue = fastBooleanParser(sValue); } return oValue; } /** * Fast long parser, low level check, replacement of Long.parseLong() * * CAUTION : do not use if the value can be negative or you will get * unexpected results * * @param in must be a set of digits with a size > 0 and be positive * * @return the long */ public static long fastLongParser(String in) { int length = in.length(); if (length == 1) { return in.charAt(0) - 48; } long out = 0; int length2 = length - 1; for (int i = 0; i < length; i++) { int digit = in.charAt(i) - 48; out += digit * Math.pow(10, (length2 - i)); } return out; } /** * Fast Boolean parser, low level check, replacement of Boolean.parseBoolean() * * @param in must be a string beginning by true or false (lower case) * * @return true, if fast boolean parser */ public static boolean fastBooleanParser(String in) { return (in.charAt(0) == 't'); } /** * Rot13 encode/decode, *

    * Thx http://www.idevelopment.info/data/Programming/java/security/ * java_cryptography_extension/rot13.java *

    * * @param in text to encode / decode in rote 13 * * @return encoded /decoded text */ public static String rot13(final String in) { if (StringUtils.isBlank(in)) { return ""; } int abyte = 0; final StringBuilder tempReturn = new StringBuilder(); for (int i = 0; i < in.length(); i++) { abyte = in.charAt(i); int cap = abyte & 32; abyte &= ~cap; abyte = ((abyte >= 'A') && (abyte <= 'Z') ? ((abyte - 'A' + 13) % 26 + 'A') : abyte) | cap; tempReturn.append((char) abyte); } return tempReturn.toString(); } /** * Matches ignore case and order. * * @param tested the string to be tested * @param key the search criteria, can be several words separated by a space * * @return whether the given tested string matches the key */ public static boolean matchesIgnoreCaseAndOrder(final String tested, final String key) { String testedLower = tested.toLowerCase(Locale.getDefault()); String keyLower = key.toLowerCase(Locale.getDefault()); StringTokenizer st = new StringTokenizer(testedLower, " "); while (st.hasMoreTokens()) { String token = st.nextToken(); if (keyLower.indexOf(token) == -1) { return false; } } return true; } /** * Encode a string to unicode representation (ie \\uxxxx\\uyyyyy...) * * @param in string to encode * * @return encoded string */ public static String encodeToUnicode(String in) { StringBuilder sb = new StringBuilder(in.length() * 5); for (int i = 0; i < in.length(); i++) { char c = in.charAt(i); byte hi = (byte) (c >>> 8); byte lo = (byte) (c & 0xff); sb.append("\\u"); sb.append(byteToHex(hi) + byteToHex(lo)); } return sb.toString(); } /** * Convert byte to hexadecimal representation. * * @param b DOCUMENT_ME * * @return the string */ public static String byteToHex(byte b) { char hexDigit[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; char[] array = { hexDigit[(b >> 4) & 0x0f], hexDigit[b & 0x0f] }; return new String(array); } /** * Returns a concatenation of argument array. * * @param strings strings to be concatened * * @return concatenation of given strings */ public static String concat(Object... strings) { StringBuilder sb = new StringBuilder(); for (Object element : strings) { sb.append(element); } return sb.toString(); } /** * Code token from aTunes 1.14.0 *Copyright (C) 2006-2009 Alex Aranda, Sylvain * Gaudard, Thomas Beckers and contributors Returns list of text between * specified chars. Both chars are included in result elements. Returns empty * list if chars are not found in string in given order For example given * string "ab cd (ef) gh (ij)" and chars '(' and ')' will return a list with * two strings: "(ef)" and "(ij)" * * @param string DOCUMENT_ME * @param beginChar DOCUMENT_ME * @param endChar DOCUMENT_ME * * @return the text between chars */ public static final List getTextBetweenChars(String string, char beginChar, char endChar) { List result = new ArrayList(); if (string == null || string.indexOf(beginChar) == -1 || string.indexOf(endChar) == -1) { return result; } String auxStr = string; int beginIndex = auxStr.indexOf(beginChar); int endIndex = auxStr.indexOf(endChar); while (beginIndex != -1 && endIndex != -1) { if (beginIndex < endIndex) { result.add(auxStr.substring(beginIndex, endIndex + 1)); } auxStr = auxStr.substring(endIndex + 1); beginIndex = auxStr.indexOf(beginChar); endIndex = auxStr.indexOf(endChar); } return result; } /** * Normalize filenames so they should be correct under any OS. * * @param name Name that should be normalized * @return the filename where special characters are replaced/removed */ public static synchronized String normalizeFilename(String name) { // some more special characters that can be replaced with more useful // values than FILLER_CHAR String temp = name.replaceAll("€", "EUR"); temp = temp.replaceAll("&", "and"); // Transform non-ASCII characters to ASCII form or drop them if no mapping available. temp = Normalizer.normalize(temp, Normalizer.Form.NFD).replaceAll("[^\\p{ASCII}]", ""); // Replace path-separators and colon that could cause trouble on other // OSes, also question mark and star can produce errors temp = FilenameUtils.normalize(temp); int[] illegalChars = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 58, 42, 63, 92, 34, 60, 62, 124 }; StringBuilder cleanName = new StringBuilder(); for (int i = 0; i < temp.length(); i++) { int c = temp.charAt(i); if (Arrays.binarySearch(illegalChars, c) < 0) { cleanName.append((char) c); } else { cleanName.append(FILLER_CHAR); } } temp = cleanName.toString(); // Make sure filename is not void if (temp.length() == 0) { temp = "normalized"; } return temp; } } jajuk-1.9.6.orig/src/main/java/org/jajuk/util/UtilGUI.java0000644000175000017500000007715611720500104023125 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.util; import com.jhlabs.image.PerspectiveFilter; import java.awt.AlphaComposite; import java.awt.Color; import java.awt.Component; import java.awt.Container; import java.awt.Cursor; import java.awt.Dimension; import java.awt.Frame; import java.awt.GradientPaint; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.GraphicsDevice; import java.awt.GraphicsEnvironment; import java.awt.Image; import java.awt.KeyEventDispatcher; import java.awt.KeyboardFocusManager; import java.awt.MouseInfo; import java.awt.Point; import java.awt.RenderingHints; import java.awt.Toolkit; import java.awt.Window; import java.awt.event.KeyEvent; import java.awt.image.BufferedImage; import java.awt.image.ColorModel; import java.awt.image.PixelGrabber; import java.io.File; import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; import java.util.Map; import java.util.StringTokenizer; import java.util.concurrent.ExecutionException; import javax.imageio.ImageIO; import javax.swing.Box; import javax.swing.BoxLayout; import javax.swing.ImageIcon; import javax.swing.JComponent; import javax.swing.JDialog; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JMenu; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTextArea; import javax.swing.JToolBar; import javax.swing.SwingUtilities; import javax.swing.SwingWorker; import javax.swing.UIManager; import javax.swing.UnsupportedLookAndFeelException; import org.jajuk.ui.helpers.FontManager; import org.jajuk.ui.helpers.FontManager.JajukFont; import org.jajuk.ui.helpers.TwoStepsDisplayable; import org.jajuk.ui.perspectives.IPerspective; import org.jajuk.ui.perspectives.PerspectiveManager; import org.jajuk.ui.views.IView; import org.jajuk.ui.widgets.CommandJPanel; import org.jajuk.ui.widgets.InformationJPanel; import org.jajuk.ui.widgets.JajukJMenuBar; import org.jajuk.ui.widgets.PerspectiveBarJPanel; import org.jajuk.ui.windows.JajukFullScreenWindow; import org.jajuk.ui.windows.JajukMainWindow; import org.jajuk.ui.windows.JajukSlimbar; import org.jajuk.ui.windows.JajukSystray; import org.jajuk.ui.windows.WindowState; import org.jajuk.ui.windows.WindowStateDecorator; import org.jajuk.util.log.Log; import org.jdesktop.swingx.decorator.Highlighter; import org.jdesktop.swingx.decorator.HighlighterFactory; import org.jvnet.substance.SubstanceLookAndFeel; import org.jvnet.substance.api.SubstanceColorScheme; import org.jvnet.substance.api.SubstanceSkin; import org.jvnet.substance.skin.SkinInfo; import org.jvnet.substance.skin.SubstanceBusinessLookAndFeel; /** * Set of GUI convenient methods. */ public final class UtilGUI { /* different types of Cursors that are available */ /** The Constant WAIT_CURSOR. DOCUMENT_ME */ public static final Cursor WAIT_CURSOR = new Cursor(Cursor.WAIT_CURSOR); /** The Constant LINK_CURSOR. DOCUMENT_ME */ public static final Cursor LINK_CURSOR = new Cursor(Cursor.HAND_CURSOR); /** The Constant DEFAULT_CURSOR. DOCUMENT_ME */ public static final Cursor DEFAULT_CURSOR = new Cursor(Cursor.DEFAULT_CURSOR); // Current cursor that is displayed /** DOCUMENT_ME. */ private static Cursor currentCursor = DEFAULT_CURSOR; /** Substance theme *. */ private static String theme; /** Alternate color rows highlighter used in every table. */ private static Highlighter alternateColorHighlighter; /** * Return whether the given highlighter is the alternateColorHighlighter. * * @param other DOCUMENT_ME * * @return whether the given highlighter is the alternateColorHighlighter */ public static boolean isAlternateColorHighlighter(Highlighter other) { return other.equals(alternateColorHighlighter); } /** * Reset the alternateColorHighlighter (during a theme change for eg). */ public static void resetAlternateColorHighlighter() { alternateColorHighlighter = null; } /** Current active color scheme *. */ private static SubstanceColorScheme colorScheme; /** Set cursor thread, stored to avoid construction. */ private static Runnable setCursorThread = new Runnable() { @Override public void run() { Container container = null; IPerspective perspective = PerspectiveManager.getCurrentPerspective(); if (perspective != null) { // Log.debug("** Set cursor: " + currentCursor); container = perspective.getContentPane(); container.setCursor(currentCursor); CommandJPanel.getInstance().setCursor(currentCursor); InformationJPanel.getInstance().setCursor(currentCursor); PerspectiveBarJPanel.getInstance().setCursor(currentCursor); } } }; /** * Private constructor to prevent instantiation of utility class. */ private UtilGUI() { } /** * Display a given image in a frame (for debuging purpose). * * @param ii DOCUMENT_ME */ public static void displayImage(final ImageIcon ii) { final JFrame jf = new JFrame(); jf.add(new JLabel(ii)); jf.pack(); jf.setVisible(true); } /** * Write down a memory image to a file. * * @param src DOCUMENT_ME * @param dest DOCUMENT_ME */ public static void extractImage(final Image src, final File dest) { final BufferedImage bi = UtilGUI.toBufferedImage(src); // Need alpha only for png and gif files); try { ImageIO.write(bi, UtilSystem.getExtension(dest), dest); } catch (final IOException e) { Log.error(e); } } /** * Gets the graphics device of main frame. * * @return the current display of the main frame */ public static GraphicsDevice getGraphicsDeviceOfMainFrame() { GraphicsEnvironment localGraphicsEnvironment = GraphicsEnvironment .getLocalGraphicsEnvironment(); for (int i = 0; i < GraphicsEnvironment.getLocalGraphicsEnvironment().getScreenDevices().length; i++) { GraphicsDevice graphicsDevice = localGraphicsEnvironment.getScreenDevices()[i]; if (graphicsDevice.getDefaultConfiguration().getBounds().contains( JajukMainWindow.getInstance().getLocation())) { return graphicsDevice; } } return localGraphicsEnvironment.getDefaultScreenDevice(); } /** * Gets the centred panel. * * @param jc DOCUMENT_ME * * @return an horizontaly centred panel */ public static JPanel getCentredPanel(final JComponent jc) { return UtilGUI.getCentredPanel(jc, BoxLayout.X_AXIS); } /** * Gets the centred panel. * * @param jc DOCUMENT_ME * @param iOrientation : vertical or horizontal orientation, use BoxLayout.X_AXIS or * BoxLayout.Y_AXIS * * @return a centred panel */ public static JPanel getCentredPanel(final JComponent jc, final int iOrientation) { final JPanel jpOut = new JPanel(); jpOut.setLayout(new BoxLayout(jpOut, iOrientation)); if (iOrientation == BoxLayout.X_AXIS) { jpOut.add(Box.createHorizontalGlue()); jpOut.add(jc); jpOut.add(Box.createHorizontalGlue()); } else { jpOut.add(Box.createVerticalGlue()); jpOut.add(jc); jpOut.add(Box.createVerticalGlue()); } return jpOut; } /** * Gets the html color. * * @param color java color * * @return HTML RGB color ex: FF0000 */ public static String getHTMLColor(final Color color) { return Long.toString(color.getRed(), 16) + Long.toString(color.getGreen(), 16) + Long.toString(color.getBlue(), 16); } /** * Get required image with specified url. * * @param url DOCUMENT_ME * * @return the image */ public static ImageIcon getImage(final URL url) { ImageIcon ii = null; final String sURL = url.toString(); try { if (UtilSystem.iconCache.containsKey(sURL)) { ii = UtilSystem.iconCache.get(sURL); } else { ii = new ImageIcon(url); UtilSystem.iconCache.put(sURL, ii); } } catch (final Exception e) { Log.error(e); } return ii; } /** * Gets the limited message. * * @param sText text to display, lines separated by \n characters * @param limit : max number of lines to be displayed without scroller * * @return formated message: either a string, or a textarea */ public static Object getLimitedMessage(final String sText, final int limit) { final int iNbLines = new StringTokenizer(sText, "\n").countTokens(); Object message = null; if (iNbLines > limit) { final JTextArea area = new JTextArea(sText); area.setRows(10); area.setColumns(50); area.setLineWrap(true); message = new JScrollPane(area); } else { message = sText; } return message; } /** * code from * http://java.sun.com/developer/onlineTraining/new2java/supplements/ * 2005/July05.html#1 Used to correctly display long messages * * @param maxCharactersPerLineCount DOCUMENT_ME * * @return the narrow option pane */ public static JOptionPane getNarrowOptionPane(final int maxCharactersPerLineCount) { // Our inner class definition class NarrowOptionPane extends JOptionPane { private static final long serialVersionUID = 1L; int lmaxCharactersPerLineCount; NarrowOptionPane(final int maxCharactersPerLineCount) { super(); this.lmaxCharactersPerLineCount = maxCharactersPerLineCount; } @Override public int getMaxCharactersPerLineCount() { return lmaxCharactersPerLineCount; } } return new NarrowOptionPane(maxCharactersPerLineCount); } /** * Resize an image. * * @param img image to resize * @param iNewWidth DOCUMENT_ME * @param iNewHeight DOCUMENT_ME * * @return resized image */ public static ImageIcon getResizedImage(final ImageIcon img, final int iNewWidth, final int iNewHeight) { Image scaleImg = img.getImage().getScaledInstance(iNewWidth, iNewHeight, Image.SCALE_AREA_AVERAGING); // Leave image cache here as we may want to keep original image return new ImageIcon(scaleImg); } /** * Gets the scaled image. * * @param img DOCUMENT_ME * @param iScale DOCUMENT_ME * * @return a scaled image */ public static ImageIcon getScaledImage(final ImageIcon img, final int iScale) { int iNewWidth; int iNewHeight; // Height is smaller or equal than width : try to optimize width iNewWidth = iScale; // take all possible width // we check now if height will be visible entirely with optimized width final float fWidthRatio = (float) iNewWidth / img.getIconWidth(); if (img.getIconHeight() * (fWidthRatio) <= iScale) { iNewHeight = (int) (img.getIconHeight() * fWidthRatio); } else { // no? so we optimize width iNewHeight = iScale; iNewWidth = (int) (img.getIconWidth() * ((float) iNewHeight / img.getIconHeight())); } return UtilGUI.getResizedImage(img, iNewWidth, iNewHeight); } /** * Setup Substance look and feel. * * @param pTheme DOCUMENT_ME */ public static void setupSubstanceLookAndFeel(final String pTheme) { // Check the theme is known, if not take the default theme final Map themes = SubstanceLookAndFeel.getAllSkins(); theme = pTheme; if (themes.get(theme) == null) { theme = Const.LNF_DEFAULT_THEME; Conf.setProperty(Const.CONF_OPTIONS_LNF, Const.LNF_DEFAULT_THEME); } // Set substance LAF try { UIManager.setLookAndFeel(new SubstanceBusinessLookAndFeel()); } catch (UnsupportedLookAndFeelException e) { Log.error(e); } // Set substance LAF SubstanceLookAndFeel.setSkin(themes.get(theme).getClassName()); // hide some useless elements such locker for not editable labels UIManager.put(SubstanceLookAndFeel.SHOW_EXTRA_WIDGETS, Boolean.FALSE); // Store current color scheme (cannot change for the wall session) colorScheme = SubstanceLookAndFeel.getCurrentSkin().getMainActiveColorScheme(); // Set view foreground colors SubstanceSkin theme = SubstanceLookAndFeel.getCurrentSkin(); SubstanceColorScheme scheme = theme.getMainActiveColorScheme(); Color foregroundActive = null; Color foregroundInactive = null; Color backgroundActive = null; Color backgroundInactive = null; if (scheme.isDark()) { foregroundActive = Color.BLACK; foregroundInactive = Color.WHITE; backgroundActive = scheme.getUltraLightColor(); backgroundInactive = scheme.getUltraDarkColor(); } else { foregroundActive = Color.WHITE; foregroundInactive = Color.BLACK; backgroundActive = scheme.getDarkColor(); backgroundInactive = scheme.getLightColor(); } UIManager.put("InternalFrame.activeTitleForeground", foregroundActive); UIManager.put("InternalFrame.inactiveTitleForeground", foregroundInactive); UIManager.put("InternalFrame.activeTitleBackground", backgroundActive); UIManager.put("InternalFrame.inactiveTitleBackground", backgroundInactive); UIManager.put("DockViewTitleBar.titleFont", FontManager.getInstance().getFont( JajukFont.VIEW_FONT)); // Set windows decoration to look and feel JFrame.setDefaultLookAndFeelDecorated(true); JDialog.setDefaultLookAndFeelDecorated(true); } /** * Display given container at given position. * * @param iFromTop max number of pixels from top * @param iFromLeft max number of pixels from left * @param window DOCUMENT_ME */ public static void setShuffleLocation(final Window window, final int iFromTop, final int iFromLeft) { window.setLocation((int) (Math.random() * iFromTop), (int) (Math.random() * iFromLeft)); } /** * Set current cursor as waiting cursor. */ public static synchronized void waiting() { if (!currentCursor.equals(WAIT_CURSOR)) { currentCursor = WAIT_CURSOR; SwingUtilities.invokeLater(setCursorThread); } } /** * Set current cursor as default cursor. */ public static synchronized void stopWaiting() { if (!currentCursor.equals(DEFAULT_CURSOR)) { currentCursor = DEFAULT_CURSOR; SwingUtilities.invokeLater(setCursorThread); } } /** * To buffered image. DOCUMENT_ME * * @param image the input image * * @return the buffered image */ public static BufferedImage toBufferedImage(final Image image) { return UtilGUI.toBufferedImage(image, image.getWidth(null), image.getHeight(null)); } /** * Create a buffered image without forced alpha channel. * * @param image the input image * @param targetWidth DOCUMENT_ME * @param targetHeight DOCUMENT_ME * * @return the buffered image */ public static BufferedImage toBufferedImage(final Image image, final int targetWidth, final int targetHeight) { return UtilGUI.toBufferedImage(image, targetWidth, targetHeight, false); } /** * Transform an image to a BufferedImage *

    * Code adapted from from http://today.java.net/pub/a/today/2007/04/03/perils-of-image-getscaledinstance.html *

    * * @param image the input image * @param forcedAlpha Force using an alpha chanel for target image * @param targetWidth DOCUMENT_ME * @param targetHeight DOCUMENT_ME * * @return buffered image from an image */ public static BufferedImage toBufferedImage(final Image image, final int targetWidth, final int targetHeight, boolean forcedAlpha) { if (image instanceof BufferedImage) { return ((BufferedImage) image); } else { // This code ensures that all the pixels in the image are loaded Image loadedImage = new ImageIcon(image).getImage(); // Use right target format according to need for alpha chanel or not (less memory use if no // alpha) int type = BufferedImage.TYPE_INT_RGB; if (forcedAlpha || hasAlpha(image)) { type = BufferedImage.TYPE_INT_ARGB; } BufferedImage ret = null; int w, h; // Use multi-step technique: start with original size, then // scale down in multiple passes with drawImage() // until the target size is reached w = image.getWidth(null); h = image.getHeight(null); // See http://today.java.net/pub/a/today/2007/04/03/perils-of-image-getscaledinstance.html for // explanations about this algorithm. // Basically, we perform image creation dichotomy to create high quality thumb at low price do { // When w/y reaches thumb height/width, it's time to to use the target thumb size exactly if (w <= targetHeight || h <= targetHeight) { w = targetWidth; h = targetHeight; } else { if (w > targetWidth) { w /= 2; if (w < targetWidth) { w = targetWidth; } } if (h > targetHeight) { h /= 2; if (h < targetHeight) { h = targetHeight; } } } BufferedImage tmp = new BufferedImage(w, h, type); Graphics2D g2 = tmp.createGraphics(); g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR); // If the input buffered image doesn't yet exist, use the input image if (ret != null) { g2.drawImage(ret, 0, 0, w, h, null); } else { g2.drawImage(loadedImage, 0, 0, w, h, null); } g2.dispose(); ret = tmp; } while (w != targetWidth || h != targetHeight); image.flush(); loadedImage.flush(); return ret; } } /** * Get3d image. * * @param img DOCUMENT_ME * * @return the 3d image */ public static BufferedImage get3dImage(Image img) { int angle = 30; int gap = 10; float opacity = 0.3f; float fadeHeight = 0.6f; // cover BufferedImage coverImage = UtilGUI.toBufferedImage(img, Const.MIRROW_COVER_SIZE, Const.MIRROW_COVER_SIZE, true); PerspectiveFilter filter1 = new PerspectiveFilter(0, angle, Const.MIRROW_COVER_SIZE - angle / 2, (int) (angle * (5.0 / 3.0)), Const.MIRROW_COVER_SIZE - angle / 2, Const.MIRROW_COVER_SIZE, 0, Const.MIRROW_COVER_SIZE + angle); coverImage = filter1.filter(coverImage, null); // reflection int imageWidth = coverImage.getWidth(); int imageHeight = coverImage.getHeight(); BufferedImage reflection = new BufferedImage(imageWidth, imageHeight, BufferedImage.TYPE_INT_ARGB); Graphics2D rg = reflection.createGraphics(); rg.drawRenderedImage(coverImage, null); rg.setComposite(AlphaComposite.getInstance(AlphaComposite.DST_IN)); rg.setPaint(new GradientPaint(0, imageHeight * fadeHeight, new Color(0.0f, 0.0f, 0.0f, 0.0f), 0, imageHeight, new Color(0.0f, 0.0f, 0.0f, opacity))); rg.fillRect(0, 0, imageWidth, imageHeight); rg.dispose(); PerspectiveFilter filter2 = new PerspectiveFilter(0, 0, coverImage.getHeight() - angle / 2, angle * 2, coverImage.getHeight() - angle / 2, coverImage.getHeight() + angle * 2, 0, coverImage.getHeight()); BufferedImage reflectedImage = filter2.filter(reflection, null); // now draw everything on one bufferedImage BufferedImage finalImage = new BufferedImage(imageWidth, (int) (1.4 * imageHeight), BufferedImage.TYPE_INT_ARGB); Graphics g = finalImage.getGraphics(); Graphics2D g2d = (Graphics2D) g; g2d.drawRenderedImage(coverImage, null); g2d.translate(0, 2 * imageHeight + gap); g2d.scale(1, -1); g2d.drawRenderedImage(reflectedImage, null); g2d.dispose(); reflection.flush(); coverImage.flush(); return finalImage; } /** * This method returns true if the specified image has transparent pixels * Found at http://www.exampledepot.com/egs/java.awt.image/HasAlpha.html * * @param image DOCUMENT_ME * * @return true if the specified image has transparent pixels */ public static boolean hasAlpha(Image image) { try { // If buffered image, the color model is readily available if (image instanceof BufferedImage) { BufferedImage bimage = (BufferedImage) image; return bimage.getColorModel().hasAlpha(); } // Use a pixel grabber to retrieve the image's color model; // grabbing a single pixel is usually sufficient PixelGrabber pg = new PixelGrabber(image, 0, 0, 1, 1, false); pg.grabPixels(); // Get the image's color model ColorModel cm = pg.getColorModel(); if (cm != null) { return cm.hasAlpha(); } } catch (Exception e) { Log.error(e); } return false; } /** * Method to attempt a dynamic update for any GUI accessible by this JVM. It * will filter through all frames and sub-components of the frames. */ public static void updateAllUIs() { Frame frames[]; frames = Frame.getFrames(); for (final Frame element : frames) { UtilGUI.updateWindowUI(element); } // update tray if (JajukSystray.isLoaded() && (JajukSystray.getInstance().getMenu() != null)) { UtilGUI.updateComponentTreeUI(JajukSystray.getInstance().getMenu()); } } /** * A simple minded look and feel change: ask each node in the tree to * updateUI() -- that is, to initialize its UI property with the * current look and feel. Based on the Sun * SwingUtilities.updateComponentTreeUI, but ensures that the update happens * on the components of a JToolbar before the JToolbar itself. * * @param c DOCUMENT_ME */ public static void updateComponentTreeUI(final Component c) { UtilGUI.updateComponentTreeUI0(c); c.invalidate(); c.validate(); c.repaint(); } /** * Update component tree u i0. DOCUMENT_ME * * @param c DOCUMENT_ME */ private static void updateComponentTreeUI0(final Component c) { Component[] children = null; if (c instanceof JToolBar) { children = ((JToolBar) c).getComponents(); if (children != null) { for (final Component element : children) { UtilGUI.updateComponentTreeUI0(element); } } ((JComponent) c).updateUI(); } else { if (c instanceof JComponent) { ((JComponent) c).updateUI(); } if (c instanceof JMenu) { children = ((JMenu) c).getMenuComponents(); } else if (c instanceof Container) { children = ((Container) c).getComponents(); } if (children != null) { for (final Component element : children) { UtilGUI.updateComponentTreeUI0(element); } } } } /** * Method to attempt a dynamic update for all components of the given * Window. * * @param window The Window for which the look and feel update has to * be performed against. */ public static void updateWindowUI(final Window window) { try { UtilGUI.updateComponentTreeUI(window); } catch (final Exception exception) { Log.error(exception); } final Window windows[] = window.getOwnedWindows(); for (final Window element : windows) { UtilGUI.updateWindowUI(element); } } /** * Gets the alternate highlighter. * * @return a theme-dependent alternate row highlighter used in tables or trees */ public static Highlighter getAlternateHighlighter() { if (alternateColorHighlighter != null) { return alternateColorHighlighter; } SubstanceSkin theme = SubstanceLookAndFeel.getCurrentSkin(); SubstanceColorScheme scheme = theme.getMainActiveColorScheme(); Color color1 = scheme.getWatermarkStampColor(); Color color2 = scheme.getWatermarkDarkColor(); Highlighter highlighter = HighlighterFactory.createAlternateStriping(color1, color2); alternateColorHighlighter = highlighter; return highlighter; } /** * Checks if is over. * * @param location DOCUMENT_ME * @param dimension DOCUMENT_ME * * @return whether the current mouse cursor if above a given component */ public static boolean isOver(Point location, Dimension dimension) { java.awt.Point p = MouseInfo.getPointerInfo().getLocation(); if (p.getX() <= location.getX() || p.getY() <= location.getY()) { return false; } return (p.getX() < (dimension.getWidth() + location.getX()) && p.getY() < (dimension .getHeight() + location.getY())); } /** * Gets the ultra light color. * * @return ultralight color for current color scheme */ static public Color getUltraLightColor() { return colorScheme.getUltraLightColor(); } /** * Gets the foreground color. * * @return foreground color for current color scheme */ static public Color getForegroundColor() { return colorScheme.getForegroundColor(); } /** * Display a dialog with given url picture. * * @param url DOCUMENT_ME * * @throws MalformedURLException the malformed url exception */ static public void showPictureDialog(String url) throws MalformedURLException { JDialog jd = new JDialog(JajukMainWindow.getInstance()); ImageIcon ii = new ImageIcon(new URL(url)); JPanel jp = new JPanel(); jp.setLayout(new BoxLayout(jp, BoxLayout.X_AXIS)); JLabel jl = new JLabel(ii); jp.add(jl); jd.setContentPane(jp); jd.pack(); jd.setLocationRelativeTo(JajukMainWindow.getInstance()); jd.setVisible(true); } /** * configures gui for repeat single enable/disable. * * @param enable DOCUMENT_ME */ public static void setRepeatSingleGui(boolean enable) { // always disable repeat all Conf.setProperty(Const.CONF_STATE_REPEAT_ALL, Const.FALSE); JajukJMenuBar.getInstance().setRepeatAllSelected(false); CommandJPanel.getInstance().setRepeatAllSelected(false); Conf.setProperty(Const.CONF_STATE_REPEAT, Boolean.toString(enable)); JajukJMenuBar.getInstance().setRepeatSelected(enable); CommandJPanel.getInstance().setRepeatSelected(enable); } /** * configures gui for repeat all enable/disable. * * @param enable DOCUMENT_ME */ public static void setRepeatAllGui(boolean enable) { // always disable repeat single Conf.setProperty(Const.CONF_STATE_REPEAT, Boolean.toString(false)); JajukJMenuBar.getInstance().setRepeatSelected(false); CommandJPanel.getInstance().setRepeatSelected(false); Conf.setProperty(Const.CONF_STATE_REPEAT_ALL, Boolean.toString(enable)); JajukJMenuBar.getInstance().setRepeatAllSelected(enable); CommandJPanel.getInstance().setRepeatAllSelected(enable); } /** * Registers the ESCAPE key on the Panel so that it closes the Dialog. * * @param window DOCUMENT_ME * @param pane DOCUMENT_ME */ public static void setEscapeKeyboardAction(final Window window, JComponent pane) { // Add keystroke to close window when pressing escape KeyboardFocusManager.getCurrentKeyboardFocusManager().addKeyEventDispatcher( new KeyEventDispatcher() { @Override public boolean dispatchKeyEvent(KeyEvent e) { // For some reasons (under Linux at least), pressing escape only trigger PRESSED // and RELEASED key events if (e.getKeyCode() == KeyEvent.VK_ESCAPE && e.getID() == KeyEvent.KEY_PRESSED && window.isFocused()) { window.dispose(); return true; } return false; } }); } /** * Build GUI for a TwoStateDisplayable component. *

    * * * @param displayable DOCUMENT_ME */ public static void populate(final TwoStepsDisplayable displayable) { SwingWorker sw = new SwingWorker() { @Override protected Object doInBackground() throws Exception { return displayable.longCall(); } @Override protected void done() { try { Object in = get(); displayable.shortCall(in); } catch (InterruptedException e) { Log.error(e); } catch (ExecutionException e) { Log.error(e); } } }; sw.execute(); } /** * Center a given window to the center of the screen. * * @param window DOCUMENT_ME */ public static void centerWindow(Window window) { Toolkit tk = Toolkit.getDefaultToolkit(); Dimension screenSize = tk.getScreenSize(); int screenHeight = screenSize.height; int screenWidth = screenSize.width; window.setLocation((screenWidth / 2) - (window.getWidth() / 2), (screenHeight / 2) - (window.getHeight() / 2)); } /** * Return any displayed window (between main window, slimbar...) * * @return any displayed window (between main window, slimbar...) */ public static Window getActiveWindow() { if (JajukMainWindow.getInstance().getWindowStateDecorator().isDisplayed()) { return JajukMainWindow.getInstance(); } else if (JajukSlimbar.getInstance().getWindowStateDecorator().isDisplayed()) { return JajukSlimbar.getInstance(); } else if (JajukFullScreenWindow.getInstance().getWindowStateDecorator().isDisplayed()) { return JajukFullScreenWindow.getInstance(); } else { // Can happen in sys tray mode only return null; } } /** * Gets the given component's parent view. * * @param component the component * * @return the parent view or null if none IView is among its ancestors */ public static IView getParentView(Component component) { try { Component parent = component.getParent(); while (parent != null && !(parent instanceof IView)) { parent = parent.getParent(); } return (IView) parent; } catch (RuntimeException e) { // Make sure to trap strange events return null; } } /** * Store window-type configuration. */ public static void storeWindowSate() { WindowStateDecorator sdSlimbar = JajukSlimbar.getInstance().getWindowStateDecorator(); WindowStateDecorator sdMainWindow = JajukMainWindow.getInstance().getWindowStateDecorator(); WindowStateDecorator sdfullscreen = JajukFullScreenWindow.getInstance() .getWindowStateDecorator(); // Set main window display at next startup as a default Conf.setProperty(Const.CONF_STARTUP_DISPLAY, Integer.toString(Const.DISPLAY_MODE_MAIN_WINDOW)); if (sdSlimbar.getWindowState() == WindowState.BUILT_DISPLAYED) { Conf.setProperty(Const.CONF_STARTUP_DISPLAY, Integer .toString(Const.DISPLAY_MODE_SLIMBAR_TRAY)); } if (sdMainWindow.isDisplayed()) { Conf .setProperty(Const.CONF_STARTUP_DISPLAY, Integer.toString(Const.DISPLAY_MODE_MAIN_WINDOW)); } // None window displayed ? set the tray only (if the show tray option is // set) if (!sdSlimbar.isDisplayed() && !sdMainWindow.isDisplayed() && !sdfullscreen.isDisplayed() && Conf.getBoolean(Const.CONF_SHOW_SYSTRAY)) { Conf.setProperty(Const.CONF_STARTUP_DISPLAY, Integer.toString(Const.DISPLAY_MODE_TRAY)); } if (sdfullscreen.getWindowState() == WindowState.BUILT_DISPLAYED) { Conf.setProperty(Const.CONF_STARTUP_DISPLAY, Integer.toString(Const.DISPLAY_MODE_FULLSCREEN)); } } } jajuk-1.9.6.orig/src/main/java/org/jajuk/util/package.html0000644000175000017500000000012011720500104023232 0ustar drazzibdrazzib Utility classes, security and hashcode facilities jajuk-1.9.6.orig/src/main/java/org/jajuk/util/UtilFeatures.java0000644000175000017500000004162511720500104024247 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.util; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.LinkedHashSet; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Scanner; import java.util.Set; import org.jajuk.base.Device; import org.jajuk.base.Directory; import org.jajuk.base.File; import org.jajuk.base.Item; import org.jajuk.base.LogicalItem; import org.jajuk.base.Playlist; import org.jajuk.base.Track; import org.jajuk.base.TrackManager; import org.jajuk.events.JajukEvent; import org.jajuk.events.JajukEvents; import org.jajuk.events.ObservationManager; import org.jajuk.events.Observer; import org.jajuk.services.dj.Ambience; import org.jajuk.services.players.QueueModel; import org.jajuk.services.players.StackItem; import org.jajuk.ui.widgets.InformationJPanel; import org.jajuk.util.error.JajukException; import org.jajuk.util.log.Log; /** * General use utilities methods. */ public final class UtilFeatures { /** Genres. */ public static final String[] GENRES = { "Blues", "Classic Rock", "Country", "Dance", "Disco", "Funk", "Grunge", "Hip-Hop", "Jazz", "Metal", "New Age", "Oldies", "Other", "Pop", "R&B", "Rap", "Reggae", "Rock", "Techno", "Industrial", "Alternative", "Ska", "Death Metal", "Pranks", "Soundtrack", "Euro-Techno", "Ambient", "Trip-Hop", "Vocal", "Jazz+Funk", "Fusion", "Trance", "Classical", "Instrumental", "Acid", "House", "Game", "Sound Clip", "Gospel", "Noise", "AlternRock", "Bass", "Soul", "Punk", "Space", "Meditative", "Instrumental Pop", "Instrumental Rock", "Ethnic", "Gothic", "Darkwave", "Techno-Industrial", "Electronic", "Pop-Folk", "Eurodance", "Dream", "Southern Rock", "Comedy", "Cult", "Gangsta", "Top 40", "Christian Rap", "Pop/Funk", "Jungle", "Native American", "Cabaret", "New Wave", "Psychedelic", "Rave", "Showtunes", "Trailer", "Lo-Fi", "Tribal", "Acid Punk", "Acid Jazz", "Polka", "Retro", "Musical", "Rock & Roll", "Hard Rock", "Folk", "Folk-Rock", "National Folk", "Swing", "Fast Fusion", "Bebob", "Latin", "Revival", "Celtic", "Bluegrass", "Avantgarde", "Gothic Rock", "Progressive Rock", "Psychedelic Rock", "Symphonic Rock", "Slow Rock", "Big Band", "Chorus", "Easy Listening", "Acoustic", "Humour", "Speech", "Chanson", "Opera", "Chamber Music", "Sonata", "Symphony", "Booty Brass", "Primus", "Porn Groove", "Satire", "Slow Jam", "Club", "Tango", "Samba", "Folklore", "Ballad", "Power Ballad", "Rhytmic Soul", "Freestyle", "Duet", "Punk Rock", "Drum Solo", "Acapella", "Euro-House", "Dance Hall", "Goa", "Drum & Bass", "Club-House", "Hardcore", "Terror", "Indie", "BritPop", "Negerpunk", "Polsk Punk", "Beat", "Christian Gangsta", "Heavy Metal", "Black Metal", "Crossover", "Contemporary C", "Christian Rock", "Merengue", "Salsa", "Thrash Metal", "Anime", "JPop", "SynthPop" }; /** * Apply play option. * * @param alFiles DOCUMENT_ME * * @return Given list to play with shuffle or others rules applied */ @SuppressWarnings("unchecked") public static List applyPlayOption(final List alFiles) { if (Conf.getBoolean(Const.CONF_STATE_SHUFFLE)) { // we need all these casts for clone() to be callable here final List alFilesToPlay = (List) ((ArrayList) alFiles) .clone(); Collections.shuffle(alFilesToPlay, UtilSystem.getRandom()); return alFilesToPlay; } return alFiles; } /** * Convert a list of files into a list of StackItem *

    * null files are ignored *

    . * * @param alFiles DOCUMENT_ME * @param bRepeat DOCUMENT_ME * @param bUserLauched DOCUMENT_ME * * @return the list< stack item> */ public static List createStackItems(final List alFiles, final boolean bRepeat, final boolean bUserLauched) { final List alOut = new ArrayList(alFiles.size()); for (org.jajuk.base.File file : alFiles) { if (file != null) { try { final StackItem item = new StackItem(file); item.setRepeat(bRepeat); item.setUserLaunch(bUserLauched); alOut.add(item); } catch (final JajukException je) { Log.error(je); } } } return alOut; } /** * Filter a given file list by ambience. * * @param al file list * @param ambience ambience * * @return the list filtered or a void list if none available track */ public static List filterByAmbience(final List al, final Ambience ambience) { // If track list is null, return a void list if (al == null || al.size() == 0) { return new ArrayList(0); } // Void filter, return the input if ((ambience == null) || (ambience.getGenres().size() == 0)) { return al; } // Filter by ambience final List out = new ArrayList(al.size() / 2); for (final org.jajuk.base.File file : al) { if (ambience.getGenres().contains(file.getTrack().getGenre())) { out.add(file); } } return out; } /** * Convenient method for getPlayableFiles(collection). * * @param item DOCUMENT_ME * * @return files */ public static List getPlayableFiles(Item item) { List list = new ArrayList(1); list.add(item); return getPlayableFiles(list); } /** * Computes file selection from item collection *

    * We assume that the collection elements all own the same type *

    * Unmounted files are selected according to the value of * CONF_OPTIONS_HIDE_UNMOUNTED option. * * @param selection an item selection (directories, files...) * * @return the files (empty list if none matching) */ public static List getPlayableFiles(List selection) { // computes selection List files = new ArrayList(100); if (selection == null || selection.size() == 0) { return files; } for (Item item : selection) { // computes logical selection if any if (item instanceof Track) { files.add(((Track) item).getBestFile(Conf.getBoolean(Const.CONF_OPTIONS_HIDE_UNMOUNTED))); } else if (item instanceof LogicalItem) { List tracks = TrackManager.getInstance().getAssociatedTracks(item, true); for (Track track : tracks) { files.add(track.getBestFile(Conf.getBoolean(Const.CONF_OPTIONS_HIDE_UNMOUNTED))); } } // computes physical selection if any else if (item instanceof org.jajuk.base.File) { files.add((org.jajuk.base.File) item); } else if (item instanceof Directory) { files.addAll(((Directory) item).getFilesRecursively()); } else if (item instanceof Device) { files.addAll(((Device) item).getFilesRecursively()); } else if (item instanceof Playlist) { try { files.addAll(((Playlist) item).getFiles()); } catch (JajukException e) { Log.error(e); } } } return files; } /** * Gets the shuffle item. * * @param DOCUMENT_ME * @param col DOCUMENT_ME * @return a single shuffle element from a list, null if none element in * provided collection */ public static T getShuffleItem(final Collection col) { if (col.size() == 0) { return null; } List list = null; if (col instanceof List) { list = (List) col; } else { list = new ArrayList(col); } return list.get((int) (Math.random() * list.size())); } /** * Return a genre string for a given genre id *. * * @param i DOCUMENT_ME * * @return the string genre */ public static String getStringGenre(final int i) { if ((i >= 0) && (i < 126)) { return GENRES[i]; } else { return Messages.getString("unknown_genre"); } } /** * Checks if is standard cover. * * @param file DOCUMENT_ME * * @return whether the given filename is a standard cover or not */ public static boolean isStandardCover(final java.io.File file) { boolean defaultCover = false; String sFileName = file.getName(); Scanner s = new Scanner(Conf.getString(Const.FILE_DEFAULT_COVER)).useDelimiter(";"); while (s.hasNext()) { String next = s.next(); defaultCover = sFileName.toLowerCase(Locale.getDefault()).matches(".*" + next + ".*"); if (defaultCover) { break; } } s.close(); if (!defaultCover) { // just for previous compatibility, now it is a directory // property defaultCover = sFileName.toLowerCase(Locale.getDefault()).matches( ".*" + Const.FILE_ABSOLUTE_DEFAULT_COVER + ".*"); } return defaultCover; } /** * No constructor. */ private UtilFeatures() { } /** * Try to compute time length in milliseconds using BasicPlayer API. (code * from jlGui 2.3) * * @param properties DOCUMENT_ME * * @return the time length estimation */ public static long getTimeLengthEstimation(final Map properties) { long milliseconds = -1; int byteslength = -1; if (properties != null) { if (properties.containsKey("audio.length.bytes")) { byteslength = ((Integer) properties.get("audio.length.bytes")).intValue(); } if (properties.containsKey("duration")) { milliseconds = (((Long) properties.get("duration")).longValue()) / 1000; } else { // Try to compute duration int bitspersample = -1; int channels = -1; float samplerate = -1.0f; int framesize = -1; if (properties.containsKey("audio.samplesize.bits")) { bitspersample = ((Integer) properties.get("audio.samplesize.bits")).intValue(); } if (properties.containsKey("audio.channels")) { channels = ((Integer) properties.get("audio.channels")).intValue(); } if (properties.containsKey("audio.samplerate.hz")) { samplerate = ((Float) properties.get("audio.samplerate.hz")).floatValue(); } if (properties.containsKey("audio.framesize.bytes")) { framesize = ((Integer) properties.get("audio.framesize.bytes")).intValue(); } if (bitspersample > 0) { milliseconds = (int) (1000.0f * byteslength / (samplerate * channels * (((float) bitspersample) / 8))); } else { milliseconds = (int) (1000.0f * byteslength / (samplerate * framesize)); } } } return milliseconds; } /** * Gets the preference for selection. * * @param selection DOCUMENT_ME * * @return first item in selection preference */ public static long getPreferenceForSelection(List selection) { // We compute preference of first item selection) { if (selection.size() == 0) { return Const.PREFERENCE_UNSET; } List items = new ArrayList(selection); // For each entry of the selection (can be album, year, track, // directory...), // we add all associated tracks and we get equals preference if any List trackList = TrackManager.getInstance().getAssociatedTracks(items, false); // List shouldn't be void (except on collection node selection in tree view // for ie) if (trackList.size() == 0) { return Const.PREFERENCE_UNSET; } Track firstTrack = trackList.get(0); long preferenceFirstItem = firstTrack.getLongValue(Const.XML_TRACK_PREFERENCE); for (int i = 1; i < trackList.size(); i++) { Track track = trackList.get(i); if (track.getLongValue(Const.XML_TRACK_PREFERENCE) != preferenceFirstItem) { return Const.PREFERENCE_UNSET; } } return preferenceFirstItem; } /** * Perform updates on this view to reflect current playing item status. * * @param oberver DOCUMENT_ME */ public static void updateStatus(Observer oberver) { // check if a track or a webradio has already been launched if (QueueModel.isPlayingRadio()) { oberver.update(new JajukEvent(JajukEvents.WEBRADIO_LAUNCHED, ObservationManager .getDetailsLastOccurence(JajukEvents.WEBRADIO_LAUNCHED))); } else if (!QueueModel.isStopped()) { oberver.update(new JajukEvent(JajukEvents.FILE_LAUNCHED, ObservationManager .getDetailsLastOccurence(JajukEvents.FILE_LAUNCHED))); oberver.update(new JajukEvent(JajukEvents.PLAYER_PLAY, ObservationManager .getDetailsLastOccurence(JajukEvents.PLAYER_PLAY))); } else { // if queue is not empty we can activate the control buttons if (QueueModel.getQueueSize() > 0) { oberver.update(new JajukEvent(JajukEvents.PLAYER_STOP)); } else { oberver.update(new JajukEvent(JajukEvents.ZERO)); } } } /** * Return sum of decimal digits in n. Code from * http://www.cs.princeton.edu/introcs/51data/CDDB.java.html * * @param n DOCUMENT_ME * * @return the long */ private static long sumOfDigits(long n) { long i = n; long sum = 0; while (i > 0) { sum = sum + (i % 10); i = i / 10; } return sum; } /** * Computes a disk id. Code based on * http://www.cs.princeton.edu/introcs/51data/CDDB.java.html * * @param durations List of durations * * @return the disk ID as a long */ public static long computeDiscID(List durations) { int totalLength = 0; int nbTracks = durations.size(); for (Long l : durations) { totalLength += l; } int checkSum = 0; for (Long duration : durations) { checkSum += sumOfDigits(duration); } long xx = checkSum % 255; long yyyy = totalLength; long zz = nbTracks; // XXYYYYZZ return ((xx << 24) | (yyyy << 8) | zz); } /** * Shuffle a list of items and ensure that final list first element * is different from the initial list's one *

    The list should not be void

    . * * @param list DOCUMENT_ME * * @return shuffled list */ public static void forcedShuffle(List list) { StackItem first = list.get(0); StackItem newFirst = first; while (newFirst.equals(first)) { Collections.shuffle(list, UtilSystem.getRandom()); newFirst = list.get(0); } } /** * Return a flat list of files for given input list without duplicates nor sorting. * * @param in DOCUMENT_ME * * @return a flat list of files for given input list * * @throws JajukException if a playlist cannot be read */ public static List getFilesForItems(List in) throws JajukException { // We use a set to drop duplicates, for ie if user select both a directory and its files Set out = new LinkedHashSet(in.size()); for (Item item : in) { if (item instanceof File) { out.add((File) item); } else if (item instanceof Directory) { Directory dir = (Directory) item; out.addAll(dir.getFilesRecursively()); } else if (item instanceof Directory) { Directory dir = (Directory) item; out.addAll(dir.getFilesRecursively()); } else if (item instanceof Device) { Device device = (Device) item; out.addAll(device.getFilesRecursively()); } else if (item instanceof Playlist) { Playlist playlist = (Playlist) item; out.addAll(playlist.getFiles()); } else if (item instanceof LogicalItem) { LogicalItem logical = (LogicalItem) item; List tracks = TrackManager.getInstance().getAssociatedTracks(logical, false); for (Track track : tracks) { // Only keep available tracks, show a warning if no available file File file = track.getBestFile(true); if (file == null) { InformationJPanel.getInstance().setMessage( Messages.getString("Error.010") + " : " + track.getName(), InformationJPanel.MessageType.WARNING); } else { out.add(track.getBestFile(true)); } } } } return new ArrayList(out); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/util/ReadOnlyIterator.java0000644000175000017500000000316311720500104025055 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.util; import java.util.Iterator; /** * A convenient class that prevents remove() method from an iterator
    * Generic class. * * @param DOCUMENT_ME */ public class ReadOnlyIterator { /** Managed iterator *. */ Iterator iterator; /** * Instantiates a new read only iterator. * * @param it The source iterator that should be wrapped. */ public ReadOnlyIterator(Iterator it) { this.iterator = it; } /** * Return the next value from the iterator. * * @return The next element from the collection. */ public V next() { return iterator.next(); } /** * Checks if there is another element in the collection. * * @return true if there is another element, false otherwise. */ public boolean hasNext() { return iterator.hasNext(); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/util/Filter.java0000644000175000017500000001133011720500104023046 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.util; import java.util.Collection; import java.util.Iterator; import java.util.regex.Pattern; import java.util.regex.PatternSyntaxException; import org.apache.commons.lang.StringUtils; import org.jajuk.base.Item; import org.jajuk.base.PropertyMetaInformation; import org.jajuk.util.log.Log; /** * Filter on meta information. */ public class Filter { /** Key. */ String key; /** Value*. */ String sValue; /** Human*. */ boolean bHuman = false; /** Exact*. */ boolean bExact = false; /** * Filter constructor. * * @param key key (property name). null if the filter is on any property * @param sValue value * @param bHuman is the filter apply value itself or its human representation if * different ? * @param bExact is the filter should match exactly the value ? */ public Filter(String key, String sValue, boolean bHuman, boolean bExact) { this.key = key; this.sValue = sValue; this.bHuman = bHuman; this.bExact = bExact; } /** * Checks if is exact. * * @return true, if is exact */ public boolean isExact() { return bExact; } /** * Checks if is human. * * @return true, if is human */ public boolean isHuman() { return bHuman; } /** * Gets the property. * * @return the property */ public String getProperty() { return key; } /** * Gets the value. * * @return the value */ public String getValue() { return sValue; } /** * Filter a list. *

    * Work on the input collection (for performance reasons and to save memory we * don't create a new list) *

    *

    * This filter is not thread safe. *

    * * @param list The input list to filter. Filtering is done in-place on this list. * @param filter The filter to apply on the list. */ public static void filterItems(Collection list, Filter filter) { if (filter == null || filter.getValue() == null) { return; } // Check if property is not the "fake" any property boolean bAny = (filter.getProperty() == null || "any".equals(filter.getProperty())); String comparator = null; String checked = filter.getValue(); // If checked is void, return the list as it if (StringUtils.isBlank(checked)) { return; } // If pattern is wrong, return a void list try { Pattern.compile(checked); } catch (PatternSyntaxException e) { Log.debug("Wrong regexp pattern: " + checked); list.clear(); return; } Iterator it = list.iterator(); while (it.hasNext()) { Item item = it.next(); // If none property set, the search if global "any" if (bAny) { comparator = item.getAny(); } else { if (filter.isHuman()) { comparator = item.getHumanValue(filter.getProperty()); } else { comparator = item.getStringValue(filter.getProperty()); } } // perform the test boolean bMatch = false; if (filter.isExact()) { // Check every item property (no not use getAny() string will not match // as it is a concatenation of all properties) for (String propertyName : item.getProperties().keySet()) { // Ignore technical/invisible property (id for instance) PropertyMetaInformation meta = item.getMeta(propertyName); if (!meta.isVisible()) { continue; } String value = item.getHumanValue(propertyName); // Escape the string so regexp ignore special characters value = UtilString.escapeString(value); if (value.matches(checked)) { bMatch = true; break; } } } else { // Do not use Regexp matches() method, too costly bMatch = UtilString.matchesIgnoreCaseAndOrder(checked, comparator); } if (!bMatch) { it.remove(); } } return; } } jajuk-1.9.6.orig/src/main/java/org/jajuk/util/error/0000755000175000017500000000000011720500104022111 5ustar drazzibdrazzibjajuk-1.9.6.orig/src/main/java/org/jajuk/util/error/NoneAccessibleFileException.java0000644000175000017500000000261111720500104030310 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.util.error; /** * DOCUMENT_ME. */ public class NoneAccessibleFileException extends JajukException { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** * constructor. * * @param code Code of the current error. */ public NoneAccessibleFileException(int code) { super(code); } /** * JajukException constructor. * * @param code Code of the current error. * @param pCause Original exception of the error. */ public NoneAccessibleFileException(int code, Throwable pCause) { super(code, pCause); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/util/error/CannotRenameException.java0000644000175000017500000000255011720500104027207 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.util.error; /** * DOCUMENT_ME. */ public class CannotRenameException extends JajukException { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** * constructor. * * @param code DOCUMENT_ME */ public CannotRenameException(int code) { super(code); } /** * JajukException constructor. * * @param code Code of the current error. * @param pCause Original exception of the error. */ public CannotRenameException(int code, Throwable pCause) { super(code, pCause); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/util/error/LyricsPersistenceException.java0000644000175000017500000000223211720500104030304 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.util.error; /** * Error in lyrics persistence. */ public class LyricsPersistenceException extends Exception { /** Default serial UID. */ private static final long serialVersionUID = 1L; /** * The Constructor. * * @param pMessage DOCUMENT_ME */ public LyricsPersistenceException(String pMessage) { super(pMessage); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/util/error/package.html0000644000175000017500000000007511720500104024374 0ustar drazzibdrazzib

    Error managment classes

    jajuk-1.9.6.orig/src/main/java/org/jajuk/util/error/JajukRuntimeException.java0000644000175000017500000000350511720500104027246 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.util.error; /** * JajukException runtime exception : to be thown in case of internal bug only. */ public class JajukRuntimeException extends RuntimeException { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** * Instantiates a new jajuk runtime exception. */ public JajukRuntimeException() { super(); // TODO Auto-generated constructor stub } /** * The Constructor. * * @param message DOCUMENT_ME * @param cause DOCUMENT_ME */ public JajukRuntimeException(String message, Throwable cause) { super(message, cause); // TODO Auto-generated constructor stub } /** * The Constructor. * * @param message DOCUMENT_ME */ public JajukRuntimeException(String message) { super(message); // TODO Auto-generated constructor stub } /** * The Constructor. * * @param cause DOCUMENT_ME */ public JajukRuntimeException(Throwable cause) { super(cause); // TODO Auto-generated constructor stub } } jajuk-1.9.6.orig/src/main/java/org/jajuk/util/error/JajukException.java0000644000175000017500000000446411720500104025707 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.util.error; import org.jajuk.util.Messages; /** * JajukException. */ public class JajukException extends Exception { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** Error code. */ private final int code; /** * JajukException constructor. * * @param code DOCUMENT_ME */ public JajukException(int code) { this(code, null, null); } /** * JajukException constructor. * * @param pCause Original exception of the error. * @param code DOCUMENT_ME */ public JajukException(int code, Throwable pCause) { this(code, null, pCause); } /** * Gets the code. * * @return the code */ public int getCode() { return this.code; } /** * JajukException constructor. * * @param code Code of the current error. * @param pMessage Message. * @param pCause Original exception of the error. */ public JajukException(int code, String pMessage, Throwable pCause) { super((pMessage != null && pMessage.length() > 0) ? Messages.getErrorMessage(code) + " : " + pMessage : Messages.getErrorMessage(code), pCause); this.code = code; } /** * JajukException constructor. * * @param code Code of the current error. * @param pMessage Message. */ public JajukException(int code, String pMessage) { super((pMessage != null && pMessage.length() > 0) ? Messages.getErrorMessage(code) + " : " + pMessage : Messages.getErrorMessage(code)); this.code = code; } } jajuk-1.9.6.orig/src/main/java/org/jajuk/util/error/TimeOutException.java0000644000175000017500000000256311720500104026227 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.util.error; /** * DOCUMENT_ME. */ public class TimeOutException extends JajukException { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** * Instantiates a new time out exception. * * @param code DOCUMENT_ME */ public TimeOutException(int code) { super(code); } /** * JajukException constructor. * * @param code Code of the current error. * @param pCause Original exception of the error. */ public TimeOutException(int code, Throwable pCause) { super(code, pCause); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/util/Const.java0000644000175000017500000011456411720500104022724 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.util; import java.net.URL; /** * Contains all technical/ non-translatable strings Do not set static final to * these constants, it is implied by the fact you are in an interface. */ public interface Const { // Misc /** Maximum size for covers in KB. */ int MAX_COVER_SIZE = 2048; /** Maximum number of remote covers. */ int MAX_REMOTE_COVERS = 10; /** Special length for player meaning end of file. */ long TO_THE_END = -1; /** Time we wait after an error in ms. */ int WAIT_AFTER_ERROR = 2000; /** We need a fix size to have the same angle effect for every cover*/ int MIRROW_COVER_SIZE = 600; /** Default playlist name. */ String DEFAULT_PLAYLIST_FILE = "playlist"; /** Max number of connection time out before stopping to look for covers. */ int STOP_TO_SEARCH = 5; /** Number of lines in the feedback mail. */ int FEEDBACK_LINES = 200; /** Max history size. */ int MAX_HISTORY_SIZE = 1000; /** Autocommit delay in ms. */ int AUTO_COMMIT_DELAY = 3600000; /** Autorefresh thread delay in ms. */ int AUTO_REFRESH_DELAY = 30000; /** Default refresh interval in mins for unknown types devices *. */ String DEFAULT_REFRESH_INTERVAL = "5"; /** Fading status code. */ int FADING_STATUS = 9999; /** Need full gc memory %. */ float NEED_FULL_GC_LEVEL = 0.90f; /** Play time to get rate +1 in secs. */ int INC_RATE_TIME = 20; /** Max number of concurrent executions by observation manager for a given event. */ int MAX_EVENT_EXECUTIONS = 15; /** Min number of tracks in a DJ selection without track unicity. */ int MIN_TRACKS_NUMBER_WITHOUT_UNICITY = 100; /** Default number of tracks in a transition. */ int DEFAULT_TRANSITION_TRACK_NUMBER = 2; /** Rate Stars columns size in pixels. */ int RATE_COLUMN_SIZE = 75; /** Play icon columns size in pixels. */ int PLAY_COLUMN_SIZE = 20; /** Proportion of best tracks. */ float BESTOF_PROPORTION = 0.05f; /** Number of milliseconds in a second. */ int MILLISECONDS_IN_A_SECOND = 1000; /** Number of seconds in a minute. */ int SECONDS_IN_A_MINUTE = 60; /** Number of minutes in an hour. */ int MINUTES_IN_AN_HOUR = 60; /** Number of pixels around window at initial startup. */ int FRAME_INITIAL_BORDER = 60; /** Maximum images cache size in MB */ int MAX_IMAGES_CACHE_SIZE = 100; /** Default webradio. */ String DEFAULT_WEBRADIO = "Bluemars [Ambient/Space-Music]"; /** Default hostame used in case of problem. */ String DEFAULT_HOSTNAME = "localhost"; /** Number of hours in a day. */ int HOURS_IN_A_DAY = 24; /** Number of album bestof items. */ int NB_BESTOF_ALBUMS = 25; /* Number of tracks for global actions (global shuffle, bestof...) */ /** DOCUMENT_ME. */ int NB_TRACKS_ON_ACTION = 200; /** Cache max age (in ms). */ long CACHE_MAX_AGE = 10 * 24 * 3600 * 1000; // 10 days /** Default auto-refresh delay for directory-type devices (mins). */ double DEFAULT_REFRESH_INTERVAL_DIRECTORY = 0.5d; /** Default auto-refresh delay for CD-type devices (mins). */ double DEFAULT_REFRESH_INTERVAL_CD = 0.0d; /** Default auto-refresh delay for directory-type devices (mins). */ double DEFAULT_REFRESH_INTERVAL_NETWORK_DRIVE = 0.0d; /** Default auto-refresh delay for directory-type devices (mins). */ double DEFAULT_REFRESH_INTERVAL_EXTERNAL_DRIVE = 3.0d; /** Default auto-refresh delay for directory-type devices (mins). */ double DEFAULT_REFRESH_INTERVAL_PLAYER = 3.0d; /** The time we wait for mplayer to start up in ms. It can take some time on slow or heavily loaded machines... */ int MPLAYER_START_TIMEOUT = 15000; /** Number of milliseconds in a day. */ int MILLISECONDS_IN_A_DAY = MILLISECONDS_IN_A_SECOND * SECONDS_IN_A_MINUTE * MINUTES_IN_AN_HOUR * HOURS_IN_A_DAY; /** Last elapsed time display mode format + 1 *. */ int FORMAT_TIME_ELAPSED_MAX = 4; /** Mplayer windows exe size in bytes. */ long MPLAYER_WINDOWS_EXE_SIZE = 15265280l; /** Mplayer windows exe size in bytes. */ long MPLAYER_OSX_EXE_SIZE = 21490476l; /** Update URL = PAD file URL. */ String CHECK_FOR_UPDATE_URL = "http://gitorious.org/jajuk/jajuk/blobs/raw/master/jajuk/src/packaging/pad/jajuk_pad.xml"; // Jajuk version /** DOCUMENT_ME. */ String JAJUK_VERSION = "VERSION_REPLACED_BY_ANT"; /** DOCUMENT_ME. */ String JAJUK_CODENAME = "Killer Queen"; /** Extention to the .jajuk_test directory in test mode only */ String TEST_VERSION = "1.9"; /** DOCUMENT_ME. */ String JAJUK_VERSION_DATE = "Build: DATE_REPLACED_BY_ANT"; /** DOCUMENT_ME. */ String JAJUK_COPYRIGHT = "Copyright 2003-2011 The Jajuk Team"; /** DOCUMENT_ME. */ String TYPE_VIDEO = "Type.video"; // -- Files and paths -- /** DOCUMENT_ME. */ String FILE_COLLECTION = "collection.xml"; // File written by the exit hook /** DOCUMENT_ME. */ String FILE_COLLECTION_EXIT = "collection_exit.xml"; // Void file created after exit collection file /** DOCUMENT_ME. */ String FILE_COLLECTION_EXIT_PROOF = "exit_proof"; /** DOCUMENT_ME. */ String FILE_REPORTING_CACHE_FILE = "cache/report"; /** Name of the preferences property file. */ String FILE_CONFIGURATION = "conf.properties"; /** Name of the temporary preferences property file. */ String FILE_CONFIGURATION_TEMP = "temp_conf.properties"; /** DOCUMENT_ME. */ String FILE_HISTORY = "history.xml"; /** Directory containing all sessions using this workspace. */ String FILE_SESSIONS = "sessions"; /** DOCUMENT_ME. */ String FILE_DEFAULT_COVER = "jajuk.file.default.cover"; /** DOCUMENT_ME. */ String FILE_ABSOLUTE_DEFAULT_COVER = "jajuk-default-cover."; // langpack name : jajuk_.properties /** DOCUMENT_ME. */ String FILE_LANGPACK_PART1 = "jajuk"; /** DOCUMENT_ME. */ String FILE_LANGPACK_PART2 = ".properties"; // logs /** DOCUMENT_ME. */ String FILE_LOGS = "jajuk.log"; /** DOCUMENT_ME. */ URL FILE_LOG4J_CONF = UtilSystem.getResource("org/jajuk/util/log/jajuk-log4j-conf.xml"); /** Cache directory name. */ String FILE_CACHE = "cache"; /** Bat Converter to DOS 8.3 format */ String FILE_FILENAME_CONVERTER = "converter.bat"; /** DOCUMENT_ME. */ String LASTFM_CACHE = "lastfm"; /** Last.fm album cover cache dir. */ String LAST_FM_ALBUM_COVER_CACHE_DIR = "album_covers"; /** Last.fm album info cache dir. */ String LAST_FM_ALBUM_INFO_CACHE_DIR = "album_info"; /** Last.fm artist info cache dir. */ String LAST_FM_ARTIST_INFO_CACHE_DIR = "artist_info"; /** Last.fm artist image cache dir. */ String LAST_FM_ARTIST_IMAGE_CACHE_DIR = "artist_images"; /** Last.fm artist info cache dir. */ String LAST_FM_ARTIST_SIMILAR_CACHE_DIR = "artist_similar"; /** Last.fm artist thumb cache dir. */ String LAST_FM_ARTIST_THUMB_CACHE_DIR = "artist_thumbs"; /** Last.fm artist info cache dir. */ String LAST_FM_ALBUM_LIST_CACHE_DIR = "album_list_info"; /** Last.fm artist wiki cache dir. */ String LAST_FM_ARTIST_WIKI_CACHE_DIR = "artist_wiki"; /** Last.fm artist submission cache dir. */ String LAST_FM_SUBMISSION_CACHE_DIR = "submission"; /** DOCUMENT_ME. */ String FILE_INTERNAL_CACHE = "internal"; /** DOCUMENT_ME. */ String FILE_THUMBS = "thumbs"; /** DOCUMENT_ME. */ String FILE_THUMB_NO_COVER = "nocover.png"; /** DOCUMENT_ME. */ String FILE_THUMB_NONE = "none.png"; /** DOCUMENT_ME. */ String FILE_DEFAULT_BESTOF_PLAYLIST = "bestof"; /** DOCUMENT_ME. */ String FILE_DEFAULT_NOVELTIES_PLAYLIST = "novelties"; /** DOCUMENT_ME. */ String FILE_DEFAULT_BOOKMARKS_PLAYLIST = "bookmarks"; /** DOCUMENT_ME. */ String FILE_DEFAULT_QUEUE_PLAYLIST = "jajuk-playlist_"; /** DOCUMENT_ME. */ String FILE_DJ_DIR = "djs"; /** DOCUMENT_ME. */ String FILE_WEB_RADIOS_REPOS = "webradios.xml"; /** DOCUMENT_ME. */ String FILE_FIFO = "fifo.lst"; /** Bootstrap file name. */ String FILE_BOOTSTRAP = ".jajuk_bootstrap.xml"; /** Old (pre-1.9) bootstrap file name */ String FILE_BOOTSTRAP_OLD = ".jajuk_bootstrap"; /** DOCUMENT_ME. */ String FILE_MPLAYER_WINDOWS_EXE = "mplayer.exe"; /** DOCUMENT_ME. */ String FILE_MPLAYER_OSX_EXE = "mplayer"; /** DOCUMENT_ME. */ String FILE_DEFAULT_PERSPECTIVES_PATH = "perspectives"; /** DOCUMENT_ME. */ String FILE_JAJUK_DOWNLOADED_FILES_SUFFIX = "_jajuk"; /** DOCUMENT_ME. */ String FILE_REPORTING_CSS_ALL_FILENAME = "report-all.css"; /** DOCUMENT_ME. */ URL FILE_REPORTING_CSS_ALL_PATH = UtilSystem.getResource("xslt/" + FILE_REPORTING_CSS_ALL_FILENAME); /** DOCUMENT_ME. */ String FILE_REPORTING_CSS_PRINT_FILENAME = "report-print.css"; /** DOCUMENT_ME. */ URL FILE_REPORTING_CSS_PRINT_PATH = UtilSystem.getResource("xslt/" + FILE_REPORTING_CSS_PRINT_FILENAME); /** Mplayer Windows exe provided by jajuk URL . */ String URL_MPLAYER_WINDOWS = "http://repository.jajuk.info/mplayer/20090114/mplayer.exe"; /** Mplayer OSX exe provided by jajuk URL . */ String URL_MPLAYER_OSX = "http://repository.jajuk.info/mplayer/osx/1.0rc2/mplayer"; /** DOCUMENT_ME. */ String URL_DEFAULT_WEBRADIOS = "http://svn2.assembla.com/svn/common-jukebox/common-jukebox/src/main/resources/preset_radios.xml"; // sequence /** DOCUMENT_ME. */ String AMBIENCE_PREFIX = "jajuk.ambience."; // Proxy type: http /** DOCUMENT_ME. */ String PROXY_TYPE_HTTP = "http"; // Proxy type: socks /** DOCUMENT_ME. */ String PROXY_TYPE_SOCKS = "socks"; // Unknown /** DOCUMENT_ME. */ String UNKNOWN_ARTIST = "unknown_artist"; /** DOCUMENT_ME. */ String UNKNOWN_ALBUM = "unknown_album"; /** DOCUMENT_ME. */ String UNKNOWN_GENRE = "unknown_genre"; /** DOCUMENT_ME. */ String UNKNOWN_YEAR = "unknown_year"; /** DOCUMENT_ME. */ String VARIOUS_ARTIST = "various_artist"; /** DOCUMENT_ME. */ String COVER_NONE = "none"; // images /** DOCUMENT_ME. */ URL IMAGES_SPLASHSCREEN = UtilSystem.getResource("images/included/jajuk-splashscreen.jpg"); /** DOCUMENT_ME. */ URL IMAGE_SEARCH = UtilSystem.getResource("images/included/search.png"); // XSLT Files /** DOCUMENT_ME. */ URL XSLT_ARTIST = UtilSystem.getResource("xslt/artist.xsl"); /** DOCUMENT_ME. */ URL XSLT_ALBUM = UtilSystem.getResource("xslt/album.xsl"); /** DOCUMENT_ME. */ URL XSLT_GENRE = UtilSystem.getResource("xslt/genre.xsl"); /** DOCUMENT_ME. */ URL XSLT_YEAR = UtilSystem.getResource("xslt/genre.xsl"); /** DOCUMENT_ME. */ URL XSLT_DIRECTORY = UtilSystem.getResource("xslt/directory.xsl"); /** DOCUMENT_ME. */ URL XSLT_DEVICE = UtilSystem.getResource("xslt/device.xsl"); /** DOCUMENT_ME. */ URL XSLT_COLLECTION_LOGICAL = UtilSystem.getResource("xslt/logical_collection.xsl"); /** DOCUMENT_ME. */ String COLLECTION_LOGICAL = "logical"; /** DOCUMENT_ME. */ String COLLECTION_PHYSICAL = "physical"; // -- Command line options -- /** Tells jajuk it is inside the IDE. */ String CLI_IDE = "ide"; /** Tells jajuk to use a .jajuk_test repository */ String CLI_TEST = "test"; /** Special forced workspace location CLI option. */ String CLI_WORKSPACE_LOCATION = "workspace"; // players impls /** DOCUMENT_ME. */ String PLAYER_IMPL_JAVALAYER = "org.jajuk.services.players.JavaLayerPlayerImpl"; /** DOCUMENT_ME. */ String PLAYER_IMPL_MPLAYER = "org.jajuk.services.players.MPlayerPlayerImpl"; /** DOCUMENT_ME. */ String PLAYER_IMPL_WEBRADIOS = "org.jajuk.services.players.WebRadioPlayerImpl"; // tag impls /** DOCUMENT_ME. */ String TAG_IMPL_NO_TAGS = "org.jajuk.services.tags.NoTagsTagImpl"; /** DOCUMENT_ME. */ String TAG_IMPL_JAUDIOTAGGER = "org.jajuk.services.tags.JAudioTaggerTagImpl"; // device types // Devices sync mode /** DOCUMENT_ME. */ String DEVICE_SYNCHRO_MODE_BI = "bi"; /** DOCUMENT_ME. */ String DEVICE_SYNCHRO_MODE_UNI = "uni"; // extensions /** DOCUMENT_ME. */ String EXT_MP3 = "mp3"; /** DOCUMENT_ME. */ String EXT_MP2 = "mp2"; /** DOCUMENT_ME. */ String EXT_PLAYLIST = "m3u"; /** DOCUMENT_ME. */ String EXT_OGG = "ogg"; /** DOCUMENT_ME. */ String EXT_WAV = "wav"; /** DOCUMENT_ME. */ String EXT_AU = "au"; /** DOCUMENT_ME. */ String EXT_AIF = "aif"; /** DOCUMENT_ME. */ String EXT_AIFF = "aiff"; /** DOCUMENT_ME. */ String EXT_FLAC = "flac"; /** Extension of the thumbnails. */ String EXT_THUMB = "png"; /** DOCUMENT_ME. */ String EXT_MPC = "mpc"; /** DOCUMENT_ME. */ String EXT_MPPLUS = "mp+"; /** DOCUMENT_ME. */ String EXT_MPP = "mpp"; /** DOCUMENT_ME. */ String EXT_WMA = "wma"; /** DOCUMENT_ME. */ String EXT_APE = "ape"; /** DOCUMENT_ME. */ String EXT_MAC = "mac"; /** DOCUMENT_ME. */ String EXT_M4A = "m4a"; /** DOCUMENT_ME. */ String EXT_REAL_RM = "rm"; /** DOCUMENT_ME. */ String EXT_REAL_RA = "ra"; /** DOCUMENT_ME. */ String EXT_RADIO = "radio"; /** DOCUMENT_ME. */ String EXT_AVI = "avi"; /** DOCUMENT_ME. */ String EXT_MPG = "mpg"; /** DOCUMENT_ME. */ String EXT_MPEG = "mpeg"; /** DOCUMENT_ME. */ String EXT_MKV = "mkv"; /** DOCUMENT_ME. */ String EXT_ASF = "asf"; /** DOCUMENT_ME. */ String EXT_WMV = "wmv"; /** DOCUMENT_ME. */ String EXT_MOV = "mov"; /** DOCUMENT_ME. */ String EXT_OGM = "ogm"; /** DOCUMENT_ME. */ String EXT_MP4 = "mp4"; /** DOCUMENT_ME. */ String EXT_WV = "wv"; /** DOCUMENT_ME. */ String EXT_FLV = "flv"; // details keys /** DOCUMENT_ME. */ String DETAIL_CURRENT_FILE_ID = "current file id"; /** DOCUMENT_ME. */ String DETAIL_CURRENT_FILE = "current file"; /** DOCUMENT_ME. */ String DETAIL_CURRENT_DATE = "current date"; /** DOCUMENT_ME. */ String DETAIL_SPECIAL_MODE_NORMAL = "norm"; /** DOCUMENT_ME. */ String DETAIL_SELECTION = "selection"; /** DOCUMENT_ME. */ String DETAIL_ORIGIN = "origin"; /** Provides details on the perspective that thrown the event. */ String DETAIL_PERSPECTIVE = "perspective"; /** Provides details on the view that thrown the event. */ String DETAIL_VIEW = "view"; /** DOCUMENT_ME. */ String DETAIL_REASON = "reason"; /** DOCUMENT_ME. */ String DETAIL_CONTENT = "content"; /** DOCUMENT_ME. */ String DETAIL_OLD = "old"; /** DOCUMENT_ME. */ String DETAIL_NEW = "new"; // startup mode /** DOCUMENT_ME. */ String STARTUP_MODE_NOTHING = "nothing"; /** DOCUMENT_ME. */ String STARTUP_MODE_SHUFFLE = "shuffle"; /** DOCUMENT_ME. */ String STARTUP_MODE_ITEM = "file"; /** DOCUMENT_ME. */ String STARTUP_MODE_LAST = "last"; /** DOCUMENT_ME. */ String STARTUP_MODE_LAST_KEEP_POS = "last_keep_pos"; /** DOCUMENT_ME. */ String STARTUP_MODE_BESTOF = "bestof"; /** DOCUMENT_ME. */ String STARTUP_MODE_NOVELTIES = "novelties"; // --- Configuration keys --- /** DOCUMENT_ME. */ String CONF_RELEASE = "jajuk.release"; /** DOCUMENT_ME. */ String CONF_PERSPECTIVE_DEFAULT = "jajuk.preference.perspective.default"; /** DOCUMENT_ME. */ String CONF_STATE_REPEAT = "jajuk.state.mode.repeat"; /** DOCUMENT_ME. */ String CONF_STATE_REPEAT_ALL = "jajuk.state.mode.repeat.all"; /** DOCUMENT_ME. */ String CONF_STATE_SHUFFLE = "jajuk.state.mode.shuffle"; /** DOCUMENT_ME. */ String CONF_STATE_KARAOKE = "jajuk.state.karaoke"; /** DOCUMENT_ME. */ String CONF_STATE_CONTINUE = "jajuk.state.mode.continue"; /** DOCUMENT_ME. */ String CONF_STATE_INTRO = "jajuk.state.mode.intro"; /** DOCUMENT_ME. */ String CONF_STARTUP_ITEM = "jajuk.startup.file"; /** DOCUMENT_ME. */ String CONF_STARTUP_MODE = "jajuk.startup.mode"; /** Tell if last jajuk session was closed in stopped mode. */ String CONF_STARTUP_STOPPED = "jajuk.startup.stopped"; /** DOCUMENT_ME. */ String CONF_CONFIRMATIONS_DELETE_FILE = "jajuk.confirmations.delete_file"; /** DOCUMENT_ME. */ String CONF_CONFIRMATIONS_EXIT = "jajuk.confirmations.exit"; /** DOCUMENT_ME. */ String CONF_CONFIRMATIONS_REMOVE_DEVICE = "jajuk.confirmations.remove_device"; /** DOCUMENT_ME. */ String CONF_CONFIRMATIONS_DELETE_COVER = "jajuk.confirmations.delete_cover"; /** DOCUMENT_ME. */ String CONF_CONFIRMATIONS_CLEAR_HISTORY = "jajuk.confirmations.clear_history"; /** DOCUMENT_ME. */ String CONF_CONFIRMATIONS_RESET_RATINGS = "jajuk.confirmations.reset_ratings"; /** DOCUMENT_ME. */ String CONF_CONFIRMATIONS_REFACTOR_FILES = "jajuk.confirmations.refactor_files"; /** DOCUMENT_ME. */ String CONF_OPTIONS_HIDE_UNMOUNTED = "jajuk.options.hide_unmounted"; /** DOCUMENT_ME. */ String CONF_OPTIONS_LOG_LEVEL = "jajuk.options.log_level"; /** DOCUMENT_ME. */ String CONF_OPTIONS_LANGUAGE = "jajuk.options.language"; /** DOCUMENT_ME. */ String CONF_OPTIONS_INTRO_BEGIN = "jajuk.options.intro.begin"; /** DOCUMENT_ME. */ String CONF_OPTIONS_INTRO_LENGTH = "jajuk.options.intro.length"; /** DOCUMENT_ME. */ String CONF_OPTIONS_LNF = "jajuk.options.lnf"; /** DOCUMENT_ME. */ String CONF_OPTIONS_NOVELTIES_AGE = "jajuk.options.novelties"; // Look and Feel /** Substance default theme *. */ String LNF_DEFAULT_THEME = "Nebula"; /** Number of visible planned tracks. */ String CONF_OPTIONS_VISIBLE_PLANNED = "jajuk.options.visible_planned"; /** Default action (play or push) when clicking on an item. */ String CONF_OPTIONS_PUSH_ON_CLICK = "jajuk.options.default_action_click"; /** Default action (play or push) when dropping on an item. */ String CONF_OPTIONS_PUSH_ON_DROP = "jajuk.options.default_action_drop"; /** Table / tree sync option prefix. */ String CONF_SYNC_TABLE_TREE = "jajuk.sync_table_tree"; /** Notificator type. */ String CONF_UI_NOTIFICATOR_TYPE = "jajuk.options.notificator_type"; /** DOCUMENT_ME. */ String CONF_P2P_SHARE = "jajuk.options.p2p.share"; /** DOCUMENT_ME. */ String CONF_P2P_ADD_REMOTE_PROPERTIES = "jajuk.options.p2p.add_remote_properties"; /** DOCUMENT_ME. */ String CONF_P2P_HIDE_LOCAL_PROPERTIES = "jajuk.options.p2p.hide_local_properties"; /** DOCUMENT_ME. */ String CONF_P2P_PASSWORD = "jajuk.options.p2p.password"; /** DOCUMENT_ME. */ String CONF_HISTORY = "jajuk.options.history"; /** DOCUMENT_ME. */ String CONF_TAGS_USE_PARENT_DIR = "jajuk.tags.use_parent_dir"; /** DOCUMENT_ME. */ String CONF_DROP_PLAYED_TRACKS_FROM_QUEUE = "jajuk.drop.played.tracks.from.queue"; /** Contains files id separated by a colon. */ String CONF_BOOKMARKS = "jajuk.bookmarks"; /** Startup display mode: 0= main window + tray, 1: tray only, 2: slimbar + tray 3 : full screen. */ String CONF_STARTUP_DISPLAY = "jajuk.startup_display_mode"; /** DOCUMENT_ME. */ int DISPLAY_MODE_MAIN_WINDOW = 0; /** DOCUMENT_ME. */ int DISPLAY_MODE_TRAY = 1; /** DOCUMENT_ME. */ int DISPLAY_MODE_SLIMBAR_TRAY = 2; /** DOCUMENT_ME. */ int DISPLAY_MODE_FULLSCREEN = 3; /** Catalog view cover mode. */ int CATALOG_VIEW_COVER_MODE_ALL = 0; /** DOCUMENT_ME. */ int CATALOG_VIEW_COVER_MODE_WITH = 1; /** DOCUMENT_ME. */ int CATALOG_VIEW_COVER_MODE_WITHOUT = 2; /** Best of size. */ String CONF_BESTOF_TRACKS_SIZE = "jajuk.bestof_size"; /** Slimbar position. */ String CONF_SLIMBAR_POSITION = "jajuk.slimbar_pos"; /** DOCUMENT_ME. */ String CONF_SLIMBAR_DISPLAY_QUEUE = "jajuk.slimbar_display_queue"; /** Gain (float). */ String CONF_VOLUME = "jajuk.volume"; /** Use regular expressions ?. */ String CONF_REGEXP = "jajuk.regexp"; /** Force mplayer to use short names *. */ String CONF_SHORT_NAMES = "jajuk.short_names"; /** Collection backup size in MB. */ String CONF_BACKUP_SIZE = "jajuk.backup_size"; /** Collection file charset (utf-8 or utf-16). */ String CONF_COLLECTION_CHARSET = "jajuk.collection_charset"; /** DOCUMENT_ME. */ String CONF_STARTUP_LAST_POSITION = "jajuk.startup.last_position"; /** DOCUMENT_ME. */ String CONF_NETWORK_USE_PROXY = "jajuk.network.use_proxy"; /** DOCUMENT_ME. */ String CONF_NETWORK_PROXY_TYPE = "jajuk.network.proxy_type"; /** DOCUMENT_ME. */ String CONF_NETWORK_PROXY_HOSTNAME = "jajuk.network.proxy_hostname"; /** DOCUMENT_ME. */ String CONF_NETWORK_PROXY_PORT = "jajuk.network.proxy_port"; /** DOCUMENT_ME. */ String CONF_NETWORK_PROXY_LOGIN = "jajuk.network.proxy_login"; /** DOCUMENT_ME. */ String CONF_NETWORK_PROXY_PWD = "jajuk.network.proxy_pwd"; /** DOCUMENT_ME. */ String CONF_LASTFM_AUDIOSCROBBLER_ENABLE = "jajuk.network.audioscrobbler"; /** DOCUMENT_ME. */ String CONF_LASTFM_USER = "jajuk.network.ASUser"; /** DOCUMENT_ME. */ String CONF_LASTFM_PASSWORD = "jajuk.network.ASPassword"; /** DOCUMENT_ME. */ String CONF_COVERS_AUTO_COVER = "jajuk.covers.auto_cover"; /** DOCUMENT_ME. */ String CONF_COVERS_MIRROW_COVER = "jajuk.covers.mirrow_cover"; /** DOCUMENT_ME. */ String CONF_COVERS_SHUFFLE = "jajuk.covers.shuffle"; /** DOCUMENT_ME. */ String CONF_COVERS_SAVE_EXPLORER_FRIENDLY = "jajuk.covers.save.explorer.friendly"; /** DOCUMENT_ME. */ String CONF_COVERS_SIZE = "jajuk.covers.size"; /** DOCUMENT_ME. */ String CONF_COVERS_ACCURACY = "jajuk.covers.accuracy"; /** DOCUMENT_ME. */ String CONF_NETWORK_CONNECTION_TO = "jajuk.network.connection_timeout"; /** Last Option selected tab. */ String CONF_OPTIONS_TAB = "jajuk.options.tab"; /** Data buffer size in bytes. */ String CONF_BUFFER_SIZE = "jajuk.buffer_size"; /** Audio buffer size in bytes. */ String CONF_AUDIO_BUFFER_SIZE = "jajuk.audio_buffer_size"; /** Window position and size. */ String CONF_WINDOW_POSITION = "jajuk.window_position"; /** is Window maximized. */ String CONF_WINDOW_MAXIMIZED = "jajuk.window_MAXIMIZED"; /** Window position and size. */ String CONF_PATTERN_FRAME_TITLE = "jajuk.frame.title"; /** Refactoring pattern*. */ String CONF_PATTERN_REFACTOR = "jajuk.refactor_pattern"; /** Animation pattern*. */ String CONF_PATTERN_ANIMATION = "jajuk.animation_pattern"; /** Balloon notifier pattern. */ String CONF_PATTERN_BALLOON_NOTIFIER = "jajuk.pattern.balloon_pattern"; /** Information view pattern. */ String CONF_PATTERN_INFORMATION = "jajuk.pattern.information_pattern"; /** Files table columns. */ String CONF_FILES_TABLE_COLUMNS = "jajuk.ui.physical_table_columns"; /** Files table edition state. */ String CONF_FILES_TABLE_EDITION = "jajuk.ui.physical_table_edition"; /** Tracks table columns. */ String CONF_TRACKS_TABLE_COLUMNS = "jajuk.ui.logical_table_columns"; /** Tracks table edition state. */ String CONF_TRACKS_TABLE_EDITION = "jajuk.ui.logical_table_edition"; /** Albums table edition state. */ String CONF_ALBUMS_TABLE_COLUMNS = "jajuk.ui.albums_table_columns"; /** Albums table edition state. */ String CONF_ALBUMS_TABLE_EDITION = "jajuk.ui.albums_table_edition"; /** Playlist editor columns to display. */ String CONF_PLAYLIST_EDITOR_COLUMNS = "jajuk.ui.playlist_editor_columns"; /** Playlist repository columns to display. */ String CONF_PLAYLIST_REPOSITORY_COLUMNS = "jajuk.ui.playlist_repository_columns"; /** Queue columns to display. */ String CONF_QUEUE_COLUMNS = "jajuk.ui.queue_columns"; /** Catalog items size. */ String CONF_THUMBS_SIZE = "jajuk.ui.cover_catalog.thumbs_size"; /** Catalog items cover filter. */ String CONF_THUMBS_SHOW_COVER = "jajuk.ui.cover_catalog.show_cover"; /** Catalog sorter*. */ String CONF_THUMBS_SORTER = "jajuk.catalog.sorter"; /** Catalog filter*. */ String CONF_THUMBS_FILTER = "jajuk.catalog.filter"; /** Display tips on startup. */ String CONF_SHOW_TIP_ON_STARTUP = "jajuk.tip.show_on_startup"; /** Wikipedia language*. */ String CONF_WIKIPEDIA_LANGUAGE = "jajuk.wikipedia.lang"; /** Cross fade duration in secs. */ String CONF_FADE_DURATION = "jajuk.fade_duration"; /** Logical tree sort order. */ String CONF_LOGICAL_TREE_SORT_ORDER = "jajuk.logical_tree_sort_order"; /** Default dj. */ String CONF_DEFAULT_DJ = "jajuk.default_dj"; /** Default web radio. */ String CONF_DEFAULT_WEB_RADIO = "jajuk.default_web_radio"; /** List of ignored versions during update check. */ String CONF_IGNORED_RELEASES = "jajuk.update.ignored_releases"; /** Check for update property. */ String CONF_CHECK_FOR_UPDATE = "jajuk.update.check_for_updates"; /** Default ambience*. */ String CONF_DEFAULT_AMBIENCE = "jajuk.default_ambience"; /* Wrong player not show again flag */ /** DOCUMENT_ME. */ String CONF_NOT_SHOW_AGAIN_PLAYER = "jajuk.not_show_again.player"; /** Concurrent session not show again flag. */ String CONF_NOT_SHOW_AGAIN_CONCURRENT_SESSION = "jajuk.not_show_again.concurrent_session"; /** Cross fade alert not show again flag *. */ String CONF_NOT_SHOW_AGAIN_CROSS_FADE = "jajuk.not_show_again.fade"; /** Laf change not show again flag *. */ String CONF_NOT_SHOW_AGAIN_LAF_CHANGE = "jajuk.not_show_laf_change"; /** Global random mode: song or album level ? *. */ String CONF_GLOBAL_RANDOM_MODE = "jajuk.global_random.mode"; /** Novelties random mode: song or album level ?*. */ String CONF_NOVELTIES_MODE = "jajuk.global_novelties.mode"; /** Initial frame size/position forced value *. */ String CONF_FRAME_POS_FORCED = "jajuk.frame.forced_position"; // Forced mplayer path /** DOCUMENT_ME. */ String CONF_MPLAYER_PATH_FORCED = "jajuk.mplayer.forced_path"; /** Hotkeys flag *. */ String CONF_OPTIONS_HOTKEYS = "jajuk.options.use_hotkeys"; /** MPLayer additional arguments *. */ String CONF_MPLAYER_ARGS = "jajuk.player.mplayer_args"; /** MPlayer additional environment variables *. */ String CONF_ENV_VARIABLES = "jajuk.player.env_variables"; /** Max Number of thumbs displayed at the same time in catalog view. */ String CONF_CATALOG_PAGE_SIZE = "jajuk.catalog.pages_size"; /** Show Catalog popups. */ String CONF_SHOW_POPUPS = "jajuk.show_popups"; /** Show systray. */ String CONF_SHOW_SYSTRAY = "jajuk.show_systray"; /** Minimize to tray. */ String CONF_MINIMIZE_TO_TRAY = "jajuk.minimize_to_tray"; /** Enable Last.FM information queries */ String CONF_LASTFM_INFO = "jajuk.lastfm_information"; /** Webradio playing at jajuk stop ?. */ String CONF_WEBRADIO_WAS_PLAYING = "jajuk.webradio.was_playing"; /** Font size. */ String CONF_FONTS_SIZE = "jajuk.fonts_size"; /** Increase rate value. */ String CONF_INC_RATING = "jajuk.inc_rating.step"; /** Use file date as discovery date option. */ String CONF_FORCE_FILE_DATE = "jajuk.force_file_date"; /** Perspective chooser icon size: 16x16, 32x32 or 40x40. */ String CONF_PERSPECTIVE_ICONS_SIZE = "jajuk.ui.perspective_icons_size"; /** Show duplicate playlists in playlist view. */ String CONF_SHOW_DUPLICATE_PLAYLISTS = "jajuk.ui.show_duplicate_playlists"; /** Smart mode selected in slimbar. */ String CONF_SLIMBAR_SMART_MODE = "jajuk.ui.slimbar.smart_mode"; /** volnorm option. */ String CONF_USE_VOLNORM = "jajuk.mplayer.volnorm"; /** None internet access switch. */ String CONF_NETWORK_NONE_INTERNET_ACCESS = "jajuk.network.none_internet_access"; /** Remembered directory for parties. */ String CONF_PREPARE_PARTY = "jajuk.prepare_party."; /** Refreshing delay. */ String CONF_REFRESHING_DELAY_MS = "jajuk.refreshing_delay_ms"; /** Shuffle/novelties mode. */ String MODE_ALBUM = "album"; /** DOCUMENT_ME. */ String MODE_TRACK = "track"; /** DOCUMENT_ME. */ String MODE_ALBUM2 = "album2"; // miscelanous /** DOCUMENT_ME. */ String TRUE = "true"; /** DOCUMENT_ME. */ String FALSE = "false"; // Date format /** DOCUMENT_ME. */ String DATE_FILE = "yyyyMMdd"; /** DOCUMENT_ME. */ String ADDITION_DATE_FORMAT = "yyyyMMdd"; // Playlists /** DOCUMENT_ME. */ String PLAYLIST_NOTE = "#Playlist generated by Jajuk " + Const.JAJUK_VERSION; // XML tags /** DOCUMENT_ME. */ String XML_COLLECTION = "collection"; /** DOCUMENT_ME. */ String XML_VERSION = "jajuk_version"; /** DOCUMENT_ME. */ String XML_TYPES = "types"; /** DOCUMENT_ME. */ String XML_TYPE = "type"; /** DOCUMENT_ME. */ String XML_DEVICES = "devices"; /** DOCUMENT_ME. */ String XML_DEVICE = "device"; /** DOCUMENT_ME. */ String XML_GENRES = "styles"; /** DOCUMENT_ME. */ String XML_GENRE = "style"; /** DOCUMENT_ME. */ String XML_ARTISTS = "authors"; /** DOCUMENT_ME. */ String XML_ALBUM_ARTISTS = "album-artists"; /** DOCUMENT_ME. */ String XML_ARTIST = "author"; /** DOCUMENT_ME. */ String XML_ALBUMS = "albums"; /** DOCUMENT_ME. */ String XML_ALBUM = "album"; /** DOCUMENT_ME. */ String XML_ALBUM_ARTIST = "album_artist"; /** DOCUMENT_ME. */ String XML_ALBUM_DISC_ID = "disc_id"; /** DOCUMENT_ME. */ String XML_TRACKS = "tracks"; /** DOCUMENT_ME. */ String XML_TRACK = "track"; /** DOCUMENT_ME. */ String XML_DIRECTORIES = "directories"; /** DOCUMENT_ME. */ String XML_DIRECTORY = "directory"; /** DOCUMENT_ME. */ String XML_FILES = "files"; /** DOCUMENT_ME. */ String XML_FILE = "file"; /** DOCUMENT_ME. */ String XML_PLAYLIST_FILES = "playlist_files"; /** DOCUMENT_ME. */ String XML_PLAYLIST_FILE = "playlist_file"; /** DOCUMENT_ME. */ String XML_PLAYLISTS = "playlists"; /** DOCUMENT_ME. */ String XML_ID = "id"; /** DOCUMENT_ME. */ String XML_YEAR = "year"; /** DOCUMENT_ME. */ String XML_YEARS = "years"; /** DOCUMENT_ME. */ String XML_PLAY = "play"; /** DOCUMENT_ME. */ String XML_FILE_DATE = "date"; /** DOCUMENT_ME. */ String XML_TRACK_NAME = "name"; /** DOCUMENT_ME. */ String XML_TRACK_ALBUM = "album"; /** DOCUMENT_ME. */ String XML_TRACK_GENRE = "style"; /** DOCUMENT_ME. */ String XML_TRACK_ARTIST = "author"; /** DOCUMENT_ME. */ String XML_TRACK_YEAR = "year"; /** DOCUMENT_ME. */ String XML_TRACK_LENGTH = "length"; /** DOCUMENT_ME. */ String XML_TRACK_TYPE = "type"; /** DOCUMENT_ME. */ String XML_TRACK_RATE = "rate"; /** DOCUMENT_ME. */ String XML_TRACK_HITS = "hits"; /** DOCUMENT_ME. */ String XML_TRACK_DISCOVERY_DATE = "added"; /** DOCUMENT_ME. */ String XML_TRACK_ORDER = "order"; /** DOCUMENT_ME. */ String XML_TRACK_DISC_NUMBER = "disc_number"; /** DOCUMENT_ME. */ String XML_TRACK_PREFERENCE = "pf"; /** DOCUMENT_ME. */ String XML_TRACK_TOTAL_PLAYTIME = "tpt"; /** DOCUMENT_ME. */ String XML_TRACK_BANNED = "ban"; /** DOCUMENT_ME. */ String XML_PLAYLIST = "playlist"; /** DOCUMENT_ME. */ String XML_NAME = "name"; /** DOCUMENT_ME. */ String XML_PATH = "path"; /** DOCUMENT_ME. */ String XML_URL = "url"; /** DOCUMENT_ME. */ String XML_QUALITY = "quality"; /** DOCUMENT_ME. */ String XML_SIZE = "size"; /** DOCUMENT_ME. */ String XML_DEVICE_MOUNT_POINT = "mount_point"; /** DOCUMENT_ME. */ String XML_DEVICE_AUTO_REFRESH = "auto_refresh"; /** DOCUMENT_ME. */ String XML_DEVICE_AUTO_MOUNT = "auto_mount"; /** DOCUMENT_ME. */ String XML_DEVICE_SYNCHRO_SOURCE = "synchro_source"; /** DOCUMENT_ME. */ String XML_DEVICE_SYNCHRO_MODE = "synchro_mode"; /** DOCUMENT_ME. */ String XML_EXPANDED = "exp"; // can be 'y' or 'n' /** Cached cover. */ String XML_ALBUM_DISCOVERED_COVER = "cover_cache"; /** Selected cover. */ String XML_ALBUM_SELECTED_COVER = "cover"; /** DOCUMENT_ME. */ String XML_DIRECTORY_PARENT = "parent"; /** DOCUMENT_ME. */ String XML_DIRECTORY_SYNCHRONIZED = "sync"; /** DOCUMENT_ME. */ String XML_TYPE_EXTENSION = "extension"; /** DOCUMENT_ME. */ String XML_TYPE_PLAYER_IMPL = "player_impl"; /** DOCUMENT_ME. */ String XML_TYPE_TAG_IMPL = "tag_impl"; /** DOCUMENT_ME. */ String XML_TYPE_IS_MUSIC = "music"; /** DOCUMENT_ME. */ String XML_TYPE_SEEK_SUPPORTED = "seek"; // icon used in the physical tree /** DOCUMENT_ME. */ String XML_TYPE_ICON = "icon"; /** comment tag. */ String XML_TRACK_COMMENT = "comment"; /** "any" criteria. */ String XML_ANY = "any"; // constructor property flag /** DOCUMENT_ME. */ String XML_CONSTRUCTOR = "constructor"; // property should be displayed ? /** DOCUMENT_ME. */ String XML_VISIBLE = "visible"; // property editable ? /** DOCUMENT_ME. */ String XML_EDITABLE = "editable"; // Property unique ? /** DOCUMENT_ME. */ String XML_UNIQUE = "unique"; // custom property flag /** DOCUMENT_ME. */ String XML_CUSTOM = "custom"; // Property /** DOCUMENT_ME. */ String XML_PROPERTY = "property"; // default value /** DOCUMENT_ME. */ String XML_DEFAULT_VALUE = "default_value"; // general dj tag /** DOCUMENT_ME. */ String XML_DJ_DJ = "dj"; // general parameters /** DOCUMENT_ME. */ String XML_DJ_GENERAL = "general_parameters"; /** DOCUMENT_ME. */ String XML_DJ_RATING_LEVEL = "rating_level"; /** DOCUMENT_ME. */ String XML_DJ_UNICITY = "unicity"; /** DOCUMENT_ME. */ String XML_DJ_FADE_DURATION = "fade_duration"; /** DOCUMENT_ME. */ String XML_DJ_MAX_TRACKS = "max_tracks"; /** DOCUMENT_ME. */ String XML_DJ_PROPORTIONS = "proportions"; /** DOCUMENT_ME. */ String XML_DJ_PROPORTION = "proportion"; /** DOCUMENT_ME. */ String XML_DJ_AMBIENCE = "ambience"; /** DOCUMENT_ME. */ String XML_DJ_GENRES = "styles"; /** DOCUMENT_ME. */ String XML_DJ_VALUE = "values"; /** DOCUMENT_ME. */ String XML_DJ_PROPORTION_CLASS = "org.jajuk.services.dj.ProportionDigitalDJ"; /** DOCUMENT_ME. */ String XML_DJ_TRANSITION_CLASS = "org.jajuk.services.dj.TransitionDigitalDJ"; /** DOCUMENT_ME. */ String XML_DJ_AMBIENCE_CLASS = "org.jajuk.services.dj.AmbienceDigitalDJ"; /** DOCUMENT_ME. */ String XML_DJ_EXTENSION = "dj"; /** DOCUMENT_ME. */ String XML_DJ_TRANSITION = "transition"; /** DOCUMENT_ME. */ String XML_DJ_TRANSITIONS = "transitions"; /** DOCUMENT_ME. */ String XML_DJ_FROM = "from"; /** DOCUMENT_ME. */ String XML_DJ_TO = "to"; /** DOCUMENT_ME. */ String XML_DJ_NUMBER = "number"; /** DOCUMENT_ME. */ String XML_STREAMS = "streams"; /** DOCUMENT_ME. */ String XML_STREAM = "stream"; /* * Reserved XML tags for property names (note that a user can choose a property name equals to * meta information attributes names without pbm) */ /** DOCUMENT_ME. */ String[] XML_RESERVED_ATTRIBUTE_NAMES = { XML_NAME, XML_ID, XML_TYPE_EXTENSION, XML_TYPE_PLAYER_IMPL, XML_TYPE_TAG_IMPL, XML_TYPE_SEEK_SUPPORTED, XML_TYPE_ICON, XML_TYPE_IS_MUSIC, XML_TYPE, XML_URL, XML_DEVICE_AUTO_MOUNT, XML_DEVICE_AUTO_REFRESH, XML_EXPANDED, XML_DEVICE_MOUNT_POINT, XML_ALBUM, XML_ARTIST, XML_GENRE, XML_TRACK_LENGTH, XML_YEAR, XML_TRACK_RATE, XML_FILES, XML_TRACK_HITS, XML_TRACK_DISCOVERY_DATE, XML_DIRECTORY_PARENT, XML_DEVICE, XML_DIRECTORY, XML_TRACK, XML_SIZE, XML_QUALITY, XML_PLAYLIST_FILES, XML_TRACK_COMMENT, XML_ANY, XML_TRACK_ORDER, XML_DEVICE_SYNCHRO_MODE, XML_DEVICE_SYNCHRO_SOURCE, XML_FILE_DATE, XML_TRACK_TOTAL_PLAYTIME, XML_TRACK_PREFERENCE, XML_TRACK_BANNED, XML_TRACK_DISC_NUMBER, XML_ALBUM_ARTIST, XML_ALBUM_DISC_ID }; /** DOCUMENT_ME. */ String PROPERTY_SEPARATOR = "Property_"; // Formats /** DOCUMENT_ME. */ String FORMAT_STRING = "Property_Format_String"; /** DOCUMENT_ME. */ String FORMAT_NUMBER = "Property_Format_Number"; /** DOCUMENT_ME. */ String FORMAT_BOOLEAN = "Property_Format_Boolean"; /** DOCUMENT_ME. */ String FORMAT_FLOAT = "Property_Format_Float"; /** DOCUMENT_ME. */ String FORMAT_DATE = "Property_Format_Date"; // Thumbs /** DOCUMENT_ME. */ String THUMBNAIL_SIZE_50X50 = "50x50"; /** DOCUMENT_ME. */ String THUMBNAIL_SIZE_100X100 = "100x100"; /** DOCUMENT_ME. */ String THUMBNAIL_SIZE_150X150 = "150x150"; /** DOCUMENT_ME. */ String THUMBNAIL_SIZE_200X200 = "200x200"; /** DOCUMENT_ME. */ String THUMBNAIL_SIZE_250X250 = "250x250"; /** DOCUMENT_ME. */ String THUMBNAIL_SIZE_300X300 = "300x300"; // Patterns /** DOCUMENT_ME. */ String PATTERN_ARTIST = "%artist"; /** DOCUMENT_ME. */ String PATTERN_ALBUM_ARTIST = "%album_artist"; /** DOCUMENT_ME. */ String PATTERN_DISC = "%disc"; /** DOCUMENT_ME. */ String PATTERN_ALBUM = "%album"; /** DOCUMENT_ME. */ String PATTERN_GENRE = "%genre"; /** DOCUMENT_ME. */ String PATTERN_YEAR = "%year"; /** DOCUMENT_ME. */ String PATTERN_TRACKNAME = "%title"; /** DOCUMENT_ME. */ String PATTERN_TRACKORDER = "%n"; /** DOCUMENT_ME. */ String PATTERN_DEFAULT_REORG = PATTERN_ALBUM_ARTIST + "/" + PATTERN_YEAR + " - " + PATTERN_ALBUM + "/" + PATTERN_TRACKORDER + " - " + PATTERN_ARTIST + " - " + PATTERN_TRACKNAME; /** DOCUMENT_ME. */ String PATTERN_DEFAULT_ANIMATION = PATTERN_TRACKNAME + " (" + PATTERN_ARTIST + ")"; // Strings /** DOCUMENT_ME. */ String FRAME_MAXIMIZED = "max"; // Alarm Clock /** DOCUMENT_ME. */ String CONF_ALARM_TIME_HOUR = "jajuk.alarm.hour"; /** DOCUMENT_ME. */ String CONF_ALARM_TIME_MINUTES = "jajuk.alarm.minutes"; /** DOCUMENT_ME. */ String CONF_ALARM_TIME_SECONDS = "jajuk.alarm.seconds"; /** DOCUMENT_ME. */ String CONF_ALARM_FILE = "jajuk.alarm.file"; /** DOCUMENT_ME. */ String CONF_ALARM_MODE = "jajuk.alarm.mode"; /** DOCUMENT_ME. */ String CONF_FORMAT_TIME_ELAPSED = "jajuk.format_elapsed_time"; /** DOCUMENT_ME. */ String CONF_ALARM_ACTION = "jajuk.alarm.action"; /** DOCUMENT_ME. */ String CONF_ALARM_ENABLED = "jajuk.alarm.enabled"; /** DOCUMENT_ME. */ String CONF_AUTO_SCROLL = "jajuk.auto_scroll"; /** DOCUMENT_ME. */ String CONF_EXPLORER_PATH = "jajuk.explorer_path"; // Alarm actions /** DOCUMENT_ME. */ String ALARM_START_ACTION = "Start Playing"; /** DOCUMENT_ME. */ String ALARM_STOP_ACTION = "Stop Playing"; // Preferences /** DOCUMENT_ME. */ long PREFERENCE_ADORE = 3; /** DOCUMENT_ME. */ long PREFERENCE_LOVE = 2; /** DOCUMENT_ME. */ long PREFERENCE_LIKE = 1; /** DOCUMENT_ME. */ long PREFERENCE_UNSET = 0; /** DOCUMENT_ME. */ long PREFERENCE_AVERAGE = -1; /** DOCUMENT_ME. */ long PREFERENCE_POOR = -2; /** DOCUMENT_ME. */ long PREFERENCE_HATE = -3; /** DOCUMENT_ME. */ String B_P_HTML = "

    "; /** DOCUMENT_ME. */ String P_B = "

    "; /** DOCUMENT_ME. */ String HTML = ""; /** File name where the tag cover is stored in. */ String TAG_COVER_FILE = "tag_cover.png"; } jajuk-1.9.6.orig/src/main/java/org/jajuk/util/MD5Processor.java0000644000175000017500000000412511720500104024112 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.util; import java.io.UnsupportedEncodingException; import java.math.BigInteger; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import org.jajuk.util.log.Log; /** * Convenient class to compute MD5 hashcodes and return them using predefined * base. */ public final class MD5Processor { /** DOCUMENT_ME. */ private static MessageDigest msgDigest; static { try { msgDigest = MessageDigest.getInstance("MD5"); } catch (NoSuchAlgorithmException e) { Log.error(e); } } /** * private constructor to avoid instantiating utility class. */ private MD5Processor() { } /** * MD5 hashcoding, return a hashcode. * * @param sIn input String * * @return hashed output */ public static final String hash(String sIn) { try { msgDigest.update(sIn.getBytes("UTF-8")); } catch (UnsupportedEncodingException e) { // This cannot normaly happen Log.error(e); return null; } byte[] digest = msgDigest.digest(); // Important : we internalize the result of this computation // because all equals between items is done with '==' operator // against strings and new discovered items call this method return new BigInteger(digest).abs().toString(36).intern(); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/util/UpgradeManager.java0000644000175000017500000005516611720500104024522 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.util; import java.io.File; import java.io.FileFilter; import java.io.FileInputStream; import java.io.IOException; import java.net.URL; import java.util.List; import java.util.Properties; import java.util.StringTokenizer; import javax.swing.JOptionPane; import org.apache.commons.io.FileUtils; import org.jajuk.base.Album; import org.jajuk.base.AlbumManager; import org.jajuk.base.Collection; import org.jajuk.base.Device; import org.jajuk.base.DeviceManager; import org.jajuk.base.SearchResult.SearchResultType; import org.jajuk.base.Track; import org.jajuk.base.TrackManager; import org.jajuk.services.core.SessionService; import org.jajuk.services.dj.AmbienceManager; import org.jajuk.ui.thumbnails.ThumbnailManager; import org.jajuk.util.log.Log; /** * Maintain all behavior needed upgrades from releases to releases. * * Jajuk version sheme is XX.YY.ZZ (two digits possible for each part of the release) */ public final class UpgradeManager implements Const { /** Last jajuk release known from Internet (parsed from a pad file). */ private static String newVersionName; /** Is it a minor or major X.Y upgrade */ private static boolean bUpgraded = false; /** Is it the first session ever ?. */ private static boolean bFirstSession = false; /** Is it an old migration (more than 1 major release) ?. */ private static boolean majorMigration = false; /** List of versions that doesn't require perspective reset at upgrade. */ private static String[] versionsNoNeedPerspectiveReset = new String[] { "1.9" }; /** * private constructor to avoid instantiating utility class. */ private UpgradeManager() { } /** * Return Jajuk number version = integer format of the padded release * * Jajuk version scheme is XX.YY.ZZ[RCn] (two digits possible for each part of the release) * * @param pStringRelease DOCUMENT_ME * * @return Jajuk number version = integer format of the padded release */ static int getNumberRelease(String pStringRelease) { if (pStringRelease == null) { // no string provided: use 1.0.0 return 10000; } String stringRelease = pStringRelease; // We drop any RCx part of the release if (pStringRelease.contains("RC")) { stringRelease = pStringRelease.split("RC.*")[0]; } // Add a trailing .0 if it is a main release like 1.X -> 1.X.0 int countDot = stringRelease.replaceAll("[^.]", "").length(); if (countDot == 1) { stringRelease = stringRelease + ".0"; } // Analyze each part of the release, throw a runtime exception if // the format is wrong at this point StringTokenizer st = new StringTokenizer(stringRelease, "."); String main = UtilString.padNumber(Integer.parseInt(st.nextToken()), 2); String minor = UtilString.padNumber(Integer.parseInt(st.nextToken()), 2); String fix = UtilString.padNumber(Integer.parseInt(st.nextToken()), 2); return Integer.parseInt(main + minor + fix); } /** * Detect current release and if an upgrade occurred since last startup. */ public static void detectRelease() { try { // Upgrade detection. Depends on: Configuration manager load final String sStoredRelease = Conf.getString(Const.CONF_RELEASE); // check if it is a new major 'x.y' release: 1.2 != 1.3 for instance if (!bFirstSession // if first session, not taken as an upgrade && (sStoredRelease == null || // null for jajuk releases < 1.2 !sStoredRelease.substring(0, 3).equals(Const.JAJUK_VERSION.substring(0, 3))) // Each RC is seen as an upgrade to force RC users to re-run upgrade code at each new RC || Const.JAJUK_VERSION.matches(".*RC.*")) { bUpgraded = true; // Now check if this is an old migration. if (!SessionService.isTestMode()) { if (isMajorMigration(Const.JAJUK_VERSION, sStoredRelease)) { majorMigration = true; } } } } catch (Exception e) { Log.error(e); } if (SessionService.isTestMode()) { // In test mode, we are always in upgraded mode bUpgraded = true; } // Now set current release in the conf Conf.setProperty(Const.CONF_RELEASE, Const.JAJUK_VERSION); } /** * Checks if is first session. * * @return true, if is first session */ public static boolean isFirstSession() { return bFirstSession; } /** * Sets the first session. * DOCUMENT_ME */ public static void setFirstSession() { bFirstSession = true; } /** * Actions to migrate an existing installation. * * Step 1 : before collection loading */ public static void upgradeStep1() { // We ignore errors during upgrade try { if (isUpgradeDetected()) { // For jajuk < 0.2 upgradeOldCollectionBackupFile(); // For Jajuk < 1.2 upgradeDefaultAmbience(); // For Jajuk < 1.3 upgradeTrackPattern(); upgradeSerFiles(); upgradeNocover(); upgradeWrongHotketOption(); // For Jajuk < 1.4 upgradePerspectivesRename(); // For Jajuk < 1.6 upgradePerspectiveButtonsSize(); upgradeDJClassChanges(); // For Jajuk < 1.7 upgradeElapsedTimeFormat(); // for Jajuk < 1.9 upgradeAlarmConfFile(); upgradeStartupConf(); } } catch (Exception e) { Log.error(e); } } /** * For Jajuk < 0.2 : remove backup file : collection~.xml * * @throws IOException Signals that an I/O exception has occurred. */ private static void upgradeOldCollectionBackupFile() throws IOException { File file = SessionService.getConfFileByPath(Const.FILE_COLLECTION + "~"); if (file.exists()) { UtilSystem.deleteFile(file); } } /** * For Jajuk <1.2, set default ambiences */ private static void upgradeDefaultAmbience() { String sRelease = Conf.getString(Const.CONF_RELEASE); if (sRelease == null || sRelease.matches("0..*") || sRelease.matches("1.0..*") || sRelease.matches("1.1.*")) { AmbienceManager.getInstance().createDefaultAmbiences(); } } /** * For Jajuk < 1.3 : changed track pattern from %track to %title */ private static void upgradeTrackPattern() { String sPattern = Conf.getString(Const.CONF_PATTERN_REFACTOR); if (sPattern.contains("track")) { Conf.setProperty(Const.CONF_PATTERN_REFACTOR, sPattern.replaceAll("track", "title")); } } /** * For Jajuk < 1.3: no more use of .ser files */ private static void upgradeSerFiles() { File file = SessionService.getConfFileByPath(""); File[] files = file.listFiles(); for (File element : files) { // delete all .ser files if (UtilSystem.getExtension(element).equals("ser")) { try { UtilSystem.deleteFile(element); } catch (IOException e) { Log.error(e); } } } } /** * For Jajuk < 1.9.3: 'cover' tag can't contain "none" string */ private static void upgradeNoneCover() { for (Album album : AlbumManager.getInstance().getAlbums()) { if (COVER_NONE.equals(album.getStringValue(XML_ALBUM_SELECTED_COVER))) { album.setProperty(XML_ALBUM_SELECTED_COVER, ""); } } } /** * For Jajuk < 1.9: bootstrap file is now in XML format *
    * If it exists and contains data in 1.7 or 1.8 format, it convert it to new XML * format (to handle backslashes properly, old format just drop them) *
    * This method doesn't yet validate provided workspace paths but only the bootstrap file * structure itself. */ public static void upgradeBootstrapFile() { try { String KEY_TEST = "test"; String KEY_FINAL = "final"; File bootstrapOld = new File(SessionService.getBootstrapPath(Const.FILE_BOOTSTRAP_OLD)); File bootstrapOldOldHome = new File(System.getProperty("user.home") + "/" + Const.FILE_BOOTSTRAP_OLD); File bootstrapNew = new File(SessionService.getBootstrapPath()); // Fix for #1473 : move the bootstrap file if required (See https://trac.jajuk.info/ticket/1473) if (UtilSystem.isUnderWindows() && !bootstrapOld.equals(bootstrapOldOldHome) && !bootstrapOld.exists() && bootstrapOldOldHome.exists()) { try { FileUtils.copyFileToDirectory(bootstrapOldOldHome, new File(UtilSystem.getUserHome())); UtilSystem.deleteFile(bootstrapOldOldHome); } catch (IOException ex) { ex.printStackTrace(); } } if (bootstrapOld.exists() && !bootstrapNew.exists()) { Properties prop = null; // Try to load a bootstrap file using plain text old format prop = new Properties(); FileInputStream fis = new FileInputStream( SessionService.getBootstrapPath(Const.FILE_BOOTSTRAP_OLD)); prop.load(fis); fis.close(); // If it exists and contains pre-1.7 bootstrap format (a single line with a raw path), // convert it to 1.7 format first if (prop.size() == 1) { // We get something like <... path ...> = String path = (String) prop.keys().nextElement(); // we use this path for both test and final workspace prop.clear(); prop.put(KEY_TEST, path); prop.put(KEY_FINAL, path); } // Make sure to populate both test and final release if (!prop.containsKey(KEY_TEST)) { prop.put(KEY_TEST, UtilSystem.getUserHome()); } if (!prop.containsKey(KEY_FINAL)) { prop.put(KEY_FINAL, UtilSystem.getUserHome()); } // Write down the new bootstrap file SessionService.commitBootstrapFile(prop); // Delete old bootstrap file bootstrapOld.delete(); } } catch (Exception e) { // Do not throw any exception from here. display raw stack trace, Logs facilities // are not yet available. e.printStackTrace(); } } /** * For Jajuk < 1.3: force nocover thumb replacement */ private static void upgradeNocover() { upgradeNoCoverDelete("50x50"); upgradeNoCoverDelete("100x100"); upgradeNoCoverDelete("150x150"); upgradeNoCoverDelete("200x200"); } /** * For Jajuk < 1.3: delete thumb for given size * * @param size DOCUMENT_ME */ private static void upgradeNoCoverDelete(String size) { File fThumbs = SessionService.getConfFileByPath(Const.FILE_THUMBS + "/" + size + "/" + Const.FILE_THUMB_NO_COVER); if (fThumbs.exists()) { try { UtilSystem.deleteFile(fThumbs); } catch (IOException e) { Log.error(e); } } } /** * jajuk 1.3: wrong option name: "false" instead of * "jajuk.options.use_hotkeys" */ private static void upgradeWrongHotketOption() { String sUseHotkeys = Conf.getString("false"); if (sUseHotkeys != null) { if (sUseHotkeys.equalsIgnoreCase(Const.FALSE) || sUseHotkeys.equalsIgnoreCase(Const.TRUE)) { Conf.setProperty(Const.CONF_OPTIONS_HOTKEYS, sUseHotkeys); Conf.removeProperty("false"); } else { Conf.setProperty(Const.CONF_OPTIONS_HOTKEYS, Const.FALSE); } } } /** * For jajuk < 1.9: Alarm configuration, file / webradio to be launched */ private static void upgradeAlarmConfFile() { String conf = Conf.getString(Const.CONF_ALARM_FILE); if (conf.indexOf('/') == -1) { conf = SearchResultType.FILE.name() + '/' + conf; Conf.setProperty(Const.CONF_ALARM_FILE, conf); } } /** * For jajuk < 1.9: Startup configuration, file / webradio to be launched */ private static void upgradeStartupConf() { String conf = Conf.getString(Const.CONF_STARTUP_ITEM); // conf = "" if none track has never been launched or if // jajuk was closed in stopped state if (!conf.equals("") && conf.indexOf('/') == -1) { conf = SearchResultType.FILE.name() + '/' + conf; Conf.setProperty(Const.CONF_STARTUP_ITEM, conf); } } /** * For jajuk <1.4 (or early 1.4), some perspectives have been renamed */ private static void upgradePerspectivesRename() { upgradePerspectivesRenameDelete("LogicalPerspective.xml"); upgradePerspectivesRenameDelete("PhysicalPerspective.xml"); upgradePerspectivesRenameDelete("CatalogPerspective.xml"); upgradePerspectivesRenameDelete("PlayerPerspective.xml"); upgradePerspectivesRenameDelete("HelpPerspective.xml"); } /** * For jajuk <1.4 (or early 1.4), delete renamed perspectives names * * @param name : perspective filename */ private static void upgradePerspectivesRenameDelete(String name) { File fPerspective = SessionService.getConfFileByPath(name); if (fPerspective.exists()) { try { UtilSystem.deleteFile(fPerspective); } catch (IOException e) { Log.error(e); } } } /** * Jajuk < 1.6. Perspective buttons size changed. */ private static void upgradePerspectiveButtonsSize() { if (Conf.getInt(Const.CONF_PERSPECTIVE_ICONS_SIZE) > 45) { Conf.setProperty(Const.CONF_PERSPECTIVE_ICONS_SIZE, "45"); } // For Jajuk 1.5 and jajuk 1.6 columns conf id changed if (Conf.getString(Const.CONF_PLAYLIST_REPOSITORY_COLUMNS).matches(".*0.*")) { Conf.setDefaultProperty(Const.CONF_PLAYLIST_REPOSITORY_COLUMNS); } if (Conf.getString(Const.CONF_QUEUE_COLUMNS).matches(".*0.*")) { Conf.setDefaultProperty(Const.CONF_QUEUE_COLUMNS); } if (Conf.getString(Const.CONF_PLAYLIST_EDITOR_COLUMNS).matches(".*0.*")) { Conf.setDefaultProperty(Const.CONF_PLAYLIST_EDITOR_COLUMNS); } } /** * For Jajuk < 1.6 (DJ classes changed) */ private static void upgradeDJClassChanges() { File[] files = SessionService.getConfFileByPath(Const.FILE_DJ_DIR).listFiles(new FileFilter() { @Override public boolean accept(File file) { if (file.isFile() && file.getPath().endsWith('.' + Const.XML_DJ_EXTENSION)) { return true; } return false; } }); for (File dj : files) { if (UtilSystem.replaceInFile(dj, "org.jajuk.dj.ProportionDigitalDJ", Const.XML_DJ_PROPORTION_CLASS, "UTF-8")) { Log.info("Migrated DJ file: {{" + dj.getName() + "}}"); } if (UtilSystem.replaceInFile(dj, "org.jajuk.dj.TransitionDigitalDJ", Const.XML_DJ_TRANSITION_CLASS, "UTF-8")) { Log.info("Migrated DJ file: {{" + dj.getName() + "}}"); } if (UtilSystem.replaceInFile(dj, "org.jajuk.dj.AmbienceDigitalDJ", Const.XML_DJ_AMBIENCE_CLASS, "UTF-8")) { Log.info("Migrated DJ file: {{" + dj.getName() + "}}"); } } } /** * For Jajuk < 1.7, elapsed time format variable name changed */ private static void upgradeElapsedTimeFormat() { if (Conf.containsProperty("format")) { Conf.setProperty(Const.CONF_FORMAT_TIME_ELAPSED, Conf.getString("format")); } } /** * For jajuk < 1.7, Update rating system */ private static void upgradeCollectionRating() { String sRelease = Conf.getString(Const.CONF_RELEASE); if (sRelease == null || sRelease.matches("0..*") || (sRelease.matches("1..*") && Integer.parseInt(sRelease.substring(2, 3)) < 7)) { Log.info("Migrating collection rating"); // We keep current ratings and we recompute them on a 0 to 100 scale, // then we suggest user to reset the rates // Start by finding max (old) rating long maxRating = 0; ReadOnlyIterator tracks = TrackManager.getInstance().getTracksIterator(); while (tracks.hasNext()) { Track track = tracks.next(); if (track.getRate() > maxRating) { maxRating = track.getRate(); } } // Then apply the new rating for (Track track : TrackManager.getInstance().getTracks()) { long newRate = (long) (100f * track.getRate() / maxRating); TrackManager.getInstance().changeTrackRate(track, newRate); } // Save collection try { Collection.commit(SessionService.getConfFileByPath(Const.FILE_COLLECTION)); } catch (final IOException e) { Log.error(e); } Log.info("Migrating rating done"); Messages.showInfoMessage(Messages.getString("Note.1")); } } /** * For jajuk < 1.9, remove album artist property for albums */ private static void upgradeNoMoreAlbumArtistsForAlbums() { if (AlbumManager.getInstance().getMetaInformation(Const.XML_ALBUM_ARTIST) != null) { AlbumManager.getInstance().removeProperty(Const.XML_ALBUM_ARTIST); } } /** * For any jajuk version, after major upgrade, force thumbs cleanup. */ private static void upgradeThumbRebuild() { // Rebuild thumbs when upgrading new Thread() { @Override public void run() { // Clean thumbs ThumbnailManager.cleanThumbs(Const.THUMBNAIL_SIZE_50X50); ThumbnailManager.cleanThumbs(Const.THUMBNAIL_SIZE_100X100); ThumbnailManager.cleanThumbs(Const.THUMBNAIL_SIZE_150X150); ThumbnailManager.cleanThumbs(Const.THUMBNAIL_SIZE_200X200); ThumbnailManager.cleanThumbs(Const.THUMBNAIL_SIZE_250X250); ThumbnailManager.cleanThumbs(Const.THUMBNAIL_SIZE_300X300); } }.start(); } /** * Actions to migrate an existing installation. * * Step 2 after collection load */ public static void upgradeStep2() { try { if (isUpgradeDetected()) { // For Jajuk < 1.7 upgradeCollectionRating(); // For Jajuk < 1.9 upgradeNoMoreAlbumArtistsForAlbums(); // For Jajuk < 1.9.3 upgradeNoneCover(); } // Major releases upgrade specific operations if (isMajorMigration()) { upgradeThumbRebuild(); } } catch (Throwable e) { Log.error(e); } } /** * Actions to migrate an existing installation. * * Step 3 after full jajuk startup */ public static void upgradeStep3() { try { // Major releases upgrade specific operations if (isMajorMigration()) { deepScanRequest(); } } catch (Throwable e) { Log.error(e); } } /** * Checks if is upgrade detected. * * @return true if it is the first session after a minor or major upgrade * session */ public static boolean isUpgradeDetected() { return bUpgraded; } /** * Check for a new Jajuk release. * * @return true if a new release has been found */ public static void checkForUpdate() { // If test mode, don't try to update if (SessionService.isTestMode()) { return; } // Try to download current jajuk PAD file String sPadRelease = null; try { String pad = DownloadManager.downloadText(new URL(Const.CHECK_FOR_UPDATE_URL)); int beginIndex = pad.indexOf(""); int endIndex = pad.indexOf(""); sPadRelease = pad.substring(beginIndex + 17, endIndex); if (!Const.JAJUK_VERSION.equals(sPadRelease) // Don't use this in test && !("VERSION_REPLACED_BY_ANT".equals(Const.JAJUK_VERSION)) // We display the upgrade icon only if PAD release is newer than current release && isNewer(Const.JAJUK_VERSION, sPadRelease)) { newVersionName = sPadRelease; return; } } catch (Exception e) { Log.debug("Cannot check for updates", e); } return; } /** * Gets the new version name. * * @return new version name if nay *

    * Example: "1.6", "1.7.8" */ public static String getNewVersionName() { return newVersionName; } /** * Is it an old migration (more than 1 major release) ? *. * * @return true, if checks if is major migration */ public static boolean isMajorMigration() { return majorMigration; } /** * Return whether two releases switch is a major upgrade or not. * * @param currentRelease DOCUMENT_ME * @param comparedRelease DOCUMENT_ME * * @return whether two releases switch is a major upgrade or not */ protected static boolean isMajorMigration(String currentRelease, String comparedRelease) { int iCurrentRelease = getNumberRelease(currentRelease); int iComparedRelease = getNumberRelease(comparedRelease); return iComparedRelease / 100 != iCurrentRelease / 100; } /** * Return whether second release is newer than first. * * @param currentRelease DOCUMENT_ME * @param comparedRelease DOCUMENT_ME * * @return whether second release is newer than first */ protected static boolean isNewer(String currentRelease, String comparedRelease) { int iCurrentRelease = getNumberRelease(currentRelease); int iComparedRelease = getNumberRelease(comparedRelease); return iComparedRelease > iCurrentRelease; } /** * Require user to perform a deep scan. */ private static void deepScanRequest() { int reply = Messages.getChoice(Messages.getString("Warning.7"), JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE); if (reply == JOptionPane.CANCEL_OPTION || reply == JOptionPane.NO_OPTION) { return; } if (reply == JOptionPane.YES_OPTION) { final Thread t = new Thread("Device Refresh Thread after upgrade") { @Override public void run() { List devices = DeviceManager.getInstance().getDevices(); for (Device device : devices) { if (device.isReady()) { device.manualRefresh(false, false, true, null); } } } }; t.setPriority(Thread.MIN_PRIORITY); t.start(); } } /** * Return whether this version need a perspective reset at upgrade. * We reset perspectives only at major upgrade and if it comes with new views. * * @return whether this version need a perspective reset at upgrade */ public static boolean doNeedPerspectiveResetAtUpgrade() { if (!isMajorMigration()) { return false; } for (String version : versionsNoNeedPerspectiveReset) { if (Const.JAJUK_VERSION.matches(version + ".*")) { return false; } } return true; } } jajuk-1.9.6.orig/src/main/java/org/jajuk/util/filters/0000755000175000017500000000000011720500104022430 5ustar drazzibdrazzibjajuk-1.9.6.orig/src/main/java/org/jajuk/util/filters/JPGFilter.java0000644000175000017500000000244711720500104025070 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.util.filters; import org.jajuk.util.JajukFileFilter; /** * jpg filter. */ public class JPGFilter extends JajukFileFilter { /** Self instance. */ private static JPGFilter self = new JPGFilter(); /** * Gets the instance. * * @return singleton */ public static JPGFilter getInstance() { return JPGFilter.self; } /** * Singleton constructor (protected for testing purposes). */ protected JPGFilter() { super(new String[] { "jpeg", "jpg" }); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/util/filters/GIFFilter.java0000644000175000017500000000237311720500104025053 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.util.filters; import org.jajuk.util.JajukFileFilter; /** * Gif filter. */ public class GIFFilter extends JajukFileFilter { /** Self instance. */ private static GIFFilter self = new GIFFilter(); /** * Gets the instance. * * @return singleton */ public static GIFFilter getInstance() { return GIFFilter.self; } /** * Singleton constructor. */ private GIFFilter() { super(new String[] { "gif" }); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/util/filters/AudioFilter.java0000644000175000017500000000504711720500104025510 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.util.filters; import java.io.File; import org.jajuk.base.Type; import org.jajuk.base.TypeManager; import org.jajuk.util.Const; import org.jajuk.util.JajukFileFilter; import org.jajuk.util.UtilSystem; /** * Audio filter. */ public final class AudioFilter extends JajukFileFilter { /** Self instance. */ private static AudioFilter self = new AudioFilter(); /** * Gets the instance. * * @return singleton */ public static AudioFilter getInstance() { return AudioFilter.self; } /** * Singleton constructor (protected for testing purposes). */ private AudioFilter() { } /* * (non-Javadoc) * * @see java.io.FileFilter#accept(java.io.File) */ @Override public boolean accept(final File f) { // Force directories acceptation if user wants to navigate into // directories if (f.isDirectory()) { if (bShowDirectories) { return true; } else { return false; } } final TypeManager mgr = TypeManager.getInstance(); final String extension = UtilSystem.getExtension(f); // check extension is known if (TypeManager.getInstance().isExtensionSupported(extension)) { // check it is an audio file return (Boolean) mgr.getTypeByExtension(extension).getValue(Const.XML_TYPE_IS_MUSIC); } return false; } /* * (non-Javadoc) * * @see javax.swing.filechooser.FileFilter#getDescription() */ @Override public String getDescription() { final StringBuilder s = new StringBuilder(); for (final Type type : TypeManager.getInstance().getAllMusicTypes()) { s.append(type.getExtension()); s.append(','); } // Remove last coma return ((s.length() > 0) ? s.substring(0, s.length() - 1) : ""); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/util/filters/package.html0000644000175000017500000000017111720500104024710 0ustar drazzibdrazzib DOCUMENT_ME jajuk-1.9.6.orig/src/main/java/org/jajuk/util/filters/ImageFilter.java0000644000175000017500000000250611720500104025466 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.util.filters; import org.jajuk.util.JajukFileFilter; /** * Image filter. */ public final class ImageFilter extends JajukFileFilter { /** Self instance. */ private static ImageFilter self = new ImageFilter(); /** * Gets the instance. * * @return singleton */ public static ImageFilter getInstance() { return ImageFilter.self; } /** * Singleton constructor (protected for testing purposes). */ private ImageFilter() { super(new String[] { "jpg", "jpeg", "gif", "png" }); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/util/filters/ReportFilter.java0000644000175000017500000000251711720500104025721 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.util.filters; import org.jajuk.util.JajukFileFilter; /** * Report filter (.html or XML file) */ public class ReportFilter extends JajukFileFilter { /** Self instance. */ private static ReportFilter self = new ReportFilter(); /** * Gets the instance. * * @return singleton */ public static ReportFilter getInstance() { return ReportFilter.self; } /** * Singleton constructor (protected for testing purposes). */ protected ReportFilter() { super(new String[] { "html", "xml" }); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/util/filters/DirectoryFilter.java0000644000175000017500000000335611720500104026414 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.util.filters; import java.io.File; import org.jajuk.util.JajukFileFilter; import org.jajuk.util.Messages; /** * Directory filter *

    * Singleton *

    . */ public final class DirectoryFilter extends JajukFileFilter { /** Self instance. */ private static DirectoryFilter self = new DirectoryFilter(); /** * Gets the instance. * * @return singleton */ public static DirectoryFilter getInstance() { return DirectoryFilter.self; } /** * Singleton constructor (protected for testing purposes). */ private DirectoryFilter() { } /* * (non-Javadoc) * * @see java.io.FileFilter#accept(java.io.File) */ @Override public boolean accept(final File f) { return f.isDirectory(); } /* * (non-Javadoc) * * @see javax.swing.filechooser.FileFilter#getDescription() */ @Override public String getDescription() { return Messages.getString("Item_Directory"); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/util/filters/AnyFileFilter.java0000644000175000017500000000335411720500104025775 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.util.filters; import java.io.File; import org.jajuk.util.JajukFileFilter; /** * Any File filter *

    * Singleton *

    . */ public final class AnyFileFilter extends JajukFileFilter { /** Self instance. */ private static AnyFileFilter self = new AnyFileFilter(); /** * Gets the instance. * * @return singleton */ public static AnyFileFilter getInstance() { return AnyFileFilter.self; } /** * Singleton constructor (protected for testing purposes). */ private AnyFileFilter() { super(new String[] {}); } /* * (non-Javadoc) * * @see javax.swing.filechooser.FileFilter#getDescription() */ @Override public String getDescription() { return "*.*"; } /* * (non-Javadoc) * * @see org.jajuk.util.JajukFileFilter#isKnownExtension(java.io.File) */ @Override protected boolean isKnownExtension(final File file) { return true; // all files are OK } } jajuk-1.9.6.orig/src/main/java/org/jajuk/util/filters/PlaylistFilter.java0000644000175000017500000000445711720500104026254 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.util.filters; import java.io.File; import org.jajuk.base.Type; import org.jajuk.base.TypeManager; import org.jajuk.util.Const; import org.jajuk.util.JajukFileFilter; import org.jajuk.util.UtilSystem; /** * Playlist filter. */ public final class PlaylistFilter extends JajukFileFilter { /** Self instance. */ private static PlaylistFilter self = new PlaylistFilter(); /** * Gets the instance. * * @return singleton */ public static PlaylistFilter getInstance() { return PlaylistFilter.self; } /** * Singleton constructor (protected for testing purposes). */ private PlaylistFilter() { } /* * (non-Javadoc) * * @see java.io.FileFilter#accept(java.io.File) */ @Override public boolean accept(final File f) { // Force directories acceptation if user wants to navigate into // directories if (f.isDirectory()) { return bShowDirectories; } else { final String extension = UtilSystem.getExtension(f); final TypeManager mgr = TypeManager.getInstance(); // check extension is known if (mgr.isExtensionSupported(extension)) { // check it is a playlist final Type playlist = mgr.getTypeByExtension(Const.EXT_PLAYLIST); return mgr.getTypeByExtension(extension).equals(playlist); } } return false; } /* * (non-Javadoc) * * @see javax.swing.filechooser.FileFilter#getDescription() */ @Override public String getDescription() { return Const.EXT_PLAYLIST; } } jajuk-1.9.6.orig/src/main/java/org/jajuk/util/filters/KnownTypeFilter.java0000644000175000017500000000355511720500104026407 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.util.filters; import java.io.File; import org.jajuk.base.Type; import org.jajuk.base.TypeManager; import org.jajuk.util.JajukFileFilter; import org.jajuk.util.UtilSystem; /** * Known type filter. */ public final class KnownTypeFilter extends JajukFileFilter { /** Self instance. */ private static KnownTypeFilter self = new KnownTypeFilter(); /** * Gets the instance. * * @return singleton */ public static KnownTypeFilter getInstance() { return KnownTypeFilter.self; } /** * Singleton constructor (protected for testing purposes). */ private KnownTypeFilter() { super(Type.getExtensionsFromTypes(TypeManager.getInstance().getTypes())); } /* * (non-Javadoc) * * @see java.io.FileFilter#accept(java.io.File) */ @Override public boolean accept(final File f) { // Force directories acceptation if user wants to navigate into // directories if (f.isDirectory()) { return bShowDirectories; } return TypeManager.getInstance().isExtensionSupported(UtilSystem.getExtension(f)); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/util/filters/HTMLFilter.java0000644000175000017500000000240311720500104025204 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.util.filters; import org.jajuk.util.JajukFileFilter; /** * HTMLfilter. */ public class HTMLFilter extends JajukFileFilter { /** Self instance. */ private static HTMLFilter self = new HTMLFilter(); /** * Gets the instance. * * @return singleton */ public static HTMLFilter getInstance() { return HTMLFilter.self; } /** * Singleton constructor. */ private HTMLFilter() { super(new String[] { "html" }); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/util/filters/NotAudioFilter.java0000644000175000017500000000452411720500104026170 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.util.filters; import java.io.File; import org.jajuk.base.TypeManager; import org.jajuk.util.Const; import org.jajuk.util.JajukFileFilter; import org.jajuk.util.UtilSystem; /** * Not Audio file filter (must be a file). */ public final class NotAudioFilter extends JajukFileFilter { /** Self instance. */ private static NotAudioFilter self = new NotAudioFilter(); /** * Gets the instance. * * @return singleton */ public static NotAudioFilter getInstance() { return NotAudioFilter.self; } /** * Singleton constructor (protected for testing purposes). */ private NotAudioFilter() { } /* * (non-Javadoc) * * @see java.io.FileFilter#accept(java.io.File) */ @Override public boolean accept(final File f) { // Force directories acceptation if user wants to navigate into // directories if (f.isDirectory()) { return bShowDirectories; } else { final String extension = UtilSystem.getExtension(f); final TypeManager mgr = TypeManager.getInstance(); // check extension is known if (mgr.isExtensionSupported(extension)) { // check it is an audio file return !(Boolean) mgr.getTypeByExtension(extension).getValue(Const.XML_TYPE_IS_MUSIC); } } // unknown type : not an audio file return true; } /* * (non-Javadoc) * * @see javax.swing.filechooser.FileFilter#getDescription() */ @Override public String getDescription() { // No need to translate, is is used internal only return "Not audio"; } } jajuk-1.9.6.orig/src/main/java/org/jajuk/util/filters/PNGFilter.java0000644000175000017500000000243711720500104025073 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.util.filters; import org.jajuk.util.JajukFileFilter; /** * Png filter. */ public class PNGFilter extends JajukFileFilter { /** Self instance. */ private static PNGFilter self = new PNGFilter(); /** * Gets the instance. * * @return singleton */ public static PNGFilter getInstance() { return PNGFilter.self; } /** * Singleton constructor (protected for testing purposes). */ protected PNGFilter() { super(new String[] { "png" }); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/util/filters/XMLFilter.java0000644000175000017500000000242411720500104025103 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.util.filters; import org.jajuk.util.JajukFileFilter; /** * XMLfilter. */ public class XMLFilter extends JajukFileFilter { /** Self instance. */ private static XMLFilter self = new XMLFilter(); /** * Gets the instance. * * @return singleton */ public static XMLFilter getInstance() { return self; } /** * Singleton constructor (protected for testing purposes). */ protected XMLFilter() { super(new String[] { "xml" }); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/util/filters/JajukPredicates.java0000644000175000017500000001224211720500104026344 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.util.filters; import java.util.Date; import java.util.List; import org.apache.commons.collections.Predicate; import org.jajuk.base.File; import org.jajuk.base.Playlist; import org.jajuk.base.Track; import org.jajuk.services.dj.Ambience; import org.jajuk.util.Const; /** * List of Predicates (filter criteria) *

    * Returns predicates used to decorate iterators *

    . */ public class JajukPredicates { /** * Age-filtering predicate Applied on tracks only. */ public static class AgePredicate implements Predicate { /** DOCUMENT_ME. */ private int iAge = 0; /** * Instantiates a new age predicate. * * @param iAge DOCUMENT_ME */ public AgePredicate(int iAge) { this.iAge = iAge; } /* * (non-Javadoc) * * @see org.apache.commons.collections.Predicate#evaluate(java.lang.Object) */ @Override public boolean evaluate(Object o) { if (!(o instanceof Track)) { return false; } Track track = (Track) o; Date now = new Date(); int iTrackAge = (int) ((now.getTime() - track.getDiscoveryDate().getTime()) / Const.MILLISECONDS_IN_A_DAY); if (iTrackAge <= iAge) { return true; } return false; } } /** * Ready (mounted) filtering predicate Applied on files only. */ public static class ReadyFilePredicate implements Predicate { /* * (non-Javadoc) * * @see org.apache.commons.collections.Predicate#evaluate(java.lang.Object) */ @Override public boolean evaluate(Object o) { return ((File) o).isReady(); } } /** * Banned filtering predicate Applied against tracks only. */ public static class BannedTrackPredicate implements Predicate { /* * (non-Javadoc) * * @see org.apache.commons.collections.Predicate#evaluate(java.lang.Object) */ @Override public boolean evaluate(Object o) { Track track = (Track) o; return !(track.getBooleanValue(Const.XML_TRACK_BANNED)); } } /** * Banned filtering predicate Applied against files only. */ public static class BannedFilePredicate implements Predicate { /* * (non-Javadoc) * * @see org.apache.commons.collections.Predicate#evaluate(java.lang.Object) */ @Override public boolean evaluate(Object o) { Track track = ((File) o).getTrack(); return !(track.getBooleanValue(Const.XML_TRACK_BANNED)); } } /** * Any file available predicate, applies against tracks only. */ public static class AnyFileReady implements Predicate { /* * (non-Javadoc) * * @see org.apache.commons.collections.Predicate#evaluate(java.lang.Object) */ @Override public boolean evaluate(Object o) { Track track = ((File) o).getTrack(); return track.getBestFile(true) != null; } } /** * Playlist predicate, filter playlists located on unmounted devices. */ public static class ReadyPlaylistPredicate implements Predicate { /* * (non-Javadoc) * * @see org.apache.commons.collections.Predicate#evaluate(java.lang.Object) */ @Override public boolean evaluate(Object o) { return ((Playlist) o).isReady(); } } /** * Ambience predicate on files, filter by provided ambience. */ public static class AmbiencePredicate implements Predicate { /** DOCUMENT_ME. */ private final Ambience ambience; /** * Instantiates a new ambience predicate. * * @param ambience DOCUMENT_ME */ public AmbiencePredicate(Ambience ambience) { this.ambience = ambience; } /* * (non-Javadoc) * * @see org.apache.commons.collections.Predicate#evaluate(java.lang.Object) */ @Override public boolean evaluate(Object o) { File tested = (File) o; return ambience.getGenres().contains(tested.getTrack().getGenre()); } } /** * Not Video predicate on tracks, filter video files. */ public static class NotVideoPredicate implements Predicate { /* * (non-Javadoc) * * @see org.apache.commons.collections.Predicate#evaluate(java.lang.Object) */ @Override public boolean evaluate(Object o) { Track tested = (Track) o; List files = tested.getFiles(); File fileTested = files.get(0); return !fileTested.getType().isVideo(); } } } jajuk-1.9.6.orig/src/main/java/org/jajuk/util/filters/JarFilter.java0000644000175000017500000000243711720500104025163 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.util.filters; import org.jajuk.util.JajukFileFilter; /** * Jar filter. */ public class JarFilter extends JajukFileFilter { /** Self instance. */ private static JarFilter self = new JarFilter(); /** * Gets the instance. * * @return singleton */ public static JarFilter getInstance() { return JarFilter.self; } /** * Singleton constructor (protected for testing purposes). */ protected JarFilter() { super(new String[] { "jar" }); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/util/DownloadManager.java0000644000175000017500000002541111720500104024670 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.util; import ext.services.network.NetworkUtils; import ext.services.network.Proxy; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.net.Authenticator; import java.net.HttpURLConnection; import java.net.PasswordAuthentication; import java.net.Proxy.Type; import java.net.URL; import java.net.URLEncoder; import java.util.ArrayList; import java.util.List; import java.util.Locale; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.jajuk.services.core.SessionService; import org.jajuk.util.log.Log; /** * Manages network downloads. */ public final class DownloadManager { /** DOCUMENT_ME. */ private static Proxy proxy; /** * private constructor to avoid instantiating utility class. */ private DownloadManager() { } /** * Gets the remote covers list. * * @param search DOCUMENT_ME * * @return a list of urls * * @throws IOException Signals that an I/O exception has occurred. */ public static List getRemoteCoversList(String search) throws IOException { List alOut = new ArrayList(20); // URL list // check void searches if (search == null || search.trim().equals("")) { return alOut; } // Select cover size int i = Conf.getInt(Const.CONF_COVERS_SIZE); String size = null; switch (i) { case 0: // small only size = "small"; break; case 1: // small or medium size = "small|medium"; break; case 2: // medium only size = "medium"; break; case 3: // medium or large size = "medium|large"; break; case 4: // large only size = "large"; break; } String sSearchUrl = "http://images.google.com/images?q=" + URLEncoder.encode(search, "ISO-8859-1") + "&ie=ISO-8859-1&hl=en&btnG=Google+Search" + "&imgsz=" + size; Log.debug("Search URL: {{" + sSearchUrl + "}}"); String sRes = downloadText(new URL(sSearchUrl)); if (sRes == null || sRes.length() == 0) { return alOut; } // Extract urls Pattern pattern = Pattern.compile("http://[^,<>]*(.jpg|.gif|.png)"); // "http://[^,]*(.jpg|.gif|.png).*[0-9]* [xX] [0-9]*.*- [0-9]*"); Matcher matcher = pattern.matcher(sRes); while (matcher.find()) { // Clean up URLS String sUrl = matcher.group().replaceAll("%2520", "%20"); URL url = new URL(sUrl); // Remove duplicates if (alOut.contains(url)) { continue; } // Ignore URLs related to Google if (url.toString().toLowerCase(Locale.getDefault()).matches(".*google.*")) { continue; } // Add the new url alOut.add(url); } return alOut; } /** * Download the resource at the given url. * * @param url url to download * @param fDestination destination file * * @throws IOException If a network problem occurs. */ public static void download(URL url, File fDestination) throws IOException { // Drop the query if user required "none Internet access from jajuk". // This method shouldn't be called anyway because we views have to deal with // this option at their level, this is a additional control. if (Conf.getBoolean(Const.CONF_NETWORK_NONE_INTERNET_ACCESS)) { return; } HttpURLConnection connection = NetworkUtils.getConnection(url, proxy); BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(fDestination)); try { BufferedInputStream bis = new BufferedInputStream(connection.getInputStream()); try { int i; while ((i = bis.read()) != -1) { bos.write(i); } } finally { bis.close(); } bos.flush(); } finally { bos.close(); } connection.disconnect(); } /** * Download the resource at the given url and cache it
    * If the file is already in cache, it is returned immediately
    * The cache is currently cleared at each Jajuk session startup. * * @param url url to download * * @return cached file or null if a problem occurred * * @throws IOException If a network problem occurs or a temporary file cannot be * written. */ public static File downloadToCache(URL url) throws IOException { // Drop the query if user required "none Internet access from jajuk". // This method shouldn't be called anyway because we views have to deal with // this option at their level, this is a additional control. if (Conf.getBoolean(Const.CONF_NETWORK_NONE_INTERNET_ACCESS)) { return null; } File file = SessionService.getCachePath(url); // We synchronize the (interned) name of the cached file to avoid // probable collisions between views synchronized (file.getName().intern()) { // check if file is not already downloaded or being downloaded if (file.exists()) { return file; } HttpURLConnection connection = NetworkUtils.getConnection(url, proxy); BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(file)); try { BufferedInputStream bis = new BufferedInputStream(connection.getInputStream()); try { int i; while ((i = bis.read()) != -1) { bos.write(i); } } finally { bis.close(); } bos.flush(); } finally { bos.close(); } connection.disconnect(); return file; } } /** * Download the cover list. * * @param url to download * @param charset DOCUMENT_ME * * @return result as an array of bytes, null if a problem occurred * * @throws IOException Signals that an I/O exception has occurred. */ public static String downloadText(URL url, String charset) throws IOException { // Drop the query if user required "none Internet access from jajuk". // This method shouldn't be called anyway because we views have to deal with // this option at their level, this is a additional control. if (Conf.getBoolean(Const.CONF_NETWORK_NONE_INTERNET_ACCESS)) { return null; } HttpURLConnection connection = NetworkUtils.getConnection(url, proxy); try { return NetworkUtils.readURL(connection, charset); } finally { connection.disconnect(); } } /** * Download text with the default charset UTF-8. * * @param url DOCUMENT_ME * * @return the string * * @throws IOException Signals that an I/O exception has occurred. */ public static String downloadText(URL url) throws IOException { return downloadText(url, "UTF-8"); } /** * Return a string for a given URL and encoding, used to retrieve text from a * cached file. * * @param url url to read * @param encoding encoding of the content of the file * * @return a string for a given URL and encoding * * @throws IOException Signals that an I/O exception has occurred. */ public static String getTextFromCachedFile(URL url, String encoding) throws IOException { // Drop the query if user required "none Internet access from jajuk". // This method shouldn't be called anyway because we views have to deal with // this option at their level, this is a additional control. if (Conf.getBoolean(Const.CONF_NETWORK_NONE_INTERNET_ACCESS)) { return null; } File file = downloadToCache(url); StringBuilder builder = new StringBuilder(); InputStream input = new BufferedInputStream(new FileInputStream(file)); try { byte[] array = new byte[1024]; int read; while ((read = input.read(array)) > 0) { builder.append(new String(array, 0, read, encoding)); } } finally { input.close(); } return builder.toString(); } /** * Set default proxy settings, used by cobra for ie. */ public synchronized static void setDefaultProxySettings() { String sProxyHost = Conf.getString(Const.CONF_NETWORK_PROXY_HOSTNAME); int iProxyPort = Conf.getInt(Const.CONF_NETWORK_PROXY_PORT); String sProxyLogin = Conf.getString(Const.CONF_NETWORK_PROXY_LOGIN); String sProxyPwd = Conf.getString(Const.CONF_NETWORK_PROXY_PWD); Type proxyType = Type.DIRECT; if (Conf.getBoolean(Const.CONF_NETWORK_USE_PROXY)) { // Set default proxy value if (Const.PROXY_TYPE_HTTP.equals(Conf.getString(Const.CONF_NETWORK_PROXY_TYPE))) { proxyType = Type.HTTP; } else if (Const.PROXY_TYPE_SOCKS.equals(Conf.getString(Const.CONF_NETWORK_PROXY_TYPE))) { proxyType = Type.SOCKS; } try { proxy = new Proxy(proxyType, sProxyHost, iProxyPort, sProxyLogin, sProxyPwd); } catch (Exception e) { Log.error(e); return; } } // Set system defaults proxy values, if we don't use DownloadManager // methods // see http://java.sun.com/j2se/1.4.2/docs/guide/net/properties.html if (Conf.getBoolean(Const.CONF_NETWORK_USE_PROXY)) { System.getProperties().put("proxySet", "true"); if (Const.PROXY_TYPE_HTTP.equals(Conf.getString(Const.CONF_NETWORK_PROXY_TYPE))) { System.setProperty("http.proxyHost", sProxyHost); System.setProperty("http.proxyPort", Integer.toString(iProxyPort)); } else if (Const.PROXY_TYPE_SOCKS.equals(Conf.getString(Const.CONF_NETWORK_PROXY_TYPE))) { System.setProperty("socksProxyHost", sProxyHost); System.setProperty("socksProxyPort ", Integer.toString(iProxyPort)); } Authenticator.setDefault(new Authenticator() { @Override protected PasswordAuthentication getPasswordAuthentication() { String user = Conf.getString(Const.CONF_NETWORK_PROXY_LOGIN); char[] pwd = UtilString.rot13(Conf.getString(Const.CONF_NETWORK_PROXY_PWD)).toCharArray(); return new PasswordAuthentication(user, pwd); } }); } } /** * Gets the proxy. * * @return the proxy */ public static Proxy getProxy() { return proxy; } } jajuk-1.9.6.orig/src/main/java/org/jajuk/util/Conf.java0000644000175000017500000004302011720500104022507 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.util; import java.awt.HeadlessException; import java.awt.Toolkit; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.Properties; import org.jajuk.services.core.SessionService; import org.jajuk.services.notification.NotificatorTypes; import org.jajuk.ui.actions.JajukActions; import org.jajuk.ui.perspectives.SimplePerspective; import org.jajuk.util.log.Log; /** * Manage all the configuration and user preferences of jajuk. *

    * Singleton */ public final class Conf implements Const { /** Properties in memory. */ private static volatile Properties properties = new Properties(); /** Default properties cache. */ private static volatile Properties defaults = new Properties(); static { setDefaultProperties(); properties = (Properties) properties.clone(); } /** * Instantiates a new conf. */ private Conf() { // empty hidden constructor } /** * Return the value of a property, or null if the property is not found. * * @param pName Name of the property. * * @return String Value of the property named pName. */ public static String getString(String pName) { return properties.getProperty(pName); } /** * Return the value of a property as a boolean or default value or default * value if value cannot be parsed. * * @param pName Name of the property. * * @return boolean value of the property named pName. */ public static boolean getBoolean(String pName) { boolean out = false; try { out = Boolean.parseBoolean(properties.getProperty(pName)); } catch (Exception e) { out = Boolean.parseBoolean(defaults.getProperty(pName)); Log.debug("Cannot parse property: " + pName); Log.debug(e); } return out; } /** * Invert a boolean value. * * @param pName DOCUMENT_ME */ public static void invert(String pName) { boolean b = Boolean.parseBoolean(properties.getProperty(pName)); setProperty(pName, Boolean.toString(!b)); } /** * Return the value of a property as a float or default value or default value * if value cannot be parsed. * * @param pName Name of the property. * * @return float value of the property named pName. */ public static float getFloat(String pName) { float out = 0f; try { out = Float.parseFloat(properties.getProperty(pName)); } catch (Exception e) { out = Float.parseFloat(defaults.getProperty(pName)); Log.debug("Cannot parse property: " + pName); Log.debug(e); } return out; } /** * Return the value of a property as an integer or default value if value * cannot be parsed. * * @param pName Name of the property. * * @return int value of the property named pName. */ public static int getInt(String pName) { int out = 0; try { out = Integer.parseInt(properties.getProperty(pName)); } catch (NumberFormatException e) { out = Integer.parseInt(defaults.getProperty(pName)); Log.debug("Cannot parse property: " + pName); Log.debug(e); } return out; } /** * Reset a given property to its defaults. * * @param property DOCUMENT_ME */ public static void setDefaultProperty(String property) { String defaultValue = (String) defaults.get(property); if (defaultValue != null) { properties.put(property, defaultValue); } else { Log.debug("Cannot reset thsi property: " + property); } } /** * Set default values. */ public static void setDefaultProperties() { // We fill with current values to keep some parameters // like passwords and that we don't want to reset defaults = (Properties) properties.clone(); defaults.put(CONF_OPTIONS_LANGUAGE, LocaleManager.getNativeLocale().getLanguage()); // User preferences defaults.put(CONF_PERSPECTIVE_DEFAULT, SimplePerspective.class.getName()); defaults.put(CONF_STATE_REPEAT, FALSE); defaults.put(CONF_STATE_REPEAT_ALL, FALSE); defaults.put(CONF_STATE_KARAOKE, FALSE); defaults.put(CONF_STATE_SHUFFLE, FALSE); defaults.put(CONF_STATE_CONTINUE, FALSE); defaults.put(CONF_STATE_INTRO, FALSE); // no startup file by default defaults.put(CONF_STARTUP_ITEM, ""); defaults.put(CONF_STARTUP_MODE, STARTUP_MODE_LAST_KEEP_POS); defaults.put(CONF_STARTUP_LAST_POSITION, "0"); defaults.put(CONF_STARTUP_STOPPED, "false"); defaults.put(CONF_CONFIRMATIONS_DELETE_FILE, TRUE); defaults.put(CONF_CONFIRMATIONS_EXIT, FALSE); defaults.put(CONF_CONFIRMATIONS_REMOVE_DEVICE, TRUE); defaults.put(CONF_CONFIRMATIONS_DELETE_COVER, TRUE); defaults.put(CONF_CONFIRMATIONS_CLEAR_HISTORY, TRUE); defaults.put(CONF_CONFIRMATIONS_RESET_RATINGS, TRUE); defaults.put(CONF_CONFIRMATIONS_REFACTOR_FILES, TRUE); defaults.put(CONF_OPTIONS_HIDE_UNMOUNTED, FALSE); defaults.put(CONF_OPTIONS_PUSH_ON_CLICK, FALSE); defaults.put(CONF_OPTIONS_PUSH_ON_DROP, FALSE); defaults.put(CONF_OPTIONS_NOVELTIES_AGE, "30"); defaults.put(CONF_OPTIONS_VISIBLE_PLANNED, "10"); defaults.put(CONF_BUFFER_SIZE, "16000"); // -1 : max available buffer set default trace level, debug in debug // mode and warning in normal mode defaults.put(CONF_AUDIO_BUFFER_SIZE, "-1"); if (SessionService.isIdeMode()) { defaults.put(CONF_OPTIONS_LOG_LEVEL, Integer.toString(Log.DEBUG)); } else { defaults.put(CONF_OPTIONS_LOG_LEVEL, Integer.toString(Log.WARNING)); } defaults.put(CONF_OPTIONS_TAB, "0"); defaults.put(CONF_OPTIONS_INTRO_BEGIN, "0"); defaults.put(CONF_OPTIONS_INTRO_LENGTH, "20"); defaults.put(CONF_UI_NOTIFICATOR_TYPE, NotificatorTypes.NONE.name()); defaults.put(CONF_P2P_SHARE, FALSE); defaults.put(CONF_P2P_ADD_REMOTE_PROPERTIES, FALSE); defaults.put(CONF_P2P_HIDE_LOCAL_PROPERTIES, TRUE); defaults.put(CONF_P2P_PASSWORD, ""); defaults.put(CONF_HISTORY, "-1"); defaults.put(CONF_TAGS_USE_PARENT_DIR, TRUE); defaults.put(CONF_DROP_PLAYED_TRACKS_FROM_QUEUE, FALSE); defaults.put(CONF_BOOKMARKS, ""); defaults.put(CONF_STARTUP_DISPLAY, Integer.toString(DISPLAY_MODE_MAIN_WINDOW)); defaults.put(CONF_BESTOF_TRACKS_SIZE, "20"); defaults.put(CONF_VOLUME, "0.5"); defaults.put(CONF_REGEXP, FALSE); defaults.put(CONF_BACKUP_SIZE, "40"); defaults.put(CONF_PATTERN_REFACTOR, PATTERN_DEFAULT_REORG); defaults.put(CONF_COLLECTION_CHARSET, "UTF-8"); defaults.put(CONF_NETWORK_USE_PROXY, FALSE); defaults.put(CONF_NETWORK_NONE_INTERNET_ACCESS, FALSE); // default proxy name, just a guess defaults.put(CONF_NETWORK_PROXY_HOSTNAME, "proxy"); defaults.put(CONF_NETWORK_PROXY_PORT, "3128"); defaults.put(CONF_NETWORK_PROXY_LOGIN, ""); defaults.put(CONF_NETWORK_CONNECTION_TO, "10"); defaults.put(CONF_NETWORK_PROXY_TYPE, PROXY_TYPE_HTTP); defaults.put(CONF_COVERS_AUTO_COVER, TRUE); defaults.put(CONF_COVERS_MIRROW_COVER, FALSE); defaults.put(CONF_COVERS_SHUFFLE, FALSE); defaults.put(CONF_COVERS_SAVE_EXPLORER_FRIENDLY, FALSE); defaults.put(FILE_DEFAULT_COVER, "front;cover;folder;back"); defaults.put(CONF_COVERS_SIZE, "3"); // medium and large defaults.put(CONF_TRACKS_TABLE_EDITION, FALSE); defaults.put(CONF_FILES_TABLE_EDITION, FALSE); defaults.put(CONF_ALBUMS_TABLE_EDITION, FALSE); defaults.put(CONF_FILES_TABLE_COLUMNS, XML_PLAY + ',' + Const.XML_TRACK + ',' + Const.XML_ALBUM + ',' + Const.XML_ARTIST + ',' + Const.XML_TRACK_GENRE + ',' + Const.XML_TRACK_RATE + ',' + Const.XML_TRACK_LENGTH); defaults.put(CONF_TRACKS_TABLE_COLUMNS, XML_PLAY + ',' + Const.XML_NAME + ',' + Const.XML_ALBUM + ',' + Const.XML_ARTIST + ',' + Const.XML_TRACK_GENRE + ',' + Const.XML_TRACK_LENGTH + ',' + ',' + Const.XML_TRACK_RATE); defaults.put(CONF_PLAYLIST_EDITOR_COLUMNS, XML_PLAY + ',' + Const.XML_TRACK_NAME + ',' + ',' + Const.XML_TRACK_ARTIST + ',' + Const.XML_TRACK_RATE); defaults.put(CONF_PLAYLIST_REPOSITORY_COLUMNS, XML_PLAY + ',' + Const.XML_NAME + ',' + Const.XML_PATH); defaults.put(CONF_QUEUE_COLUMNS, XML_PLAY + ',' + Const.XML_TRACK_NAME + ',' + ',' + Const.XML_TRACK_ARTIST + ',' + Const.XML_TRACK_RATE); defaults.put(CONF_ALBUMS_TABLE_COLUMNS, XML_PLAY + ',' + Const.XML_ALBUM + ',' + Const.XML_ARTIST + ',' + Const.XML_GENRE + ',' + Const.XML_YEAR + ',' + Const.XML_TRACK_RATE + ',' + Const.XML_TRACK_LENGTH + ',' + Const.XML_TRACKS + ',' + Const.XML_TRACK_DISCOVERY_DATE); int width = 800; int height = 600; // When ran as unit tests, no X11 server is available, catch HeadLess // Exception try { // Default Window position: X,Y,X_size,Y_size width = (int) (Toolkit.getDefaultToolkit().getScreenSize().getWidth()); // Limit initial screen size (reported as problematic by some users on // dual // heads) if (width > 1400) { width = 1200; } else { width = width - 2 * FRAME_INITIAL_BORDER; } height = (int) (Toolkit.getDefaultToolkit().getScreenSize().getHeight()); if (height > 1200) { height = 1000; } else { height = height - 2 * FRAME_INITIAL_BORDER; } } catch (HeadlessException he) { Log.debug("No graphical server available, use default screen values"); } defaults.put(CONF_WINDOW_POSITION, FRAME_INITIAL_BORDER + "," + FRAME_INITIAL_BORDER + "," + width + "," + height); defaults.put(CONF_WINDOW_MAXIMIZED, "false"); defaults.put(CONF_THUMBS_SHOW_COVER, Integer.toString(Const.CATALOG_VIEW_COVER_MODE_ALL)); defaults.put(CONF_THUMBS_SIZE, THUMBNAIL_SIZE_100X100); defaults.put(CONF_THUMBS_SORTER, "2"); // sort by album // filter on albums defaults.put(CONF_THUMBS_FILTER, "0"); defaults.put(CONF_WIKIPEDIA_LANGUAGE, defaults.get(CONF_OPTIONS_LANGUAGE)); defaults.put(CONF_FADE_DURATION, "6"); // sort by genre defaults.put(CONF_LOGICAL_TREE_SORT_ORDER, "0"); defaults.put(CONF_DEFAULT_DJ, "");// default dj defaults.put(CONF_DEFAULT_AMBIENCE, "");// default ambience // wrong player show again boolean defaults.put(CONF_GLOBAL_RANDOM_MODE, MODE_TRACK); defaults.put(CONF_NOVELTIES_MODE, MODE_TRACK); defaults.put(CONF_PATTERN_ANIMATION, PATTERN_DEFAULT_ANIMATION); defaults.put(CONF_FRAME_POS_FORCED, ""); defaults.put(CONF_OPTIONS_HOTKEYS, FALSE); defaults.put(CONF_MPLAYER_ARGS, ""); defaults.put(CONF_ENV_VARIABLES, ""); defaults.put(CONF_USE_VOLNORM, "false"); defaults.put(CONF_SHOW_TIP_ON_STARTUP, FALSE); defaults.put(CONF_CATALOG_PAGE_SIZE, "100"); defaults.put(CONF_SHOW_POPUPS, FALSE); defaults.put(CONF_SHOW_SYSTRAY, TRUE); defaults.put(CONF_MINIMIZE_TO_TRAY, FALSE); defaults.put(CONF_FONTS_SIZE, "12"); defaults.put(CONF_MPLAYER_PATH_FORCED, ""); defaults.put(CONF_INC_RATING, "5"); defaults.put(CONF_OPTIONS_LNF, LNF_DEFAULT_THEME); defaults.put(CONF_DEFAULT_WEB_RADIO, DEFAULT_WEBRADIO); defaults.put(CONF_CHECK_FOR_UPDATE, TRUE); defaults.put(CONF_IGNORED_RELEASES, ""); defaults.put(CONF_LASTFM_AUDIOSCROBBLER_ENABLE, FALSE); defaults.put(CONF_LASTFM_INFO, TRUE); defaults.put(CONF_WEBRADIO_WAS_PLAYING, FALSE); defaults.put(CONF_PERSPECTIVE_ICONS_SIZE, "32"); // We use trailing pattern to allow scripting like MSN plugins to // detect jajuk frames and extract current track defaults.put(CONF_PATTERN_FRAME_TITLE, '~' + PATTERN_TRACKNAME + " (" + PATTERN_ARTIST + ")~"); defaults.put(CONF_PATTERN_BALLOON_NOTIFIER, Messages.getString("FIFO.10") + " " + Messages.getString("InformationJPanel.8")); defaults.put(CONF_PATTERN_INFORMATION, Messages.getString("FIFO.10") + " " + Messages.getString("InformationJPanel.8")); defaults.put(CONF_SHOW_DUPLICATE_PLAYLISTS, FALSE); defaults.put(CONF_FORMAT_TIME_ELAPSED, "0"); defaults.put(CONF_AUTO_SCROLL, TRUE); // By defaults, display slimbar at the center of the screen to fix #768 : under MAC, // it is overlaid the menu bar (the menu bar can't be overlaid, even by always on top frames) defaults.put(CONF_SLIMBAR_POSITION, (width / 2) + "," + (height / 2)); defaults.put(CONF_SLIMBAR_DISPLAY_QUEUE, FALSE); defaults.put(CONF_SLIMBAR_SMART_MODE, JajukActions.SHUFFLE_GLOBAL.toString()); defaults.put(CONF_ALARM_ACTION, ALARM_START_ACTION); defaults.put(CONF_ALARM_ENABLED, FALSE); defaults.put(CONF_ALARM_FILE, ""); defaults.put(CONF_ALARM_MODE, STARTUP_MODE_SHUFFLE); defaults.put(CONF_ALARM_TIME_HOUR, "08"); defaults.put(CONF_ALARM_TIME_MINUTES, "00"); defaults.put(CONF_ALARM_TIME_SECONDS, "00"); defaults.put(CONF_EXPLORER_PATH, ""); // NOT SHOW AGAIN defaults.put(CONF_NOT_SHOW_AGAIN_PLAYER, FALSE); defaults.put(CONF_NOT_SHOW_AGAIN_CONCURRENT_SESSION, FALSE); defaults.put(CONF_NOT_SHOW_AGAIN_CROSS_FADE, FALSE); defaults.put(CONF_NOT_SHOW_AGAIN_LAF_CHANGE, FALSE); //Refresh delay to slow down refresh (some NAS are crashing due to intensive load) defaults.put(CONF_REFRESHING_DELAY_MS, "0"); // Make a copy of default values properties = (Properties) defaults.clone(); } /** * Return default property for given key. * * @param key DOCUMENT_ME * * @return default property for given key */ public static String getDefaultProperty(String key) { return defaults.getProperty(key); } /** * Restore a specific property. * * @param key property name to restore */ public static void restoreValue(String key) { setProperty(key, defaults.getProperty(key)); } /** * Set a property. * * @param sName DOCUMENT_ME * @param sValue DOCUMENT_ME */ public static void setProperty(String sName, String sValue) { properties.setProperty(sName, sValue); } /** * Commit properties into a file. Some preferences corruption * have been reported (see https://trac.jajuk.info/ticket/1611) * so we added more robust commit features : we commit the properties * to a temporary file, try to parse it back (to detect invalid characters like \n) and * if the parsing is ok, we override the old preference file with the * temporary one. * * @throws IOException Signals that an I/O exception has occurred. */ public static void commit() throws IOException { File fTempFile = SessionService.getConfFileByPath(Const.FILE_CONFIGURATION_TEMP); OutputStream str = new FileOutputStream(fTempFile); // Write the temporary file try { properties.store(str, "User configuration"); } finally { str.flush(); str.close(); } // Check if it is valid checkTempPreferenceFile(); // If still here, we override the old preference file // by the temporary one. // Note that the system may crash then. It is why'll try // to load the temp file at next startup if we can't find // the regular file. overridePreferenceFile(); } /** * Check if the temporary preference file is valid. * * @throws IOException if the file is invalid */ private static void checkTempPreferenceFile() throws IOException { File fTempFile = SessionService.getConfFileByPath(Const.FILE_CONFIGURATION_TEMP); // Try to parse it again InputStream in = new FileInputStream(fTempFile); try { new Properties().load(in); } finally { in.close(); } } /** * Override. * * @throws IOException Signals that an I/O exception has occurred. */ private static void overridePreferenceFile() throws IOException { File finalFile = SessionService.getConfFileByPath(Const.FILE_CONFIGURATION); File fTempFile = SessionService.getConfFileByPath(Const.FILE_CONFIGURATION_TEMP); try { UtilSystem.move(fTempFile, finalFile); } catch (Exception e) { throw new IOException(e); } } /** * Contains property. * * @param property DOCUMENT_ME * * @return whether the given property is known */ public static boolean containsProperty(String property) { return properties.containsKey(property); } /** * Load properties from in file. */ public static void load() { try { InputStream str = new FileInputStream(SessionService .getConfFileByPath(Const.FILE_CONFIGURATION)); try { properties.load(str); } finally { str.close(); } } catch (IOException e) { e.printStackTrace(); // do not use log system here Messages.showErrorMessage(114); } } /** * Gets the properties. * * @return Returns the properties. */ public static Properties getProperties() { return properties; } /** * Remove a property. * * @param sKey property key to remove */ public static void removeProperty(String sKey) { properties.remove(sKey); } }jajuk-1.9.6.orig/src/main/java/org/jajuk/util/Messages.java0000644000175000017500000005713411720500104023404 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.util; import java.awt.Component; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.net.URL; import java.util.ArrayList; import java.util.List; import java.util.Locale; import java.util.Properties; import java.util.StringTokenizer; import javax.swing.Icon; import javax.swing.ImageIcon; import javax.swing.JDialog; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTextArea; import javax.swing.SwingUtilities; import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; import net.miginfocom.swing.MigLayout; import org.jajuk.ui.widgets.OKCancelPanel; import org.jajuk.ui.windows.JajukMainWindow; import org.jajuk.util.log.Log; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; /** * Utility class to get strings from localized property files *

    * Singleton *

    . */ public class Messages extends DefaultHandler { /** Messages initialized flag. */ protected static boolean bInitialized = false; /** All choice option, completes JDialog options. */ public static final int ALL_OPTION = 10; /** Specific Yes NO All Cancel option. */ public static final int YES_NO_ALL_CANCEL_OPTION = 11; /** User choice. */ private static int choice; /** Messages themselves extracted from an XML file to this properties class*. */ protected static Properties properties; /** English messages used as default*. */ private static Properties propertiesEn; /** * Contains. * * @param sKey DOCUMENT_ME * * @return whether given key exists */ public static boolean contains(final String sKey) { return getPropertiesEn().containsKey(sKey); } /** * Gets the string. * * @param key DOCUMENT_ME * * @return the string */ public static String getString(final String key) { String sOut = key; try { sOut = getProperties().getProperty(key); if (sOut == null) { // this property is unknown for this local, try // in English sOut = getPropertiesEn().getProperty(key); } // at least, returned property is the key name but we trace an // error to show it if (sOut == null) { Log.error(105, "key: " + key, new Exception()); sOut = key; } } catch (final Exception e) { // system error Log.error(e); } return sOut; } /** * Fetch all messages from a given base key. *

    * Example: * *

       * example.0=Message 1
       * example.1=Message 2
       * example.2=Message 3
       * 
    * * Using Messages.getAll("example"); will return a size 3 String * array containing the messages in order. *

    * The keys need to have continuous numbers. So, adding * example.5=Message 5 to the bundle, will not result in adding it to * the array without first adding example.3 and example.4. * * @param base The base to use for generating the keys. * * @return An array of Strings containing the messages linked to the key, * never null. If base.0 is not found, and empty * array is returned. */ public static String[] getAll(final String base) { final List msgs = new ArrayList(); final String prefix = base + "."; try { final Properties lProperties = getProperties(); final Properties defaultProperties = getPropertiesEn(); for (int i = 0;; i++) { String sOut = lProperties.getProperty(prefix + i); if (sOut == null) { // this property is unknown for this local, try in English sOut = defaultProperties.getProperty(prefix + i); // unknown property, assume we found all properties in the set if (sOut == null) { break; } } else { // Remove HTML tags sOut = sOut.replaceAll("<.*>", ""); } msgs.add(sOut); } } catch (final Exception e) { // System error Log.error(e); } return msgs.toArray(new String[msgs.size()]); } /** * Gets the shuffle tip of the day. * * @return a shuffled tip of the day
    */ public static String getShuffleTipOfTheDay() { try { String totd = null; String[] tips = Messages.getAll("TipOfTheDay"); // index contains the index of the last provided totd int index = (int) (UtilSystem.getRandom().nextFloat() * (tips.length - 1)); // display the next one totd = Messages.getString("TipOfTheDay." + index); // Remove tags totd = totd.replaceAll("<.*>", ""); // Increment and save index return totd; } catch (Exception e) { Log.error(e); // Make sure to handle every problem: this code is used in slash screen // and we won't propagate exception that could prevent jajuk from starting return ""; } } /** * Return Flag icon for given description. * * @param sDesc DOCUMENT_ME * * @return the icon */ public static Icon getIcon(final String sDesc) { Icon icon = new ImageIcon(UtilSystem.getResource("icons/16x16/flag_" + LocaleManager.getLocaleForDesc(sDesc) + ".png")); return icon; } /** * *************************************************************************** * Parse a fake properties file inside an XML file as CDATA. * * @param locale DOCUMENT_ME * * @return a properties with all entries * * @throws IOException Signals that an I/O exception has occurred. * @throws SAXException the SAX exception * @throws ParserConfigurationException the parser configuration exception * @throws Exception */ private static Properties parseLangpack(final Locale locale) throws SAXException, IOException, ParserConfigurationException { final Properties lProperties = new Properties(); // Choose right jajuk_.properties file to load final StringBuilder sbFilename = new StringBuilder(Const.FILE_LANGPACK_PART1); if (!Locale.ENGLISH.equals(locale)) { // for English, properties file is // simply jajuk.properties sbFilename.append('_').append(locale); } sbFilename.append(Const.FILE_LANGPACK_PART2); // property file URL, either in the jajuk.jar jar // (normal execution) or found as regular file if in // development debug mode String resource = "org/jajuk/i18n/" + sbFilename.toString(); URL url = UtilSystem.getResource(resource); if (url == null) { throw new IOException("Could not read resource: " + resource); } // parse it, actually it is a big properties file as CDATA in an XML // file final SAXParserFactory spf = SAXParserFactory.newInstance(); spf.setValidating(false); spf.setNamespaceAware(false); final SAXParser saxParser = spf.newSAXParser(); saxParser.parse(url.openStream(), new DefaultHandler() { // this buffer will contain the entire properties strings StringBuilder sb = new StringBuilder(15000); // call for each element strings, actually will be called // several time if the element is large (our case : large CDATA) @Override public void characters(final char[] ch, final int start, final int length) throws SAXException { sb.append(ch, start, length); } // call when closing the tag ( in our case ) @Override public void endElement(final String uri, final String localName, final String qName) throws SAXException { final String sWhole = sb.toString(); // ok, parse it ( comments start with #) final StringTokenizer st = new StringTokenizer(sWhole, "\n"); while (st.hasMoreTokens()) { final String sLine = st.nextToken(); if ((sLine.length() > 0) && !sLine.startsWith("#") && (sLine.indexOf('=') != -1)) { final StringTokenizer stLine = new StringTokenizer(sLine, "="); // get full value after the '=', we don't use the // stringtokenizer to allow // using = characters in the value final String sValue = sLine.substring(sLine.indexOf('=') + 1); // trim to ignore space at begin end end of lines lProperties.put(stLine.nextToken().trim(), sValue); } } } }); return lProperties; } /** * Return the message display to the user corresponding to the error code. * * @param code Error code. * * @return String Message corresponding to the error code. */ public static String getErrorMessage(final int code) { String sOut = Integer.toString(code); try { sOut = getString("Error." + UtilString.padNumber(code, 3)); } catch (final Exception e) { System.out.println("### Error getting error message for code: " + code); } return sOut; } /** * Show a dialog waiting for a user decision *

    * CAUTION! the thread which calls this method musn't have locks on resources * : otherwise it can conduct to GUI freeze *

    . * * @param sText : dialog text * @param iType message type like JOptionPane.WARNING * @param optionsType DOCUMENT_ME * * @return the choice */ public static int getChoice(final String sText, final int optionsType, final int iType) { try { // Make sure to reset the choice and to return a non-existing choice if // the GUI fails choice = JOptionPane.DEFAULT_OPTION; Runnable t = new Thread("Get choice thread") { @Override public void run() { // This must be done in the EDT final ConfirmDialog confirm = new ConfirmDialog(sText, getTitleForType(iType), optionsType, iType, JajukMainWindow.getInstance()); choice = confirm.getResu(); } }; // invokeAndWait method cannot be called from the EDT if (SwingUtilities.isEventDispatchThread()) { t.run(); } else { SwingUtilities.invokeAndWait(t); } } catch (InterruptedException e) { Log.error(e); } catch (InvocationTargetException e) { Log.error(e); } return choice; } /** * Gets the title for type. * * @param iType DOCUMENT_ME * * @return String for given JOptionPane message type */ private static String getTitleForType(final int iType) { switch (iType) { case JOptionPane.ERROR_MESSAGE: return Messages.getString("Error"); case JOptionPane.WARNING_MESSAGE: return Messages.getString("Warning"); case JOptionPane.INFORMATION_MESSAGE: return Messages.getString("Info"); } return ""; } /** * Show a dialog with specified warning message. * * @param sMessage DOCUMENT_ME */ public static void showWarningMessage(final String sMessage) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { new DetailsMessageDialog(sMessage, getTitleForType(JOptionPane.WARNING_MESSAGE), JOptionPane.WARNING_MESSAGE, null, null); } }); } /** * Show a dialog with specified warning message + a "not show again" button. * * @param sMessage DOCUMENT_ME * @param sProperty : property name */ public static void showHideableWarningMessage(final String sMessage, final String sProperty) { // User required to hide this message if (Conf.getBoolean(sProperty)) { return; } SwingUtilities.invokeLater(new Runnable() { @Override public void run() { final HideableMessageDialog message = new HideableMessageDialog(sMessage, getTitleForType(JOptionPane.WARNING_MESSAGE), sProperty, JOptionPane.WARNING_MESSAGE, null); message.getResu(); } }); } /** * Show a dialog with specified error message and an icon. * * @param sMessage DOCUMENT_ME * @param icon DOCUMENT_ME */ public static void showInfoMessage(final String sMessage, final Icon icon) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { new DetailsMessageDialog(sMessage, getTitleForType(JOptionPane.INFORMATION_MESSAGE), JOptionPane.INFORMATION_MESSAGE, null, icon); } }); } /** * Show a dialog with specified error message and infosup. * * @param code DOCUMENT_ME * @param sInfoSup DOCUMENT_ME */ public static void showErrorMessage(final int code, final String sInfoSup) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { new ErrorMessageDialog(code, sInfoSup); } }); } /** * Show a dialog with specified error message. * * @param code DOCUMENT_ME */ public static void showErrorMessage(final int code) { showErrorMessage(code, null); } /** * Show a dialog with specified error message and infosup and details. * * @param sInfoSup DOCUMENT_ME * @param code DOCUMENT_ME * @param sDetails DOCUMENT_ME */ public static void showDetailedErrorMessage(final int code, final String sInfoSup, final String sDetails) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { new DetailsMessageDialog(Messages.getErrorMessage(code) + " : " + sInfoSup, getTitleForType(JOptionPane.ERROR_MESSAGE), JOptionPane.ERROR_MESSAGE, sDetails, null); } }); } /** * Show a dialog with specified error message with infos up. * * @param sMessage DOCUMENT_ME * @param sInfoSup DOCUMENT_ME */ public static void showInfoMessage(final String sMessage, final String sInfoSup) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { new DetailsMessageDialog(sMessage + " : " + sInfoSup, getTitleForType(JOptionPane.INFORMATION_MESSAGE), JOptionPane.INFORMATION_MESSAGE, null, null); } }); } /** * Show a dialog with specified error message. * * @param sMessage DOCUMENT_ME */ public static void showInfoMessage(final String sMessage) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { new DetailsMessageDialog(sMessage, getTitleForType(JOptionPane.INFORMATION_MESSAGE), JOptionPane.INFORMATION_MESSAGE, null, null); } }); } /** * Return true if the messaging system is started, can be useful mainly at * startup by services ( like logs) using them to avoid dead locks Messages * service is initialized after current has been set. * * @return true, if checks if is initialized */ public static boolean isInitialized() { return bInitialized; } /** * Gets localized and human property name for given key. * * @param sKey DOCUMENT_ME * * @return the human property name or the property itself if not translated */ public static String getHumanPropertyName(String sKey) { String sOut = sKey; if (Messages.contains(Const.PROPERTY_SEPARATOR + sKey)) { return Messages.getString(Const.PROPERTY_SEPARATOR + sKey); } return sOut; } /** * Gets the properties. * * @return Returns the properties. * * @throws ParserConfigurationException the parser configuration exception * @throws IOException Signals that an I/O exception has occurred. * @throws SAXException the SAX exception */ public static Properties getProperties() throws SAXException, IOException, ParserConfigurationException { if (properties == null) { // reuse English if possible if (Locale.ENGLISH.equals(LocaleManager.getLocale())) { properties = getPropertiesEn(); } else { properties = parseLangpack(LocaleManager.getLocale()); } } return properties; } /** * Gets the properties en. * * @return Returns the propertiesEn. */ public static Properties getPropertiesEn() { if (propertiesEn == null) { try { propertiesEn = parseLangpack(Locale.ENGLISH); } catch (final Exception e) { Log.error(e); } } return propertiesEn; } } /** * Confirmation Dialog */ class ConfirmDialog extends JajukDialog { /** * Confirm dialog constructor * * @param sText * @param sTitle * @param int optionType : kind of options like JOptionPane.OK_CANCEL *

    * Specific option: Messages.ALL_OPTION *

    * @param iType * message type like JOptionPane.WARNING */ ConfirmDialog(final String sText, final String sTitle, final int optionsType, final int iType, Component parent) { super(); final JOptionPane optionPane = UtilGUI.getNarrowOptionPane(72); if (optionsType == Messages.YES_NO_ALL_CANCEL_OPTION) { optionPane.setOptions(new Object[] { Messages.getString("Yes"), Messages.getString("No"), Messages.getString("YestoAll"), Messages.getString("Cancel") }); } else { optionPane.setOptionType(optionsType); } optionPane.setMessageType(iType); optionPane.setMessage(UtilGUI.getLimitedMessage(sText, 20)); final JDialog dialog = optionPane.createDialog(null, sTitle); dialog.setModal(true); dialog.setAlwaysOnTop(true); dialog.pack(); dialog.setLocationRelativeTo(parent); dialog.setVisible(true); final Object resu = optionPane.getValue(); // Set Cancel as default iResu = JOptionPane.CANCEL_OPTION; if (optionPane.getValue() == null) { // User closed the dialog using the cross icon iResu = JOptionPane.CANCEL_OPTION; } else if (resu instanceof String) { // Options are string when using custom options if (resu.equals(Messages.getString("YestoAll"))) { iResu = Messages.ALL_OPTION; } else if (resu.equals(Messages.getString("Yes"))) { iResu = JOptionPane.YES_OPTION; } else if (resu.equals(Messages.getString("No"))) { iResu = JOptionPane.NO_OPTION; } else if (resu.equals(Messages.getString("Cancel"))) { iResu = JOptionPane.CANCEL_OPTION; } else if (resu.equals(Messages.getString("Ok"))) { iResu = JOptionPane.OK_OPTION; } else if (resu.equals(Messages.getString("Default"))) { iResu = JOptionPane.DEFAULT_OPTION; } } else if (resu instanceof Integer) { // result is an integer when using JOptionPane standard types iResu = (Integer) resu; } // manually dispose to free up memory, somehow this is not done automatically! dialog.dispose(); } } /** * Message Dialog */ class DetailsMessageDialog extends JajukDialog { /** * Message dialog constructor * * @param sText * @param sTitle * @param iType */ DetailsMessageDialog(final String sText, final String sTitle, final int iType, final String sDetails, final Icon icon) { super(); final JOptionPane optionPane = UtilGUI.getNarrowOptionPane(72); optionPane.setMessage(sText); if (sDetails != null) { final Object[] options = { Messages.getString("Ok"), Messages.getString("Details") }; optionPane.setOptions(options); } optionPane.setMessageType(iType); if (icon != null) { optionPane.setIcon(icon); } final JDialog dialog = optionPane.createDialog(null, sTitle); dialog.setModal(true); dialog.setAlwaysOnTop(true); dialog.setVisible(true); if (optionPane.getValue().equals(Messages.getString("Details"))) { // details final JDialog dialogDetail = new JDialog(dialog, Messages.getString("Details")); final JPanel jp = new JPanel(); jp.setLayout(new MigLayout("ins 5", "[800]", "[600][]")); final JTextArea jta = new JTextArea(sDetails); jta.setEditable(false); jp.add(new JScrollPane(jta), "wrap"); final OKCancelPanel jbOKC = new OKCancelPanel(new ActionListener() { @Override public void actionPerformed(final ActionEvent arg0) { dialogDetail.dispose(); } }); jp.add(jbOKC, "span,alignx center"); dialogDetail.setModal(true); dialogDetail.setAlwaysOnTop(true); dialogDetail.setContentPane(jp); dialogDetail.pack(); dialogDetail.setLocationRelativeTo(JajukMainWindow.getInstance()); dialogDetail.setVisible(true); // manually dispose to free up memory, somehow this is not done automatically! dialog.dispose(); } // manually dispose to free up memory, somehow this is not done automatically! dialog.dispose(); } } /** * Hideable message dialog (has a "not show again" button) */ class HideableMessageDialog extends JajukDialog { /** * Message dialog constructor * * @param sText * @param sTitle * @param sProperty * @param iType * @param icon */ HideableMessageDialog(final String sText, final String sTitle, final String sProperty, final int iType, final Icon icon) { super(); final JOptionPane optionPane = UtilGUI.getNarrowOptionPane(72); optionPane.setMessage(UtilGUI.getLimitedMessage(sText, 20)); final Object[] options = { Messages.getString("Ok"), Messages.getString("Hide") }; optionPane.setOptions(options); optionPane.setMessageType(iType); if (icon != null) { optionPane.setIcon(icon); } final JDialog dialog = optionPane.createDialog(null, sTitle); dialog.setAlwaysOnTop(true); // keep it modal (useful at startup) dialog.setModal(true); dialog.pack(); dialog.setLocationRelativeTo(JajukMainWindow.getInstance()); dialog.setVisible(true); if (Messages.getString("Hide").equals(optionPane.getValue())) { // Not show again Conf.setProperty(sProperty, Const.TRUE); } // manually dispose to free up memory, somehow this is not done automatically! dialog.dispose(); } } /** * Error message dialog */ class ErrorMessageDialog extends JajukDialog { /** * Message dialog constructor * * @param sText * @param sTitle * @param sProperty * @param iType * @param icon */ ErrorMessageDialog(final int code, final String sInfoSup) { super(); final JOptionPane optionPane = UtilGUI.getNarrowOptionPane(72); optionPane.setMessage(UtilGUI.getLimitedMessage(Messages.getErrorMessage(code) + (sInfoSup != null ? (" : " + sInfoSup) : ""), 20)); final Object[] options = { Messages.getString("Ok") }; optionPane.setOptions(options); optionPane.setMessageType(JOptionPane.ERROR_MESSAGE); final JDialog dialog = optionPane.createDialog(null, Messages.getString("Error")); dialog.setAlwaysOnTop(true); // keep it modal (useful at startup) dialog.setModal(true); dialog.pack(); dialog.setLocationRelativeTo(JajukMainWindow.getInstance()); dialog.setVisible(true); // manually dispose to free up memory, somehow this is not done automatically! dialog.dispose(); } } abstract class JajukDialog { /** Dialog output */ protected int iResu = -2; /** * * @return the user option */ public int getResu() { return iResu; } } jajuk-1.9.6.orig/src/main/java/org/jajuk/util/IconLoader.java0000644000175000017500000007562311720500104023657 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.util; import java.util.HashMap; import java.util.Map; import javax.swing.ImageIcon; /** * Load icons from this class *

    * Use: IconLoader.getIcon(JajukIcons.) *

    */ final public class IconLoader { /** Icons cache *. */ private static Map cache = new HashMap(200); /** * No instantiation. */ private IconLoader() { } /** * Gets the no cover icon. * * @param size The size of the icon to return. * * @return the nocover icon for specified size */ public static ImageIcon getNoCoverIcon(int size) { String constant = new StringBuilder("NO_COVER_").append(size).append('X').append(size) .toString(); return getIcon(JajukIcons.valueOf(JajukIcons.class, constant)); } /** * Gets the icon. * * @param icon the JajukIcons name * * @return an image icon for given icon name.Note that all images are cached * before being returned. */ public static ImageIcon getIcon(JajukIcons icon) { // Try to recover the icon from the cache first if (cache.containsKey(icon)) { return cache.get(icon); } ImageIcon out = null; if (icon == JajukIcons.NO_COVER) { out = new ImageIcon(UtilSystem.getResource("images/included/" + Const.FILE_THUMB_NO_COVER)); } else if (icon == JajukIcons.NONE) { out = new ImageIcon(UtilSystem.getResource("images/included/" + Const.FILE_THUMB_NONE)); } else if (icon == JajukIcons.NO_COVER_50X50) { out = UtilGUI.getResizedImage(getIcon(JajukIcons.NO_COVER), 50, 50); } else if (icon == JajukIcons.NO_COVER_100X100) { out = UtilGUI.getResizedImage(getIcon(JajukIcons.NO_COVER), 100, 100); } else if (icon == JajukIcons.NO_COVER_150X150) { out = UtilGUI.getResizedImage(getIcon(JajukIcons.NO_COVER), 150, 150); } else if (icon == JajukIcons.NO_COVER_200X200) { out = UtilGUI.getResizedImage(getIcon(JajukIcons.NO_COVER), 200, 200); } else if (icon == JajukIcons.NO_COVER_250X250) { out = UtilGUI.getResizedImage(getIcon(JajukIcons.NO_COVER), 250, 250); } else if (icon == JajukIcons.NO_COVER_300X300) { out = UtilGUI.getResizedImage(getIcon(JajukIcons.NO_COVER), 300, 300); } else if (icon == JajukIcons.LOGO) { out = new ImageIcon(UtilSystem.getResource("icons/64x64/jajuk-icon_64x64.png")); } else if (icon == JajukIcons.TRAY) { out = new ImageIcon(UtilSystem.getResource("icons/22x22/jajuk-icon_22x22.png")); } else if (icon == JajukIcons.COVER_16X16) { out = new ImageIcon(UtilSystem.getResource("icons/16x16/thumbnail_16x16.png")); } // Correctly displayed under JRE 1.6, ugly under Linux/JRE 1.5 else if (icon == JajukIcons.LOGO_FRAME) { out = new ImageIcon(UtilSystem.getResource("icons/16x16/jajuk-icon_16x16.png")); } else if (icon == JajukIcons.REPEAT) { out = new ImageIcon(UtilSystem.getResource("icons/16x16/repeat_16x16.png")); } else if (icon == JajukIcons.REPEAT_ALL) { out = new ImageIcon(UtilSystem.getResource("icons/16x16/repeat_all_16x16.png")); } else if (icon == JajukIcons.SHUFFLE) { out = new ImageIcon(UtilSystem.getResource("icons/16x16/shuffle_16x16.png")); } else if (icon == JajukIcons.CONTINUE) { out = new ImageIcon(UtilSystem.getResource("icons/16x16/continue_16x16.png")); } else if (icon == JajukIcons.INTRO) { out = new ImageIcon(UtilSystem.getResource("icons/16x16/intro_16x16.png")); } else if (icon == JajukIcons.KARAOKE) { out = new ImageIcon(UtilSystem.getResource("icons/16x16/karaoke_16x16.png")); } else if (icon == JajukIcons.SHUFFLE_GLOBAL) { out = new ImageIcon(UtilSystem.getResource("icons/32x32/shuffle_global_32x32.png")); } else if (icon == JajukIcons.SHUFFLE_GLOBAL_16X16) { out = new ImageIcon(UtilSystem.getResource("icons/16x16/shuffle_global_16x16.png")); } else if (icon == JajukIcons.BESTOF) { out = new ImageIcon(UtilSystem.getResource("icons/32x32/bestof_32x32.png")); } else if (icon == JajukIcons.BESTOF_16X16) { out = new ImageIcon(UtilSystem.getResource("icons/16x16/bestof_16x16.png")); } else if (icon == JajukIcons.MUTED) { out = new ImageIcon(UtilSystem.getResource("icons/32x32/mute_32x32.png")); } else if (icon == JajukIcons.VOLUME_LEVEL1) { out = new ImageIcon(UtilSystem.getResource("icons/32x32/volume1.png")); } else if (icon == JajukIcons.VOLUME_LEVEL2) { out = new ImageIcon(UtilSystem.getResource("icons/32x32/volume2.png")); } else if (icon == JajukIcons.VOLUME_LEVEL3) { out = new ImageIcon(UtilSystem.getResource("icons/32x32/volume3.png")); } else if (icon == JajukIcons.WEBRADIO) { out = new ImageIcon(UtilSystem.getResource("icons/32x32/webradio_32x32.png")); } else if (icon == JajukIcons.NOVELTIES) { out = new ImageIcon(UtilSystem.getResource("icons/32x32/novelties_32x32.png")); } else if (icon == JajukIcons.NOVELTIES_16X16) { out = new ImageIcon(UtilSystem.getResource("icons/16x16/novelties_16x16.png")); } else if (icon == JajukIcons.PLAYER_NEXT_SMALL) { out = new ImageIcon(UtilSystem.getResource("icons/16x16/player_next_16x16.png")); } else if (icon == JajukIcons.SAVE_AS) { out = new ImageIcon(UtilSystem.getResource("icons/16x16/saveas_16x16.png")); } else if (icon == JajukIcons.PLAYER_PREVIOUS_SMALL) { out = new ImageIcon(UtilSystem.getResource("icons/16x16/player_previous_16x16.png")); } else if (icon == JajukIcons.PLAYER_PREVIOUS) { out = new ImageIcon(UtilSystem.getResource("icons/32x32/player_previous_32x32.png")); } else if (icon == JajukIcons.PLAYER_PREVIOUS_BIG) { out = new ImageIcon(UtilSystem.getResource("icons/64x64/player_previous_64x64.png")); } else if (icon == JajukIcons.PLAYER_NEXT) { out = new ImageIcon(UtilSystem.getResource("icons/32x32/player_next_32x32.png")); } else if (icon == JajukIcons.PLAYER_NEXT_BIG) { out = new ImageIcon(UtilSystem.getResource("icons/64x64/player_next_64x64.png")); } else if (icon == JajukIcons.INC_RATING) { out = new ImageIcon(UtilSystem.getResource("icons/16x16/inc_rating_16x16.png")); } else if (icon == JajukIcons.REW) { out = new ImageIcon(UtilSystem.getResource("icons/32x32/player_rew_32x32.png")); } else if (icon == JajukIcons.PLAYER_REWIND_BIG) { out = new ImageIcon(UtilSystem.getResource("icons/64x64/player_rew_64x64.png")); } else if (icon == JajukIcons.AUTOSCROLL) { out = new ImageIcon(UtilSystem.getResource("icons/16x16/autoscroll.png")); } else if (icon == JajukIcons.REW_16X16) { out = new ImageIcon(UtilSystem.getResource("icons/16x16/player_rew_16x16.png")); } else if (icon == JajukIcons.PLAYER_PLAY) { out = new ImageIcon(UtilSystem.getResource("icons/32x32/player_play_32x32.png")); } else if (icon == JajukIcons.PLAYER_PLAY_BIG) { out = new ImageIcon(UtilSystem.getResource("icons/64x64/player_play_64x64.png")); } else if (icon == JajukIcons.PLAY_16X16) { out = new ImageIcon(UtilSystem.getResource("icons/16x16/player_play_16x16.png")); } else if (icon == JajukIcons.PLAYER_PAUSE) { out = new ImageIcon(UtilSystem.getResource("icons/32x32/player_pause_32x32.png")); } else if (icon == JajukIcons.PLAYER_PAUSE_BIG) { out = new ImageIcon(UtilSystem.getResource("icons/64x64/player_pause_64x64.png")); } else if (icon == JajukIcons.PAUSE_16X16) { out = new ImageIcon(UtilSystem.getResource("icons/16x16/player_pause_16x16.png")); } else if (icon == JajukIcons.PLAYER_STOP) { out = new ImageIcon(UtilSystem.getResource("icons/32x32/player_stop_32x32.png")); } else if (icon == JajukIcons.PLAYER_STOP_BIG) { out = new ImageIcon(UtilSystem.getResource("icons/64x64/player_stop_64x64.png")); } else if (icon == JajukIcons.STOP_16X16) { out = new ImageIcon(UtilSystem.getResource("icons/16x16/player_stop_16x16.png")); } else if (icon == JajukIcons.FWD) { out = new ImageIcon(UtilSystem.getResource("icons/32x32/player_fwd_32x32.png")); } else if (icon == JajukIcons.PLAYER_FORWARD_BIG) { out = new ImageIcon(UtilSystem.getResource("icons/64x64/player_fwd_64x64.png")); } else if (icon == JajukIcons.FWD_16X16) { out = new ImageIcon(UtilSystem.getResource("icons/16x16/player_fwd_16x16.png")); } else if (icon == JajukIcons.VOLUME) { out = new ImageIcon(UtilSystem.getResource("icons/16x16/volume_16x16.png")); } else if (icon == JajukIcons.CLOSE) { out = new ImageIcon(UtilSystem.getResource("icons/16x16/close_16x16.png")); } else if (icon == JajukIcons.SLIM_WINDOW) { out = new ImageIcon(UtilSystem.getResource("icons/16x16/slim_window_16x16.png")); } else if (icon == JajukIcons.FULL_SCREEN) { out = new ImageIcon(UtilSystem.getResource("icons/16x16/full_window_16x16.png")); } else if (icon == JajukIcons.POSITION) { out = new ImageIcon(UtilSystem.getResource("icons/16x16/position_16x16.png")); } else if (icon == JajukIcons.INFO) { out = new ImageIcon(UtilSystem.getResource("icons/16x16/info_16x16.png")); } else if (icon == JajukIcons.BOOKMARK_FOLDERS) { out = new ImageIcon(UtilSystem.getResource("icons/16x16/bookmark_16x16.png")); } else if (icon == JajukIcons.PERSPECTIVE_SIMPLE) { out = new ImageIcon(UtilSystem.getResource("icons/40x40/perspective_simple_40x40.png")); } else if (icon == JajukIcons.PERSPECTIVE_PHYSICAL) { out = new ImageIcon(UtilSystem.getResource("icons/40x40/perspective_physic_40x40.png")); } else if (icon == JajukIcons.PERSPECTIVE_LOGICAL) { out = new ImageIcon(UtilSystem.getResource("icons/40x40/perspective_logic_40x40.png")); } else if (icon == JajukIcons.PERSPECTIVE_STATISTICS) { out = new ImageIcon(UtilSystem.getResource("icons/40x40/perspective_stat_40x40.png")); } else if (icon == JajukIcons.PERSPECTIVE_CONFIGURATION) { out = new ImageIcon(UtilSystem.getResource("icons/40x40/perspective_configuration_40x40.png")); } else if (icon == JajukIcons.PERSPECTIVE_PLAYER) { out = new ImageIcon(UtilSystem.getResource("icons/40x40/perspective_player_40x40.png")); } else if (icon == JajukIcons.PERSPECTIVE_CATALOG) { out = new ImageIcon(UtilSystem.getResource("icons/40x40/perspective_catalog_40x40.png")); } else if (icon == JajukIcons.PERSPECTIVE_PLAYLISTS) { out = new ImageIcon(UtilSystem.getResource("icons/40x40/perspective_playlists_40x40.png")); } else if (icon == JajukIcons.PERSPECTIVE_INFORMATION) { out = new ImageIcon(UtilSystem.getResource("icons/40x40/perspective_information_40x40.png")); } else if (icon == JajukIcons.OPEN_FILE) { out = new ImageIcon(UtilSystem.getResource("icons/16x16/fileopen_16x16.png")); } else if (icon == JajukIcons.EXIT) { out = new ImageIcon(UtilSystem.getResource("icons/16x16/exit_16x16.png")); } else if (icon == JajukIcons.NEW) { out = new ImageIcon(UtilSystem.getResource("icons/16x16/new_16x16.png")); } else if (icon == JajukIcons.SEARCH) { out = new ImageIcon(UtilSystem.getResource("icons/16x16/search_16x16.png")); } else if (icon == JajukIcons.DELETE) { out = new ImageIcon(UtilSystem.getResource("icons/16x16/delete_16x16.png")); } else if (icon == JajukIcons.PROPERTIES) { out = new ImageIcon(UtilSystem.getResource("icons/16x16/properties_16x16.png")); } else if (icon == JajukIcons.VOID) { out = new ImageIcon(UtilSystem.getResource("icons/16x16/void_16x16.png")); } else if (icon == JajukIcons.CONFIGURATION) { out = new ImageIcon(UtilSystem.getResource("icons/16x16/configure_16x16.png")); } else if (icon == JajukIcons.MOUNT) { out = new ImageIcon(UtilSystem.getResource("icons/16x16/mount_16x16.png")); } else if (icon == JajukIcons.UPDATE_MANAGER) { out = new ImageIcon(UtilSystem.getResource("icons/16x16/update_manager_16x16.png")); } else if (icon == JajukIcons.UNMOUNT) { out = new ImageIcon(UtilSystem.getResource("icons/16x16/unmount_16x16.png")); } else if (icon == JajukIcons.TRACES) { out = new ImageIcon(UtilSystem.getResource("icons/16x16/traces_16x16.png")); } else if (icon == JajukIcons.TEST) { out = new ImageIcon(UtilSystem.getResource("icons/16x16/test_16x16.png")); } else if (icon == JajukIcons.REORGANIZE) { out = new ImageIcon(UtilSystem.getResource("icons/16x16/reorganize_16x16.png")); } else if (icon == JajukIcons.REFRESH) { out = new ImageIcon(UtilSystem.getResource("icons/16x16/refresh_16x16.png")); } else if (icon == JajukIcons.RESTORE_ALL_VIEWS) { out = new ImageIcon(UtilSystem.getResource("icons/16x16/refresh_all_16x16.png")); } else if (icon == JajukIcons.SYNCHRO) { out = new ImageIcon(UtilSystem.getResource("icons/16x16/synchro_16x16.png")); } else if (icon == JajukIcons.DEVICE_NEW) { out = new ImageIcon(UtilSystem.getResource("icons/64x64/new_64x64.png")); } else if (icon == JajukIcons.DEVICE_CD_MOUNTED) { out = new ImageIcon(UtilSystem.getResource("icons/64x64/cdrom_mount_64x64.png")); } else if (icon == JajukIcons.DEVICE_CD_UNMOUNTED) { out = new ImageIcon(UtilSystem.getResource("icons/64x64/cdrom_unmount_64x64.png")); } else if (icon == JajukIcons.DEVICE_EXT_DD_MOUNTED) { out = new ImageIcon(UtilSystem.getResource("icons/64x64/ext_dd_mount_64x64.png")); } else if (icon == JajukIcons.DEVICE_EXT_DD_UNMOUNTED) { out = new ImageIcon(UtilSystem.getResource("icons/64x64/ext_dd_unmount_64x64.png")); } else if (icon == JajukIcons.DEVICE_DIRECTORY_MOUNTED) { out = new ImageIcon(UtilSystem.getResource("icons/64x64/folder_mount_64x64.png")); } else if (icon == JajukIcons.DEVICE_DIRECTORY_UNMOUNTED) { out = new ImageIcon(UtilSystem.getResource("icons/64x64/folder_unmount_64x64.png")); } else if (icon == JajukIcons.DEVICE_PLAYER_MOUNTED) { out = new ImageIcon(UtilSystem.getResource("icons/64x64/player_mount_64x64.png")); } else if (icon == JajukIcons.DEVICE_PLAYER_UNMOUNTED) { out = new ImageIcon(UtilSystem.getResource("icons/64x64/player_unmount_64x64.png")); } else if (icon == JajukIcons.DEVICE_NETWORK_DRIVE_MOUNTED) { out = new ImageIcon(UtilSystem.getResource("icons/64x64/nfs_mount_64x64.png")); } else if (icon == JajukIcons.DEVICE_NETWORK_DRIVE_UNMOUNTED) { out = new ImageIcon(UtilSystem.getResource("icons/64x64/nfs_unmount_64x64.png")); } else if (icon == JajukIcons.DEVICE_CD_MOUNTED_SMALL) { out = new ImageIcon(UtilSystem.getResource("icons/22x22/cdrom_mount_22x22.png")); } else if (icon == JajukIcons.DEVICE_CD_UNMOUNTED_SMALL) { out = new ImageIcon(UtilSystem.getResource("icons/22x22/cdrom_unmount_22x22.png")); } else if (icon == JajukIcons.DEVICE_EXT_DD_MOUNTED_SMALL) { out = new ImageIcon(UtilSystem.getResource("icons/22x22/ext_dd_mount_22x22.png")); } else if (icon == JajukIcons.DEVICE_EXT_DD_UNMOUNTED_SMALL) { out = new ImageIcon(UtilSystem.getResource("icons/22x22/ext_dd_unmount_22x22.png")); } else if (icon == JajukIcons.DEVICE_NETWORK_DRIVE_MOUNTED_SMALL) { out = new ImageIcon(UtilSystem.getResource("icons/22x22/nfs_mount_22x22.png")); } else if (icon == JajukIcons.DEVICE_NETWORK_DRIVE_UNMOUNTED_SMALL) { out = new ImageIcon(UtilSystem.getResource("icons/22x22/nfs_unmount_22x22.png")); } else if (icon == JajukIcons.DEVICE_DIRECTORY_MOUNTED_SMALL) { out = new ImageIcon(UtilSystem.getResource("icons/22x22/folder_mount_22x22.png")); } else if (icon == JajukIcons.DEVICE_DIRECTORY_UNMOUNTED_SMALL) { out = new ImageIcon(UtilSystem.getResource("icons/22x22/folder_unmount_22x22.png")); } else if (icon == JajukIcons.DEVICE_PLAYER_MOUNTED_SMALL) { out = new ImageIcon(UtilSystem.getResource("icons/22x22/player_mount_22x22.png")); } else if (icon == JajukIcons.DEVICE_PLAYER_UNMOUNTED_SMALL) { out = new ImageIcon(UtilSystem.getResource("icons/22x22/player_unmount_22x22.png")); } else if (icon == JajukIcons.OK) { out = new ImageIcon(UtilSystem.getResource("icons/22x22/ok_22x22.png")); } else if (icon == JajukIcons.OK_SMALL) { out = new ImageIcon(UtilSystem.getResource("icons/16x16/ok_16x16.png")); } else if (icon == JajukIcons.KO) { out = new ImageIcon(UtilSystem.getResource("icons/22x22/ko_22x22.png")); } else if (icon == JajukIcons.TRACK) { out = new ImageIcon(UtilSystem.getResource("icons/16x16/track_16x16.png")); } else if (icon == JajukIcons.DIRECTORY_SYNCHRO) { out = new ImageIcon(UtilSystem.getResource("icons/16x16/dir_synchro_16x16.png")); } else if (icon == JajukIcons.DIRECTORY_DESYNCHRO) { out = new ImageIcon(UtilSystem.getResource("icons/16x16/dir_desynchro_16x16.png")); } else if (icon == JajukIcons.PLAYLIST_FILE) { out = new ImageIcon(UtilSystem.getResource("icons/16x16/playlist_16x16.png")); } else if (icon == JajukIcons.GENRE) { out = new ImageIcon(UtilSystem.getResource("icons/16x16/genre_16x16.png")); } else if (icon == JajukIcons.EMPTY) { out = new ImageIcon(UtilSystem.getResource("icons/16x16/empty_16x16.png")); } else if (icon == JajukIcons.ARTIST) { out = new ImageIcon(UtilSystem.getResource("icons/16x16/artist_16x16.png")); } else if (icon == JajukIcons.ALBUM) { out = new ImageIcon(UtilSystem.getResource("icons/16x16/album_16x16.png")); } else if (icon == JajukIcons.YEAR) { out = new ImageIcon(UtilSystem.getResource("icons/16x16/clock_16x16.png")); } else if (icon == JajukIcons.APPLY_FILTER) { out = new ImageIcon(UtilSystem.getResource("icons/16x16/filter_16x16.png")); } else if (icon == JajukIcons.DISCOVERY_DATE) { out = new ImageIcon(UtilSystem.getResource("icons/16x16/calendar_16x16.png")); } else if (icon == JajukIcons.CLEAR_FILTER) { out = new ImageIcon(UtilSystem.getResource("icons/16x16/clear_16x16.png")); } else if (icon == JajukIcons.ADVANCED_FILTER) { out = new ImageIcon(UtilSystem.getResource("icons/16x16/complex_search_16x16.png")); } else if (icon == JajukIcons.PLAYLIST_NEW) { out = new ImageIcon(UtilSystem.getResource("icons/32x32/playlist_new_32x32.png")); } else if (icon == JajukIcons.PLAYLIST_NEW_SMALL) { out = new ImageIcon(UtilSystem.getResource("icons/16x16/new_16x16.png")); } else if (icon == JajukIcons.PLAYLIST_BOOKMARK) { out = new ImageIcon(UtilSystem.getResource("icons/32x32/playlist_bookmark_32x32.png")); } else if (icon == JajukIcons.PLAYLIST_BOOKMARK_SMALL) { out = new ImageIcon(UtilSystem.getResource("icons/16x16/bookmark_16x16.png")); } else if (icon == JajukIcons.PLAYLIST_BESTOF) { out = new ImageIcon(UtilSystem.getResource("icons/32x32/bestof_32x32.png")); } else if (icon == JajukIcons.PLAYLIST_NOVELTIES) { out = new ImageIcon(UtilSystem.getResource("icons/32x32/novelties_32x32.png")); } else if (icon == JajukIcons.RUN) { out = new ImageIcon(UtilSystem.getResource("icons/16x16/player_play_16x16.png")); } else if (icon == JajukIcons.ADD) { out = new ImageIcon(UtilSystem.getResource("icons/16x16/add_16x16.png")); } else if (icon == JajukIcons.REMOVE) { out = new ImageIcon(UtilSystem.getResource("icons/16x16/remove_16x16.png")); } else if (icon == JajukIcons.UP) { out = new ImageIcon(UtilSystem.getResource("icons/16x16/up_16x16.png")); } else if (icon == JajukIcons.DOWN) { out = new ImageIcon(UtilSystem.getResource("icons/16x16/down_16x16.png")); } else if (icon == JajukIcons.ADD_SHUFFLE) { out = new ImageIcon(UtilSystem.getResource("icons/16x16/add_shuffle_16x16.png")); } else if (icon == JajukIcons.CLEAR) { out = new ImageIcon(UtilSystem.getResource("icons/16x16/clear_16x16.png")); } else if (icon == JajukIcons.SAVE) { out = new ImageIcon(UtilSystem.getResource("icons/16x16/save_16x16.png")); } else if (icon == JajukIcons.EXT_DRIVE) { out = new ImageIcon(UtilSystem.getResource("icons/16x16/ext_drive_16x16.png")); } else if (icon == JajukIcons.DEFAULT_COVER) { out = new ImageIcon(UtilSystem.getResource("icons/16x16/ok_16x16.png")); } else if (icon == JajukIcons.FINISH_ALBUM) { out = new ImageIcon(UtilSystem.getResource("icons/32x32/finish_album_32x32.png")); } else if (icon == JajukIcons.FINISH_ALBUM_16X16) { out = new ImageIcon(UtilSystem.getResource("icons/16x16/finish_album_16x16.png")); } else if (icon == JajukIcons.NET_SEARCH) { out = new ImageIcon(UtilSystem.getResource("icons/16x16/netsearch_16x16.png")); } else if (icon == JajukIcons.TRACK_FIFO_PLANNED) { out = new ImageIcon(UtilSystem.getResource("icons/16x16/clock_16x16.png")); } else if (icon == JajukIcons.TRACK_FIFO_NORM) { out = new ImageIcon(UtilSystem.getResource("icons/16x16/player_play_16x16.png")); } else if (icon == JajukIcons.TRACK_FIFO_REPEAT) { out = new ImageIcon(UtilSystem.getResource("icons/16x16/repeat_16x16.png")); } else if (icon == JajukIcons.TRACK_FIFO_PLAYING) { out = new ImageIcon(UtilSystem.getResource("icons/16x16/ok_16x16.png")); } else if (icon == JajukIcons.WIZARD) { out = new ImageIcon(UtilSystem.getResource("icons/16x16/wizard_16x16.png")); } else if (icon == JajukIcons.TYPE_MP3) { out = new ImageIcon(UtilSystem.getResource("icons/16x16/type_mp3_16x16.png")); } else if (icon == JajukIcons.TYPE_MP2) { out = new ImageIcon(UtilSystem.getResource("icons/16x16/type_mp2_16x16.png")); } else if (icon == JajukIcons.TYPE_OGG) { out = new ImageIcon(UtilSystem.getResource("icons/16x16/type_ogg_16x16.png")); } else if (icon == JajukIcons.TYPE_AU) { out = new ImageIcon(UtilSystem.getResource("icons/16x16/type_wav_16x16.png")); } else if (icon == JajukIcons.TYPE_AIFF) { out = new ImageIcon(UtilSystem.getResource("icons/16x16/type_wav_16x16.png")); } else if (icon == JajukIcons.TYPE_FLAC) { out = new ImageIcon(UtilSystem.getResource("icons/16x16/type_flac_16x16.png")); } else if (icon == JajukIcons.TYPE_MPC) { out = new ImageIcon(UtilSystem.getResource("icons/16x16/type_wav_16x16.png")); } else if (icon == JajukIcons.TYPE_WMA) { out = new ImageIcon(UtilSystem.getResource("icons/16x16/type_wma_16x16.png")); } else if (icon == JajukIcons.TYPE_APE) { out = new ImageIcon(UtilSystem.getResource("icons/16x16/type_ape_16x16.png")); } else if (icon == JajukIcons.TYPE_AAC) { out = new ImageIcon(UtilSystem.getResource("icons/16x16/type_aac_16x16.png")); } else if (icon == JajukIcons.TYPE_WAV) { out = new ImageIcon(UtilSystem.getResource("icons/16x16/type_wav_16x16.png")); } else if (icon == JajukIcons.TYPE_RAM) { out = new ImageIcon(UtilSystem.getResource("icons/16x16/type_ram_16x16.png")); } else if (icon == JajukIcons.NO_EDIT) { out = new ImageIcon(UtilSystem.getResource("icons/16x16/stop_16x16.png")); } else if (icon == JajukIcons.EDIT) { out = new ImageIcon(UtilSystem.getResource("icons/16x16/edit_16x16.png")); } else if (icon == JajukIcons.UNKNOWN) { out = new ImageIcon(UtilSystem.getResource("icons/16x16/presence_unknown_16x16.png")); } else if (icon == JajukIcons.TIP) { out = new ImageIcon(UtilSystem.getResource("icons/40x40/tip_40x40.png")); } else if (icon == JajukIcons.TIP_SMALL) { out = new ImageIcon(UtilSystem.getResource("icons/16x16/tip_16x16.png")); } else if (icon == JajukIcons.OPEN_DIR) { out = new ImageIcon(UtilSystem.getResource("icons/40x40/folder_open_40x40.png")); } else if (icon == JajukIcons.STAR_0) { out = new ImageIcon(UtilSystem.getResource("icons/16x16/star0_16x16.png")); } else if (icon == JajukIcons.STAR_1) { out = new ImageIcon(UtilSystem.getResource("icons/16x16/star1_16x16.png")); } else if (icon == JajukIcons.STAR_2) { out = new ImageIcon(UtilSystem.getResource("icons/16x16/star2_16x16.png")); } else if (icon == JajukIcons.STAR_3) { out = new ImageIcon(UtilSystem.getResource("icons/16x16/star3_16x16.png")); } else if (icon == JajukIcons.STAR_4) { out = new ImageIcon(UtilSystem.getResource("icons/16x16/star4_16x16.png")); } else if (icon == JajukIcons.DROP_DOWN_32X32) { out = new ImageIcon(UtilSystem.getResource("icons/32x32/dropdown_32x32.png")); } else if (icon == JajukIcons.DROP_DOWN_16X16) { out = new ImageIcon(UtilSystem.getResource("icons/16x16/dropdown_16x16.png")); } else if (icon == JajukIcons.DIGITAL_DJ) { out = new ImageIcon(UtilSystem.getResource("icons/32x32/ddj_32x32.png")); } else if (icon == JajukIcons.DIGITAL_DJ_16X16) { out = new ImageIcon(UtilSystem.getResource("icons/16x16/ddj_16x16.png")); } else if (icon == JajukIcons.WEBRADIO_16X16) { out = new ImageIcon(UtilSystem.getResource("icons/16x16/webradio_16x16.png")); } else if (icon == JajukIcons.LIST) { out = new ImageIcon(UtilSystem.getResource("icons/16x16/contents_16x16.png")); } else if (icon == JajukIcons.CDDB) { out = new ImageIcon(UtilSystem.getResource("icons/16x16/cddb_16x16.png")); } else if (icon == JajukIcons.PLAY_TABLE) { out = new ImageIcon(UtilSystem.getResource("icons/16x16/player_play_16x16.png")); } else if (icon == JajukIcons.DEFAULTS) { out = new ImageIcon(UtilSystem.getResource("icons/16x16/undo_16x16.png")); } else if (icon == JajukIcons.DEFAULTS_BIG) { out = new ImageIcon(UtilSystem.getResource("icons/22x22/undo_22x22.png")); } else if (icon == JajukIcons.ACCURACY_LOW) { out = new ImageIcon(UtilSystem.getResource("icons/16x16/accuracy_low_16x16.png")); } else if (icon == JajukIcons.ACCURACY_MEDIUM) { out = new ImageIcon(UtilSystem.getResource("icons/16x16/accuracy_medium_16x16.png")); } else if (icon == JajukIcons.ACCURACY_HIGH) { out = new ImageIcon(UtilSystem.getResource("icons/16x16/accuracy_high_16x16.png")); } else if (icon == JajukIcons.REPORT) { out = new ImageIcon(UtilSystem.getResource("icons/16x16/report_16x16.png")); } else if (icon == JajukIcons.PUSH) { out = new ImageIcon(UtilSystem.getResource("icons/16x16/push_16x16.png")); } else if (icon == JajukIcons.COPY) { out = new ImageIcon(UtilSystem.getResource("icons/16x16/editcopy_16x16.png")); } else if (icon == JajukIcons.CUT) { out = new ImageIcon(UtilSystem.getResource("icons/16x16/editcut_16x16.png")); } else if (icon == JajukIcons.PASTE) { out = new ImageIcon(UtilSystem.getResource("icons/16x16/editpaste_16x16.png")); } else if (icon == JajukIcons.LAUNCH) { out = new ImageIcon(UtilSystem.getResource("icons/16x16/launch_16x16.png")); } else if (icon == JajukIcons.HISTORY) { out = new ImageIcon(UtilSystem.getResource("icons/16x16/history_16x16.png")); } else if (icon == JajukIcons.POPUP) { out = new ImageIcon(UtilSystem.getResource("icons/16x16/popup_16x16.png")); } else if (icon == JajukIcons.ALARM) { out = new ImageIcon(UtilSystem.getResource("icons/16x16/alarm_16x16.png")); } else if (icon == JajukIcons.BAN) { out = new ImageIcon(UtilSystem.getResource("icons/16x16/ban_16x16.png")); } else if (icon == JajukIcons.UNBAN) { out = new ImageIcon(UtilSystem.getResource("icons/16x16/ok_16x16.png")); } else if (icon == JajukIcons.PREFERENCE_ADORE) { out = new ImageIcon(UtilSystem.getResource("icons/16x16/preference-adore_16x16.png")); } else if (icon == JajukIcons.PREFERENCE_AVERAGE) { out = new ImageIcon(UtilSystem.getResource("icons/16x16/preference-average_16x16.png")); } else if (icon == JajukIcons.PREFERENCE_POOR) { out = new ImageIcon(UtilSystem.getResource("icons/16x16/preference-poor_16x16.png")); } else if (icon == JajukIcons.PREFERENCE_HATE) { out = new ImageIcon(UtilSystem.getResource("icons/16x16/preference-hate_16x16.png")); } else if (icon == JajukIcons.PREFERENCE_LIKE) { out = new ImageIcon(UtilSystem.getResource("icons/16x16/preference-like_16x16.png")); } else if (icon == JajukIcons.PREFERENCE_LOVE) { out = new ImageIcon(UtilSystem.getResource("icons/16x16/preference-love_16x16.png")); } else if (icon == JajukIcons.PREFERENCE_UNSET) { out = new ImageIcon(UtilSystem.getResource("icons/16x16/preference-unknown_16x16.png")); } else if (icon == JajukIcons.PREPARE_PARTY) { out = new ImageIcon(UtilSystem.getResource("icons/16x16/ext_drive_16x16.png")); } else if (icon == JajukIcons.PREPARE_PARTY_32X32) { out = new ImageIcon(UtilSystem.getResource("icons/32x32/ext_drive_32x32.png")); } else if (icon == JajukIcons.COPY_TO_CLIPBOARD) { out = new ImageIcon(UtilSystem.getResource("icons/16x16/copy_url_clipboard_16x16.png")); } else if (icon == JajukIcons.AMBIENCE) { out = new ImageIcon(UtilSystem.getResource("icons/32x32/ambience_32x32.png")); } else if (icon == JajukIcons.OPEN_EXPLORER) { out = new ImageIcon(UtilSystem.getResource("icons/16x16/explorer_16x16.png")); } else if (icon == JajukIcons.TREE_TABLE_SYNC) { out = new ImageIcon(UtilSystem.getResource("icons/16x16/tree-table-sync_16x16.png")); } else if (icon == JajukIcons.DONATE) { out = new ImageIcon(UtilSystem.getResource("icons/16x16/donate_16x16.png")); } else if (icon == JajukIcons.DISC_NUMBER) { out = new ImageIcon(UtilSystem.getResource("icons/16x16/disc_number_16x16.png")); } // Cache the result if (!cache.containsKey(icon)) { cache.put(icon, out); } return out; } } jajuk-1.9.6.orig/src/main/java/org/jajuk/util/JajukIcons.java0000644000175000017500000002157111720500104023671 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.util; /** * List of Jajuk icons. */ public enum JajukIcons { /** DOCUMENT_ME. */ NO_COVER, /** DOCUMENT_ME. */ NONE, /** DOCUMENT_ME. */ NO_COVER_50X50, /** DOCUMENT_ME. */ NO_COVER_100X100, /** DOCUMENT_ME. */ NO_COVER_150X150, /** DOCUMENT_ME. */ NO_COVER_200X200, /** DOCUMENT_ME. */ NO_COVER_250X250, /** DOCUMENT_ME. */ NO_COVER_300X300, /** DOCUMENT_ME. */ LOGO, /** DOCUMENT_ME. */ TRAY, /** DOCUMENT_ME. */ COVER_16X16, /** DOCUMENT_ME. */ LOGO_FRAME, /** DOCUMENT_ME. */ REPEAT, /** DOCUMENT_ME. */ REPEAT_ALL, /** DOCUMENT_ME. */ SHUFFLE, /** DOCUMENT_ME. */ CONTINUE, /** DOCUMENT_ME. */ INTRO, /** DOCUMENT_ME. */ KARAOKE, /** DOCUMENT_ME. */ SHUFFLE_GLOBAL, /** DOCUMENT_ME. */ SHUFFLE_GLOBAL_16X16, /** DOCUMENT_ME. */ BESTOF, /** DOCUMENT_ME. */ BESTOF_16X16, /** DOCUMENT_ME. */ MUTED, /** DOCUMENT_ME. */ VOLUME_LEVEL1, /** DOCUMENT_ME. */ VOLUME_LEVEL2, /** DOCUMENT_ME. */ VOLUME_LEVEL3, /** DOCUMENT_ME. */ WEBRADIO, /** DOCUMENT_ME. */ NOVELTIES, /** DOCUMENT_ME. */ NOVELTIES_16X16, /** DOCUMENT_ME. */ PLAYER_NEXT_SMALL, /** DOCUMENT_ME. */ SAVE_AS, /** DOCUMENT_ME. */ PLAYER_PREVIOUS_SMALL, /** DOCUMENT_ME. */ PLAYER_PREVIOUS, /** DOCUMENT_ME. */ PLAYER_PREVIOUS_BIG, /** DOCUMENT_ME. */ PLAYER_NEXT, /** DOCUMENT_ME. */ PLAYER_NEXT_BIG, /** DOCUMENT_ME. */ INC_RATING, /** DOCUMENT_ME. */ REW, /** DOCUMENT_ME. */ REW_16X16, /** DOCUMENT_ME. */ PLAYER_PLAY, /** DOCUMENT_ME. */ PLAY_16X16, /** DOCUMENT_ME. */ PLAYER_PAUSE, /** DOCUMENT_ME. */ PAUSE_16X16, /** DOCUMENT_ME. */ PLAYER_STOP, /** DOCUMENT_ME. */ STOP_16X16, /** DOCUMENT_ME. */ FWD, /** DOCUMENT_ME. */ FWD_16X16, /** DOCUMENT_ME. */ VOLUME, /** DOCUMENT_ME. */ CLOSE, /** DOCUMENT_ME. */ SLIM_WINDOW, /** DOCUMENT_ME. */ FULL_SCREEN, /** DOCUMENT_ME. */ POSITION, /** DOCUMENT_ME. */ INFO, /** DOCUMENT_ME. */ BOOKMARK_FOLDERS, /** DOCUMENT_ME. */ PERSPECTIVE_SIMPLE, /** DOCUMENT_ME. */ PERSPECTIVE_PHYSICAL, /** DOCUMENT_ME. */ PERSPECTIVE_LOGICAL, /** DOCUMENT_ME. */ PERSPECTIVE_STATISTICS, /** DOCUMENT_ME. */ PERSPECTIVE_CONFIGURATION, /** DOCUMENT_ME. */ PERSPECTIVE_PLAYER, /** DOCUMENT_ME. */ PERSPECTIVE_CATALOG, /** DOCUMENT_ME. */ PERSPECTIVE_PLAYLISTS, /** DOCUMENT_ME. */ PERSPECTIVE_INFORMATION, /** DOCUMENT_ME. */ OPEN_FILE, /** DOCUMENT_ME. */ EXIT, /** DOCUMENT_ME. */ NEW, /** DOCUMENT_ME. */ SEARCH, /** DOCUMENT_ME. */ DELETE, /** DOCUMENT_ME. */ PROPERTIES, /** DOCUMENT_ME. */ VOID, /** DOCUMENT_ME. */ CONFIGURATION, /** DOCUMENT_ME. */ MOUNT, /** DOCUMENT_ME. */ UPDATE_MANAGER, /** DOCUMENT_ME. */ UNMOUNT, /** DOCUMENT_ME. */ TRACES, /** DOCUMENT_ME. */ TEST, /** DOCUMENT_ME. */ REORGANIZE, /** DOCUMENT_ME. */ REFRESH, /** DOCUMENT_ME. */ RESTORE_ALL_VIEWS, /** DOCUMENT_ME. */ SYNCHRO, /** DOCUMENT_ME. */ DEVICE_NEW, /** DOCUMENT_ME. */ DEVICE_CD_MOUNTED, /** DOCUMENT_ME. */ DEVICE_CD_UNMOUNTED, /** DOCUMENT_ME. */ DEVICE_EXT_DD_MOUNTED, /** DOCUMENT_ME. */ DEVICE_EXT_DD_UNMOUNTED, /** DOCUMENT_ME. */ DEVICE_DIRECTORY_MOUNTED, /** DOCUMENT_ME. */ DEVICE_DIRECTORY_UNMOUNTED, /** DOCUMENT_ME. */ DEVICE_PLAYER_MOUNTED, /** DOCUMENT_ME. */ DEVICE_PLAYER_UNMOUNTED, /** DOCUMENT_ME. */ DEVICE_NETWORK_DRIVE_MOUNTED, /** DOCUMENT_ME. */ DEVICE_NETWORK_DRIVE_UNMOUNTED, /** DOCUMENT_ME. */ DEVICE_CD_MOUNTED_SMALL, /** DOCUMENT_ME. */ DEVICE_CD_UNMOUNTED_SMALL, /** DOCUMENT_ME. */ DEVICE_EXT_DD_MOUNTED_SMALL, /** DOCUMENT_ME. */ DEVICE_EXT_DD_UNMOUNTED_SMALL, /** DOCUMENT_ME. */ DEVICE_NETWORK_DRIVE_MOUNTED_SMALL, /** DOCUMENT_ME. */ DEVICE_NETWORK_DRIVE_UNMOUNTED_SMALL, /** DOCUMENT_ME. */ DEVICE_DIRECTORY_MOUNTED_SMALL, /** DOCUMENT_ME. */ DEVICE_DIRECTORY_UNMOUNTED_SMALL, /** DOCUMENT_ME. */ DEVICE_PLAYER_MOUNTED_SMALL, /** DOCUMENT_ME. */ DEVICE_PLAYER_UNMOUNTED_SMALL, /** DOCUMENT_ME. */ OK, /** DOCUMENT_ME. */ OK_SMALL, /** DOCUMENT_ME. */ KO, /** DOCUMENT_ME. */ TRACK, /** DOCUMENT_ME. */ DIRECTORY_SYNCHRO, /** DOCUMENT_ME. */ DIRECTORY_DESYNCHRO, /** DOCUMENT_ME. */ PLAYLIST_FILE, /** DOCUMENT_ME. */ GENRE, /** DOCUMENT_ME. */ EMPTY, /** DOCUMENT_ME. */ ARTIST, /** DOCUMENT_ME. */ ALBUM, /** DOCUMENT_ME. */ YEAR, /** DOCUMENT_ME. */ APPLY_FILTER, /** DOCUMENT_ME. */ DISCOVERY_DATE, /** DOCUMENT_ME. */ CLEAR_FILTER, /** DOCUMENT_ME. */ ADVANCED_FILTER, /** DOCUMENT_ME. */ PLAYLIST_NEW, /** DOCUMENT_ME. */ PLAYLIST_NEW_SMALL, /** DOCUMENT_ME. */ PLAYLIST_BOOKMARK, /** DOCUMENT_ME. */ PLAYLIST_BOOKMARK_SMALL, /** DOCUMENT_ME. */ PLAYLIST_BESTOF, /** DOCUMENT_ME. */ PLAYLIST_NOVELTIES, /** DOCUMENT_ME. */ RUN, /** DOCUMENT_ME. */ ADD, /** DOCUMENT_ME. */ REMOVE, /** DOCUMENT_ME. */ UP, /** DOCUMENT_ME. */ DOWN, /** DOCUMENT_ME. */ ADD_SHUFFLE, /** DOCUMENT_ME. */ CLEAR, /** DOCUMENT_ME. */ SAVE, /** DOCUMENT_ME. */ EXT_DRIVE, /** DOCUMENT_ME. */ DEFAULT_COVER, /** DOCUMENT_ME. */ FINISH_ALBUM, /** DOCUMENT_ME. */ FINISH_ALBUM_16X16, /** DOCUMENT_ME. */ NET_SEARCH, /** DOCUMENT_ME. */ TRACK_FIFO_PLANNED, /** DOCUMENT_ME. */ TRACK_FIFO_NORM, /** DOCUMENT_ME. */ TRACK_FIFO_REPEAT, /** DOCUMENT_ME. */ TRACK_FIFO_PLAYING, /** DOCUMENT_ME. */ WIZARD, /** DOCUMENT_ME. */ TYPE_MP3, /** DOCUMENT_ME. */ TYPE_MP2, /** DOCUMENT_ME. */ TYPE_OGG, /** DOCUMENT_ME. */ TYPE_AU, /** DOCUMENT_ME. */ TYPE_AIFF, /** DOCUMENT_ME. */ TYPE_FLAC, /** DOCUMENT_ME. */ TYPE_MPC, /** DOCUMENT_ME. */ TYPE_WMA, /** DOCUMENT_ME. */ TYPE_APE, /** DOCUMENT_ME. */ TYPE_AAC, /** DOCUMENT_ME. */ TYPE_WAV, /** DOCUMENT_ME. */ TYPE_RAM, /** DOCUMENT_ME. */ NO_EDIT, /** DOCUMENT_ME. */ EDIT, /** DOCUMENT_ME. */ UNKNOWN, /** DOCUMENT_ME. */ TIP, /** DOCUMENT_ME. */ TIP_SMALL, /** DOCUMENT_ME. */ OPEN_DIR, /** DOCUMENT_ME. */ STAR_0, /** DOCUMENT_ME. */ STAR_1, /** DOCUMENT_ME. */ STAR_2, /** DOCUMENT_ME. */ STAR_3, /** DOCUMENT_ME. */ STAR_4, /** DOCUMENT_ME. */ DROP_DOWN_32X32, /** DOCUMENT_ME. */ DROP_DOWN_16X16, /** DOCUMENT_ME. */ DIGITAL_DJ, /** DOCUMENT_ME. */ DIGITAL_DJ_16X16, /** DOCUMENT_ME. */ WEBRADIO_16X16, /** DOCUMENT_ME. */ LIST, /** DOCUMENT_ME. */ CDDB, /** DOCUMENT_ME. */ PLAY_TABLE, /** DOCUMENT_ME. */ DEFAULTS, /** DOCUMENT_ME. */ DEFAULTS_BIG, /** DOCUMENT_ME. */ ACCURACY_LOW, /** DOCUMENT_ME. */ ACCURACY_MEDIUM, /** DOCUMENT_ME. */ ACCURACY_HIGH, /** DOCUMENT_ME. */ REPORT, /** DOCUMENT_ME. */ PUSH, /** DOCUMENT_ME. */ COPY, /** DOCUMENT_ME. */ CUT, /** DOCUMENT_ME. */ PASTE, /** DOCUMENT_ME. */ LAUNCH, /** DOCUMENT_ME. */ HISTORY, /** DOCUMENT_ME. */ POPUP, /** DOCUMENT_ME. */ ALARM, /** DOCUMENT_ME. */ BAN, /** DOCUMENT_ME. */ PREFERENCE_HATE, /** DOCUMENT_ME. */ PREFERENCE_POOR, /** DOCUMENT_ME. */ PREFERENCE_AVERAGE, /** DOCUMENT_ME. */ PREFERENCE_LIKE, /** DOCUMENT_ME. */ PREFERENCE_LOVE, /** DOCUMENT_ME. */ PREFERENCE_ADORE, /** DOCUMENT_ME. */ PREFERENCE_UNSET, /** DOCUMENT_ME. */ UNBAN, /** DOCUMENT_ME. */ PREPARE_PARTY, /** Larger icon for Prepare Party Wizard. */ PREPARE_PARTY_32X32, /** DOCUMENT_ME. */ COPY_TO_CLIPBOARD, /** DOCUMENT_ME. */ OPEN_EXPLORER, /** DOCUMENT_ME. */ AMBIENCE, /** DOCUMENT_ME. */ PLAYER_FORWARD_BIG, /** DOCUMENT_ME. */ PLAYER_STOP_BIG, /** DOCUMENT_ME. */ PLAYER_PLAY_BIG, /** DOCUMENT_ME. */ PLAYER_PAUSE_BIG, /** DOCUMENT_ME. */ PLAYER_REWIND_BIG, /** DOCUMENT_ME. */ AUTOSCROLL, /** Tree/table synchronization icon. */ TREE_TABLE_SYNC, /** Money. */ DONATE, /** Disc number. */ DISC_NUMBER } jajuk-1.9.6.orig/src/main/java/org/jajuk/util/JajukFileFilter.java0000644000175000017500000001545111720500104024643 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.util; import java.io.File; import java.util.Locale; import javax.swing.filechooser.FileFilter; import org.apache.commons.lang.StringUtils; /** * Advanced file filter. * * @see The * description for direction to use *

    * Example: new * JajukFilter(false,JajukFileFilter.DirectoryFilter.getInstance(), * JajukFileFilter.AudioFilter.getInstance()); *

    * This class can be use by file choosers (probably a JajukFileChooser) and * for engine file selection that uses the raw accept method. In the second * case, it can be useful to use grouping filters like music or report (but * it is not intended to be used by file choosers that require only one * extension by filter) and or/and argument given as an argument */ public class JajukFileFilter extends FileFilter implements java.io.FileFilter, Const { // TODO: this class contains two things: filtering on a list of extensions, but also basic FileFiltering // that is overwritten later on, we should investigate if we can separate those two concerns... // also some filters do not really depend on JajukFileFilter, e.g. DirectoryFilter, and thus // might return incorrect data in certain cases, e.g. extension... /** Filters. */ private JajukFileFilter[] filters = {}; /** Show directories (useful to allow user to navigate). */ protected boolean bShowDirectories = false; /** List of Extensions for the current filter. */ protected String[] extensions = {}; /** DOCUMENT_ME. */ protected String extensionsString = ""; /** And or OR applied to multi filters ?. */ private boolean bAND = true; /** * Filter constructor. * * @param bAND DOCUMENT_ME * @param filters undefined list of jajuk filter to be applied (logical AND applied * between filters) */ public JajukFileFilter(final boolean bAND, final JajukFileFilter... filters) { super(); this.bAND = bAND; this.filters = new JajukFileFilter[filters.length]; System.arraycopy(filters, 0, this.filters, 0, filters.length); } /** * Filter constructor. * * @param filters undefined list of jajuk filter to be applied (logical AND applied * between filters) *

    * Example: only audio files new * JajukFilter(JajukFileFilter.AudioFilter.getInstance()); *

    */ public JajukFileFilter(final JajukFileFilter... filters) { this(true, filters); } /** * Filter constructor, used mostly by subclasses to define type-safe * JajukFileFilters defining their own extensions lists, and occasionally * overriding some methods to influence the filtering process. * * @param extensions an array of extension strings */ public JajukFileFilter(final String[] extensions) { super(); this.extensions = (extensions != null) ? extensions : new String[] {}; final int size = this.extensions.length; for (int i = 0; i < size; i++) { this.extensions[i] = this.extensions[i].toLowerCase(Locale.getDefault()); extensionsString += this.extensions[i] + ','; } // Drop last coma if (!StringUtils.isBlank(extensionsString)) { extensionsString = extensionsString.substring(0, extensionsString.length() - 1); } } /** * Returns the filtering boolean status, after having combined all filters * with either an AND or OR logical rule. * * @param f file to test * * @return true, if accept */ @Override public boolean accept(final File f) { boolean acceptance = false; if (filters.length != 0) { boolean test = false; if (bAND) { test = true; for (final JajukFileFilter element : filters) { test &= element.accept(f); } } else { for (final JajukFileFilter element : filters) { test |= element.accept(f); } } acceptance = test; } else { acceptance = show(f); } return acceptance; } /* * (non-Javadoc) * * @see javax.swing.filechooser.FileFilter#getDescription() */ @Override public String getDescription() { return extensionsString; } /** * Returns an array of strings containing the extension patterns defined by * the current JajukFileFilter object instance. * * @return array of extension strings */ public String[] getExtensions() { // copy to not expose internal array String[] lExt = new String[extensions.length]; System.arraycopy(extensions, 0, lExt, 0, extensions.length); return lExt; } /** * Gets the filters. * * @return the filters */ public JajukFileFilter[] getFilters() { // copy to not expose internal array JajukFileFilter[] lFilter = new JajukFileFilter[filters.length]; System.arraycopy(filters, 0, lFilter, 0, filters.length); return lFilter; } /** * Checks if the given file's extension matches the ones expected by the * filter's registered extension. Beware that this method may be overwritten. * * @param file the file to be filtered * * @return known-extension flag */ protected boolean isKnownExtension(final File file) { if (file != null) { final String extension = UtilSystem.getExtension(file).toLowerCase(Locale.getDefault()); for (final String ext : extensions) { if (extension.equals(ext)) { return true; } } } return false; } /** * Force the filter to accept or reject directories. * * @param b directory acceptance flag */ public void setAcceptDirectories(final boolean b) { bShowDirectories = b; } /** * Checks if the given file should be shown, according if it is a directory * and that directory display is activated, or a file with a known extension. * Beware that this method or the isKnownExtension may be overwritten. * * @param file the file to be filtered * * @return display status flag (fallback is false) */ protected boolean show(final File file) { return (file.isDirectory()) ? bShowDirectories : (isKnownExtension(file)); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/util/UtilPrepareParty.java0000644000175000017500000004752411720500104025113 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.util; import ext.ProcessLauncher; import java.io.BufferedWriter; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Properties; import org.apache.commons.io.FileUtils; import org.apache.commons.lang.StringUtils; import org.jajuk.base.FileManager; import org.jajuk.base.Playlist; import org.jajuk.base.PlaylistManager; import org.jajuk.base.SmartPlaylist; import org.jajuk.events.JajukEvent; import org.jajuk.events.JajukEvents; import org.jajuk.events.ObservationManager; import org.jajuk.services.dj.Ambience; import org.jajuk.services.dj.AmbienceManager; import org.jajuk.services.dj.DigitalDJ; import org.jajuk.services.dj.DigitalDJManager; import org.jajuk.ui.helpers.StarsHelper; import org.jajuk.util.error.JajukException; import org.jajuk.util.log.Log; /** * Utilities for the Prepare Party Wizard. Extracted into a separate class for * easier testing. */ public class UtilPrepareParty { /** * Instantiates a new util prepare party. * * private constructor to avoid instantiation */ private UtilPrepareParty() { } /** * Filter provided list by removing files that have lower rating. * * @param files the list to process. * @param rate The require rating level * * @return The adjusted list. */ public static List filterRating(List files, Integer rate) { final List newFiles = new ArrayList(); for (org.jajuk.base.File file : files) { // only add files that have a rate equal or higher than the level set if (StarsHelper.getStarsNumber(file.getTrack()) >= rate) { newFiles.add(file); } } return newFiles; } /** * Filter the provided list by removing files if the specified length (in * minutes) is exceeded. * * @param files The list of files to process. * @param time The number of minutes playing length to have at max. * * @return The modified list. */ public static List filterMaxLength(List files, Integer time) { final List newFiles = new ArrayList(); long accumulated = 0; for (org.jajuk.base.File file : files) { // check if we now exceed the max length, getDuration() is in seconds, but // we want to use minutes if ((accumulated + file.getTrack().getDuration()) / 60 > time) { return newFiles; } accumulated += file.getTrack().getDuration(); newFiles.add(file); } // there were not enough files to reach the limit, return the full list return files; } /** * Filter the provided list by removing files after the specified size is * reached. * * @param files The list of files to process. * @param size The size in MB that should not be exceeded. * * @return The modified list. */ public static List filterMaxSize(List files, Integer size) { final List newFiles = new ArrayList(); long accumulated = 0; for (org.jajuk.base.File file : files) { // check if we now exceed the max size, getSize() is in byte, but we want // to use MB if ((accumulated + file.getSize()) / (1024 * 1024) > size) { return newFiles; } accumulated += file.getSize(); newFiles.add(file); } // there were not enough files to reach the limit, return the full list return files; } /** * Filter the provided list by removing files after the specified number of * tracks is reached. * * @param files The list of files to process. * @param tracks The number of tracks to limit the list. * * @return The modified list. */ public static List filterMaxTracks(List files, Integer tracks) { final List newFiles = new ArrayList(); int count = 0; for (org.jajuk.base.File file : files) { // check if we have reached the max if (count > tracks) { return newFiles; } count++; newFiles.add(file); } // there were not enough files to reach the limit, return the full list return files; } /** * Filter the provided list by removing files so only the specified media is * included. * * @param files The list of files to process. * @param ext The number of tracks to filter the list. * * @return The modified list. */ public static List filterMedia(final List files, final String ext) { final List newFiles = new ArrayList(); for (org.jajuk.base.File file : files) { if (file.getType() != null && file.getType().getExtension() != null && file.getType().getExtension().equals(ext)) { newFiles.add(file); } } return newFiles; } /** * Get files from the specified DJ. * * @param name The name of the DJ. * * @return A list of files. */ public static List getDJFiles(final String name) { DigitalDJ dj = DigitalDJManager.getInstance().getDJByName(name); return dj.generatePlaylist(); } /** * Get files from the specified Ambience. * * @param name The name of the Ambience. * * @return A list of files. */ public static List getAmbienceFiles(String name) { final List files; Ambience ambience = AmbienceManager.getInstance().getAmbienceByName(name); files = new ArrayList(); // Get a shuffle selection List allFiles = FileManager.getInstance().getGlobalShufflePlaylist(); // Keep only right genres and check for unicity for (org.jajuk.base.File file : allFiles) { if (ambience.getGenres().contains(file.getTrack().getGenre())) { files.add(file); } } return files; } /** * Get files from the specified Playlist. If the name of the playlist is equal * to the name of the temporary playlist provided to the Wizard, then this * Playlist is used instead. * * @param name The name of the Playlist. * @param tempPlaylist The playlist provided upon starting of the Wizard, null if none * provided. * * @return A list of files. * * @throws JajukException the jajuk exception */ public static List getPlaylistFiles(String name, Playlist tempPlaylist) throws JajukException { // if we chose the temp-playlist, use this one if (tempPlaylist != null && name.equals(tempPlaylist.getName())) { return tempPlaylist.getFiles(); } // get the Playlist from the Manager by name Playlist playlist = PlaylistManager.getInstance().getPlaylistByName(name); return playlist.getFiles(); } /** * Get files in random order. * * @return Returns a list of all files shuffled into random order. */ public static List getShuffleFiles() { // Get a shuffle selection from all files return FileManager.getInstance().getGlobalShufflePlaylist(); } /** * Get files from the BestOf-Playlist. * * @return The list of files that match the "BestOf"-criteria * * @throws JajukException the jajuk exception */ public static List getBestOfFiles() throws JajukException { Playlist pl = new SmartPlaylist(Playlist.Type.BESTOF, "tmp", "temporary", null); return pl.getFiles(); } /** * Get the files from the current "Novelties"-criteria. * * @return The files that are new currently. * * @throws JajukException the jajuk exception */ public static List getNoveltiesFiles() throws JajukException { Playlist pl = new SmartPlaylist(Playlist.Type.NOVELTIES, "tmp", "temporary", null); return pl.getFiles(); } /** * Get the files from the current Queue. * * @return The currently queued files. * * @throws JajukException the jajuk exception */ public static List getQueueFiles() throws JajukException { Playlist pl = new SmartPlaylist(Playlist.Type.QUEUE, "tmp", "temporary", null); return pl.getFiles(); } /** * Get the files that are bookmarked. * * @return The currently bookmarked files. * * @throws JajukException the jajuk exception */ public static List getBookmarkFiles() throws JajukException { Playlist pl = new SmartPlaylist(Playlist.Type.BOOKMARK, "tmp", "temporary", null); return pl.getFiles(); } /** * Split the commandline into separate elements by observing double quotes. * * @param command The command in one string. E.g. "perl /usr/bin/pacpl". * * @return A list of single command elements. e.g. {"perl", "/usr/bin/pacpl"} */ private static List splitCommand(String command) { List list = new ArrayList(); StringBuilder word = new StringBuilder(); boolean quote = false; int i = 0; while (i < command.length()) { char c = command.charAt(i); // word boundary if (Character.isWhitespace(c) && !quote) { i++; // finish current word list.add(word.toString()); word = new StringBuilder(); // skip more whitespaces while (Character.isWhitespace(command.charAt(i)) && i < command.length()) { i++; } } else { // on quote we either start or end a quoted string if (c == '"') { quote = !quote; } word.append(c); i++; } } // finish last word if (word.length() > 0) { list.add(word.toString()); } return list; } /** * Check if the Perl Audio Converter can be used. * * @param pacpl The command-string to call pacpl, e.g. "pacpl" or "perl * C:\pacpl\pacpl", ... * * @return true, if check pacpl */ public static boolean checkPACPL(String pacpl) { // here we just want to verify that we find pacpl // first build the commandline for "pacpl --help" // see the manual page of "pacpl" List list = splitCommand(pacpl); list.add("--help"); // create streams for catching stdout and stderr ByteArrayOutputStream out = new ByteArrayOutputStream(); ByteArrayOutputStream err = new ByteArrayOutputStream(); int ret = 0; final ProcessLauncher launcher = new ProcessLauncher(out, err, 10000); try { ret = launcher.exec(list.toArray(new String[list.size()])); } catch (IOException e) { ret = -1; Log.debug("Exception while checking for 'pacpl', cannot use functionality to convert media files while copying: " + e.getMessage()); } // if we do not find the application or if we got an error, log some details // and disable notification support if (ret != 0) { // log out the results Log.debug("pacpl command returned to out(" + ret + "): " + out.toString()); Log.debug("pacpl command returned to err: " + err.toString()); Log.info("Cannot use functionality to convert media files, application 'pacpl' seems to be not available correctly."); return false; } // pacpl is enabled and seems to be supported by the OS return true; } /** * Call the external application "pacpl" to convert the specified file into * the specified format and store the resulting file in the directory listed. * * @param pacpl The command-string to call pacpl, e.g. "pacpl" or "perl * C:\pacpl\pacpl", ... * @param file The file to convert. * @param toFormat The target format. * @param toDir The target location. * @param newName The new name to use (this is used for normalizing and numbering * the files, ...) * * @return 0 if processing was OK, otherwise the return code indicates the * return code provided by the pacpl script * * TODO: currently this uses the target-location as temporary * directory if intermediate-conversion to WAV is necessary, this * might be sub-optimal for Flash-memory where too many writes kills * the media card earlier. We probably should use the temporary * directory for conversion instead and do another copy at the end. */ public static int convertPACPL(String pacpl, File file, String toFormat, java.io.File toDir, String newName) { // first build the commandline for "pacpl" // see the manual page of "pacpl" // first split the command itself with observing quotes, splitting is // necessary because it can be something like "perl /pacpl" List list = splitCommand(pacpl); // where to store the file list.add("--outdir"); list.add(toDir.getAbsolutePath()); // specify new filename list.add("--outfile"); list.add(newName); // specify output format list.add("--to"); list.add(toFormat); // now add the actual file to convert list.add(file.getAbsolutePath()); // create streams for catching stdout and stderr ByteArrayOutputStream out = new ByteArrayOutputStream(); ByteArrayOutputStream err = new ByteArrayOutputStream(); int ret = 0; StringBuffer commandLog = new StringBuffer(); for (String arg : list) { commandLog.append(arg + " "); } Log.debug("Using this pacpl command: {{" + commandLog.toString() + "}}"); final ProcessLauncher launcher = new ProcessLauncher(out, err); try { ret = launcher.exec(list.toArray(new String[list.size()]), null, new java.io.File(System.getProperty("java.io.tmpdir"))); } catch (IOException e) { ret = -1; Log.error(e); } // log out the results if (!out.toString().isEmpty()) { Log.debug("pacpl command returned to out(" + ret + "): " + out.toString()); if (out.toString().indexOf("encode failed") != -1) { ret = -1; } } else { Log.debug("pacpl command returned: " + ret); } if (!err.toString().isEmpty()) { Log.debug("pacpl command returned to err: " + err.toString()); if (err.toString().indexOf("encode failed") != -1) { ret = -1; } } return ret; } /** * Copies the files contained in the list to the specified directory. * * @param files The list of flies to copy. * @param destDir The target location. * @param isNormalize DOCUMENT_ME * @param isConvertMedia DOCUMENT_ME * @param media DOCUMENT_ME * @param convertCommand DOCUMENT_ME */ public static void copyFiles(final List files, final java.io.File destDir, final boolean isNormalize, final boolean isConvertMedia, final String media, final String convertCommand) { Thread thread = new Thread("PrepareParty - File Copy") { @Override public void run() { UtilGUI.waiting(); // start time to display elapsed time at the end long lRefreshDateStart = System.currentTimeMillis(); // start copying and create a playlist on the fly int convert_errors = 0; final java.io.File file = new java.io.File(destDir.getAbsolutePath() + "/playlist.m3u"); try { final BufferedWriter bw = new BufferedWriter(new FileWriter(file)); try { bw.write(Const.PLAYLIST_NOTE); int count = 0; for (final org.jajuk.base.File entry : files) { // update progress count++; // We can use the actual file name as we do numbering of the files, // this is important for existing playlists to keep the order String name = StringUtils.leftPad(Integer.valueOf(count).toString(), 5, '0') + '_' + entry.getFIO().getName(); // normalize filenames if necessary if (isNormalize) { name = UtilString.normalizeFilename(name); } // check if we need to convert the file format if (isConvertMedia && !entry.getType().getExtension().equals(media)) { // Notify that we are converting a file Properties properties = new Properties(); properties.put(Const.DETAIL_CONTENT, entry.getName()); properties.put(Const.DETAIL_NEW, name + "." + media); ObservationManager.notify(new JajukEvent(JajukEvents.FILE_CONVERSION, properties)); int ret = UtilPrepareParty.convertPACPL(convertCommand, entry.getFIO(), media, destDir, name); if (ret != 0) { convert_errors++; // do a normal copy of original format if it cannot be converted FileUtils.copyFile(entry.getFIO(), new File(destDir, name)); } else { // Conversion is done, new filename is name = name + "." + media; } } else { // do a normal copy otherwise FileUtils.copyFile(entry.getFIO(), new File(destDir, name)); } // increase hits for this track/file as it is likely played outside of Jajuk entry.getTrack().incHits(); // write playlist as well bw.newLine(); bw.write(name); // Notify that a file has been copied Properties properties = new Properties(); properties.put(Const.DETAIL_CONTENT, entry.getName()); ObservationManager.notify(new JajukEvent(JajukEvents.FILE_COPIED, properties)); } bw.flush(); } finally { bw.close(); } // Send a last event with null properties to inform the // client that the party is done ObservationManager.notify(new JajukEvent(JajukEvents.FILE_COPIED)); } catch (final IOException e) { Log.error(e); Messages.showErrorMessage(180, e.getMessage()); return; } finally { long refreshTime = System.currentTimeMillis() - lRefreshDateStart; // inform the user about the number of resulting tracks StringBuilder sbOut = new StringBuilder(); sbOut.append(Messages.getString("PreparePartyWizard.31")).append(" ") .append(destDir.getAbsolutePath()).append(".\n").append(files.size()).append(" ") .append(Messages.getString("PreparePartyWizard.23")).append(" ") .append(((refreshTime < 1000) ? refreshTime + " ms." : refreshTime / 1000 + " s.")); // inform user if converting did not work if (convert_errors > 0) { sbOut.append("\n").append(Integer.toString(convert_errors)) .append(Messages.getString("PreparePartyWizard.36")); } String message = sbOut.toString(); Log.debug(message); UtilGUI.stopWaiting(); // Display end of copy message with stats Messages.showInfoMessage(message); } } }; thread.start(); } } jajuk-1.9.6.orig/src/main/java/org/jajuk/i18n/0000755000175000017500000000000011720500104020562 5ustar drazzibdrazzibjajuk-1.9.6.orig/src/main/java/org/jajuk/i18n/jajuk_el.properties0000644000175000017500000025100011720500104024462 0ustar drazzibdrazzib Σελίδα συστήματος βαθμολόγησης). Οι προηγούμενες βαθμολογίες έχουν μετατραπεί σε μία κλίμακα από 0 έως 100 αλλά συνιστούμε να επαναφέρετε όλες τις βαθμολογίες από την οπτική Προτιμήσεις -> καρτέλα Ιστορικό (προσοχή: όλες οι βαθμολογίες τα χαθούν) #Οι απαντήσεις πρέπει να είναι: ναι / όχι / ακύρο Confirmation_exit=Θέλετε πραγματικά να κλείσετε το Jajuk? Confirmation_delete=Προσοχή! Πρόκειται να διαγράψετε το/τα παρακάτω αρχεί(ο/α) απο το δίσκο, είστε βέβαιος ? Confirmation_void_refresh=Προσοχή! Πρόκειται να προσπελάσετε μία κενή συσκευή.Στο Unix, βεβαιωθείτε ότι η συσκεύη είναι ενεργοποιημένη διαφορετικά θα χάσετε τις πληροφορίες του Jajuk για τη συσκευή αυτή . Είστε σίγουρος? Confirmation_remove_device=Θέλετε σίγουρα να απομακρύνετε αυτή τη συσκευή? Confirmation_delete_cover=Θέλετε σίγουρα να διαγράψετε αυτή την πρόσοψη από το δίσκο? Confirmation_delete_files=Θέλετε σίγουρα να διαγράψετε αυτά τα αρχεία από το δίσκο? Confirmation_delete_dirs=Θέλετε σίγουρα να διαγράψετε αυτά τους καταλόγους από το δίσκο? Confirmation_clear_history=Θέλετε σίγουρα να καθαρίσετε το ιστορικό? Confirmation_reset_ratings=Θέλετε σίγουρα να επαναφέρετε όλα τις βαθμολογίες στο μηδέν? Confirmation_refactor_files=Θέλετε σίγουρα να μετονομάσετε το/τα επιλεγμέν(ο/α) αρχεί(ο/α)? Confirmation_restore_all=Η πλήρης επαναφορά των προβολών απαιτεί επανεκκίνηση του Jajuk, θέλετε quit ? Confirmation_defaults_radios=Αυτό θα διαγράψει όλους τους ραδιοφωνικούς σταθμούς που δημιουργήσατε προηγουμένως, είστε βέβαιος ? Confirmation_delete_empty_dirs=Οι επόμενοι κατάλογοι είναι άδειοι. Θέλετε να τους διαγράψετε? Confirmation_file_overwrite=Αυτό το αρχείο υπάρχει ήδη. Θέλετε να αντικαταστήσετε αυτό το αρχείο? Confirmation_file_number=αρχεία θα διαγραφούν. Confirmation_alarm_stop=Θέλετε σίγουρα να σταματήσετε αυτόν το συναγερμό? Confirmation_defaults=Προσέξτε ότι έτσι θα επαναφερθούν όλες οι καρτέλες στις προεπιλεγμένες τιμές (και όχι μόνο η τρέχουσα), είστε βέβαιος ? Confirmation_rebuild_thumbs=Αυτό θα αναδημιουργήσει τις μικρογραφίες όλων των άλμουμ σας, μπορεί να διαρκέσει αρκετά λεπτά για μεγάλες συλλογές. Είστε βέβαιος ? Confirmation_reset_preferences=Θέλετε σίγουρα να επαναφέρετε τις προτιμήσεις των κομματιών ? Device_type.directory=Φάκελος Device_type.file_cd=CD αρχείων μουσικής Device_type.audio_cd=CD Ήχου Device_type.extdd=Εξωτερικός Σκληρός Δίσκος Device_type.player=Συσκευή Αναπαραγωγής Device_type.network_drive=Συσκευή δικτύου Device_type.remote=Απομακρυσμένο (Μη υλοποιημένο) Perspective_Description_Simple=Απλή Perspective_Description_Files=Αρχεία Perspective_Description_Tracks=Κομμάτια Perspective_Description_Configuration=Ρύθμιση Perspective_Description_Statistics=Στατιστικά Perspective_Description_Help=Βοήθεια Perspective_Description_Display=Αναπαραγωγή Perspective_Description_Albums=Άλμπουμ Perspective_Description_Info=Πληροροφορίες Perspective_Description_Playlists=Λίστες αναπαραγωγής Item_Playlist_File=λίστας αναπαραγωγής Item_Track=Τίτλος Item_Album=Άλμπουμ Item_Artist=Καλλιτέχνης Item_Genre=Είδος Item_Device=Συσκευή Item_File=Αρχείο Item_Directory=Φάκελος Item_Year=Έτος Property_id=Id Property_name=Όνομα Property_type=Τύπος Property_url=Url Property_mount_point=Σημείο ενεργοποίησης Property_auto_refresh=Αυτόματη Ανανέωση Property_auto_mount=Αυτόματη ενεργοποίηση Property_album=Άλμπουμ Property_style=Είδος Property_author=Καλλιτέχνης Property_length=Διάρκεια Property_year=Έτος Property_rate=Αξιολόγηση Property_files=Αρχεία Property_hits=Hits Property_filename=Αρχείο Property_date=Ημερομηνία Property_added=Ημερομηνία Εύρεσης Property_parent=Κατάλογος Γονέας Property_device=Συσκευή Property_directory=Φάκελος Property_track=Κομμάτι Property_size=Μέγεθος (MB) Property_quality=Ποιότητα Property_hashcode=Hashcode(Κωδικός Κατακερματισμού) Property_playlist_files=λίστες αναπαραγωγής Property_comment=Σχόλιο Property_order=Κομμάτι Property_path=Πλήρες μονοπάτι Property_tracks=Κομμάτια Property_file_date=Ημερομηνία Αρχείου Property_Format_Number=Αριθμός Property_Format_String=Αλφαριθμητικό Property_Format_Boolean=Δυαδικός Property_Format_Float=Πραγματικός Property_Format_Date=Ημερομηνία Property_Format_URL=Url Property_pf=Προτίμηση Property_tpt=Συνολικός χρόνος αναπαραγωγής (secs) Property_ban=Απαγορευμένο Language_desc_en=Αγγλικά Language_desc_fr=Γαλλικά Language_desc_de=Γερμανικά Language_desc_it=Ιταλικά Language_desc_sv=Σουηδικά Language_desc_nl=Ολλανδικά Language_desc_zh=Κινέζικα Language_desc_es=Ισπανικά Language_desc_ca=Καταλονικά Language_desc_ko=Κορεατικά Language_desc_el=Ελληνικά Language_desc_ru=Ρωσικά Language_desc_gl=Γαλικιανά #--- Error codes --- Error.000=Άγνωστο σφάλμα Error.005=Σφάλμα ανάλυσης αρχείου συλλογής Error.007=Σφάλμα αναπραγωγής αρχείου, ίσως ο MPlayer δεν ξεκίνησε την αναπαραγωγή πριν το timeout, timeout: Error.008=Σφάλμα παύσης αχείου Error.009=Αδύνατη η ανάγνωση του αρχείου Error.010=Αδύνατη η εύρεση αρχείου συσχετισμένου με αυτό το κομμάτι σε ενεργοποιημένη συσκευή Error.011=Τεχνικό Σφάλμα κατά την ενεργοποίηση της συσκευής ή κενή συσκευή Error.012=Τεχνικό Σφάλμα when απενεργοποίηση της συσκευής, πιθανώς χρησιμοποιείται από άλλη εφαρμογή Error.013=Αδύνατη η απομάκρυνση της συσκευής: είτε ενεργοποιείται είτε ανανεώνεται αυτή τη στιγμή Error.016=Αδύνατη η προσπέλαση της συσκευής. Παρακαλώ εισάγετε το σημείο ενεργοποίησης της συσκευής. Πχ: '/cdrom' στο Unix,'e:' στα MS Windows Error.017=Σφάλμα ανάλυσης λίστας αναπαραγωγής Error.018=Δεν μπορούν να βρεθούν προσβάσιμα κομμάτια Error.019=Μία υπάρχουσα συσκευή έχει ήδη αυτό το όνομα Error.020=Σφάλμα IO κατά την αντιγραφή του αρχείου. Ίσως ο δίσκος είναι γεμάτος Error.021=Το πεδίο URL είναι υποχρεωτικό. Πχ: 'd:\music' στα MS Windows, '/home/foo/music' στο Unix Error.022=Το πεδίο Όνομα είναι υποχρεωτικό. Πχ: 'Σκληρός Δίσκος', 'CD ROCK' Error.023=Αδύνατη η εκτέλεση του κομματιού εκκίνησης Error.024=Αδύνατη η εγγραφή του αρχείου Error.025=Ένα από τα αρχεία που θέλετε να διαβάσετε είναι σε απενεργοποιημένη συσκευή Error.026=Σφάλμα καταχώρησης των players Error.027=Ο συγχρονισμός εγκαταλήφθηκε Error.028=Σφάλμα αποθήκευσης λίστας αναπαραγωγής Error.029=Μία υπάρχουσα συσκευή είναι κατάλογος γονέας αυτής της συσκευής, έχει το ίδιο μονοπάτι, ή είναι κατάλογος παιδί Error.030=Υπερβολικές αποτυχίες σύνδεσης. Ο Jajuk έχει σταματήσει την αναζήτηση online εξωφύλλων Error.101=Η συσκευή δεν υπάρχει ή δεν είναι προσβάσιμη Error.102=Σφάλμα Error.103=Σφάλμα ανάγνωσης πληροφοριών ετικέτας Error.104=Σφάλμα εγγραφής πληροφοριών ετικέτας Error.105=Δε βρέθηκε Resource Bundle key Error.106=Μη συλληφθείσα εξαίρεση Error.107=Η συσκευή ήδη ανανεώνεται ή συγχρονίζεταισ Error.108=Σφάλμα ανάλυσης αρχείου Οπτικής Error.109=Η κλάση υλοποίησης του player η της ετικέτας είναι μη προσβάσιμη Error.110=Το όνομα αυτής της ιδιότητας είναι δεσμευμένο από το εσωτερικό σύστημα του Jajuk. Παρακαλώ διαλέξτε άλλο Error.111=Η συσκευή είναι ήδη ενεργοποιμένη Error.112=Η συσκευή δεν μπορεί να ενεργοποιηθεί Error.113=Δεν είναι δυνατή η αποθήκευση των ρυθμίσεων του χρήστη Error.114=Δεν είναι δυνατή η ανάγνωση των ρυθμίσεων του χρήστη Error.118=Σφάλμα κατά την επεξεργασία του αιτήματος γεγονότος Error.119=Σφάλμα κατά την ανάλυση του αρχείου ιστορικού ή το αρχείο δεν υπάρχει Error.120=Δεν είναι δυνατή η πρόσβαση στη συσκευή: είτε δεν είναι ενεργοποιμένη, είτε ανανεώνεται, είτε συγχρονίζεται Error.121=Η συσκευή είναι σε χρήση και δεν μπορεί να απενεργοποιηθεί Error.122=Σφάλμα FIFO Error.123=Σφάλμα ρύθμισης εμφάνισης-αίσθησης Error.124=Το Jajuk τρέχει ήδη. Μόνο ένα στιγμιότυπο του Jajuk μπορεί να τρέχει κάθε στιγμή. Error.125=Η συσκευή είναι ήδη απενεργοποιμένη Error.126=Η αναζήτηση δεν υποστηρίζεται από αυτή τη μορφή ήχου Error.127=Δεν βρέθηκαν καινούργια κομμάτια για το επιλεγμένο χρονικό όριο. Μπορείτε να ορίσετε το χρονικό όριο στην Προβολή Προτιμήσεις Error.128=Το τρέχον κομμάτι είναι το πρώτο της συλλογής. Δεν υπάρχει προηγούμενο κομμάτι Error.129=Σφάλμα κατά την φόρτωση εικόνας εξωφύλλου Error.131=Δεν είναι δυνατή η διαγραφή του αρχείου Error.133=Το αρχείο συλλογής σας διεκόπει για άγνωστο λόγο. Το Jajuk κατάφερε να επαναφέρει ένα εφεδρικό αρχείο Error.134=Δεν είναι δυνατή η μετονομασία του αρχείου Error.135=Το αρχείο δεν υπάρχει Error.136=Η ενέργεια απέτυχε Error.137=Λάθος μορφή Error.138=Κάποια αρχεία που αντιστοιχίζονται με αυτά τα κομμάτια βρίσκονται σε απενεργοποιμένες συσκευές και συνεπώς δεν έχουν αλλάξει. Error.140=Μη έγκυρο αλφαριθμητικό: δεν πρέπει να περιέχει τους χαρακτήρες & ' " < ή > Error.141=Αυτή η λίστα αναπαραγωγής βρίσκεται σε απενεργοποιμένη η ανανεούμενη συσκευή και δεν είναι διαθέσιμη Error.142=Αυτή η λίστα αναπαραγωγής δείχνει σε μη-υπάρχοντα κομμάτια ή κομμάτια που βρίσκονται εκτός γνωστών συσκευών. Τα κομμάτια αυτά έχουν παραλειφθεί. Error.143=Μη προσβάσιμη τοποθεσία συσκευής Error.144=Σφάλμα ανάλυσης DJ Error.145=Αδύνατη η εκτέλεση του DJ Error.146=Το τρέχον μοτίβο του organizer είναι λάθος.
    Έγκυρες τιμές είναι: %artist (όνομα Καλλιτέχνη); %title (τίτλος Κομματιού); %album (όνομα album);
    %n (Track leading zero); %genre (είδος κομματιού); %year (Έτος)
    και το μοτίβο πρέπει να περιέχει τουλάχιστον ένα shash Error.147=Κάποια αρχεία δεν μετακινήθηκαν (δείτε τις λεπτομέρειες για περισσότερες πληροφορίες) Error.148=Το πεδίο Έτους είναι άγνωστο Error.149=Το πεδίο Άλμπουμ είναι άγνωστο Error.150=Το πεδίο Καλλιτέχνη είναι άγνωστο Error.151=Το πεδίου Τίτλου Κομματιού είναι άγνωστο Error.152=Το πεδίου Κομματιού είναι άγνωστο Error.153=Το πεδίου Είδους είναι άγνωστο Error.154=Δεν είναι δυνατή η μετονομασία του αρχείου, ελέγξτε για λάθος χαρακτήρα στο όνομα του αρχείου ή τις ετικέτες Error.155=Σφάλαμα κατά το retagging των αρχείων, ελέγξτε τα δικαιώματα πρόσβασης Error.156=Κενή Συλλογή Error.157=Λάθος DJ, παρακαλώ επιλέξτε ή δημιουργήστε DJ από το κουμπί DJ της Προβολής Ελέγχου Error.158=Οι περιορισμοί του DJ δεν μπορούν να ληφθούν υπ'όψιν ή δεν υπάρχει διαθέσιμο κομμάτι Error.159=Το συσχετισμένο περριβάλλον έχει διαγραφεί Error.160=Το αρχείο δε μετακινήθηκε, το όνομα αρχείου πηγής και στόχου είναι ίδια. Error.161=Αδύνατη η εγγράφη στον κατάλογο, ελέγξτε τις άδειες πρόσβασης Error.162=Αυτή η εξατομικευμένη ιδιότητα υπάρχει ήδη Error.163=Σφάλμα στην επαναφορά των προεπιλεγμένων Προβολών Error.164=Δε βρέθηκαν προσβάσιμα κομμάτια για το περιβάλλον : Error.165=Λάθος μονοπάτι για τη συλλογή, ο φάκελος δεν μπορεί να βρεθεί η δεν επιτρέπεται η εγγραφή Error.166=Κενό άλμπουμ, αδύνατυ η λήψη εξώφυλλου Error.167=Αδύνατη η δημιουργία αναφοράς Error.168=Δε βρέθηκαν όμοια (duplicate) αρχεία Error.169=Η ενέργεια απέτυχε. Σημειώστε ότι αυτή η ενέργεια απαιτεί σύνδεση Internet για τη λήψη της λίστας σταθμών. Error.170=Σφάλμα αναπαραγωγής webradio Error.171=Δεν έχει οριστεί πηγή συγχρονισμού για αυτήν τη συσκευή, ορίστε την χρησιμοποιώντας τον οδηγό ρύθμισης συσκευών (στην εμφάνιση Συσκευές, κάντε click στη συσκευή). Error.172=Ανέκυψε σφάλμα κατά τη διαγραφή των ακόλουθων αρχείων: Error.173=Ανέκυψε σφάλμα κατά τη διαγραφή των ακόλουθων καταλόγων: Error.174=Σφάλμα κατά την πρόσβαση στην ιστοσελίδα του Freedb, ελένξτε τη σύνδεση με το δίκτυο Error.175=Η λειτουργία ακυρώθηκε Error.176=Εσφαλμένη μορφή, η προτίμηση πρέπει να επιλεχθεί μεταξύ -3 και 3 Error.177=Παρακαλώ εισάγετε έγκυρο χρόνο στη μορφή (ΩΩ24:ΛΛ:ΔΔ) #Warnings Warning.0=Ο MPlayer δε βρέθηκε. Κάποιες μορφές ήχου (flac, wma, aac, mpg2 ... ) θα απενεργοποιηθούν. Αν ο MPlayer είναι ήδη εγκατεστημενός, παρακαλώ ορίστε το μονοπάτι του στην προβλή Προτιμήσεις/καρτέλα Για προχωρημένους. Warning.1=Λάθος έκδοση του MPlayer, MPlayer1.0Pre8 ή ανώτερος απαιτείται. Κάποια μορφές ήχου θα απενεργοποιηθούν. Παρακαλώ δείτε τις οδηγίες εγκατάστασης στο http://jajuk.sourceforge.net/installation.html για να διορθώσετε αυτό το πρόβλημα. Warning.2=Φαίνεται ότι κάποιος άλλος χρησιμοποιεί αυτήν τη στιγμή την τρέχουσα συλλογή του jajuk. Last user to quit will overwrite configuration (options, rates...). Warning.3=Αδύνατο το download του Mplayer. Αν βρίσκεστε πίσω από HTTP proxy, παρακαλώ ρυθμίστε το στην προβολή Προτιμήσεις / καρτέλα Δίκτυο και επανεκκινήστε το Jajuk. Warning.4=Ο Mplayer απαιτείται για να ακούσετε web radios Warning.5=Ο φάκελος προορισμού υπάρχει ήδη, κάποια αρχεία ενδέχεται να επανεγγραφούν, είστε σίγουρος ? #--- Strings by class --- ParameterView.0=Διάρκεια Ιστορικού: ParameterView.2=Ρυθμίστε το χρόνο σε μέρες που θα διατηρείται ιστορικό των κομματιών που παίχτηκαν. Δώστε -1 αν δε θέλετε καθόλου ιστορικό και 0 αν θέλετε μόνιμο ιστορικό. ParameterView.3=Καθαρισμός Ιστορικού ParameterView.4=Καθαρισμός Ιστορικού ParameterView.8=Ιστορικό/Βαθμολογίες ParameterView.9=Αναπαραγωγή: ParameterView.10=Τίποτα ParameterView.11=Δε θα παίζεται μουσική όταν ξεκινάει ο Jajuk ParameterView.12=Τελευταίο κομμάτι από την αρχή ParameterView.13=Αναπαραγωγή του τελευταίου κομματιού από την αρχή ParameterView.14=Τυχαίο κομμάτι ParameterView.15=Αναπαραγωγή ενός τυχαίου κομματιού από ολόκληρη τη συλλογή ParameterView.16=Κομμάτι: ParameterView.17=Διαλέξτε ένα αρχείο για ανπαραγωγή κατά το ξεκίνημα ParameterView.18=Διαλέξτε ένα αρχείο για ανπαραγωγή κατά το ξεκίνημα. Αρχίστε την πληκτρολόγηση για να δείτε μία φιλτραρισμένη λίστα. ParameterView.19=Ξεκίνημα ParameterView.26=Επιβεβαιώσεις ParameterView.27=Πριν τη φυσική διαγραφή ενός αρχείου ParameterView.28=Ερώτηση πριν τη φυσική διαγραφή ενός αρχείου ParameterView.29=Πριν την έξοδο από το Jajuk ParameterView.30=Ερώτηση πριν την έξοδο από το Jajuk ParameterView.33=Επιλογές ParameterView.35=Απόκρυψη κομματιών που βρίσκονται σε απενεργοποιμένες συσκευές ParameterView.36=Επανεκκίνηση όταν φτάσει στο τέλος της συλλογής ParameterView.37=Επανεκκίνηση όλης τη συλλογής όταν φτάσει στο τέλος στην κατάσταση λειτουργίας Συνέχιση ParameterView.38=Γλώσσα: ParameterView.42=Επιλέξτε τη γλώσσα διασύνδεσης ParameterView.43=Θέμα: ParameterView.44=Διαλέξτε θέμα

    (Μπορεί να απαιτήσει επανεκκίνηση του jajuk ώστε να ανανεωθεί) ParameterView.46=Επίπεδο Log: ParameterView.47=Καταστροφικό ParameterView.48=Σφάλμα ParameterView.49=Προειδοποίηση ParameterView.50=Πληροφορίες ParameterView.51=Αποσφαλμάτωση ParameterView.52=Jajuk verbosity: Καταστροφικό: εμφανίζει μόνο κρίσιμα σφάλματα, Σφάλμα: +εμφανίζει σφάλματα, Πληροφορίες: +εμφανίζει μυνήματα πληροφοριών, Προειδοποίηση: +εμφανίζει προειδοποιήσεις, Αποσφαλμάτωση: οποιοδήποτε μύνημα ParameterView.59=Θέση εκκίνησης εισαγωγής (%): ParameterView.60=Θέση εισαγωγής μέσα στο κομμάτι in % από 0 (αρχή κομματιού) έως 99 (τέλος κομματιού) ParameterView.61=Μήκος εισαγωγής (δευτερόλεπτα): ParameterView.62=Μήκος εισαγωγής (σε δευτερόλεπτα) ParameterView.85=Εφαρμογή ParameterView.86=Επαναφορά Προεπιλογών ParameterView.87=Προτιμήσεις ParameterView.98=Patterns ParameterView.99=Διεξαγωγή ανίχνευσης ετικέτας σε βάθος ParameterView.100=Εξαναγκασμός του Jajuk να ξαναδιαβάσει τις πραγματικές id3 ετικέτες.

    Αυτό μπορεί να είναι χρήσιμο στην ανανέωση ετικετών που τροποποιήθηκαν χρησιμοποιώντας άλλο πρόγραμμα.

    ParameterView.101=Χρήση του ονόματος του καταλόγου γονέα ως ονόματος άλμπουμ ParameterView.102=Αν επιλεγεί, το όνομα του καταλόγου γονέα θα χρησιμοποιηθεί ως το όνομα του άλμπουμ για τα κομμάτια των οποίων η ID3 ετικέτα δεν μπορέι να χρησιμοποιηθεί. ParameterView.109=Οι επιλογές αποθηκεύτηκαν ParameterView.110=Οι επιλογές πήραν τις προεπιλεγμένες τιμές ParameterView.111=Μέγεθος της λίστας αναπαραγωγής καλύτερων: ParameterView.112=Δώστε τον αριθμό των κομματιών στη λίστα αναπαραγωγής καλύτερων (από 1 έως 100) ParameterView.113=Χρήση κανονικών εκφράσεων στα φίλτρα ParameterView.114=Χρήση κανονικών εκφράσεων (Regexp μορφή) στα φίτρα πινάκων. Παράδειγμα: .*κάτι.* ParameterView.115=Για προχωρημένους ParameterView.116=Εφεδικό αντίγραφο αρχείου συλλογής ParameterView.117=Επιλέξτε αυτό αν θέλετε να δημιουργήσετε εφεδρικά αντίγραφα του αρχείου συλλογής σας στα αρχεία collection-.xml ParameterView.118=Μέγεθος εφεδρικού αντίγραφου (MB) ParameterView.119=Μέγεθος εφεδρικού αντίγραφου (MB) ParameterView.120=Σύνολο χαρακτήρων της συλλογής ParameterView.121=Σύνολο χαρακτήρων της συλλογής. Το UTF-16 είναι καλύτερο για Ασιατικές γλώσσες και το UTF-8 για Ευρωπαικές γλώσσες. ParameterView.129=Χρονικό όριο καινούργιων κομματιών (μέρες): ParameterView.130=Χρονικό όριο καινούργιων κομματιών σε μέρες: όλα τα κομμάτια που προστίθενται μετάξύ αυτού του αριθμού των ημερών εμφανίζονται στη λίστα αναπαραγωγής καινούργιων κομματιών ParameterView.131=Καλύτερο κομμάτι ParameterView.132=Αναπαραγωγή ενός από τα αγαπημένα σας κομμάτια στο ξεκίνημα ParameterView.133=Καινούργιο κομμάτι ParameterView.134=Αναπαραγωγή ενός καινούργιου κομματιού από τη συλλογή σας στο ξεκίνημα ParameterView.135=Τελευταίο κομμάτι από την τελευταία θέση ParameterView.136=Αναπαραγωγή του κομματιού που παίχτηκε τελευταίο από τη θέση που σταμάτησε ParameterView.139=Δίκτυο ParameterView.142=Proxy user name ParameterView.143=Proxy login name χρησιμοποιείται για πιστοποίηση αυθεντικότητας ParameterView.144=Proxy host name ParameterView.145=Proxy host name ή διεύθυνση IP ParameterView.146=Proxy θύρα ParameterView.147=Proxy TCP-IP θύρα (συχνά 3128) ParameterView.148=Online Λήψη εξωφύλλων ParameterView.149=Χρησιμοποιείστε το αυτόματο εξώφυλλο για να κατεβάσετε εξώφυλλα από άλμπουμ από το Διαδίκτυο (αν απαιτείται, ρυθμίστε τον proxy στην καρτέλα δικτύου) ParameterView.150=Μέγεθος εξωφύλλων ParameterView.151=Μέγεθος εξωφύλλων που κατεβαίβηκαν ParameterView.155=Ακρίβεια αναζήτησης. Όσο μεγαλύτερη είναι η ακίβεια, τόσο λιγότερες λανθασμένες εικόνες εξωφύλλων θα παίρνετε. ParameterView.156=Χαμηλή (αναζήτηση όλων των λέξεων) ParameterView.157=Μέτρια (αναζήτηση ομαδοποιημένων λέξεων) ParameterView.158=Υψηλή (αναζήτηση mandatory ομαδοποιημένων λέξεων) ParameterView.159=Εξώφυλλα ParameterView.160=Χρονικό όριο σύνδεσης(δευτερόλεπτα) ParameterView.161=Χρονικό όριο σύνδεσης σε δευτερόλεπτα: Μία απομακρυσμένη ενέργεια αποτυγχάνει αν ένας peer δεν ανταποκριθεί σε αυτόν το χρόνο. ParameterView.162=Χρονικό όριο μεταφοράς(δευτερόλεπτα) ParameterView.163=Χρονικό όριο μεταφοράς σε δευτερόλεπτα: Μία απομακρυσμένη ενέργεια αποτυγχάνει αν τα απαιτούμενα δεδομένα δεν έχουν κατέβει πλήρως σε αυτόν το χρόνο. ParameterView.164=Πριν την αφαίρεση μίας συσκευής ParameterView.165=Ερώτηση πριν την αφαίρεση μίας συσκευής ParameterView.166=Τυχαία εξώφυλλα ParameterView.167=Εμφάνιση ενός τυχαίου εξωφύλλου ParameterView.169=Προαποθήκευση εξωφύλλων ParameterView.170=Προαποθήκευση όλων των διαθέσιμων εξωφύλλων όποτε είναι δυνατό ParameterView.171=Πριν τη διαγραφή ενός εξωφύλλου από το δίσκο ParameterView.172=Ερώτηση πριν τη διαγραφή ενός εξωφύλλου από το δίσκο ParameterView.177=Αριθμός των προγραμματισμένων κομματιών που είναι ορατά ParameterView.178=Ο αριθμός των προγραμματισμένων κομματιών που θα εμφανιστούν στη λίστα αναπαραγωγής ParameterView.179=Προώθηση με επιλογή ParameterView.180=Αν επιλεγεί, κάνοντας διπλό κλικ σε ένα κομμάτι της συλλογής αυτό προστίθεται στη λίστα αναπαραγωγής ParameterView.181=Προώθηση με drag & drop ParameterView.182=Αν επιλεγεί, τα κομμάτια της συλλογής μπορούν με drag and drop να προστεθούν στη λίστα αναπαραγωγής ParameterView.183=Συγχρονισμός Προβολής Δέντρου και Πίνακα ParameterView.184=Αν επιλεγεί, η Προβολή Πίνακα θα δείχνει μόνο κομμάτια που επιλέγονται στην Προβολή Δέντρου ParameterView.185=Εμφάνιση μπαλονιού κατά την εκκίνηση ενός κομματιού ParameterView.186=Επανεκκίνηση αξιολογήσεων ParameterView.187=Επαναφορά των αξιολογήσεων όλων των κομματιών στο μηδέν ParameterView.188=Πριν το σβήσιμο του ιστορικού ParameterView.189=Πριν την επαναφορά των αξιολογήσεων ParameterView.190=Διάρκεια επικάλυψης-σβησίματος (δευτερόλεπτα) ParameterView.191=Ο αριθμός των δευτερολέπτων επικάλυψης-σβησίματος μεταξύ των κομματιών ParameterView.192=Πρότυπο του οργανωτή αρχείων ParameterView.193=Διαθέσιμα πρότυπα :%artist (Όνομα καλλιτέχνη); %title (Τίτλος κομματιού); %album (Όνομα άλμπουμ); %n (Track leading zero); %genre (Κατηγορία κομματιού); %year (Έτος) ParameterView.194=Πριν την οργάνωση των αρχείων ParameterView.195=Προβολή Κινούμενων Εικόνων: ParameterView.196=Ενεργοποίηση Θερμών Πλήκτρων ParameterView.197=Κάνει κάποια πλήκτρα όπως το F8 να λειτουργούν ακόμη και αν το Jajuk δεν είναι στο επίκεντρο ParameterView.198=Κάποιες αλλαγές θα ενεργοποιηθούν μόνο στο επόμενο η ξεκίνημα του Jajuk ParameterView.199=Scrobble my listening ParameterView.200=Αυτή η επιλογή στέλνει πληροφορίες στο Last.fm ParameterView.201=Last.FM όνομα-χρήστη ParameterView.202=Το όνομα χρήστη που χρησιμοποιείται στο Last.FM ParameterView.203=Last.FM κωδικός-πρόσβασης ParameterView.204=Ο κωδικός πρόσβασης που χρησιμοποιείται στο Last.FM ParameterView.205=Ορίσματα του MPlayer ParameterView.206=Πρόσθετα ορίσματα του MPlayer όπως '-ao esd' ή '-ao arts' ή '-novideo (για να εμποδιστεί η αναπαραγωγή video)' για παράδειγμα ParameterView.207=Jajuk home path ParameterView.208=Ορισμός του φακέλου που περιέχει τη διαμόρφωση του Jajuk (προεπιλεγμένο: /.jajuk) ParameterView.209=Το μονοπάτι του Jajuk configuration έχει αλλάξει για τον τρέχοντα χρήστη (η προηγούμενη συλλογή έχει διατηρηθεί στην παλιά θέση). Το Jajuk μπορεί τώρα να επανεκκινηθεί. ParameterView.210=Αν το cross fade δε λειτουργεί, προσπαθείστε να προσθέσετε <-ao esd> στο Gnome ή <-ao arts> στο KDE στο πεδίο πρόσθετων παραμέτρων στη μηχανή Ήχου( Προβολή Προτιμήσεις / Καρτέλα Για Προχωρημένους). ParameterView.211=Μικρό μόνο ParameterView.212=Μικρό και μεσαίο ParameterView.213=Μεσαίο μόνο ParameterView.214=Μεσαίο και μεγάλο ParameterView.215=Μεγάλο μόνο ParameterView.216=Αναζήτηση χρησιμοποιώντας το όνομα του καλλιτέχνη ParameterView.217=Αναζήτηση χρησιμοποιώντας το όνομα του άλμπουμ ParameterView.218=Αναζήτηση χρησιμοποιώντας το όνομα του κομματιού ParameterView.219=Μεταβλητές περιβάλλοντος ParameterView.220=Ορισμός των μεταβλητών περιβάλλοντος που χρησιμοποιούνται από τον audio player (ARTS_SERVER στο KDE ή ESPEAKER στο Gnome για παράδειγμα). μορφή: var1=xx var2=yyy... #Respect English size for next item ParameterView.221=Μέγεθος Σελίδας προβολής κατάλογος (0: όλα σε μία) ParameterView.222=Ορισμός του αριθμού των άλμπουμ ανά σελίδα στην προβολή κατάλογος. 0: εμφάνιση όλων των εξωφύλλων σε μία σελίδα. ParameterView.223=Μέγεθος γραμματοσειρών ParameterView.224=Ορισμός του μεγέθους των γραμματοσειρών κειμένου ParameterView.225=GUI ParameterView.226=Λειτουργίες ParameterView.228=Εμφάνιση album popups ParameterView.229=Προτιμήσεις προβολής καταλόγου ParameterView.233=Το θέμα θα εφαρμοστεί στο επόμενο ξεκίνημα του Jajuk ParameterView.234=Έλεγχος για ανανεωμένες εκδόσεις του Jajuk ParameterView.235=Last.FM ParameterView.236=No Proxy ParameterView.237=HTTP proxy ParameterView.238=SOCKS proxy ParameterView.239=Proxy password ParameterView.240=Enable Last.FM information queries ParameterView.241=Αν επιλεγεί, το Jajuk θα λάβει ποικίλες πληροφορίες για άλμπουμ και άλλα από το website του Last.FM (βλέπε Προβολή Πρόταση(suggestion) ParameterView.242=Μονοπάτι του Mplayer ParameterView.243=Ορίστε εδώ το πλήρες μονοπάτι με το εκτελέσιμο του mplayer (επιτρέπονται τα κενά)
    Παράδειγμα: /Applications/MPlayer OSX.app/Contents/Resources/External_Binaries/mplayer_intel.app/Contents/MacOS/mplayer ParameterView.244=ημερομηνία Ανακάλυψης = ημερομηνία Αρχείου ParameterView.245=Αν επιλεγεί, το jajuk θεωρεί ως ημερομηνία ανακάλυψης την ημερομηνία συστήματος των αρχείων ήχου
    Απαιτεί να ληφθούν υπόψη οι deep ανανεώσεις ParameterView.246=Μέγεθος εικονιδίων της μπάρας Οπτικών (σε pixels) ParameterView.247=Το μονοπάτι προορισμού περιέχει ένα υπάρχον Jajuk workspace. Το workspace έχει μεταφερθεί σε αυτό το μονοπάτι για τον τρέχοντα χρήστη (το προηγούμενο workspace έχει διατηρηθεί στην παλιά θέση). Το jajuk μπορεί τώρα να επανεκκινηθεί. ParameterView.248=Τίτλος πλαισιού : ParameterView.249=Επαναφορά προτιμήσεων ParameterView.250=Επαναφορά ορισμένων από το χρήστη προτιμήσεων ParameterView.251=Το ιστορικό επαναφέρθηκε με επιτυχία ParameterView.252=Οι βαθμολογίες και ο αριθμός αναπραγωγών επαναφέρθηκαν με επιτυχία ParameterView.253=Οι προτιμήσεις επαναφέρθηκαν με επιτυχία Main.21=Επιβεβαίωση Main.22=Downloading MPlayer Player.0=Αναμονή για γραμμή ήχου (κατειλλημένη) Device.25=] ανανεώθηκε σε Device.27= νέα αρχεία Device.31=Συγχρονισμός [ Device.33=Ο συγχρονισμός έγινε σε Device.35= δημιουργηθέντα αρχεία ( Device.36= MB) Device.41=Συγχροισμός [ Device.42=] Αντιγραφή [ Device.43= μη αναγνώσιμες ετικέτες Device.44=Είσοδος(Entering) FIFO.4=). Θέλετε να προσπαθήσετε να το ενεργοποιήσετε ? FIFO.10=Παίζει τώρα: FIFO.13= Kbps FIFO.14=Παίζει τώρα Web Radio: HistoryItem.0=dd/MM/yy HH:mm DeviceWizard.0=Ρύθμιση Συσκευής DeviceWizard.1=Τύπος Συσκευής(*): DeviceWizard.2=Όνομα Συσκευής(*): DeviceWizard.3=Τοποθεσία Συσκευής(*): DeviceWizard.4=Unix mount point (προαιρετικό): DeviceWizard.7=Πραγματοποίηση στιγμιαίας ανανέωσης DeviceWizard.8=Αυτόματη ενεργοποίηση στο ξεκίνημα DeviceWizard.10=Συγχρονισμένη με: DeviceWizard.11=Συγχρονισμός μονής κατεύθυνσης DeviceWizard.12=Όλα τα νέα αρχεία που βρίσκονται στη συσκευή-πηγή αντιγράφονται σε αυτή τη συσκευή. Τίποτα δε γράφεται στη συσκευή-πηγή. DeviceWizard.13=Αμφίδρομος συγχρονισμός DeviceWizard.14=Όλα τα νέα αρχεία που βρίσκονται στη μία συσκευή αντιγράφονται στην άλλη DeviceWizard.43=Παρακαλώ επιλέξτε κατάλογο DeviceWizard.44=Η συσκευή δημιουργήθηκε DeviceWizard.45=Παρακαλώ δώστε ένα όνομα στη συσκευή. Πχ: CD A, Laptop... DeviceWizard.46=Παρακαλώ δώστε την τοποθεσία της συσκευής. Πχ: d:\music στα Windows, /home/foo/music στο Unix DeviceWizard.48=Επιλέξτε αυτό αν θέλετε να πραγματοποιήσετε μία άμεση ανανέωση της συσκευής (προτείνεται).

    Σημειώστε ότι αυτή η διαδικασία μπορεί να διαρκέσει αρκετά για μεγάλες συσκευές.

    DeviceWizard.49=Επιλέξτε αυτό αν θέλετε να ενεργοποιήσετε αυτόματα τη συσκευή όταν το Jajuk ξεκινάει.

    Προτείνεται για καταλόγους στον τρέχοντα σκληρό δίσκο, αλλά όχι για CDs.

    DeviceWizard.50=Δώστε το διάστημα σε λεπτά για την αυτόματη αναζήτηση νέων αρχείων (0: καθόλου αναζήτηση, 0.5 λεπτά είναι το ελάχιστο interval) DeviceWizard.51=Διαλέξτε αυτό αν θέλετε να συγχρονίσετε αυτή τη συσκευή με μία άλλη DeviceWizard.52=Διαλέξτε συσκευή-πηγή DeviceWizard.53=Ανανέωση της συσκευής κάθε #limited string size DeviceWizard.54=λεπ. JajukJMenuBar.0=Αρχείο JajukJMenuBar.1=Άνοιγμα αρχείου JajukJMenuBar.3=Έξοδος JajukJMenuBar.5=Ιδιότητες JajukJMenuBar.6=Δημιουργία εξατομικευμένης ιδιότητας JajukJMenuBar.7=Διαγραφή εξατομικευμένης ιδιότητας JajukJMenuBar.8=Προβολές JajukJMenuBar.9=Λειτουργίες JajukJMenuBar.10=Επανάληψη JajukJMenuBar.11=Τυχαία σειρά JajukJMenuBar.12=Συνέχιση JajukJMenuBar.13=Εισαγωγή JajukJMenuBar.14=Βοήθεια JajukJMenuBar.15=Περιεχόμενα της Βοήθειας JajukJMenuBar.16=About JajukJMenuBar.17=Επαναφορά προεπιλεγμένων Προβολών JajukJMenuBar.18=Οδηγός Συσκευής JajukJMenuBar.19=Αναφορά σφάλματος ή αιτήματος χαρακτηριστικού-γνωρίσματος JajukJMenuBar.20=Συμβουλή της Ημέρας JajukJMenuBar.21=Ρυθμίσεις JajukJMenuBar.22=Προτιμήσεις JajukJMenuBar.23=Εμφάνιση ιχνών αποσφαλμάτωσης JajukJMenuBar.24=Εμφάνιση μόνο των διαθέσιμων κομματιών JajukJMenuBar.25=Εμφάνιση Προβολής JajukJMenuBar.26=Επαναφορά Προβολών(σε όλες τις οπτικές) JajukJMenuBar.27=Έλεγχος για ανανεωμένες εκδόσεις του Jajuk JajukJMenuBar.28=Εργαλεία JajukJMenuBar.29=Έξυπνες Λειτουργίες PlaylistFileItem.1=Kαινούργια PlaylistFileItem.2=Νέα λίστα αναπαραγωγής PlaylistFileItem.3=Bookmarks PlaylistFileItem.4=Καλύτερα PlaylistFileItem.5=Τρέχουσα ουρά JajukFileChooser.0=Επιλογέας αρχείου SearchBox.0=Διεξαγωγή αναζήτησης μεταξύ κομματιών, καλλιτεχνών, ειδών, καταλόγων... CommandJPanel.0=Εμφάνιση ιστορικού αναπαραγωγής CommandJPanel.1=Κατάσταση λειτουργίας Επανάληψη: Αναπαράγει τα κομμάτια σε κύκλο CommandJPanel.2=Κατάσταση λειτουργίας Τυχαία Σειρά: Παίζει τυχαία επιλεγμένα κομμάτια CommandJPanel.3=Κατάσταση λειτουργίας Συνέχιση: Συνεχίζει με την αναπαραγωγή προγραμματισμένων κομματιών όταν τελειώσει CommandJPanel.4=Κατάσταση λειτουργίας Εισαγωγή: Παίζει μόνο ένα μέρος κάθε κομματιού. Ο χρόνος και η σχετική απόσταση μπορούν να οριστούν στην Προβολή Προτιμήσεις CommandJPanel.5=Αναπαραγωγή μιας τυχαίας επιλογής από ολόκληρη τη συλλογή CommandJPanel.6=Αναπαραγωγή των δικών σας αγαπημένων κομματιών CommandJPanel.7=Σίγαση CommandJPanel.8=ναπαραγωγή του προηγούμενου κομματιού στη τρέχουσα επιλογή
    Shift+click εκκινεί το προηγούμενο άλμπουμ CommandJPanel.9=Αναπαραγωγή του επόμενου κομματιού στη τρέχουσα επιλογή
    Shift+click εκκινεί το επόμενο άλμπουμ CommandJPanel.10=Γρήγορη επαναφορά στο τρέχον κομμάτι
    Shift+click για επανάληψη CommandJPanel.11=Παύση / Συνέχιση τρέχοντος κομματιού CommandJPanel.12=Διακοπή CommandJPanel.13=Γρήγορα μπροστά στο τρέχον κομμάτι CommandJPanel.14=Ένταση CommandJPanel.15==Κάντε click εδώ για να αλλάξετε τη μορφή εμφάνισης του χρόνου CommandJPanel.16=Launch DJ selection CommandJPanel.17=Διαχείριση των DJs CommandJPanel.18=Εκκίνηση προεπιλεγμένου DJ CommandJPanel.19=Διαχείρηση των Περιβαλλόντων CommandJPanel.20=Κομμάτι - κομμάτι CommandJPanel.21=Ανακάτεμα Άλμπουμ - άλμπουμ CommandJPanel.22=Άλμπουμ - άλμπουμ CommandJPanel.23=Κάντε Click to clear search CommandJPanel.24=Διαμόρφωση των web ραδιοφώνων CommandJPanel.25=Άνοιγμα του ραφιοφώνου InformationJPanel.5=Συνολικός χρόνος αναπραγωγής μουσικής InformationJPanel.6=Βitrate κομματιού InformationJPanel.7=Πρόοδος τρέχοντος κομματιού #song name BY artist ON album name InformationJPanel.8=%title από %artist στο %album AbstractPlaylistEditorView.0=Τίτλος AbstractPlaylistEditorView.1=Τοποθεσία AbstractPlaylistEditorView.2=Τρέξτε αυτήν τη λίστα αναπαραγωγής AbstractPlaylistEditorView.3=Αποθηκεύστε αυτήν τη λίστα αναπαραγωγής AbstractPlaylistEditorView.4=Προσθέστε ένα item σε αυτήν τη λίστα αναπαραγωγής AbstractPlaylistEditorView.5=Διαγράψτε ένα item από αυτήν τη λίστα αναπαραγωγής AbstractPlaylistEditorView.6=Μετακινήστε το επιλεγμένο κομμάτι επάνω AbstractPlaylistEditorView.7=Μετακινήστε το επιλεγμένο κομμάτι κάτω AbstractPlaylistEditorView.9=Διαγράψτε αυτήν τη λίστα αναπαραγωγής AbstractPlaylistEditorView.10=Προσθέστε ένα τυχαίο κομμάτι σε αυτήν τη λίστα αναπαραγωγής AbstractPlaylistEditorView.15=Λίστες αναπαραγωγής AbstractPlaylistEditorView.17=Πρόκειται να ανανεώσετε τις ακόλουθες λίστες αναπαραγωγής: AbstractPlaylistEditorView.18=Κομμάτι στην ουρά AbstractPlaylistEditorView.19=Επαναλαμβανόμενο κομμάτι AbstractPlaylistEditorView.20=Προγραμματισμένο κομμάτι AbstractPlaylistEditorView.21=Κομμάτι λίστας αναπαραγωγής AbstractPlaylistEditorView.22=Αποθήκευση λίστας αναπαραγωγής AbstractPlaylistEditorView.27=Προετοιμασία Party AbstractPlaylistEditorView.28=ο φάκελος δημιουργήθηκε επιτυχώς στο StatView.0=Άλλα StatView.1=Είδη StatView.2=Δεν υπάρχουν διαθέσιμα δεδομένα StatView.3=Άλλα StatView.4=Μέγεθος ανά συσκευή (Gb) StatView.5=Δεν υπάρχουν διαθέσιμα δεδομένα StatView.7=Μέγεθος συλλογής ανά μήνα StatView.8=Μήνες StatView.9=Μέγεθος (Gb) StatView.10=Δεν υπάρχουν διαθέσιμα δεδομένα StatView.12=Συνολικός αριθμός κομματιών ανά μήνα StatView.13=Μήνες StatView.14=Αριθμός κομματιών StatView.15=Δεν υπάρχουν διαθέσιμα δεδομένα StatView.16=Στατιστικά StatView.24=Παλιότερα CDScanView.0=Ετικέτα CD: CDScanView.1=Ετικέτα CD. Πχ: CD1, ROCK... CDScanView.2=Ετικέτα CD. Πχ: CD1, ROCK... CDScanView.3=Τοποθεσία CD: CDScanView.4=Τοποθεσία που βρίσκεται το CD. Πχ: '/cdrom' στο Unix, 'e:' στα MS Windows... CDScanView.5=Τοποθεσία που βρίσκεται το CD. Πχ: '/cdrom' στο Unix, 'e:' στα MS Windows... CDScanView.6=Σάρωση CDScanView.12=Σαρωτής CD CDScanView.18=Σαρώνει το CD και προσθέτει όλα τα μουσικά αρχεία στη συλλογή CDScanView.19=Διαλέξτε την τοποθεσία του CD TracksTreeView.0=Δέντρο Κομματιών TracksTreeView.27=Συλλογή TracksTreeView.31= κομμάτια TracksTreeView.33=Δημιουργία αναφοράς TracksTreeView.34=Λήψη ετικετών Online TracksTreeView.35=Ημερομηνία ανακάλυψης TracksTreeView.36=λιγότερο από μία εβδομάδα TracksTreeView.37=λιγότερο από ένα μήνα TracksTreeView.38=λιγότερο από έξι μήνες TracksTreeView.39=παλιότερο TracksTreeView.40=λιγότερο από ένα έτος TracksTreeView.41=λιγότερο από δύο έτη TracksTreeView.42=λιγότερο από πέντε έτη TracksTreeView.43=λιγότερο από δέκα έτη TracksTreeView.44=λιγότερο από τρεις μήνες TracksTreeView.45=Έτος CoverView.2=Διαγραφή αυτού του εξωφύλλου από το δίσκο CoverView.3=Εξώφυλλο CoverView.4=Προηγούμενη εικόνα από το δίσκο και/ή το web αν η επιλογή αυτόματο-εξώφυλλο είναι επιλεγμένη CoverView.5=Επόμενη εικόνα από το δίσκο και/ή το web αν η επιλογή αυτόματο-εξώφυλλο είναι επιλεγμένη CoverView.6=Αποθήκευση εξωφύλλου με το πραγματικό του όνομα CoverView.8=Χρήση αυτού του cover εξωφύλλου σαν το επιλεγμένο εξώφυλλο για αυτό το άλμπουμ CoverView.9=Εξώφυλλα CoverView.10=Αποθήκευση εξωφύλλου ως CoverView.11=Το εξώφυλλο αποθηκεύτηκε CoverView.12=Άλμπουμ CoverView.13=Τίτλος AnimationView.0=Κινούμενες Εικόνες FilesTreeView.0=Δέντρο Αρχείων FilesTreeView.3=Αντιγραφή FilesTreeView.4=Αποκοπή FilesTreeView.5=Επικόλληση FilesTreeView.7=Διαγραφή FilesTreeView.14=Αποσυγχρονισμός FilesTreeView.15=Επανασυγχρονισμός FilesTreeView.16=Δημιουργία λίστας αναπαραγωγής FilesTreeView.17=Αντιγραφή FilesTreeView.18=Αποκοπή FilesTreeView.28=Ενεργοποίηση FilesTreeView.29=Απενεργοποίηση FilesTreeView.30=Εξαναγκασμένη ανανέωση FilesTreeView.31=Συγχρονισμός FilesTreeView.32=Έλεγχος FilesTreeView.33=Δημιουργία λιστών αναπαραγωγής FilesTreeView.40=Αντιγραφή FilesTreeView.41=Αποκοπή FilesTreeView.42=Επικόλληση FilesTreeView.47=Συλλογή FilesTreeView.52= αρχεία: FilesTreeView.53= GB FilesTreeView.54= MB FilesTreeView.55=Ρύθμιση συσκευής FilesTreeView.59=Θέλετε να διεξάγετε γρήγορη ή σε βάθος (επανανάγνωση ετικετών) αναζήτηση? FilesTreeView.60=Γρήγορη FilesTreeView.61=Σε βάθος FilesTreeView.62=Οργάνωση αρχείων TracksTableView.0=Πίνακας κομματιών TracksTableView.7=Αναπαραγωγή TracksTableView.8=Προώθηση TracksTableView.9=Τυχαία αναπαραγωγή TracksTableView.10=Επανάληψη TracksTableView.11=Αναπαραγωγή Άλμπουμ TracksTableView.12=Αναπαραγωγή Καλλιτέχνη TracksTableView.14=Ιδιότητες TracksTableView.15=Προσθήκη στα αγαπημένα AbstractTableView.0=Φίλτρο: AbstractTableView.1=Ιδιότητα για φιλτράρισμα AbstractTableView.3=Τιμή που χρησιμοποιείται από το φίλτρο AbstractTableView.4=Εφαρμογή φίλτρου AbstractTableView.5=Καθαρισμός του φίλτρου AbstractTableView.6=Εφαρμογή προχωρημένου φίλτρου AbstractTableView.7=περιέχει: AbstractTableView.8=Οτιδήποτε AbstractTableView.10=(Μη διαθέσιμο) AbstractTableView.11=Κάνει τον πίνακα τροποποιήσιμο AboutView.7=About AboutView.8=Άδεια AboutView.9=Σύστημα AboutView.10=About PhysicalPlaylistRepositoryView.0=Αναπαραγωγή PhysicalPlaylistRepositoryView.1=Επεξεργασία PhysicalPlaylistRepositoryView.2=Αποθήκευση ως PhysicalPlaylistRepositoryView.3=Διαγραφή PhysicalPlaylistRepositoryView.4=Ιδιότητες PhysicalPlaylistRepositoryView.6=Φυσικές Λίστες αναπαραγωγής PhysicalPlaylistRepositoryView.8=Έξυπνη PhysicalPlaylistRepositoryView.9=Ουρά αναπαραγωγής PhysicalPlaylistRepositoryView.10=Τρέχουσα ουρά: σύρετε και αφήστε κομμάτια για αναπαραχθούν PhysicalPlaylistRepositoryView.11=Νέα PhysicalPlaylistRepositoryView.12=Νέα λίστα αναπαραγωγής: σύρετε και αφήστε κομμάτια για να τα προσθέσετε στη λίστα αναπαραγωγής PhysicalPlaylistRepositoryView.13=Bookmarks PhysicalPlaylistRepositoryView.14=Bookmark λίστα αναπαραγωγής: σύρετε και αφήστε κομμάτια to bookmark PhysicalPlaylistRepositoryView.15=Καλύτερα PhysicalPlaylistRepositoryView.16=Λίστα αναπαραγωγής Καλύτερα: περιέχει τα κομμάτια που ακούτε περισσότερο PhysicalPlaylistRepositoryView.17=Καινούργια PhysicalPlaylistRepositoryView.18=Λίστα αναπαραγωγής Καινούργια: περιέχει τα νεότερα κομμάτια PhysicalPlaylistRepositoryView.19=Προετοιμασία Party FilesTableView.0=Πίνακας Αρχείων FilesTableView.15=Αναπαραγωγή καταλόγου #Dev: do not use ID = 16, next label is FilesTableView.17 DeviceView.0=Προσθήκη συσκευής DeviceView.1=Απομάκρυνση απενεργοποιμένης συσκευής (δε διαγράφει τίποτα από το δίσκο) DeviceView.2=Ιδιότητες επιλεγμένης συσκευής DeviceView.3=Ενεργοποίηση επιλεγμένης συσκευής DeviceView.4=Απενεργοποίηση επιλεγμένης συσκευής DeviceView.5=Έλεγχος διαθεσιμότητας επιλεγμένης συσκευής DeviceView.6=Εξαναγκασμένη ανανέωση της επιλεγμένης συσκευής DeviceView.7=Συγχρονισμός επιλεγμένης συσκευής DeviceView.8=Ενεργοποίηση DeviceView.9=Απενεργοποίηση DeviceView.10=Έλεγχος DeviceView.11=Εξαναγκασμένη ανανέωση DeviceView.12=Συγχρονισμός DeviceView.13=Απομάκρυνση συσκευής DeviceView.14=Ρύθμιση DeviceView.17=Νέα DeviceView.18=Προσθήκη συσκευής DeviceView.21=Αυτή η συσκευή είναι διαθέσιμη DeviceView.22=Αυτή η συσκευή είναι απροσπέλαστη DeviceView.23=Συσκευές JajukWindow.1=Ήχος JajukWindow.2=Σίγαση JajukWindow.3=Jajuk JajukWindow.4=Έξοδος JajukWindow.5=About Jajuk JajukWindow.6=Τυχαία αναπαραγωγή JajukWindow.7=Αναπαραγωγή των Καλύτερων JajukWindow.10=Παύση JajukWindow.11=Διακοπή JajukWindow.12=Αναπαραγωγή JajukWindow.13=Προηγούμενο JajukWindow.14=Επόμενο JajukWindow.15=Αναπαραγωγή Καινούργιων JajukWindow.16=Συνέχιση Άλμουμ JajukWindow.17=Jajuk: Advanced Jukebox JajukWindow.18=Έτοιμο για αναπαραγωγή JajukWindow.19=Σίγαση/Ήχος JajukWindow.21=Έξοδος JajukWindow.22=About Jajuk JajukWindow.23=Αναπαραγωγή τυχαίων κομματιών από τη συλλογή JajukWindow.24=Αναπαραγωγή των πιο δημοφιλών κομματιών της συλλογής JajukWindow.26=Αναπαραγωγή/Παύση JajukWindow.27=Διακοπή JajukWindow.29=Προηγούμενο Κομμάτι - left-click+[SHIFT]= προηγούμενο άλμπουμ. JajukWindow.30=Επόμενο Κομμάτι - left-click+[SHIFT]= επόμενο άλμπουμ. JajukWindow.31=Αναπαραγωγή των νεότερων κομματιών της συλλογής JajukWindow.32=Συνέχιση Άλμπουμ: Finish playing the current album JajukWindow.33=Ένταση JajukWindow.34=Θέση JajukWindow.35=Παίζει: JajukWindow.36=Τρέχον Περιβάλλον: JajukWindow.37=Δεν έχει οριστεί Περιβάλλον #Do not use JajukWindow.38, next is JajukWindow.39 SimpleDeviceWizard.0=Γρήγορη δημιουργία συσκευής FirstTimeWizard.0=Γρήγορο ξεκίνημα FirstTimeWizard.1=Καλώς Ήρθατε! Αυτός ο οδηγός θα σας βοηθήσει στη δημιουργία της μουσικής σας συλλογής. FirstTimeWizard.2=Παρακαλώ επιλέξτε την τοποθεσία της μουσικής σας FirstTimeWizard.4=Εμφάνιση βοήθειας τώρα FirstTimeWizard.5=Παρακαλώ επιλέξτε κατάλογο FirstTimeWizard.6=Προχωρημένες προτιμήσεις FirstTimeWizard.7=Ορισμός του φακέλου που περιέχει το χώρο-εργασίας του Jajuk : HelpView.2=Βοήθεια DownloadManager.0=Το Jajuk χρειάζεται τον κωδικό πρόσβασης του HTTP proxy σας για να λάβει εξώφυλλα.
    Αν δεν τα θέλετε, παρακαλώ αλλάξτε τις ρυθμίσεις σας στην καρτέλα Εξώφυλλα της Προβολής Προτιμήσεις.
    Αν δεν έχετε proxy, παρακαλώ αλλάξτε τις ρυθμίσεις σας στην καρτέλα Δίκτυο της Προβολής Προτιμήσεις. DownloadManager.1=Απαιτείται Κωδικός Πρόσβασης PropertiesWizard.0=Ιδιότητες αντικειμένου PropertiesWizard.1=Ιδιότητα PropertiesWizard.2=Τιμή PropertiesWizard.3=Τροποποιήσιμη? PropertiesWizard.4=Σύνδεσμος PropertiesWizard.6=Επιλογή PropertiesWizard.7=Τύπος PropertiesWizard.8=Επιτυχώς ενημερομένη ιδιότητα PropertiesWizard.9=Δεν υπάρχει τροποποιήσιμη ιδιότητα για αυτήν την επιλογή PropertiesWizard.10=οι ιδιότητες έχουν οριστεί PropertiesWizard.11=Εγγραφή ετικέτας σε: PropertiesWizard.12=Σύνδεσμος στις ιδιότητες του δοθέντος στοιχείου NewPropertyWizard.0=Δημιουργία Εξατομικευμένης Ιδιότητας NewPropertyWizard.3=(*)Τύπος NewPropertyWizard.4=Μορφή NewPropertyWizard.5=Προεπιλεγμένη τιμή CustomPropertyWizard.0=(*)Αντικείμενο CustomPropertyWizard.1=(*)Όνομα Εξατομικευμένης Ιδιότητας RemovePropertyWizard.0=Διαγραφή Εξατομικευμένης Ιδιότητας QualityFeedbackWizard.20=Ένα νέο παράθυρο θα ανοίξει τώρα για να υποβάλετε το ticket σας στον εξωτερικό σας πλοηγό(browser). Τα τελευταία σας anonymized traces έχουν ήδη προωθηθεί στο clipboard σας, παρακαλώ επικολλήστε τα στο πεδίο περιγραφής(description field) αν είναι αναφορά σφάλματος (αυτό θα αυξήσει σε μεγάλο βαθμό τις πιθανότητες διόρθωσης του προβλήματός σας). IncRateAction.0=Αύσηση της αξιολόγησης του τρέχοντος κομματιού SplashScreen.0=Αρχικοί έλεγχοι SplashScreen.1=Φόρτωμα συλλογής SplashScreen.2=Εκκίνηση της μηχανής μουσικής SplashScreen.3=Εκκίνηση της διασύνδεσης γραφικών CatalogView.0=Κατάλογος εξωφύλλων #Note: CatalogView.2 label musn't be much larger than in english for correct display in 800x600 CatalogView.2=Εμφάνιση των άλμπουμ χωρίς εξώφυλλο CatalogView.3=Ανανέωση του καταλόγου CatalogView.4=Μέγεθος μικρογραφίας: CatalogView.5=Δημιουργήθηκε μικρογραφία για: CatalogView.7=Λήψη εξωφύλλων online CatalogView.8=Δε βρέθηκε εξώφυλλο CatalogView.9=Προηγούμενη CatalogView.10=Επόμενη CatalogView.11=Σελίδα: CatalogView.12=Εμφάνιση προηγούμενης σελίδας μικρογραφιών CatalogView.13=Εμφάνιση επόμενης σελίδας μικρογραφιών CatalogView.14=Επιλέξτε σελίδα μικρογραφιών προς εμφάνιση CatalogView.15=Μέγεθος Μικρογραφιών: CatalogView.16=άλμπουμ CatalogView.17=/σελίδα CatalogView.18=Επιλογή εξωφύλλου CatalogView.19=Αναδόμηση μικρογραφιών CatalogView.20=Εμφάνιση λεπτομέρειας WikipediaView.0=Wikipedia WikipediaView.1=Επιλέξτε γλώσσα: WikipediaView.3=Δε βρέθηκε αποτέλεσμα WikipediaView.5=Αναζήτηση με το όνομα Καλλιτέχνη WikipediaView.6=Αναζήτηση με το όνομα Άλμπουμ WikipediaView.7=Αναζήτηση με βάση τον τίτλο TipOfTheDayView.0=Συμβουλή της ημέρας TipOfTheDayView.1=Ήξερες...? TipOfTheDayView.2=Εμφάνιση στο ξεκίνημα? CDDBWizard.0=Αποδοχή CDDBWizard.1=Όνομα αρχείου CDDBWizard.2=Τίτλος τρέχοντος Κομματιού CDDBWizard.3=Τίτλος τρέχοντος Άλμπουμ CDDBWizard.4=Προτεινόμενος Τίτλος Κομματιού CDDBWizard.5=Προτεινόμενος Τίτλος Άλμπουμ : CDDBWizard.6=Έγινε! Βρέθηκε CDDBWizard.7=πιθανές ταυτίσεις CDDBWizard.12=Δε βρέθηκε ταύτιση! CDDBWizard.14=Αυτός ο κατάλογος δεν περιέχει αρχεία CDDBWizard.16=Κατηγορία: CDDBWizard.17=Βρέθηκε αποτέλεσμα που ταυτίζεται ακριβώς! CDDBWizard.18=Ταύτιση/Ταυτίσεις CDDBWizard.19=Λήψη ετικετών Online RefactorWizard.0=Το αρχείο μετακινήθηκε : DigitalDJWizard.0=Επιλέξτε τη μορφή του νέου DJ DigitalDJWizard.1=Προγραμματισμός βασισμένος σε μεταβάσεις (ROCK -> POP) DigitalDJWizard.2=Προγραμματισμός βασισμένος σε ποσοστά (20% JAZZ, 30% ROCK) DigitalDJWizard.3=Προγραμματισμός βασισμένος σε περιβάλλον (Soft, Party...) DigitalDJWizard.4=Οδηγός Ψηφιακού DJ DigitalDJWizard.5=Γενική Ρύθμιση του DJ DigitalDJWizard.6=Όνομα του DJ (*) DigitalDJWizard.8=Ελάχιστος αριθμός αστεριών: DigitalDJWizard.9=Επικάλυψη-σβήσιμο (δευτερόλεπτα): DigitalDJWizard.10=Τα κομμάτια παίζονται μόνο μία φορά DigitalDJWizard.11=Drop DigitalDJWizard.12=Από Είδη DigitalDJWizard.13=Σε Είδη DigitalDJWizard.14=Επιλογή ειδών (επιτρέπονται οι πολλαπλές επιλογές) DigitalDJWizard.15=Αριθμός κομματιών DigitalDJWizard.16=Θέλεις... DigitalDJWizard.17=Να δημιουργήσεις καινούργιο DJ? DigitalDJWizard.18=Να αλλάξεις έναν υπάρχοντα DJ? DigitalDJWizard.19=Να διαγράψεις έναν DJ? DigitalDJWizard.20=Νέος DJ βασισμένος σε μεταβάσεις #limited string size DigitalDJWizard.21=Διαγραφή #limited string size DigitalDJWizard.22=Προέλευση #limited string size DigitalDJWizard.23=Προορισμός #limited string size DigitalDJWizard.24=Nb #limited string size DigitalDJWizard.25=Αρχίζει με: DigitalDJWizard.26=Παρακαλώ δημιουργείστε τουλάχιστον μία μετάβαση #limited string size DigitalDJWizard.27=Επιλογή ειδών #limited string size DigitalDJWizard.28=% DigitalDJWizard.29=Νέος DJ βασισμένος σε ποσοστά DigitalDJWizard.30=Παρακαλώ δημιουργείστε τουλάχιστον ένα ποσοστό DigitalDJWizard.31=Νέος DJ βασισμένος σε περιβάλλον DigitalDJWizard.32=Νέο DigitalDJWizard.33=Δημιουργία νέου περιβάλλοντος DigitalDJWizard.34=Διαγραφή DigitalDJWizard.35=Διαγραφή επιλεγμένου περιβάλλοντος DigitalDJWizard.36=Όνομα του Περιβάλλοντος DigitalDJWizard.37=Όνομα DigitalDJWizard.38=Παρακαλώ δημιουργείστε τουλάχιστον ένα περιβάλλον DigitalDJWizard.39=Παρακαλώ συμπληρώστε το όνομα του περιβάλλοντος και επιλέξτε τα είδη του περιβάλλοντος DigitalDJWizard.40=Παρακαλώ διαλέξτε έναν DJ DigitalDJWizard.41=Παρακαλώ δώστε ένα όνομα στον DJ DigitalDJWizard.42=Ένας DJ με αυτό το όνομα υπάρχει ήδη DigitalDJWizard.43=Αλλαγή DJ DigitalDJWizard.44=Διαλέξτε τον DJ που θα ρυθμίσετε DigitalDJWizard.45=Επιλογή ενέργειας DigitalDJWizard.46=Επιλογή τύπου DJ DigitalDJWizard.47=Παρακαλώ διαλέξτε ή δημιουργείστε περιβάλλον DigitalDJWizard.48=Γενικά Χαρακτηριστικά DigitalDJWizard.49=Παρακαλώ συμπληρώστε τα γενικά χαρακτηριστικά του DJ DigitalDJWizard.50=Παρακαλώ ορίστε ποσοστά DigitalDJWizard.51=Διαγραφή DJ DigitalDJWizard.52=Παρακαλώ ορίστε μεταβάσεις DigitalDJWizard.53=Ελάχιστος αριθμός αστεριών αξιολόγησης για τα κομμάτια που επιλέγονται (1: όλα τα κομμάτια) DigitalDJWizard.54=Διάρκει επικάλυψης-σβησίματος ανάμεσα στα κομμάτια DigitalDJWizard.55=Αν επιλεγεί θα περιέχεται κάθε κομμάτι μόνο μία φορά DigitalDJWizard.56=Οδηγός Περιβαλλόντων DigitalDJWizard.57=Διαχείριση των περιβάλλονόντων DigitalDJWizard.58=Επιλογή περιβάλλοντος: DigitalDJWizard.59=Το άθροισμα όλων των ποσοστών πρέπει να είναι < 100 % DigitalDJWizard.60=Υπάρχον όνομα περιβάλλοντος DigitalDJWizard.61=Διαγραφή DJ #limited string size DigitalDJWizard.62=Προεπιλογές DigitalDJWizard.63=Προσθήκη προεπιλεγμένων περιβαλλόντων DigitalDJWizard.64=Οτιδήποτε DigitalDJWizard.66=Επιλογή προεπιλεγμένου Περιβάλλοντος #--- Tips of day --- Ambience.0=Rock/Pop Ambience.1=Rap Ambience.2=HardRock Ambience.3=Techno Ambience.4=Electro Ambience.5=Classical Ambience.6=Soft Ambience.7=Party Ambience.8=Jazz Ambience.9=World Ambience.10=Others Ambience.11=Folk/Oldies Ambience.12=Inde Ambience.13=Latin DebugLogAction.0=Καταγραφή ιχνών αποσφαλμάτωσης DebugLogAction.1=Ανανέωση CopyClipboardAction.0=Αντιγραφή διεύθυνσης στο clipboard LaunchInBrowserAction.0=Άνοιγμα διεύθυνσης στον προεπιλεγμένο browser ReportAction.0=Αναφορά επιτυχούς δημιουργίας ReportAction.1=Μουσική Αναφορά Jajuk ReportAction.2=Παρακαλώ λάβετε υπ'όψην το περιβάλλον και μην εκτυπώνετε αν δεν είναι απολύτως απαραίτητο ReportAction.3=Λίστα Άλμπουμ ReportAction.4=Κομμάτια ανά άλμπουμ ReportAction.5=Λίστα καλλιτεχνών ReportAction.6=Άλμπουμ ανά καλλιτέχνες ReportAction.7=Λίστα είδος ReportAction.8=Άμλπουμ ανά είδος ReportAction.9=Artists/ άλμπουμ ανά είδος ReportAction.10=Λίστα φακέλων ReportAction.11=Αρχεία ανά φάκελο ReportAction.12=Όνομα αρχείου ReportAction.13=Όνομα κομματιού ReportAction.14=Λίστα συσκευών ReportAction.15=Φάκελοι ανά συσκευή ReportAction.16=Φάκελοι/ αρχεία ReportAction.17=συλλογή ReportAction.18=Artists/ άλμπουμ/ κομμάτια ανά genre ReportAction.19=Μεταπήδηση σε: ActionMove.0=Επικόλληση ActionRefresh.0=Εξαναγκασμένη ανανέωση ActionRefresh.1=Ανανέωση του καταλόγου RenameAction.0=Μετονομασία RenameAction.1=Παρακαλώ εισάγετε το νέο όνομα για αυτό το αρχείο: RenameAction.2=PΠαρακαλώ εισάγετε το νέο όνομα για αυτόν τον κατάλογο: NewFolderAction.0=Νέος Φάκελος NewFolderAction.1=Παρακαλώ εισάγετε το όνομα του νέου Φακέλου: NewFolderAction.2=Υπάρχει ήδη Φάκελος με αυτό το όνομα. LyricsView.0=Στίχοι ActionDelete.0=Τα αρχεία διαγράφηκαν ActionDelete.1=Οι κατάλογοι διαγράφηκαν FindDuplicateTracksAction.0=Δε βρέθηκαν διπλά (όμοια) κομμάτια. FindDuplicateTracksAction.1=Βρέθηκαν διπλά (όμοια) κομμάτια FindDuplicateTracksAction.2=Εύρεση διπλών (όμοιων) κομματιών FindDuplicateTracksAction.3=Λίστα διπλών (όμοιων) κομματιών που βρέθηκαν FindDuplicateTracksAction.4=Επιλογή όλων των διπλών (όμοιων) κομματιών RefreshDialog.0=Προετοιμασία ανανέωσης συσκευής... RefreshDialog.1=Ανανέωση συσκεής σε εξέλιξη RefreshDialog.2=Ανανέωση συσκεής σε εξέλιξη: RefreshDialog.3=Καθάρισμα παλαιών αρχείων RadioWizard.0=Παρακαλώ επιλέξτε ή δημιουργείστε ραδιόφωνο web RadioWizard.1=Διαχείριση ραδιοφώνων web RadioWizard.2=Νέο RadioWizard.3=Διαγραφή RadioWizard.4=Προεπιλογές RadioWizard.5=Ένα ραδιόφωνο web με αυτό το όνομα υπάρχει ήδη RadioWizard.6=Όνομα ραδιοφώνου web RadioWizard.7=Οδηγός ραδιοφώνου web RadioWizard.8=URL RadioWizard.9=Όνομα RadioWizard.10=Λάθος URL RadioWizard.11=Το όνομα και το URL είναι απαραίτητα UpdateManager.0=Μία νέα έκδοση του Jajuk ( UpdateManager.1=) έχει εντοπιστεί, μπορείτε να την κατεβάσετε από http://jajuk.info UpdateManager.2=Δεν βρέθηκε καμία διαθέσιμη νέα έκδοση έως τώρα LastFmManager.0=Παρακαλώ προσέξτε ότι η υποστήριξη του Last.FM είναι απενεργοποιημένη. Αν θέλετε να ενεργοποιήσετε το Last.FM , ορίστε το Last.FM login και password στην προβολή Προτιμήσεις / καρτέλα Last.FM . SuggestionView.0=Προτάσεις SuggestionView.1=Προτιμόμενα SuggestionView.2=Νεότερα SuggestionView.3=Άλλα άλμπουμ SuggestionView.4=Παρόμοιοι καλλιτέχνες SuggestionView.5=Ακούγονται σπάνια SuggestionView.7=Τίποτα για εμφάνιση

    Οι πληροφορίες του Last.FM εμφανίζονται μόνο αν:
    • Πάιζει ένα κομμάτι
    • Είναι γνωστός ο artist του κομματιού που παίζεται (σωστό tag)
    • Η επιλογή "Ενεργοποίση των Last.FM information queries" είναι επιλεγμένη στην προβολή Προτιμήσεις / καρτέλα Last.FM
    AbstractThumbnail.0=Άνοιγμα σελίδας LAST.FM AlbumsTableView.0=Πίνακας άλμπουμ AlbumsTableView.1=Αριθμός κομματιών AlarmClock.0=Ορισμός νέου συναγερμού AlarmClock.1=Εμφάνιση συναγερμών που έχουν οριστεί AlarmClock.2=Δεν έχουν οριστεί συναγερμοί AlarmClock.3=Συναγερμός AlarmClock.4=Ο χρόνος έχει ήδη παρέλθει ! AlarmClock.5=Μήνυμα υπενθύμισης για σας: AlarmDialog.0=Χρόνος (ΩΩ24:ΛΛ:ΔΔ) AlarmDialog.1=Ώρα AlarmDialog.2=Λεπτά AlarmDialog.3=Δευτερόλεπτα AlarmDialog.4=Ενέργεια συναγερμού AlarmDialog.5=Επιλογή ενέργειας συναγερμού AlarmDialog.6=Μήνυμα: AlarmDialog.7=Ορισμός μηνύματος υπενθύμισης AlarmDialog.8=Ημερησίως AlarmDialog.9=Ορισμός συναγερμού ημερησίως. ShowPropertiesAction.0=Εμφάνιση ιδιοτήτων αντικειμένου QueueView.1=Ακύρωση της ουράς JajukSlimWindow.0=Εμφάνιση/απόκρυψη του Jajuk slimbar BanSelectionAction.0=Αποκλεισμός BanSelectionAction.1=Αποκλεισμός του αντικειμένου έτσι ώστε να μην επιλεγεί ξανά UnBanSelectionAction.0=Άρση αποκελισμού UnBanSelectionAction.1=Άρετε τον αποκλεισμό αντικειμένων έτσι ώστε να μπορούν να προταθούν ξανά Preference.0=Ορισμός προσωπικής επιλογής για το τρέχον κομμάτιbr>Λαμβάνεται υπόψη για τον υπολογισμό της τελικής βαθμολογίας Preference.1=Σκουπίδι Preference.2=Χαμηλό Preference.3=Μέτριο Preference.4=Καλό Preference.5=Εξαιρετικό Preference.6=Κλασσικό Preference.7=Επιλογές... Preference.8=Χωρίς επιλογή # TipOfTheDay are automatically generated with the Jajuk Manual. # To change tip of the day use page: http://jajuk.info/index.php/Tip_of_the_day TipOfTheDay.0= Tip 0: μπορείς να ξαναπαίξεις το τρέχον κομμάτι από την αρχή με [Shift+click] στο κουμπί επαναφοράς TipOfTheDay.1= Tip 1: μπορείς να ξαναπαίξεις το τρέχον άλμπουμ από το πρώτο του κομμάτι με [Shift+click] TipOfTheDay.2= Tip 2: μπορείς να προσθέσεις τυχαία κομμάτια σε λίστες αναπαραγωγής χρησιμοποιώντας το κουμπί ? στον επεξεργαστή λίστας αναπαραγωγής TipOfTheDay.3= Tip 3: μπορείς λάβεις εξώφυλλα online ακόμη και πίσω από proxy server χρησιμοποιώντας την καρτέλα Δίκτυο της Προβολής Προτιμήσεις TipOfTheDay.4= Tip 4: το Jajuk περιέχει ένα slimbar (Maximize κουμπί στην πάνω αριστερή πλευρά του μενού) για τον έλεγχο της αναπαραγωγής, το οποίο καταλαμβάνει λίγο μόνο χώρο στην επιφάνεια εργασίας TipOfTheDay.5= Tip 5: μπορείς να κρύψεις τα μη διαθέσιμα κομμάτια επιλέγοντας "Εμφάνιση μόνο ενεργοποιημένων συσκευών" στην καρτέλα Επιλογές της Προβολής Προτιμήσεις TipOfTheDay.6= Tip 6: μπορείς να πραγματοποιήσεις σχεδόν κάθε λειτουργία του Jajuk χρησιμοποιώντας το πληκτρολόγιο TipOfTheDay.7= Tip 7: μπορείς να σύρεις και να αφήσεις αντικείμενα από Δενδρικές Προβολές στον επεξεργαστή λίστας αναπαραγωγής και στην αποθήκη λιστών αναπαραγωγής TipOfTheDay.8= Tip 8: μπορείς να ακούσεις εισαγωγές κομματιών χρησιμοποιώντας την κατάσταση λειτουργίας Εισαγωγή TipOfTheDay.9= Tip 9: μπορείς ρυθμίσεις την διάρκεια επικάλυψης-σβησίματος στην καρτέλα Επιλογές της Προβολής Προτιμήσεις TipOfTheDay.10= Tip 10: το Jajuk μπορεί να χρησιμοποιηθεί σαν προχωρημένο ξυπνητήρι με τη χρήση του χαρακτηριστικού Συναγερμός το οποίο είναι διαθέσιμο από το μενού Εργαλεία TipOfTheDay.11= Tip 11: μπορείς να ελέγξεις της κύριες λειτουργίες του Jajuk χρησιμοποιώντας μόνο the tray (Linux & Windows)? TipOfTheDay.12= Tip 12: το Θέμα του Jajuk μπορεί να διαμορφωθεί από την καρτέλα GUI της Προβολής Προτιμήσεις TipOfTheDay.13= Tip 13: μπορείς να ρυθμίσεις τη συμπεριφορά του διπλού-click και του drag and drop (προώθηση και αναπαραγωγή) στην καρτέλα Επιλογές της Προβολής Προτιμήσεις TipOfTheDay.14= Tip 14: τα "προγραμματισμένα" κομμάτια του Jajuk είναι κομμάτια που θα αναπαραχθούν μετά τις τρέχουσες επιλογές κομματιών TipOfTheDay.15= Tip 15: η διασύνδεση γραφικών του Jajuk είναι πλήρως dockable και ότι μπορείς να σύρεις και να αφήσεις Προβολές ώστε να τις οργανώσεις ξανά TipOfTheDay.16= Tip 16: μπορείς να πάρεις το συνολικό αριθμό αρχείων και κομματιών επιλέγοντας τον κόμβο "Συλλογή" στην Προβολή Φυσικού ή Λογικού Δέντρου TipOfTheDay.17= Tip 17: μπορείς να λάβεις ετικέτες online με τη λειτουργία "Λήψη ετικετών online" σε καταλόγους στην Προβολή Φυσικού Δέντρου TipOfTheDay.18= Tip 18: η μπάρα ιστορικού του Jajuk (κάτω μέρος του παραθύρου) εμφανίζει όλα τα κομμάτια που παίχτηκαν προηγουμένως TipOfTheDay.19= Tip 19: yμπορείς να πραγματοποιήσεις γρήγορες αναζητήσεις χρησιμοποιώντας το κουτί Αναζήτησης (κάτω μέρος του παραθύρου) TipOfTheDay.20= Tip 20: μπορείς να αναφέρεις σφάλματα ή αιτήματα λειτουργίας-χαρακτηριστικού χρησιμοποιώντας τον οδηγό ποιότητας (Βοήθεια -> Αναφορά θέματος) TipOfTheDay.21= Tip 21: οι DJs του Jajuk μπορούν να δημιουργήσουν έξυπνες λίστες αναπαραγωγής ακολουθώντας τους κανόνες σου TipOfTheDay.22= Tip 22: μπορείς να λάβεις τους στίχους κομματιώνμ χρησιμοποιώντας την "Προβολή Στίχοι" TipOfTheDay.23= Tip 23: η προβολή Προτάσεις προβάλλει πληροφορίες του LAST.FM όπως παρόμοιους καλλιτέχνες TipOfTheDay.24= Tip 24: μπορείς να ορίσεις μία εικόνα background της επιλογής σου στην προβολή Προτιμήσεις / καρτέλα GUI TipOfTheDay.25= Tip 25: μπορείς να προβάλεις/αποκρύψεις unmounted συσκευές με ένα click στη μενού μπάρα "Ρυθμίσεις" TipOfTheDay.26= Tip 26: τώρα μπορείς να επιλέξεις κατάλογο για τα δεδομένα του Jajuk (όπως έναν εξωτερικό δίσκο) για να διατηρήσεις τα δεδομένα και τις προτιμήσεις σε οποιονδήποτε υπολογιστή (βλέπε καρτέλα "Προχωρημένοι" στην προβολή Προτιμήσεις) ? TipOfTheDay.27= Tip 27: μπορείς να προσθέσεις οποιαδήποτε προβολή σε οποιαδήποτε οπτική χρησιμοποιώντας τη menu μπάρα "Προβολές" TipOfTheDay.28= Tip 28: you can launch a wikipedia page in you default browser using the "Launch address in default browser" icon Image:launch_16x16.png TipOfTheDay.29= Tip 29: Jajuk supports web radios Image:webradio_32x32.png ]]> jajuk-1.9.6.orig/src/main/java/org/jajuk/i18n/package.html0000644000175000017500000000014311720500104023041 0ustar drazzibdrazzib

    Internationalisation classes and translation properties files

    jajuk-1.9.6.orig/src/main/java/org/jajuk/i18n/jajuk_ru.properties0000644000175000017500000026577611720500104024541 0ustar drazzibdrazzib недопустимо. Error.141=Этот плейлист находится на размонтированном устройстве и не может быть изменен. Error.142=Этот плейлист содержит треки, расположенные за пределами известного устройства. Они будут проигнорированы Error.143=Расположение устройства недоступно Error.144=Ошибка DJ Error.145=Невозможно запустить DJ Error.146=Текущий шаблон организации неверен.
    Возможные атрибуты: %artist (Имя исполнителя); %album_artist (Исполнитель альбома); %title (Название трека); %album (Альбом);
    %n (номер, начиная с нуля); %genre (жанр); %year (год), %disc (номер диска)
    и наконец, шаблон должен содержать хотя бы одну косую черту Error.147=Некоторые файлы не могут быть перемещены (Смотрите детали) Error.148=Неизвестное значение поля "год" Error.149=Неизвестное значение поля "Альбом" Error.150=Неизвестное значение поля "Исполнитель" Error.151=Неизвестное значение поля "название трека" Error.152=Неизвестное значение поля "трек" Error.153=Неизвестное значение поля "жанр" Error.154=Невозможно переименовать файл. Проверьте недопустимые символы в имени или тегах Error.155=Ошибка переназначения тегов, проверьте права Error.156=Пустая коллекция Error.157=Неверный ДиДжей, пожалуйста, выберите "создание ДиДжея" в соответствующем диалоге "управление ДиДжеями" Error.158=Нет допустимых треков или ДиДжей создан неверно. Error.159=Ассоциируемое окружение было удалено Error.160=Файл не перемещен, исходное и целевое места совпадают Error.161=Невозможна запись в папку, проверьте права. Error.162=Это пользовательское поле уже существует Error.163=Ошибка восстановления вида ракурсов Error.164=Нет доступных треков для данного окружения Error.165=Ошибка рабочего пути, папка не существует или закрыта для записи Error.166=Пустой альбом, невозможно дать обложку Error.167=Невозможно создать отчет Error.168=Не найдено файлов-дубликатов Error.169=Операция не удалась. Имейте ввиду, что эта операция требует подключения к Интернету, для получения списка станций Error.170=Ошибка проигрывания веб-радио Error.171=Пока нет источника синхронизации. Установите его, используя соответствующее диалоговое окно (В разделе настроек, выберите "новое устройство") Error.172=Во время воспроизведения файл и папки, в которых он находися, не могут быть удалены либо изменены. Error.173=Во время удаления следующей(их) папки(ок) произошла ошибка. Error.174=Ошибка в доступе к сайту Freedb, проверьте соединение с Интернетом Error.175=Операция отменена Error.176=Ошибка создания плейлиста Error.177=Пожалуйста, введите время в корректном формате (ЧЧ24:ММ:СС) Error.179=Невозможно открыть системный обозреватель файлов, попробуйте вручную указать путь к нему в разделе "Настройки" вкладка "Расширенные" Error.180=Ошибка при копировании файлов #Warnings Warning.0=MPlayer не найден по указанному пути. Некоторые аудио форматы (flac, wma, aac, mpg2 и некоторые свойства ogg)не будут поддерживаться. Для использования MPlayer вручную укажите точное местоположение, если он установлен.(Раздел "Настройки" вкладка "Расширенные") Warning.1=Старая версия MPlayer. Требуется версия 1.0ЗPre8 или выше. Некоторые форматы не поддерживаются Warning.2=Убедитесь, что никто, кроме вас, не использует рабочую папку Jajuk в данный момент. Последний вышедший пользователь меняет базу коллекции (рейтинги, вид и т.п.) Warning.3=Невозможно загрузить MPlayer. Проверьте ваше соединение с Интернетом. Настройки прокси-сервера (если он используется) можно поменять в разделе "Настройки" вкладка "Сеть" Warning.4=MPlayer необходим для прослушивания веб-радио Warning.5=Папка назначения уже существует. Некоторые файлы будут перезаписаны. Вы уверены? Warning.6=Нет доступных для проигрывания треков.(Совет: попробуйте смонтировать необходимые устройства или смените окружение) Warning.7=Jajuk необходимо полностью пересканировать коллекцию для обновления. Провести это сейчас? (Вы также можете сделать это в любое время в окне "устройства") #--- Strings by class --- ParameterView.0=Длительность списка истории: ParameterView.2=Установите время в днях для сохранения списка истории воспроизведенных композиций.
    Введите -1, чтобы не вести список истории, 0 - для постоянного списка истории ParameterView.3=Очистить историю ParameterView.4=Очистить историю ParameterView.8=История ParameterView.9=Проигрывать: ParameterView.10=Ничего ParameterView.11=Не играть музыку когда запускается Jajuk ParameterView.12=Последний трек, играть сначала ParameterView.13=Играть последний воспроизведенный трек с его начала ParameterView.14=Случайный трек ParameterView.15=Играть произвольный трек,
    выбранный из всей базы коллекции ParameterView.16=Трек/Радио : ParameterView.17=Выберите файл, проигрываемый при старте ParameterView.18=Выберите файл проигрываемый при старте. Начните набор для просмотра отфильтрованных композиций. ParameterView.19=Старт плеера ParameterView.26=Подтверждения ParameterView.27=Перед физическим удалением файла ParameterView.28=Спросить перед физическим удалением файла ParameterView.29=Перед выходом из Jajuk ParameterView.30=Спросить перед выходом из Jajuk. ParameterView.33=Опции ParameterView.35=Скрывать треки, расположенные на размонтированных устройствах ParameterView.36=Сначала, когда достигнут конец коллекции. ParameterView.37=Перезапустить проигрывание всей коллекции,
    когда достигнут ее конец, при включенном "бесконечном режиме" ParameterView.38=Язык: ParameterView.42=Выберите язык интерфейса: ParameterView.43=Тема: ParameterView.44=Выберите тему

    (Может потребоваться перезапуск Jajuk, для полного преображения интерфейса) ParameterView.46=Уровень ведения журнала: ParameterView.47=Критические ошибки ParameterView.48=Ошибки ParameterView.49=Предупреждения ParameterView.50=Информация ParameterView.51=Отладка ParameterView.52=Уровень ведения журнал Jajuk:
    критические ошибки: записывать только критические ошибки,
    ошибки: +ошибки программы,
    информация: +информационные сообщения,
    предупреждения: +показ предупреждений,
    отладка: все сообщения ParameterView.59=Начало ознакомления (%): ParameterView.60=Позиция внутри трека, с которой начинается воспроизведение
    в режиме "ознакомления" в процентах (0 - начало, 99- конец) ParameterView.61=Продолжительность ознакомления (сек.): ParameterView.62=Продолжительность звучания трека в режиме "ознакомления" в секундах ParameterView.85=Применить ParameterView.86=Восстановить умолчания ParameterView.87=Настройки ParameterView.98=Атрибуты ParameterView.99=Произвести глубокое сканирование тегов ParameterView.100=Форсировать перечитывание актуальных id3 тегов.

    Это может использоваться для обновления тегов треков, измененных внешней программой.

    ParameterView.101=Использовать имя папки для названия альбома ParameterView.102=Если отмечено, имя родительской папки будет использоваться
    для установления названия альбома, для треков без id3 тега ParameterView.109=Настройки сохранены ParameterView.110=Настройки установлены в начальное положение ParameterView.111=количество лучших треков: ParameterView.112=Установите размер плейлиста лучших треков (от 1 до 100) ParameterView.113=Использовать регулярные выражения в фильтрах ParameterView.114=Использовать регулярные выражения в фильтрах (язык запросов RegExp). Например *foo.* ParameterView.115=Расширенные ParameterView.116=Файл резервной копии коллекции ParameterView.117=Отметьте опцию если хотите сделать
    резервную копию коллекции. Используется xml формат ParameterView.118=Размер копии (МБ) ParameterView.119=Размер резервной копии в МБ ParameterView.120=Кодировка коллекции ParameterView.121=Кодировка. UTF-16 оптимизирована для азиатских языков,
    UTF-8 для европейских ParameterView.129=Лимит времени для новинок (дни): ParameterView.130=Установите лимит времени для новинок в днях:
    Все треки, добавленные в пределах этого значения
    будут показаны в списке новинок ParameterView.131=Лучший трек ParameterView.132=Проигрывать один из избранных треков при загрузке ParameterView.133=Новый трек ParameterView.134=Проигрывать новый трек из вашей коллекции при загрузке ParameterView.135=Последний трек с текущей позиции ParameterView.136=Проигрывать последний проигранный трек с прерванного места ParameterView.139=Сеть ParameterView.142=Имя пользователя прокси: ParameterView.143=Логин, используемый для авторизации ParameterView.144=Адрес прокси-сервера: ParameterView.145=Адрес прокси-сервера или его сетевое имя ParameterView.146=Порт прокси-сервера: ParameterView.147=TCP-IP порт прокси сервера (как правило, 3128) ParameterView.148=Загружать обложки онлайн ParameterView.149=Использовать автозагрузку обложек альбома из Интернета
    (требуется работающее и настроенное подключение) ParameterView.150=Размер обложек ParameterView.151=Размер загружаемых обложек ParameterView.155=Качество поиска.
    Высокое позволяет более точно находить обложки. ParameterView.156=Низкое качество (поиск по всем словам) ParameterView.157=Среднее (поиск по фразам) ParameterView.158=Высокое (поиск исключительно всей фразы) ParameterView.159=Обложки ParameterView.160=Таймаут соединения (сек.) ParameterView.161=Таймаут соединения в секундах.
    Если сервер не отвечает в течение этого срока, соединение считается неудачным. ParameterView.162=Таймаут передачи (сек.) ParameterView.163=В секундах. Если в течение этого срока данные не были загружены,
    соединение прерывается и считается неудачным ParameterView.164=Перед извлечением устройства ParameterView.165=Спросить перед извлечением устройства ParameterView.166=Случайная обложка ParameterView.167=Демонстрировать случайную обложку ParameterView.169=Предзагрузка обложек ParameterView.170=Загрузить все доступные обложки,
    когда это будет возможно ParameterView.171=Перед удалением с диска обложки ParameterView.172=Спросить перед удалением обложки с диска ParameterView.177=Количество видимых планируемых треков ParameterView.178=Количество видимых планируемых треков в плейлисте ParameterView.179=Добавлять в плейлист по щелчку ParameterView.180=Если отмечено, двойной щелчок будет добавлять
    в текущий плейлист данный(е) трек(и) ParameterView.181=Добавлять перетаскиванием ParameterView.182=Если отмечено, возможно
    перетаскивание треков в окно плейлиста ParameterView.186=Сбросить рейтинги ParameterView.187=Сбрасывает все рейтинги треков к нулю ParameterView.188=Перед очисткой истории ParameterView.189=Перед сбросом рейтингов ParameterView.190=Продолжительность перетекания (сек) ParameterView.191=Длительность перетекания
    (кроссфейдинг) между треками в секундах ParameterView.192=Шаблон организации файлов ParameterView.193=Доступные атрибуты:
    %artist (Исполнитель);
    %album_artist (Исполнитель альбома, если не найден, используется "Исполнитель");
    %title (Название);
    %album (Альбом);
    %n (Трек №);
    %genre (Жанр);
    %year (год);
    %disc (номер диска) ParameterView.194=Перед организацией файлов ParameterView.195=Шаблон анимации ParameterView.196=Разрешить горячие клавиши ParameterView.197=Разрешить некоторые ключи,
    вроде F9, F10 для управления, даже если Jajuk неактивен ParameterView.198=Эти изменения вступят в силу при следующем запуске Jajuk ParameterView.199=Отправлять список прослушиваемых ParameterView.200=Эта опция разрешает отправку
    информации о прослушиваемых треках на сервер Last.fm ParameterView.201=Имя пользователя Last.fm: ParameterView.202=Введите имя пользователя для Last.fm ParameterView.203=Пароль для Last.fm ParameterView.204=Пароль в сервисе Last.fm ParameterView.205=Аргументы звукового движка ParameterView.206=Дополнительные параметры MPlayer,
    такие как '-ao esd', '-ao arts'
    или '-novideo' (для запрета проигрывания видео) ParameterView.207=Путь конфигурации Jajuk ParameterView.208=Установить папку, содержащую конфигурацию Jajuk.
    По умолчанию - домашняя папка пользователя ParameterView.209=Путь конфигурации Jajuk был изменен для текущего пользователя.
    Предыдущие файлы сохранены на прежнем месте. Jajuk будет закрыт и перезагружен. ParameterView.210=Если перетекание не работает, попробуйте добавить <-ao esd> в Gnome
    или <-ao arts> в KDE в дополнительных параметрах
    Звуковой системы (Настройки - Расширенные). ParameterView.211=Только маленькие ParameterView.212=Маленькие и средние ParameterView.213=Только средние ParameterView.214=Средние и большие ParameterView.215=Только большие ParameterView.216=Искать, используя имя исполнителя ParameterView.217=Искать, используя название альбома ParameterView.218=Искать, используя название трека ParameterView.219=Варианты окружения ParameterView.220=Установить варианты окружения, используя аудио плееры.
    (ARTS_SERVER в KDE или ESPEAKER в Gnome).
    Формат: var1=xx var2=yyy... #Respect English size for next item ParameterView.221=Размер стр. каталога(0-все в одном) ParameterView.222=Установить количество альбомов
    на одной странице в ракурсе каталогов ParameterView.223=Размер шрифта ParameterView.224=Установить размер шрифта текста ParameterView.225=Интерфейс ParameterView.226=Режимы ParameterView.228=Показывать всплывающие окна альбомов ParameterView.229=Настройки каталога альбомов ParameterView.233=Полное обновление интерфейса произойдет после перезагрузки Jajuk ParameterView.234=Проверять новые версии Jajuk ParameterView.235=Last.fm ParameterView.236=Без прокси ParameterView.237=HTTP прокси ParameterView.238=SOCKS прокси ParameterView.239=Пароль прокси ParameterView.240=Разрешить запросы Last.fm ParameterView.241=Если отмечено, Jajuk будет собирать различную информацию
    по альбомам, исполнителям и т.д. с сайта Last.fm ParameterView.242=Путь к MPlayer ParameterView.243=Установите полный путь к mplayer (допустимы пробелы)
    Например: /Applications/MPlayer OSX.app/Contents/Resources/External_Binaries/mplayer_intel.app/Contents/MacOS/mplayer ParameterView.244=Установить дату файла, как дату добавления ParameterView.245=Если отмечено, Jajuk установит дату создания файлов, как дату добавления в коллекцию.
    Потребуется полное обновление текущего профиля пользователя ParameterView.246=Размер кнопок меню ракурсов(в пикселях) ParameterView.247=Путь назначения содержит существующую рабочую папку Jajuk.
    Эта папка будет переключена на этот путь для текущего пользователя (Предыдущая рабочая папка будет сохранена на прежнем месте).
    Сейчас Jajuk будет закрыт и перезагружен. ParameterView.248=Шаблон заголовка окна ParameterView.249=Сбросить настройки ParameterView.250=Сбросить настройки программы к начальным ParameterView.251=История успешно очищена ParameterView.252=Рейтинги и счетчики проигрывания успешно сброшены ParameterView.253=Настройки успешно сброшены ParameterView.254=Использовать краткие имена Windows ParameterView.255=[Только в 32-х битной Windows]
    Если отмечено, заставляет mplayer использовать имена аудио файлов в кратком формате Windows,
    для исправления ошибок в некоторых локалях ParameterView.256=Имена файлов обложек по умолчанию ParameterView.257=Jajuk использует этот текст при поиске файлов обложек в папке (без расширения). Несколько значений отделяются знаком ";" . Например: "папка;обложка;folder;cover" ParameterView.260=Сохранять обложки в режиме совместимости в Проводником Windows ParameterView.261=Сохранять загруженные обложки как "folder.jpg/png...", что используется Проводником Windows как значок для папки ParameterView.262=Использовать нормализацию громкости ParameterView.263=Усилить громкость без искажения звука ParameterView.264=Запретить Jajuk любой доступ в Интернет ParameterView.265=Запретить программе доступ в Интернет. (Интернет используют функции LastFM, Википедия, Слова песни, поиск обложек и пр.) ParameterView.266=Удалять проигранные треки из очереди ParameterView.267=Треки, которые проигрывались в списке буду удалены из дальнейшей очереди ParameterView.268=Конфигурация прокси ParameterView.269=Путь к исполняемому файлу Проводника файлов ParameterView.270=Путь к исполняемому файлу внешнего файлового обозревателя ParameterView.271=Показывать в трее ParameterView.272=Если отмечено, Jajuk можно будет управлять из трея
    (поддерживается не во всех операционных системах) ParameterView.273=Отражение обложки ParameterView.274=Если отмечено, обложка будет показана с отражением ParameterView.275=Уведомление при смене трека : ParameterView.276=Выберите тип уведомления при смене трека (Всплывающее окошко которое появляется на переднем плане и исчезает через некоторое время) ParameterView.277=Шаблон уведомления ParameterView.278=Этот шаблон устанавливает текст, демонстрируемый в экранном уведомлении при смене трека ParameterView.279=Информационный шаблон ParameterView.280=Этот шаблон устанавливает текст, показываемый в окне информации (нижняя часть экрана) ParameterView.281=Сворачивать в трей ParameterView.282=Если отмечено, главное окно Jajuk, будет сворачиваться в значок в трее без появления в панели задач Main.21=Подтверждения Main.22=Проверка/Загрузка MPlayer Player.0=Ожидание аудиолинии (занята) Device.25=] обновлено за Device.27= новых файлов Device.31=синхр. [ Device.33=Синхронизация выполнена за Device.35= созданные файлы ( Device.36= МБ) Device.41=синхр. [ Device.42=] Копирование [ Device.43= нечитаемые теги Device.44=Сканирование Device.45=Копирование [ Device.46=Конвертация [ Device.47=] в [ FIFO.4=). Хотите попытаться смонтировать его? FIFO.10=Сейчас играет: FIFO.13= Кбит/с FIFO.14=Сейчас играет веб-радио: HistoryItem.0=dd.MM.yy HH:mm DeviceWizard.0=Конфигурация устройства DeviceWizard.1=Тип устройства*: DeviceWizard.2=Имя устройства*: DeviceWizard.3=Расположение устройства*: DeviceWizard.7=Провести полное обновление DeviceWizard.8=Автомонтирование при загрузке DeviceWizard.10=Синхронизировать с: DeviceWizard.11=Односторонняя синхронизация DeviceWizard.12=Все новые файлы найденные в устройстве-источнике
    будут скопированы на приемник.
    Ничего не будет записано на устройство-источник DeviceWizard.13=Двусторонняя синхронизация DeviceWizard.14=Все новые файлы на одном устройстве
    будут скопированы на другое DeviceWizard.43=Пожалуйста, выберите папку DeviceWizard.44=Устройство создано DeviceWizard.45=Пожалуйста, дайте имя устройству.
    Например: CD, переносной диск, ноутбук DeviceWizard.46=Пожалуйста, укажите расположение устройства.
    Например: D:/Music, /home/collection, DeviceWizard.48= Отметьте, если хотите немедленно обновить устройство (рекомендуется).

    Внимание, эта операция может занять время, особенно для емких или медленных устройств

    DeviceWizard.49=Отметьте, если хотите автоматически монтировать устройство при старте Jajuk.

    Рекомендуется для папок на локальном диске, но не для CD

    DeviceWizard.50=Установите интервал в минутах для автоматического поиска
    (0 - без сканирования. 0.5- минимальный интервал) DeviceWizard.51=Отметьте, если хотите синхронизировать одно устройство с другим DeviceWizard.52=Выберите устройство-источник DeviceWizard.53=Обновлять устройство каждые #limited string size DeviceWizard.54=мин. DeviceWizard.55=Неверное значение : интервал обновления может быть либо 0, либо числом больше 0.5 JajukJMenuBar.0=Файл JajukJMenuBar.1=Открыть файл JajukJMenuBar.3=Выход JajukJMenuBar.5=Теги JajukJMenuBar.6=Создать пользовательский тег JajukJMenuBar.7=Удалить пользовательский тег JajukJMenuBar.8=Вид JajukJMenuBar.9=Режим JajukJMenuBar.10=Повтор JajukJMenuBar.11=Случайно JajukJMenuBar.12=Бесконечно JajukJMenuBar.13=Ознакомление JajukJMenuBar.14=Помощь JajukJMenuBar.15=Содержание помощи JajukJMenuBar.16=О Jajuk JajukJMenuBar.17=К начальному виду (этот ракурс) JajukJMenuBar.18=Помощник устройств JajukJMenuBar.19=Отправить отчет об ошибке или пожелания JajukJMenuBar.20=Совет дня JajukJMenuBar.21=Конфигурация JajukJMenuBar.22=Настройки JajukJMenuBar.23=Показать вывод отладки JajukJMenuBar.24=Показывать только доступные треки JajukJMenuBar.25=Добавить окно JajukJMenuBar.26=К начальному виду (все ракурсы) JajukJMenuBar.27=Проверить обновления JajukJMenuBar.28=Функции JajukJMenuBar.29=Автосписки JajukJMenuBar.30=Повторить все JajukJMenuBar.31=Караоке # next two lines are only used in development/test mode, translation is therefore optional JajukJMenuBar.32=Инициализировать Сборщик мусора (garbage collector)(только в тестовом режиме) JajukJMenuBar.33=Выполнить самостоятельную отправку собранных данных (только в режиме тестирования) PlaylistFileItem.1=Hовые треки PlaylistFileItem.2=Новый плейлист PlaylistFileItem.3=Закладки PlaylistFileItem.4=Лучшие треки PlaylistFileItem.5=Очередь JajukFileChooser.0=Выбор файла SearchBox.0=Предоставляет поиск по трекам,
    артистам, альбомам, жанрам... CommandJPanel.0=Показать историю воспроизведения CommandJPanel.1=[Ctrl-t] Режим повтора:
    Играть треки в цикле CommandJPanel.2=[Ctrl-h] Случайно: Играть треки
    в случайном порядке CommandJPanel.3=Бесконечный режим: Продолжить воспроизведение
    с автоматически запланированными треками CommandJPanel.4=Режим ознакомления: Играть только часть трека
    (время и место, см. настройки) CommandJPanel.5=Играть случайно выбранный трек из всей коллекции. CommandJPanel.6=Играть избранные треки CommandJPanel.8=[F9] Вернуться к предыдущему треку в выбранной секции
    Щелчок правой кнопкой повторит текущий трек
    Shift+щелчок - предыдущий альбом
    CTRL+щелчок - повторить текущий альбом CommandJPanel.9=[F10] Перейти к следующему треку в выбранной секции
    Shift+щелчок - следующий альбом CommandJPanel.10=[Alt-gr F9] Перемотка назад
    Shift+щелчок в начало трека CommandJPanel.13=[Alt-gr F0] Перемотка вперед CommandJPanel.15=Щелкните здесь для показа времени.
    Проигранного/оставшегося, в сек./процентах CommandJPanel.16=Запуск секции ДиДжея CommandJPanel.17=Управление ДиДжеями CommandJPanel.18=Запустить ДиДжея по умолчанию CommandJPanel.19=Управление Окружением CommandJPanel.20=Перемешивать потреково CommandJPanel.21=Перемешивать поальбомно CommandJPanel.22=Перемешивать внутри альбомов CommandJPanel.23=Щелкните здесь для очистки поиска CommandJPanel.24=Настроить веб-радио CommandJPanel.25=Включить радио CommandJPanel.26=Режим Повторить все: Играть очередь в цикле CommandJPanel.27=Режим Караоке: заглушить голос в проигрываемых треках
    (вступит в силу только со следующего трека) InformationJPanel.5=Осталось времени всего [кол-во треков в очереди] InformationJPanel.6=Битрейт трека InformationJPanel.7=Позиция # %xxx are patterns, don't translate them ! InformationJPanel.8=%title исполняет %artist из альбома %album # Keep next label short InformationJPanel.9=<Не выбрано> AbstractPlaylistEditorView.0=Название AbstractPlaylistEditorView.1=Расположение AbstractPlaylistEditorView.2=Запустить этот плейлист AbstractPlaylistEditorView.3=Сохранить этот плейлист AbstractPlaylistEditorView.4=Добавить в этот плейлист AbstractPlaylistEditorView.5=Удалить элемент AbstractPlaylistEditorView.6=Переместить вверх AbstractPlaylistEditorView.7=Переместить вниз AbstractPlaylistEditorView.9=Очистить плейлист AbstractPlaylistEditorView.10=Добавить случайный трек в плейлист AbstractPlaylistEditorView.15=Плейлисты AbstractPlaylistEditorView.17=Вы обновляете следующие плейлисты: AbstractPlaylistEditorView.18=Трек в очереди AbstractPlaylistEditorView.19=Повторяемый трек AbstractPlaylistEditorView.20=Запланированный трек AbstractPlaylistEditorView.21=Трек плейлиста AbstractPlaylistEditorView.22=Плейлист сохранен AbstractPlaylistEditorView.27=Подготовить вечеринку.
    Создать копию файлов из плейлиста в выбранное место AbstractPlaylistEditorView.28=Папка успешно создана в AbstractPlaylistEditorView.29=Играющий трек StatView.0=Другие StatView.1=Жанры StatView.2=Нет данных StatView.3=Другие StatView.4=Размер на диске (ГБ) StatView.5=Нет данных StatView.7=Размер коллекции по месяцам StatView.8=Месяцы StatView.9=Размер (ГБ) StatView.10=Нет данных StatView.12=Всего кол-во треков за месяц StatView.13=Месяцы StatView.14=Количество треков StatView.15=Нет данных StatView.16=Статистика StatView.24=Старше CDScanView.0=Метка CD CDScanView.1=Метка CD. Например: CD1, Рок CDScanView.2=Метка CD. Например: CD1, ROCK... CDScanView.3=Расположение CD: CDScanView.4=Местоположение CD.
    Например, /cdrom для Unix/Linux или Е:/ для Windows. CDScanView.5=Местоположение CD.
    Например, /cdrom для Unix/Linux или Е:/ для Windows. CDScanView.6=Сканировать CDScanView.12=CD сканер CDScanView.18=Сканирование CD и добавление всей музыки в коллекцию. CDScanView.19=Выберите расположение CD-привода AbstractTreeView.0=Свернуть всё TracksTreeView.0=Дерево треков TracksTreeView.27=Коллекция TracksTreeView.31= треков TracksTreeView.33=Создать отчет TracksTreeView.34=Получить теги онлайн TracksTreeView.35=Добавлено TracksTreeView.36=Меньше одной недели TracksTreeView.37=Меньше одного месяца TracksTreeView.38=Меньше 6 месяцев TracksTreeView.39=Старше TracksTreeView.40=менее чем один год TracksTreeView.41=менее чем 2 года TracksTreeView.42=менее чем 5 лет TracksTreeView.43=менее чем 10 лет TracksTreeView.44=менее чем 3 месяца TracksTreeView.45=Год CoverView.2=Удалить эту обложку с диска CoverView.3=Обложка CoverView.4=

    Предыдущее изображение с диска и/или из Интернета,

    если активна опция автообложек

    CoverView.5=

    Следующее изображение с диска и/или из Интернета,

    если активна опция автообложек

    CoverView.6=

    Сохранить обложку под ее оригинальным именем

    С клавишей CTRL: Сохранить обложку как...

    CoverView.8=Использовать эту обложку по умолчанию для этого альбома CoverView.9=обложек CoverView.10=Сохранить обложку как... CoverView.11=Обложка сохранена CoverView.12=Альбом CoverView.13=Название AnimationView.0=Анимация FilesTreeView.0=Дерево файлов FilesTreeView.3=Копировать FilesTreeView.4=Вырезать FilesTreeView.5=Вставить FilesTreeView.7=Удалить FilesTreeView.14=Рассинхронизировать FilesTreeView.15=Пересинхронизировать FilesTreeView.16=Создать плейлист FilesTreeView.17=Копировать FilesTreeView.18=Вырезать FilesTreeView.28=Монтировать FilesTreeView.29=Размонтировать FilesTreeView.30=Форсировать обновление FilesTreeView.31=Синхронизировать FilesTreeView.32=Тест FilesTreeView.33=Создать плейлист FilesTreeView.40=Копировать FilesTreeView.41=Вырезать FilesTreeView.42=Вставить FilesTreeView.47=Коллекция FilesTreeView.52= файлов: FilesTreeView.53= ГБ FilesTreeView.54= МБ FilesTreeView.55=Конфигурация FilesTreeView.59=Хотите провести быстрое или полное (с перечитыванием тегов) обновление? FilesTreeView.60=Быстрое FilesTreeView.61=Полное FilesTreeView.62=Организация файлов TracksTableView.0=Таблица треков TracksTableView.7=Играть TracksTableView.8=Добавить TracksTableView.9=Играть случайно TracksTableView.10=Играть в цикле TracksTableView.11=Слушать Альбом TracksTableView.12=Слушать Исполнителя TracksTableView.14=Свойства TracksTableView.15=Закладка TracksTableView.16=Вставить следующей AbstractTableView.0=Фильтр: AbstractTableView.1=Поле для фильтра AbstractTableView.3=Значение, используемое для фильтра AbstractTableView.4=Установить фильтр AbstractTableView.5=Очистить фильтр AbstractTableView.6=Применить расширенный фильтр AbstractTableView.7=содержит: AbstractTableView.8=Что угодно AbstractTableView.10=(Недоступно) AbstractTableView.11=Сделать таблицу редактируемой AboutView.7=О программе AboutView.8=Лицензия AboutView.9=Система AboutView.10=О программе AboutView.11=Copyright 2003-2011
    команда разработчиков Jajuk" PhysicalPlaylistRepositoryView.0=Играть PhysicalPlaylistRepositoryView.1=Править PhysicalPlaylistRepositoryView.2=Сохранить как... PhysicalPlaylistRepositoryView.3=Удалить PhysicalPlaylistRepositoryView.4=Свойства PhysicalPlaylistRepositoryView.6=Физические Плейлисты PhysicalPlaylistRepositoryView.8=Автосписки PhysicalPlaylistRepositoryView.9=Очередь проигрывания PhysicalPlaylistRepositoryView.10=Текущая очередь: перетащите треки для проигрывания PhysicalPlaylistRepositoryView.11=Новый PhysicalPlaylistRepositoryView.12=Новый плейлист: перетащите треки для добавления в плейлист PhysicalPlaylistRepositoryView.13=Закладки PhysicalPlaylistRepositoryView.14=Плейлист закладок: перетащите треки для добавления в закладки PhysicalPlaylistRepositoryView.15=Лучшие треки PhysicalPlaylistRepositoryView.16=Плейлист лучших: содержит самые прослушиваемые треки PhysicalPlaylistRepositoryView.17=Новые треки PhysicalPlaylistRepositoryView.18=Плейлист новинок: содержит новые треки PhysicalPlaylistRepositoryView.19=Подготовить вечеринку.
    Создать копию файлов из плейлиста в выбранную папку FilesTableView.0=Таблица файлов FilesTableView.15=Играть файлы в папке #Dev: do not use ID = 16, next label is FilesTableView.17 DeviceView.0=Добавить устройство DeviceView.1=Удалить размонтированное устройство (ничего не удаляет с диска) DeviceView.2=Свойства выбранного устройства DeviceView.3=Примонтировать выбранное устройство DeviceView.4=Размонтировать выбранное устройство DeviceView.5=Тестировать устройство на доступность DeviceView.6=Форсировать обновление на выбранном устройстве DeviceView.7=Синхронизировать выбранное устройство DeviceView.8=Монтировать DeviceView.9=Размонтировать DeviceView.10=Тестировать DeviceView.11=Форсировать обновление DeviceView.12=Синхронизировать DeviceView.13=Удалить устройство DeviceView.14=Конфигурация DeviceView.17=Новое устройство DeviceView.18=Добавить устройство DeviceView.21=Это устройство доступно DeviceView.22=Это устройство недоступно DeviceView.23=Устройства JajukWindow.1=Включить звук JajukWindow.2=Приглушить JajukWindow.3=Jajuk JajukWindow.4=Выход JajukWindow.5=О Jajuk JajukWindow.6=Играть случайно JajukWindow.7=Играть Лучшие треки JajukWindow.10=Пауза JajukWindow.12=Возобновить JajukWindow.13=Назад JajukWindow.14=Вперед JajukWindow.15=Играть Новые треки JajukWindow.16=Доиграть альбом JajukWindow.17=Jajuk: Функциональный плеер JajukWindow.18=Готов к работе JajukWindow.19=[F8] Вылк./Вкл. звук
    Используйте колесико мыши для установки громкости JajukWindow.21=Выход JajukWindow.22=О Jajuk JajukWindow.23=Играть случайные треки из коллекции JajukWindow.24=Играть самые популярные треки из коллекции JajukWindow.26=[Ctrl-p] Пауза/Возобновить JajukWindow.27=[Ctrl-s] Стоп JajukWindow.31=Играть самые новые треки из коллекции JajukWindow.32=Полностью доиграть текущий альбом JajukWindow.33=[Ctrl-UP/DOWN] Громкость JajukWindow.34=Позиция JajukWindow.35=Играет: JajukWindow.36=Текущее окружение: JajukWindow.37=Не установлено окружения #Do not use JajukWindow.38, next is JajukWindow.39 JajukWindow.39=Сейчас играет JajukWindow.40=Правка дополнительных тегов JajukWindow.41=Открывает диалог для правки активных дополнительных тегов JajukDonate.1=Пожертвовать JajukDonate.2=Развитие Jajuk требует вложения средств, для подробной информации посетите нашу страницу о бюджете проекта. JajukDonate.3=Бюджет JajukDonate.4=Если вы хотите поддержать Jajuk, пожалуйста сделайте пожертвование. ActiveTagsWizard.1=Доступные теги ActiveTagsWizard.2=Активированные теги ActiveTagsWizard.3=Правка дополнительных тегов, которые Jajuk может показывать. Информация считывается прямо из аудиофайлов (например, из id3 тегов, в случае файлов mp3). Если вы хотите активировать новый тег, потребуется полное сканирование коллекции. Это может занять несколько минут, в зависимости от размера вашей коллекции. SimpleDeviceWizard.0=экспресс создание устройства FirstTimeWizard.0=Быстрый старт FirstTimeWizard.1=


    Добро Пожаловать! Это первый запуск Jajuk, поэтому вначале давайте создадим вашу коллекцию

    FirstTimeWizard.2=

    Пожалуйста, укажите расположение вашей музыки,

    щелкнув на кнопку справа.

    (Первое обновление потребует времени)

    FirstTimeWizard.4=Показать помощь по программе прямо сейчас. (Онлайн) FirstTimeWizard.5=Пожалуйста выберите папку FirstTimeWizard.6=Расширенные настройки FirstTimeWizard.7=Установить рабочую папку Jajuk : FirstTimeWizard.8=Выбранная папка: FirstTimeWizard.9=Не выбрано HelpView.2=Помощь DownloadManager.0=Jajuk требуется пароль прокси-сервера HTTP для загрузки обложек из Интернета
    Если вы не хотите этого, пожалуйста измените ваши настройки во вкладке "Обложки" в настройках.
    Если вы не используете прокси-сервер, пожалуйста измените настройки соответствующим образом во вкладке "Сеть" в настройках DownloadManager.1=Требуется пароль PropertiesWizard.0=Свойства объекта PropertiesWizard.1=Поле PropertiesWizard.2=Значение PropertiesWizard.3=Редактируемое? PropertiesWizard.4=Ссылка PropertiesWizard.6=Выбор PropertiesWizard.7=Тип PropertiesWizard.8=Успешное обновление тега PropertiesWizard.9=Нет редактируемого тега для текущего выбора PropertiesWizard.10=тегов прописано PropertiesWizard.11=Записать тег в: PropertiesWizard.12=Ссылка на получение деталей тега NewPropertyWizard.0=Создать свой тег NewPropertyWizard.3=(*) Тип NewPropertyWizard.4=Формат NewPropertyWizard.5=Начальное значение CustomPropertyWizard.0=(*) Объект CustomPropertyWizard.1=(*) Имя тега RemovePropertyWizard.0=Удалить свой тег QualityFeedbackWizard.20=Откроется новое окно в вашем внешнем браузере. Анонимные технические сведения уже скопированы в буфер обмена, пожалуйста вставьте их в поле описания проблемы если это отчет об ошибке. (Это сильно повысит шанс исправить вашу проблему). IncRateAction.0=Повысить рейтинг текущего трека SplashScreen.0=Проверка целостности SplashScreen.1=Загрузка коллекции SplashScreen.2=Запуск музыкального движка SplashScreen.3=Загрузка графического интерфейса CatalogView.0=Каталог альбомов #Note: CatalogView.2 label musn't be much larger than in English for correct display in 800x600 CatalogView.2=Показать без обложек CatalogView.3=Обновить каталог CatalogView.4=Размер миниатюр CatalogView.5=Создать миниатюру для: CatalogView.7=Выберите обложку CatalogView.8=Не найдено обложки CatalogView.9=Назад CatalogView.10=Дальше CatalogView.11=Стр.: CatalogView.12=На предыдущую стр. миниатюр: CatalogView.13=На следующую стр. миниатюр: CatalogView.16=альбомов CatalogView.14=Выберите страницу миниатюр для отображения CatalogView.15=Размер миниатюр: CatalogView.17=/стр. CatalogView.18=Выбор обложки CatalogView.19=Обновить миниатюры CatalogView.20=Показать детали альбома CatalogView.21=Показать все альбомы CatalogView.22=Показать альбомы с обложками WikipediaView.0=Википедия WikipediaView.1=Выберите язык: WikipediaView.3=Нет результата WikipediaView.5=Поиск по имени Исполнителя WikipediaView.6=Поиск по Альбому WikipediaView.7=Поиск по названию трека WikipediaView.8=Загрузка WikipediaView.9=Невозможно загрузить информацию из Википедии WikipediaView.10=Невозможен поиск при неизвестном исполнителе TipOfTheDayView.0=Совет дня TipOfTheDayView.1=Знаете ли вы...? TipOfTheDayView.2=Показать при загрузке CDDBWizard.0=Подтвердить CDDBWizard.1=Имя файла CDDBWizard.2=Текущее название трека CDDBWizard.3=Текущее название альбома CDDBWizard.4=Предлагаемое название трека CDDBWizard.5=Предлагаемое имя альбома CDDBWizard.6=Готово! Найдено CDDBWizard.7=Возможные значения CDDBWizard.12=Не найдено вариантов! CDDBWizard.14=Эта папка не содержит каких-либо файлов CDDBWizard.16=Жанр: CDDBWizard.17=Найдено точное совпадение! CDDBWizard.18=Совпадения CDDBWizard.19=Получить теги онлайн RefactorWizard.0=Файл перемещен: DigitalDJWizard.0=Выберите поведение нового ДиДжея DigitalDJWizard.1=Поведение, основанное на переходах (Rock -> Pop) DigitalDJWizard.2=Поведение, основанное на пропорциях (20%Rock, 20%Synthpop) DigitalDJWizard.3=Поведение, основанное на окружении (Party, Soft) DigitalDJWizard.4=Помощник управления ДиДжеями DigitalDJWizard.5=Основная конфигурация ДиДжея DigitalDJWizard.6=Имя ДиДжея (*) DigitalDJWizard.8=Минимум звезд у трека: DigitalDJWizard.9=Время перетекания (сек.): DigitalDJWizard.10=Играть Без повторов DigitalDJWizard.11=Бросить DigitalDJWizard.12=Из жанров DigitalDJWizard.13=В жанры DigitalDJWizard.14=Выбор жанров (возможно множественное выделение): DigitalDJWizard.15=Количество треков DigitalDJWizard.16=Вы хотите... DigitalDJWizard.17=Пригласить нового ДиДжея? DigitalDJWizard.18=Изменить существующего ДиДжея? DigitalDJWizard.19=Удалить ДиДжея? DigitalDJWizard.20=Новый Диджей, с переходным поведением #limited string size DigitalDJWizard.21=Удалить #limited string size DigitalDJWizard.22=Начать #limited string size DigitalDJWizard.23=Закончить #limited string size DigitalDJWizard.24=Треки DigitalDJWizard.26=Пожалуйста, выберите хотя бы один переход #limited string size DigitalDJWizard.27=Жанры #limited string size DigitalDJWizard.28=% DigitalDJWizard.29=Новый Диджей, с пропорциональным поведением DigitalDJWizard.30=Пожалуйста, выберите хотя бы одну часть DigitalDJWizard.31=Новый Диджей, с поведением от окружения DigitalDJWizard.32=Новое DigitalDJWizard.33=Создать новое окружение DigitalDJWizard.34=Удалить DigitalDJWizard.35=Удалить выбранные окружения DigitalDJWizard.36=Имя окружения DigitalDJWizard.37=Имя DigitalDJWizard.38=Пожалуйста, создайте хотя бы одно окружение DigitalDJWizard.39=Пожалуйста, введите имя окружения и выберите для него жанры DigitalDJWizard.40=Пожалуйста, выберите ДиДжея DigitalDJWizard.41=Пожалуйста, дайте имя ДиДжею DigitalDJWizard.42=ДиДжей с таким именем уже есть DigitalDJWizard.43=Редактировать ДиДжеев DigitalDJWizard.44=Выберите ДиДжея для редактирования DigitalDJWizard.45=Выбор дальнейших действий DigitalDJWizard.46=Выбор профиля DigitalDJWizard.47=Пожалуйста выберите или создайте окружение DigitalDJWizard.48=Основные характеристики DigitalDJWizard.49=Пожалуйста, укажите основные характеристики ДиДжея DigitalDJWizard.50=Пожалуйста, определите пропорции DigitalDJWizard.51=Удаление ДиДжея DigitalDJWizard.52=Пожалуйста, определите переходы DigitalDJWizard.53=Минимальное количество звезд рейтинга для отбора треков (1 - все треки) DigitalDJWizard.54=Длительность перехода между треками DigitalDJWizard.55=Если отмечено, программа ДиДжея будет содержать треки без повторения DigitalDJWizard.56=Помощник окружений DigitalDJWizard.57=Управление окружениями DigitalDJWizard.58=Выбор окружения: DigitalDJWizard.59=Сумма всех частей должна быть меньше 100% DigitalDJWizard.60=Имя окружения уже существует DigitalDJWizard.61=Удалить ДиДжея #limited string size DigitalDJWizard.62=По умолчанию DigitalDJWizard.63=Восстановить окружения по умолчанию DigitalDJWizard.64=Любое DigitalDJWizard.66=Выбор окружения по умолчанию (Окружение - это набор жанров, см. руководство) DigitalDJWizard.67=Ограничение треков в очереди DigitalDJWizard.68=Максимальное количество треков в очереди PreparePartyWizard.1=Подготовить вечеринку PreparePartyWizard.2=Выбор источника для треков PreparePartyWizard.3=Вначале укажите треки для вашей вечеринки PreparePartyWizard.4=Выберите лимиты PreparePartyWizard.5=Пожалуйста, определите какие-либо ограничения PreparePartyWizard.6=ДиДжеи PreparePartyWizard.7=Окружения PreparePartyWizard.8=Плейлисты PreparePartyWizard.9=Случайные треки PreparePartyWizard.10=Максимум треков PreparePartyWizard.11=Максимальное количество включенных треков PreparePartyWizard.12=Максимальный размер(в МБ) PreparePartyWizard.13=Общий максимальный размер в мегабайтах, который вы планируете создать PreparePartyWizard.14=Максимальная продолжительность(в минутах) PreparePartyWizard.15=Максимальная продолжительность вечеринки в минутах PreparePartyWizard.16=Запрещенные типы файлов PreparePartyWizard.17=Выберите, чтобы использовать только определенные аудиофайлы. Это может быть полезно если конечный аудиоплеер поддерживает не все типы файлов PreparePartyWizard.18=Выберите местоположение PreparePartyWizard.19=Выберите место, в котором файлы для вечеринки будут храниться. Для файлов будет создана подпапка. PreparePartyWizard.20=Пожалуйста, выберите целевое место PreparePartyWizard.21=Выбранная папка: PreparePartyWizard.22=Выбрите целевую папку PreparePartyWizard.23=Файлы будут скопированы в PreparePartyWizard.24=Лучшие треки PreparePartyWizard.25=Новинки PreparePartyWizard.26=Унифицировать имена файлов PreparePartyWizard.27=Унификация имен файлов заменит иностранные символы, что сделает файлы независимыми от операционных систем и различных кодировок. PreparePartyWizard.31=Цель: PreparePartyWizard.32=Файлы в очереди PreparePartyWizard.33=Отмеченные файлы PreparePartyWizard.34=Пытаться конвертировать в другие форматы PreparePartyWizard.35=Использует внешнюю утилиту "pacpl - Perl Audio Converter" для конвертации файлов если это необходимо. PreparePartyWizard.36= файл(ы) невозможно конвертировать в заданный формат. PreparePartyWizard.37=(требуется PACPL, посетите Perl Audio Converter) PreparePartyWizard.38=Конфигурация настроек конвертации PreparePartyWizard.39=Пожалуйста определите команду для выполнения Perl Audio Converter.
    В Linux это часто команда "pacpl" или "perl <install-location>/pacpl.
    В Windows - обычно "perl <install-location>\pacpl PreparePartyWizard.40=Конфигурация... Ambience.0=Рок/Поп Ambience.1=Рэп Ambience.2=Тяжелый Рок Ambience.3=Техно Ambience.4=Электро Ambience.5=Классика Ambience.6=Мягкий Ambience.7=Пати Ambience.8=Джаз Ambience.9=Мировое Ambience.10=Другие Ambience.11=Фолк/старина Ambience.12=Инди Ambience.13=Латин DebugLogAction.0=Листинг отладки DebugLogAction.1=Обновить CopyClipboardAction.0=Копировать адрес в буфер обмена LaunchInBrowserAction.0=Запустить ссылку в браузере по умолчанию ReportAction.0=Отчет успешно создан ReportAction.1=Музыкальный отчет Jajuk ReportAction.2=Пожалуйста, относитесь с уважением к Окружающей Среде и не распечатывайте без крайней необходимости ReportAction.3=Список альбомов ReportAction.4=Треков в альбоме ReportAction.5=Список исполнителей ReportAction.6=Альбомы у исполнителей ReportAction.7=Список жанров ReportAction.8=Альбомы в жанре ReportAction.9=Исполнители/ альбомы в жанре ReportAction.10=Список папок ReportAction.11=Файлы в папке ReportAction.12=Имя файла ReportAction.13=Имя трека ReportAction.14=Список устройств ReportAction.15=Папки на устройстве ReportAction.16=Папки/ файлы ReportAction.17=коллекции ReportAction.18=Исполнители/ альбомы/ треки в стиле ReportAction.19=Перейти к: ActionMove.0=Вставить ActionRefresh.0=Обновить ActionRefresh.1=Обновить папку RenameAction.0=Переименовать RenameAction.1=Пожалуйста, введите новое имя для этого файла: RenameAction.2=Пожалуйста, введите новое имя для этой папки: NewFolderAction.0=Новая папка NewFolderAction.1=Пожалуйста, введите имя новой папки: NewFolderAction.2=Папка с таким именем уже существует. LyricsView.0=Слова песни LyricsView.1=Слова не найдены, доступ в Интернет запрещен, используйте меню настроек, для разрешения LyricsView.2=Войти в режим редактирования текста LyricsView.3=Выйти из режима редактирования текста LyricsView.4=Сохранить текст LyricsView.5=Удалить текст ActionDelete.0=Файлы удалены ActionDelete.1=Папки удалены FindDuplicateTracksAction.0=Не найдено дубликатов FindDuplicateTracksAction.1=Найдены дубликаты FindDuplicateTracksAction.2=Поиск дублированных треков FindDuplicateTracksAction.3=Список найденных дубликатов треков FindDuplicateTracksAction.4=Выбрать все треки-дубликаты RefreshDialog.0=Подготовка к обновлению устройства... RefreshDialog.1=Обновление устройства RefreshDialog.2=Обновляемое устройство: RefreshDialog.3=Почистить старые файлы RadioWizard.0=Пожалуйста, выберите или создайте станцию веб-радио RadioWizard.1=Управление станциями веб-радио RadioWizard.2=Новая RadioWizard.3=Удалить RadioWizard.4=По умолчанию RadioWizard.5=Станция с таким именем уже существует RadioWizard.6=Имя станции RadioWizard.7=Помощник веб-радиостанций RadioWizard.8=URL RadioWizard.9=Имя RadioWizard.10=Неверный адрес URL RadioWizard.11=Имя и URL обязательны UpdateManager.0=Доступна новая версия Jajuk ( UpdateManager.1=)! Вы можете загрузить ее с сайта http://jajuk.info UpdateManager.2=Пока что нет новых релизов SuggestionView.0=Рекомендации SuggestionView.1=Любимые SuggestionView.2=Новые SuggestionView.3=Другие альбомы SuggestionView.4=Еще исполнители SuggestionView.5=Забытые SuggestionView.7=Нельзя ничего отобразить

    Информация с Last.fm показывается только если:
    • Трек воспроизводится
    • Известен исполнитель трека (корректный тег)
    • Включена опция "Разрешить запросы Last.fm" во вкладке "Last.FM" в настройках
    • Опция "Запретить Jajuk любой доступ в Интернет" отключена в "Настройках" вкладке "Сеть"
    AbstractThumbnail.0=Открыть страницу LAST.FM AlbumsTableView.0=Таблица альбомов AlbumsTableView.1=Кол-во треков AlarmClock.0=Установить будильник #Next value : 6 AlarmDialog.0=Время (ЧЧ24:ММ:СС) AlarmDialog.1=Час AlarmDialog.2=Минуты AlarmDialog.3=Секунды AlarmDialog.4=Действие будильника AlarmDialog.5=Выберите действие будильника #Next value : 11 ShowPropertiesAction.0=Показать свойства объекта QueueView.1=Пустая очередь QueueView.2=Перелистывать таблицу автоматически к текущему проигрываемому треку JajukSlimWindow.0=вкл./выкл. мини-Jajuk JajukFullscreen.0=Разрешить/Запретить полноэкранный режим BanSelectionAction.0=Запретить BanSelectionAction.1=Запретить объект, чтобы он никогда не выбирался UnBanSelectionAction.0=Снять запрет UnBanSelectionAction.1=Снять запрет с объекта(ов), чтобы вновь активировать его(их) OpenExplorerAction.0=Открыть в Проводнике OpenExplorerAction.1=Открыть папку используя внешний обозреватель файлов Preference.0=Дать свою оценку текущему треку
    Это будет использовано для вычисления окончательного рейтинга Preference.1=Мусор Preference.2=Плохо Preference.3=Средне Preference.4=Хорошо Preference.5=Превосходно Preference.6=Классика Preference.7=Оценка... Preference.8=Не указано ArtistView.0=Исполнитель Notificator.NONE=Нет Notificator.TOAST=Тост Notificator.BALLOON=Облако Notificator.track_change.webradio_title=Играет веб-радио : Notificator.track_change.track_title=Играет трек : SyncTreeTableAction.0=Синхронизировать вид дерева и таблицы SyncTreeTableAction.1=Синхронизация вида дерева и таблицы
    Когда используется, при выборе элемента в таблице, тот же элемент раскрывается и выделяется в дереве
    При выделении в таблице - элементы в дереве фильтруются соответственно # --- Tips of day --- originally controlled by Jajuk's manual (English) - Selectus TipOfTheDay.0=Совет 0. Вы можете повторить текущий трек сначала, щелкнув с SHIFT на кнопке вперед. TipOfTheDay.1=Совет 1. Вы можете повторить текущий альбом с первого трека щелкнув [CTRL+click] на кнопке "Играть предыдущий" TipOfTheDay.2=Совет 2. Вы можете добавить случайные композиции в список, нажав на кнопку ? в редакторе плейлиста. TipOfTheDay.3=Совет 3. Вы можете получить обложки для альбомов из Интернета, даже используя прокси сервер, настроив его во вкладке "Сеть" настроек. TipOfTheDay.4=Совет 4. Теперь Вам доступен мини-Jajuk (кнопка в правом верхнем углу), который занимает совсем немного места на рабочем столе, позволяя управлять воспроизведением, не сворачивая плеер. TipOfTheDay.5=Совет 5. Вы можете скрывать недоступные треки на размонтированных устройствах опцией "Показывать только доступные треки", находящейся во вкладке "Опции" настроек. TipOfTheDay.6=Совет 6. Вы можете использовать любые функции Jajuk через клавиатуру. (См. настройки) TipOfTheDay.7=Совет 7. Вы можете перетаскивать объекты из дерева на плейлист. TipOfTheDay.8=Совет 8. Вы можете быстро ознакомиться с новым диском или альбомом, используя режим ознакомления. TipOfTheDay.9=Совет 9. Вы можете задать время перекрестного затухания во вкладке "Режимы" настроек. TipOfTheDay.10=Совет 10. Вы можете запускать Jajuk в свернутом виде, отключив опцию "Показывать окно после загрузки" в настройках. TipOfTheDay.11=Совет 11. Вы можете управлять Jajuk используя только трей. (В Windows и Linux) TipOfTheDay.12=Совет 12. Тема Jajuk настраивается во вкладке "Интерфейс" в настройках. TipOfTheDay.13=Совет 13. Вы можете настроить двойной щелчок и перетаскивание во вкладке "Опции" настроек. TipOfTheDay.14=Совет 14. Jajuk может "планировать" треки, которые будут играть после завершения вами добавленных в зависимости от ваших предпочтений. TipOfTheDay.15=Совет 15. Интерфейс Jajuk очень гибкий. Вы можете перетащить окна, расположив удобным образом. Развернуть их, переместить, сделать вкладками, или скрыть их и показывать только при наведении. TipOfTheDay.16=Совет 16. Вы можете узнать точное количество треков и файлов в вашей коллекции, выбрав точку "коллекция" в окне вида треков или файлов. TipOfTheDay.17=Совет 17. Вы можете заполнить теги автоматически, благодаря функции "получить теги онлайн" в контекстном меню дерева файлов или треков. TipOfTheDay.18=Совет 18. "Список истории" вверху экрана содержит ранее проигранные треки. TipOfTheDay.19=Совет 19. Вы можете выполнить быстрый поиск, используя строку поиска вверху экрана. TipOfTheDay.20=Совет 20. Вы можете отправить отчет об ошибке или ваши пожелания, используя соответствующую опцию в меню "Помощь". TipOfTheDay.21=Совет 21. ДиДжей Jajuk может работать в соответствии с созданными вами правилами. TipOfTheDay.22=Совет 22. Вы можете узнать слова песни, взглянув на окно "Слова песни". TipOfTheDay.23=Совет 23. Вы можете получать информацию с last.fm о похожих исполнителях или песнях. TipOfTheDay.24=Совет 24. Вы можете запретить треки, которые Вам не нравятся через панель управления или в окне мини-Jajuk. TipOfTheDay.25=Совет 25. Вы можете показать/спрятать недоступные треки в один щелчок в меню "Конфигурация". TipOfTheDay.26=Совет 26. Теперь вы можете выбрать любую папку для данных Jajuk, чтобы держать ваши настройки и данные в любом месте, на любом компьютере. (Опция во вкладке "Расширенные" настроек) TipOfTheDay.27=Совет 27. Вы можете добавить любое окно в любой ракурс, используя меню "Вид". TipOfTheDay.28=Совет 28. Вы можете запустить веб-страницу в вашем любимом браузере используя эту иконку Image:launch_16x16.png/ TipOfTheDay.29=Совет 29. Jajuk поддерживает веб-радио Image:webradio_32x32.png/ TipOfTheDay.30=Совет 30. Jajuk можно управлять удаленно через шину D-bus, если она доступна на данной платформе (то есть не в среде Windows). Это позволяет использовать мультимедиа клавиши клавиатуры для управления плеером. Смотрите онлайн-руководство для подробного описания этой и других функций. ]]> jajuk-1.9.6.orig/src/main/java/org/jajuk/i18n/jajuk_de.properties0000644000175000017500000017437411720500104024474 0ustar drazzibdrazzib Rating system page). Ihre bisherigen Bewertungen wurden automatisch in den Bereich 0 bis 100 umgerechnet, wir schlagen trotzdem vor, alle Bewertungen in der Einstellungsansicht im Reiter Geschichte zurückzusetzen (Achtung: Alle bisherigen Bewertungen werden dadurch gelöscht) #Write confirmation so replies are: yes / no / cancel Confirmation_exit=Wollen Sie Jajuk wirklich verlassen? Confirmation_delete=Achtung! Die folgenden Dateien werden physikalisch von der Festplatte gelöscht. Möchten Sie fortfahren? Confirmation_void_refresh=Achtung! Sie sind dabei auf eine leere Quelle zuzugreifen. Stellen Sie unter Unix sicher, dass die Quelle gemountet ist - ansonsten gehen Jajuk Einstellungen dieser Quelle verloren. Wollen Sie fortfahren? Confirmation_remove_device=Wollen Sie diese Quelle wirklich entfernen? Confirmation_delete_cover=Wollen Sie dieses Cover wirklich löschen (wird von der Festplatte gelöscht)? Confirmation_delete_files=Möchten Sie die folgenden Dateien von der Festplatte löschen? Confirmation_delete_dirs=Möchten Sie die folgenden Verzeichnisse von der Festplatte löschen? Confirmation_clear_history=Wollen Sie die Historie wirklich löschen? Confirmation_reset_ratings=Wollen Sie die Titel-Bewertungen wirklich zurücksetzen? Confirmation_refactor_files=Sollen die selektierten Dateien wirklich umbenannt werden? Confirmation_restore_all=Wenn Sie alle Ansichten zurücksetzen wollen, muss Jajuk neu gestartet werden. Möchten Sie Jajuk jetzt beenden? Confirmation_defaults_radios=Hiermit werden alle Radiostationen gelöscht, die Sie bisher angelegt haben. Möchten Sie fortfahren? Confirmation_delete_empty_dirs=Die folgenden Verzeichnisse sind leer. Wollen Sie diese löschen? Confirmation_file_overwrite=Diese Datei existiert bereits. Wollen Sie diese Datei überschreiben? Confirmation_file_number=Datei(en) werden gelöscht. Confirmation_alarm_stop=Soll dieser Alarm wirklich gestoppt werden? Confirmation_defaults=Dadurch werden all Tab-Einstellungen auf Standardwerte zurückgesetzt (nicht nur die aktuelle Ansicht). Sind Sie sicher? Confirmation_reset_preferences=Wollen Sie wirklich alle Titelvorgaben zurücksetzen? Device_type.directory=Verzeichnis Device_type.file_cd=Musikdateien CD Device_type.audio_cd=Audio CD Device_type.extdd=Externe Festplatte Device_type.player=Digital Audio Player Device_type.network_drive=Netzlaufwerk Device_type.remote=Remote (Nicht implementiert) Perspective_Description_Simple=Einfach Perspective_Description_Files=Dateien Perspective_Description_Tracks=Titel Perspective_Description_Configuration=Konfiguration Perspective_Description_Statistics=Statistiken Perspective_Description_Help=Hilfe Perspective_Description_Display=Player Perspective_Description_Albums=Alben Perspective_Description_Info=Information Perspective_Description_Playlists=Playlists Item_Playlist_File=Playlist Item_Track=Titel Item_Album=Album Item_Artist=Artist Item_Genre=Stil Item_Device=Quelle Item_File=Datei Item_Directory=Verzeichnis Item_Year=Jahr Item_AlbumArtist=Album-Artist Property_id=Id Property_name=Name Property_type=Typ Property_url=Url Property_mount_point=Mount Point Property_auto_refresh=Auto Aktualisierung Property_auto_mount=Auto Mount Property_album=Album Property_style=Stil Property_author=Artist Property_album_artist=Album Artist Property_disc_number=CD Property_length=Länge Property_year=Jahr Property_rate=Bewertung Property_files=Dateien Property_hits=Treffer Property_filename=Datei Property_date=Datum Property_added=Discovery Datum Property_parent=Übergeordnetes Verzeichnis Property_device=Quelle Property_directory=Verzeichnis Property_track=Titel Property_size=Größe (MB) Property_quality=Qualität Property_hashcode=Hashcode Property_playlist_files=Playlists Property_comment=Kommentar Property_order=Reihenfolge Property_path=kompletter Pfad Property_tracks=Titel Property_file_date=Dateidatum Property_Format_Number=Nummer Property_Format_String=Text Property_Format_Boolean=Bool'scher Wert Property_Format_Float=Fließkomma Property_Format_Date=Datum Property_Format_URL=URL Property_pf=Einstellungen Property_tpt=Gesamtspielzeit (Sek) Property_ban=Ausgeschlossen Property_disc_id=DiscID Language_desc_en=Englisch Language_desc_fr=Französisch Language_desc_de=Deutsch Language_desc_it=Italienisch Language_desc_sv=Schwedisch Language_desc_nl=Holländisch Language_desc_zh=Chinesisch Language_desc_es=Spanisch Language_desc_ca=Katalonisch Language_desc_ko=Koreanisch Language_desc_el=Griechisch Language_desc_ru=Russisch Language_desc_gl=Galicisch Language_desc_cs=Tschechisch Language_desc_pt=Portugiesisch #--- Error codes --- Error.000=Unbekannter Fehler Error.005=Fehler beim Analysieren der Kollektionsdatei Error.007=Fehler beim Abspielen der Datei, eventuell konnte MPlayer bis zum Timeout nicht mit dem Abspielen beginnen: Error.008=Fehler beim Anhalten der Datei Error.009=Datei kann nicht gelesen werden Error.010=Zu diesem Titel kann in der aktiven Quelle keine Datei gefunden werden Error.011=Technischer Fehler beim Aktivieren der Quelle oder leere Quelle Error.012=Technischer Fehler beim Deaktivieren der Quelle, möglicherweise wird sie von einem anderen Programm verwendet Error.013=Die Quelle kann nicht entfernt werden: sie ist entweder aktiv oder wird gerade aktualisiert Error.016=Auf die angegebene Quelle kann nicht zugegriffen werden, bitte geben Sie einen mount point an. Bsp: '/cdrom' unter Unix, 'e:' unter MS Windows Error.017=Fehler beim Analysieren der Playlist Error.018=Kein Titel dieser Playlist kann geöffnet werden Error.019=Eine existierende Quelle besitzt bereits diesen Namen Error.020=I/O Fehler beim Kopieren der Datei, überprüfen Sie ob genug Speicher auf der Festplatte frei ist Error.021=URL Feld muss angegeben werden. Bsp: 'd:\music' unter MS Windows, '/home/foo/music' unter Unix Error.022=Feldname muss angegeben werden. Bsp: 'Festplatte', 'ROCK CD' Error.023=Kann Starttitel nicht abspielen Error.024=Datei kann nicht geschrieben werden Error.025=Eine der zu lesenden Dateien befindet sich in einer inaktiven Quelle Error.026=Fehler beim Registrieren der Player Error.027=Synchronisation abgebrochen Error.028=Fehler beim Speichern der Playlist Error.029=Eine existierende Quelle ist ein übergeordneter Ordner dieser Quelle, hat den gleichen Pfad oder ist ein untergeordneter Ordner Error.030=Zu viele fehlgeschlagene Verbindungen. Jajuk sucht keine Online Covers mehr. Error.101=Die Quelle existiert nicht oder kann nicht erreicht werden Error.102=Fehler Error.103=Fehler beim Lesen der Etikett (id3 tag) Information Error.104=Fehler beim Schreiben der Etikett (id3 tag) Information Error.105=Resource Bundle Schlüssel nicht gefunden Error.106=Unbekannte Ausnahme Error.107=Wird bereits aktualisiert oder synchronisiert Error.108=Fehler beim Analysieren der Ansichten Datei Error.109=Player oder Etikett Klasse nicht auffindbar Error.110=Dieser Eigenschaftsname ist für Jajuk reserviert, bitte wählen Sie einen anderen Namen Error.111=Die Quelle ist bereits aktiv Error.112=Quelle kann nicht aktiviert werden Error.113=Benutzereinstellungen können nicht gespeichert werden Error.114=Benutzereinstellungen können nicht gelesen werden Error.118=Fehler beim Verarbeiten eines Event Requests Error.119=Fehler beim Analysieren der Historien Datei oder fehlende Historien Datei Error.120=Auf die Quelle kann nicht zugegriffen werden: sie ist entweder nicht aktiv, oder sie wird gerade aktualisiert oder synchronisiert Error.121=Die Quelle ist in Verwendung und kann nicht deaktiviert werden Error.122=Fehler im FIFO Error.123=Fehler beim Setzen des Designs Error.124=Jajuk läuft bereits -- Sie können Jajuk nicht mehrmals ausführen. Error.125=Quelle ist bereits deaktiviert Error.126=Suchen wird von diesem Audio Format nicht unterstützt Error.127=Keine neuen Titel in der angegebenen Zeitgrenze, Sie können diesen Wert in den Einstellungen setzen Error.128=Das derzeitige Lied ist das erste in der Kollektion, es sind keine davorliegenden Lieder verfügbar Error.129=Fehler beim Laden des Covers Error.131=Datei kann nicht gelöscht werden Error.133=Ihre Kollektionsdatei war fehlerhaft. Jajuk hat die fehlerhafte Datei durch eine Sicherung ersetzt. Error.134=Datei kann nicht umbenannt werden Error.135=Datei existiert nicht Error.136=Operation fehlgeschlagen Error.137=Falsches Format Error.138=Einige zu diesem Titel gehörigen Dateien sind auf einer nicht aktivierten Quelle und wurden daher nicht geändert. Error.140=Ungültiger Text: die Zeichen & ' " < oder > sollten nicht vorkommen Error.141=Diese Playlist befindet sich auf einer deaktivierten oder sich gerade aktualisierenden Quelle und ist daher nicht verfügbar Error.142=Diese Playlist beinhaltet nicht existierende Titel oder Titel außerhalb der bekannten Quellen. Diese Titel wurden ignoriert. Error.143=Quelle nicht auffindbar Error.144=Fehler beim Lesen des DJ Error.145=Kann DJ nicht speichern Error.146=Das aktuelle Muster ist ungültig.
    Gültige Werte sind: %artist (Artist); %album_artist (Album Artist); %title (Titelname); %album (Albumname);
    %n (führende Null); %genre (Genre); %year (Jahr); %disc (CD-Nummer)
    und das Muster muss mindestens einen Schrägstrich enthalten Error.147=Einige Dateien konnten nicht verschoben werden (siehe Details für nähere Information) Error.148=Feld Jahr ist unbekannt Error.149=Feld Album ist unbekannt Error.150=Feld Artist ist unbekannt Error.151=Feld Titelname ist unbekannt Error.152=Feld Titel ist unbekannt Error.153=Feld Stil ist unbekannt Error.154=Datei kann nicht umbenannt werden, bitte auf ungültige Zeichen in Dateinamen oder Tags überprüfen Error.155=Retagging der Dateien ist fehlgeschlagen, bitte Zugriffsrechte überprüfen Error.156=Leere Kollektion Error.157=Ungültiger DJ. Bitte selektieren oder erzeugen Sie einen DJ mit Hilfe der DJ Schaltfläche. Error.158=Die DJ Bedingungen/Einstellungen können nicht angewandt werden oder es ist kein entsprechender Titel verfügbar Error.159=Zugeteilte Umgebung wurde entfernt Error.160=Datei nicht kopiert, Quell- und Zieldateiname sind gleich. Error.161=Kann nicht in Verzeichnis schreiben, bitte Zugriffsrechte überprüfen Error.162=Diese spezielle Eigenschaft existiert bereits Error.163=Fehler beim Wiederherstellen der Standard-Ansichten Error.164=Keine Titel gefunden für Umgebung: Error.165=Ungültiges Musikverzeichnis - es kann nicht gefunden werden oder ist nicht beschreibbar. Error.166=Leeres Album - kann kein Cover suchen Error.167=Konnte keinen Bericht erstellen Error.168=Keine doppelten Dateien gefunden Error.169=Aktion fehlgeschlagen. Bitte beachten Sie, dass diese Aktion eine Internetverbindung benötigt, um eine Liste von Radiostationen zu laden. Error.170=Fehler beim Abspielen des Webradios Error.171=Für diese Quelle wurde noch keine Synchronisationsquelle definiert. Definieren Sie diese bitte in der Quellen-Konfiguration (auf die Quelle in der Quellen-Ansicht klicken). Error.172=Dateien, die gerade Abgespielt werden, und die dazugehöriugen Verzeichnisse können nicht gelöscht oder verändert werden. Error.173=Es ist ein Fehler beim Löschen der folgenden Verzeichnisse aufgetreten: Error.174=Fehler beim Zugriff auf die Freedb-Webseite, bitte überprüfen Sie Ihre Netzwerkverbindung Error.175=Aktion abgebrochen Error.176=Fehler beim Generieren der Playlist Error.177=Bitte eine gültige Zeit im Format HH24:MM:SS eingeben. Error.178=Vollbildmodus wird von ihrem System nicht untersützt. Error.179=Kann den Systemdateiexplorer nicht öffnen, bitte setzten sie einen Pfad in den Einstellungen (Erweitert) Error.180=Fehler beim Kopieren der Dateien #Warnings Warning.0=MPlayer wurde nicht gefunden. Einige Audio- und Videoformate werden deaktiviert (flac, wma, aac, mpg2, ...). Falls MPlayer installiert ist und verwendet werden soll, müssen Sie den Pfad zu MPlayer manuell in der Konfigurations-Ansicht unter Einstellungen/Erweitert eingeben. Warning.1=Falsches MPlayer Release - Version MPlayer1.0Pre8 oder höher wird benötigt. Einige Audioformate werden deaktiviert. Warning.2=Es sieht so aus als würde das Jajuk Arbeitsverzeichnis auch von jemand anderem benutzt. Dadurch können Konfigurationen (Optionen, Bewertungen, ...) gegenseitig überschrieben werden! Warning.3=MPlayer kann nicht heruntergeladen werden. Wenn Sie einen HTTP Proxy verwenden, konfigurieren Sie diesen bitte in der Jajuk Konfiguration unter Einstellungen im Bereich Netzwerk und starten Sie Jajuk erneut. Warning.4=MPlayer wird benötigt um Web Radios zu hören Warning.5=Das Zielverzeichnis ist bereits vorhanden, einige Dateien könnten überschrieben werden. Möchten Sie fortfahren? Warning.6=Kein Titel zum Abspielen bereit. (Tipp: versuchen Sie eine Quelle einzuhängen oder verändern Sie eine der Umgebungen) Warning.7=Jajuk hat festgestellt, dass aufgrund einer neuen Version eine Aktualisierung nötig ist. Wollen Sie diese jetzt durchführen? (Sie können diese auch jederzeit später in der Quellen-Ansicht auslösen). #--- Strings by class --- ParameterView.0=Zeitraum der Historie: ParameterView.2=Legen Sie hier fest, wieviele Tage sich das System die angehörten Titel merkt. -1 schaltet diese Funktion aus, 0 setzt die Historie auf unendlich. ParameterView.3=Historie löschen ParameterView.4=Die aktuelle Historie löschen ParameterView.8=Historie/Bewertungen ParameterView.9=Start: ParameterView.10=Nichts ParameterView.11=Keine Musik nach dem Starten ParameterView.12=Letzter Titel von Anfang an ParameterView.13=Den letzten Titel der vorherigen Session spielen ParameterView.14=Titel mischen ParameterView.15=Einen zufälligen Titel der gesamten Kollektion spielen ParameterView.16=Titel/Radio: ParameterView.17=Wählen Sie eine Datei, die nach dem Starten gespielt wird ParameterView.18=Wählen Sie eine Datei, die nach dem Starten gespielt wird. Eine gefilterte Liste wird angezeigt sobald Sie zu tippen beginnen. ParameterView.19=Start ParameterView.26=Bestätigungen ParameterView.27=Bevor eine Datei physikalisch gelöscht wird ParameterView.28=Bestätigung einholen bevor eine Date wirklich aus dem Dateisystem gelöscht wird ParameterView.29=Bevor Jajuk beendet wird ParameterView.30=Vor dem Beenden von Jajuk eine Bestätigung einholen ParameterView.33=Optionen ParameterView.35=Blendet Titel aus, die sich in inaktiven Quellen befinden ParameterView.36=Neustart am Ende der Kollektion ParameterView.37=Die Kollektion noch einmal von vorne weg abspielen, wenn das Ende im Modus Fortsetzen erreicht wird ParameterView.38=Sprache: ParameterView.42=Wählen Sie die gewünschte Sprache der Benutzeroberfläche ParameterView.43=Design: ParameterView.44=Wählen Sie ein Design für das Aussehen der Oberfläche

    (Ein Jajuk Neustart könnte nötig sein um die Oberfläche komplett zu aktualisieren) ParameterView.46=Log Stufe: ParameterView.47=Schwere Fehler ParameterView.48=Fehler ParameterView.49=Warnungen ParameterView.50=Informationen ParameterView.51=Alles (debug) ParameterView.52=Jajuk Log Einträge: Schwere Fehler: nur schwere Fehler anzeigen, Fehler: +normale Fehler, Warnungen: + Warnungen, Informationen: + Informations-Meldungen, Alles (debug): alle Meldungen ParameterView.59=Anspielen ab (%): ParameterView.60=Wo sollen Titel angspielt werden: Position in %, von 0 (Anfang der Datei) bis 99 (Ende der Datei) ParameterView.61=Anspieldauer (Sek.): ParameterView.62=Legen Sie fest wieviele Sekunden lang ein Titel angespielt wird ParameterView.85=Übernehmen ParameterView.86=Standard wiederherstellen ParameterView.87=Einstellungen ParameterView.98=Muster ParameterView.99=Etiketten komplett lesen ParameterView.100=Zwinge Jajuk dazu, alle Etiketten (id3 tags) neu zu lesen.

    Das kann nützlich sein, wenn die Etiketten mit einem anderen Programm geändert wurden. ParameterView.101=Stammverzeichnis als Albumnamen ParameterView.102=Wenn für einen Titel kein Album Name im Etikett (id3 tag) gefunden werden kann, soll der Name des Verzeichnisses verwendet werden. ParameterView.109=Einstellungen gespeichert ParameterView.110=Einstellungen auf Standardwerte zurückgesetzt ParameterView.111=Best of Playlist Größe: ParameterView.112=Anzahl an Titeln in der Best of Playlist (1 bis 100) ParameterView.113=Regexp in Filtern verwenden ParameterView.114=Regular Expressions verwenden (Regexp Format) ParameterView.115=Erweitert ParameterView.116=Backup der Kollektionsdatei: ParameterView.117=Aktivieren Sie diesen Punkt, wenn die Kollektionsdatei auf collection-.xml Dateien gesichert werden soll ParameterView.118=Backup Größe (MB) ParameterView.119=Backup Größe in Megabyte ParameterView.120=Kodierung der Kollektionsdatei: ParameterView.121=Wählen Sie eine Kodierung: UTF-16 eignet sich für asiatische Sprachen, UTF-8 ist für europäische Sprachen ausgelegt. ParameterView.129=Zeitbegrenzung neuer Titel (Tage): ParameterView.130=Zeitbegrenzung für neue Titel in Tagen: Alle Titel die in diesem Zeitraum hinzugefügt wurden, werden als neue Titel bezeichnet ParameterView.131=Best of Titel ParameterView.132=Spielt beim Start einen Titel aus der Best of Liste ParameterView.133=Neuer Titel ParameterView.134=Spielt beim Start einen neuen Titel (siehe Parameter für Zeitbegrenzung neuer Titel!) ParameterView.135=Letzter Titel bei letzter Position ParameterView.136=Spielt den zuletzt gespielten Titel an der Position weiter, an der gestoppt wurde. ParameterView.139=Netzwerk ParameterView.142=Proxy Benutzername: ParameterView.143=Proxy Benutzername zur Authentisierung ParameterView.144=Proxy Rechnername: ParameterView.145=Name des Proxy Rechners (oder IP Adresse) ParameterView.146=Proxy Port: ParameterView.147=TCP-IP Port des Proxys (meistens 3128) ParameterView.148=Automatische Covers ParameterView.149=Lädt Covers aus dem Internet (wenn nötig bitte den Proxy Server konfigurieren) ParameterView.150=Cover Größe: ParameterView.151=Größe für Covers die aus dem Internet geladen werden ParameterView.155=Je höher die Suchgenauigkeit, desto seltener werden falsche Covers gefunden werden ParameterView.156=Niedrige Genauigkeit (alle Wörter) ParameterView.157=Mittlere Genauigkeit (Wortgruppen) ParameterView.158=Hohe Genauigkeit (zwingende Wortgruppen) ParameterView.159=Covers ParameterView.160=Verbindung Timeout (sec): ParameterView.161=Timeout der Verbindung in Sekunden: die Aktion schlägt fehl, wenn in dieser Zeit keine Antwort zurückkommt ParameterView.162=Übertragung Timeout (sec). ParameterView.163=Timeout der Datenübertragung in Sekunden: die Aktion schlägt fehl, wenn ein Download in dieser Zeit nicht fertig wird ParameterView.164=Vor Löschen einer Quelle ParameterView.165=Bestätigung vor dem Löschen einer Quelle einholen ParameterView.166=Covers mischen ParameterView.167=Covers werden durchgemixt und zufällig eines angezeigt ParameterView.169=Covers vorausladen ParameterView.170=Wenn möglich, alle verfügbaren Covers sofort herunterladen um sie später schnell verfügbar zu haben ParameterView.171=Vor Löschen eines Covers ParameterView.172=Bestätigung einholen bevor ein Cover endgültig gelöscht wird ParameterView.177=Anzahl an geplanten Titeln: ParameterView.178=Anzahl an geplanten Titeln die in der Playlist angezeigt werden sollen ParameterView.179=Hinten anstellen bei Auswahl ParameterView.180=Durch Doppelklick oder Auswahl werden die Titel an die Wiedergabeliste angehängt (und nicht sofort gespielt) ParameterView.181=Hinten anstellen bei Drag&Drop ParameterView.182=Ein mit Drag&Drop in die Playlist gezogener Titel wird hinten angehängt (und nicht sofort gespielt) ParameterView.186=Bewertungen zurücksetzen ParameterView.187=Bewertungen für Titel auf Null zurücksetzen ParameterView.188=Vor dem Löschen der Historie ParameterView.189=Vor dem Zurücksetzen der Bewertungen ParameterView.190=Überblendung (Sek.) ParameterView.191=Dauer der Überblendung zwischen zwei Titeln in Sekunden ParameterView.192=Dateiorganisator: ParameterView.193=Verfügbare Platzhalter: %artist (Artist); %album_artist (Album Artist, wenn dieser nicht definiert ist, wird der Track-Artist verwendet); %title (Titelname); %album (Album); %n (Nummer); %genre (Genre); %year (Jahr); %disc (CD-Nummer) ParameterView.194=Vor dem Organisieren der Dateien ParameterView.195=Animationssicht: ParameterView.196=Hotkeys aktivieren ParameterView.197=Einige Hotkeys (wie F8) aktivieren, auch wenn Jajuk nicht den Fokus hat ParameterView.198=Einige Änderungen werden erst beim nächsten Jajuk Start aktiv ParameterView.199=Scrobbeln was ich höre ParameterView.200=Diese Option sendet Informationen an Last.FM ParameterView.201=Last.FM Benutzername: ParameterView.202=Der Benutzername für den Daten an Last.FM geschickt werden ParameterView.203=Last.FM Passwort: ParameterView.204=Das Passwort zu diesem Benutzernamen ParameterView.205=Mplayer Argumente: ParameterView.206=Zusätzliche MPlayer Argumente wie '-ao esd', '-ao arts' oder '-novideo' (zum Beispiel um das Abspielen von Videos zu unterbinden) ParameterView.207=Jajuk Arbeitsverzeichnis: ParameterView.208=Setzt das Verzeichnis wo Jajuk seine Konfiguration speichert (Standard: home Verzeichnis des Benutzers) ParameterView.209=Das Jajuk Arbeitsverzeichnis wurde geändert (das alte Arbeitsverzeichnis wurde nicht gelöscht). Jajuk wird nun beendet und kann anschließend neu gestartet werden. ParameterView.210=Wenn Musik-Überblendungen nicht funktionieren, versuchen Sie bei den Sound Engine Einstellungen (Einstellungs Ansicht / Erweitert) folgende Werte anzugeben: <-ao esd> (Gnome) oder <-ao arts> (KDE). ParameterView.211=Nur klein ParameterView.212=Klein und mittel ParameterView.213=Nur mittel ParameterView.214=Mittel und groß ParameterView.215=Nur groß ParameterView.216=Nach Artist suchen ParameterView.217=Nach Album suchen ParameterView.218=Nach Titel suchen ParameterView.219=Umgebungsvariablen: ParameterView.220=Umgebungsvariablen für den Audio Player setzen (z.B. ARTS_SERVER unter KDE oder ESPEAKER unter Gnome). Format: var1=xx var2=yyy... #Respect English size for next item ParameterView.221=Seitengröße für Katalogansicht (0: alle): ParameterView.222=Legt die Anzahl der Alben pro Seite in der Katalog Ansicht fest. 0: alle Covers auf einer Seite anzeigen. ParameterView.223=Schriftgröße: ParameterView.224=Schriftgröße festlegen ParameterView.225=GUI ParameterView.226=Modi ParameterView.228=Album Popups anzeigen ParameterView.229=Katalog Ansicht Einstellungen ParameterView.233=Das Design wird erst beim nächsten Start von Jajuk verwendet ParameterView.234=Nach Updates suchen ParameterView.235=Last.FM ParameterView.236=Kein Proxy ParameterView.237=HTTP proxy ParameterView.238=SOCKS proxy ParameterView.239=Proxy Passwort: ParameterView.240=Last.FM Informationen laden ParameterView.241=Wenn aktiv, lädt Jajuk Informationen zu Alben, Artisten usw. von der Last.FM Webseite (siehe Vorschläge) ParameterView.242=MPlayer Pfad: ParameterView.243=Vollständiger Pfad zu MPlayer inkl. ausführbarer Datei (Leerzeichen sind erlaubt)
    Beispiel: /Applications/MPlayer OSX.app/Contents/Resources/External_Binaries/mplayer_intel.app/Contents/MacOS/mplayer ParameterView.244=Dateidatum = Entdeckungsdatum ParameterView.245=Durch diese Option verwendet Jajuk das Dateidatum als Entdeckungsdatum.
    Ein kompletter Refresh ist nötig um die Änderungen sichtbar zu machen ParameterView.246=Icon-Größe in der Ansicht-Übersicht (in Pixel) ParameterView.247=Der Zielpfad enthält einen bestehenden Arbeitsbereich für Jajuk. Der Arbeitsbereich wurde für den atuellen Benutzer auf dieses Verzeichnis gewechselt (Der vorherige Arbeitsbereich ist an der ursprünglichen Position gesichert). Jajuk wird nun beendet und kann anschließend neu gestartet werden. ParameterView.248=Titel: ParameterView.249=Einstellungen zurücksetzen ParameterView.250=Benutzereinstellungen zurücksetzen ParameterView.251=Verlauf wurde geleert ParameterView.252=Bewertungen und Abspielzeiten wurden zurückgesetzt ParameterView.253=Einstellungen wurden zurückgesetzt ParameterView.254=Kurze Windows-Namen verwenden ParameterView.255=[Windows 32 bits] Wenn Sie diese Option auswählen, wird MPlayer gezwungen, kürzere Dateinamen zu verwenden, dadurch können Probleme mit einigen Sprachversionen vermieden werden ParameterView.256=Dateinamen für Standard-Cover ParameterView.257=Jajuk sucht nach einer Coverbilddatei, deren Name diesen Text beinhaltet und verwendet dieses als Standard (;;...) ParameterView.260=Album-Cover im Windows Explorer Format speichern ParameterView.261=Heruntergeladene Cover werden als folder.jpg/png/... gespeichert, damit der Windows Explorer diese als Ordner-Icon verwendet. ParameterView.262=Verwende Audionormalisierung ParameterView.263=Maximiere die Lautstärke ohne den Klang zu verzerren ParameterView.264=keine Verbindung mit dem Internet herstellen ParameterView.265=keine Verbindung mit dem Internet herstellen, wenn man z.B. sich im Büro aufhällt ParameterView.266=Entferne gespielte Tracks von der Wiedergabliste ParameterView.267=Alle Tracks, die sich vor dem aktuellen befinden, werden aus der Wiedergabliste entfernt ParameterView.268=Proxy-Einstellungen ParameterView.269=Pfad zur ausfürbaren Explorer Datei ParameterView.270=Aufrufpfad für den externen Dateibrowser ParameterView.271=Zeige Taskleistensymbol ParameterView.272=wenn aktiviert, dann können viele Funktionen von Jajuk über das Taskleistensymbol aufgerufen werden ParameterView.273=Cover spiegeln ParameterView.274=wenn aktiviert, dann wird das Cover gekippt und gespiegelt ParameterView.275=Titeländerung: ParameterView.276=Wählen sie die Art der Benachrichtigung bei Titeländerungen aus (Der "toast" ist ein Nachrichten-Popup welches kurz angezeigt wird und anschließend von selbst wieder verschwindet) ParameterView.277=Muster für Blasen-Benachrichtungen: ParameterView.278=Dieses Muster bestimmt den Text der in der Blasen-Benachrichtigung bei Titeländerungen angezeigt wird ParameterView.279=Informationsmuster: ParameterView.280=Dieses Muster bestimmt den Text der in der Informationsansicht angezeigt wird (im unteren Bereich des Fensters) ParameterView.281=In den Systemtray minimieren ParameterView.282=Erlaubt, das Hauptfenster bei Minimierung nur mehr im Systemtray und nicht mehr in der Taskbar anzuzeigen Main.21=Bestätigung Main.22=MPlayer wird geprüft/heruntergeladen Player.0=Warte auf Audio-Ressource (in Verwendung) Device.25=] aktualisiert in Device.27= neue Dateien Device.31=Sync. [ Device.33=Synchronisation fertig in Device.35= erzeugte Dateien ( Device.36= MB) Device.41=Sync. [ Device.42=] Kopiere [ Device.43= unlesbare tags Device.44=Gehe in Device.45=Kopiere [ Device.46=Konvertiere [ Device.47=] nach [ FIFO.4=). Möchten Sie es aktivieren ? FIFO.10=Spiele jetzt: FIFO.13= Kbps FIFO.14=Spiele Web Radio: HistoryItem.0=dd.MM.yy HH:mm DeviceWizard.0=Quellen Konfiguration DeviceWizard.1=Art der Quelle(*): DeviceWizard.2=Name der Quelle(*): DeviceWizard.3=Ort der Quelle(*): DeviceWizard.7=Sofort eine Aktualisierung durchführen DeviceWizard.8=Beim Starten immer aktivieren DeviceWizard.10=Synchronisiert mit: DeviceWizard.11=Unidirektionale Synchronisation DeviceWizard.12=Neue Titel aus der Synchronisations-Quelle werden in diese neue Quelle übernommen. Die Synchronisations-Quelle wird nicht verändert. DeviceWizard.13=Bidirektionale Synchronisation DeviceWizard.14=Alle neuen Titel werden in die jeweils andere Quelle übernommen. DeviceWizard.43=Bitte wählen Sie ein Verzeichnis DeviceWizard.44=Quelle erstellt DeviceWizard.45=Bitte geben Sie der Quelle einen Namen. Z.B.: CD A, Laptop... DeviceWizard.46=Bitte geben Sie den Ort der Quelle an. Z.B.: d:\music unter Windows, /home/foo/music unter Unix DeviceWizard.48=Wählen Sie das aus, wenn sofort eine Aktualisierung der Quelle durchgeführt werden soll (empfohlen)

    Bitte beachten Sie: Diese Operation kann bei umfangreichen Quellen etwas länger dauern. DeviceWizard.49=Wählen Sie das aus, wenn die Quelle nach dem Start automatisch aktiviert werden soll

    Dies macht vor allem für Verzeichnisse auf der lokalen Festplatte Sinn, bei CDs sollte man es eher vermeiden. DeviceWizard.50=Geben Sie ein Datei-Aktualisierungsintervall in Minuten an (0 = keine Aktualisierung, 0.5 min ist der kleinste mögliche Wert) DeviceWizard.51=Wählen Sie das aus, wenn Sie diese Quelle mit einer anderen synchronisieren möchten DeviceWizard.52=Wählen Sie eine Synchronisations-Quelle DeviceWizard.53=Quelle aktualisieren alle #limited string size DeviceWizard.54=Min DeviceWizard.55=Falscher Wert: Das Intervall für die Aktualisieren kann nur 0 oder eine Nummer größer oder gleich 0,5 sein. JajukJMenuBar.0=Datei JajukJMenuBar.1=Datei öffnen JajukJMenuBar.3=Beenden JajukJMenuBar.5=Eigenschaften JajukJMenuBar.6=Neue Eigenschaft JajukJMenuBar.7=Eigenschaft löschen JajukJMenuBar.8=Fenster JajukJMenuBar.9=Modi JajukJMenuBar.10=Wiederholen JajukJMenuBar.11=Mischen JajukJMenuBar.12=Fortsetzen JajukJMenuBar.13=Anspielen JajukJMenuBar.14=Hilfe JajukJMenuBar.15=Inhalt der Hilfe JajukJMenuBar.16=Über Jajuk JajukJMenuBar.17=Standard Fensterpositionen wiederherstellen (aktuelle Ansicht) JajukJMenuBar.18=Quellenassistent JajukJMenuBar.19=Problem oder Verbesserungsvorschläge melden JajukJMenuBar.20=Tipp des Tages JajukJMenuBar.21=Konfiguration JajukJMenuBar.22=Einstellungen JajukJMenuBar.23=Debug-Infos anzeigen JajukJMenuBar.24=Nur verfügbare Titel anzeigen JajukJMenuBar.25=Ansicht anzeigen JajukJMenuBar.26=Standard Fensterpositionen wiederherstellen (alle Ansichten) JajukJMenuBar.27=Jajuk Updates suchen JajukJMenuBar.28=Tools JajukJMenuBar.29=Smart JajukJMenuBar.30=Alles wiederholen JajukJMenuBar.31=Karaoke # next two lines are only used in development/test mode, translation is therefore optional JajukJMenuBar.32=Ein vollständige Garbage-Collection durchführen (nur im Testmodus) JajukJMenuBar.33=Die Kollektion jetzt speichern (nur im Testmodus) PlaylistFileItem.1=Neuheiten PlaylistFileItem.2=Neue Playlist PlaylistFileItem.3=Bookmarks PlaylistFileItem.4=Best Of PlaylistFileItem.5=Wiedergabeliste JajukFileChooser.0=Dateiauswahl SearchBox.0=Eine Suche in Titeln, Artisten, Verzeichnissen, ... durchführen CommandJPanel.0=Abspiel-Historie ansehen CommandJPanel.1=[Strg-t] Titel wiederholen: aktuellen Titel in einer Schleife spielen CommandJPanel.2=[Strg-h] Wiedergabeliste mischen: Titel in zufälliger Reihenfolge spielen CommandJPanel.3=Wiedergabeliste fortsetzen: Setzt am Ende mit nächstem Titel fort CommandJPanel.4=Titel anspielen: Spielt von jedem Titel nur einen Teil. Offset und Länge können in der Konfigurations-Ansicht eingestellt werden. CommandJPanel.5=Eine gemischte Auswahl der gesamten Kollektion spielen CommandJPanel.6=Ihre eigenen Lieblingstitel spielen CommandJPanel.8=[F9] Den vorherigen Titel der aktuellen Auswahl spielen
    Rechter Mausklick spielt das aktuelle Stück nocheinmal
    Shift+Klick startet das vorherige Album CommandJPanel.9=[F10] Den nächsten Titel der aktuellen Auswahl spielen
    Shift+Klick startet nächstes Album CommandJPanel.10=[AltGr F9] Schnelles Zurückspielen im aktuellen Titel
    Shift+Klick um aktuellen Titel neu zu starten CommandJPanel.13=[AltGr F10] Schnelles vorspielen im aktuellen Titel CommandJPanel.14=Lautstärke CommandJPanel.15=Hier klicken, um das Format der Zeitanzeige zu verändern CommandJPanel.16=DJ Auswahl starten CommandJPanel.17=DJs verwalten CommandJPanel.18=Ausgewählten DJ starten CommandJPanel.19=Umgebungen verwalten CommandJPanel.20=Titel für Titel CommandJPanel.21=Album für Album mischen CommandJPanel.22=Album für Album CommandJPanel.23=Klicken um Suche zurückzusetzen CommandJPanel.24=Web Radios konfigurieren CommandJPanel.25=Radio einschalten CommandJPanel.26=Wiedergabeliste wiederholen CommandJPanel.27=Karaoke, Gesang von Track entfernen (findet erst beim nächsten abgespielten Track Anwendung) InformationJPanel.5=Restliche Laufzeit der Wiedergabeliste [Anzahl an verbleibender Titel] InformationJPanel.6=Bitrate des Titels InformationJPanel.7=Fortschritt des aktuellen Titels #song name BY artist ON album name InformationJPanel.8=%title von %artist aus dem Album "%album" InformationJPanel.9= AbstractPlaylistEditorView.0=Titel AbstractPlaylistEditorView.1=Ort AbstractPlaylistEditorView.2=Diese Playlist spielen AbstractPlaylistEditorView.3=Playlist speichern AbstractPlaylistEditorView.4=Einen Titel zu dieser Playlist hinzufügen AbstractPlaylistEditorView.5=Titel entfernen AbstractPlaylistEditorView.6=Titel nach vorne schieben AbstractPlaylistEditorView.7=Titel nach hinten schieben AbstractPlaylistEditorView.9=Diese Playlist löschen AbstractPlaylistEditorView.10=Einen zufälligen Titel zu dieser Playlist hinzufügen AbstractPlaylistEditorView.15=Playlists AbstractPlaylistEditorView.17=Sie sind dabei, die folgenden Playlist-Dateien zu speichern: AbstractPlaylistEditorView.18=Titel in Wiedergabeliste AbstractPlaylistEditorView.19=Wiederholter Titel AbstractPlaylistEditorView.20=Geplanter Titel AbstractPlaylistEditorView.21=Playlist Titel AbstractPlaylistEditorView.22=Playlist gespeichert AbstractPlaylistEditorView.27=Party zusammenstellen AbstractPlaylistEditorView.28=Verzeichnis wurde erzeugt in AbstractPlaylistEditorView.29=Aktueller Titel StatView.0=Andere StatView.1=Verteilung der Musikrichtungen StatView.2=Keine Daten verfügbar StatView.3=Andere StatView.4=Größe pro Quelle (GB) StatView.5=Keine Daten verfügbar StatView.7=Größe der Kollektion pro Monat StatView.8=Monate StatView.9=Größe (GB) StatView.10=Keine Daten verfügbar StatView.12=Gesamtzahl der Titel pro Monat StatView.13=Monate StatView.14=Anzahl Titel StatView.15=Keine Daten verfügbar StatView.16=Statistiken StatView.24=vorher CDScanView.0=Bezeichnung der CD: CDScanView.1=Geben Sie die Bezeichnung der CD ein. Z.B.: CD1, ROCK... CDScanView.2=Geben Sie die Bezeichnung der CD ein. Z.B.: CD1, ROCK... CDScanView.3=Ort: CDScanView.4=Der Ort wo die CD gefunden werden kann. Z.B.: '/cdrom' unter Unix, 'e:' unter MS Windows... CDScanView.5=Der Ort wo die CD gefunden werden kann. Z.B.: '/cdrom' unter Unix, 'e:' unter MS Windows... CDScanView.6=Scannen CDScanView.12=CD Scanner CDScanView.18=Durchsucht die CD und fügt alle Musikdateien zur Kollektion hinzu CDScanView.19=Wählen Sie einen Ort aus AbstractTreeView.0=Alles zusammenfalten TracksTreeView.0=Titel Baum TracksTreeView.27=Kollektion TracksTreeView.31= Titel TracksTreeView.33=Bericht erstellen TracksTreeView.34=Tags online holen TracksTreeView.35=Discovery Datum TracksTreeView.36=weniger als eine Woche TracksTreeView.37=weniger als ein Monat TracksTreeView.38=weniger als sechs Monate TracksTreeView.39=älter TracksTreeView.40=weniger als ein Jahr TracksTreeView.41=weniger als zwei Jahre TracksTreeView.42=weniger als fünf Jahre TracksTreeView.43=weniger als zehn Jahre TracksTreeView.44=weniger als drei Monate TracksTreeView.45=Jahr CoverView.2=Dieses Cover permanent löschen CoverView.3=Cover CoverView.4=Vorheriges Bild (von der Festplatte und aus dem Web, wenn automatische Covers aktiviert sind) CoverView.5=Nächstes Bild (von der Festplatte und aus dem Web, wenn automatische Covers aktiviert sind) CoverView.6=

    Cover unter Originalnamen speichern

    Mit Strg: Cover speichern unter...

    CoverView.8=Dieses Cover als Default für dieses Album verwenden CoverView.9=Covers CoverView.10=Cover speichern unter CoverView.11=Cover gespeichert CoverView.12=Album CoverView.13=Titel AnimationView.0=Animation FilesTreeView.0=Dateibaum FilesTreeView.3=Kopieren FilesTreeView.4=Ausschneiden FilesTreeView.5=Einfügen FilesTreeView.7=Löschen FilesTreeView.14=Desynchronisieren FilesTreeView.15=Erneut synchronisieren FilesTreeView.16=Playlist erstellen FilesTreeView.17=Kopieren FilesTreeView.18=Ausschneiden FilesTreeView.28=Aktivieren FilesTreeView.29=Deaktivieren FilesTreeView.30=Aktualisieren erzwingen FilesTreeView.31=Synchronisieren FilesTreeView.32=Testen FilesTreeView.33=Playlists erstellen FilesTreeView.40=Kopieren FilesTreeView.41=Ausschneiden FilesTreeView.42=Einfügen FilesTreeView.47=Kollektion FilesTreeView.52= Dateien: FilesTreeView.53= GB FilesTreeView.54= MB FilesTreeView.55=Konfigurieren FilesTreeView.59=Wollen Sie eine schnelle oder eine gründliche (Tags neu lesen) Aktualisierung durchführen? FilesTreeView.60=Schnell FilesTreeView.61=Gründlich FilesTreeView.62=Dateien organisieren TracksTableView.0=Titel Tabelle TracksTableView.7=Abspielen TracksTableView.8=Hinten anstellen TracksTableView.9=Gemischt spielen TracksTableView.10=Wiederholt spielen TracksTableView.11=Album spielen TracksTableView.12=Artist spielen TracksTableView.14=Einstellungen TracksTableView.15=Zu Favoriten hinzufügen TracksTableView.16=Als Nächstes abspielen AbstractTableView.0=Filter: AbstractTableView.1=Zu filternde Eigenschaft AbstractTableView.3=Wert des Filters (wonach gefiltert wird) AbstractTableView.4=Filter anwenden AbstractTableView.5=Filter löschen AbstractTableView.6=Einen erweiterten Filter anwenden AbstractTableView.7=enthält: AbstractTableView.8=Irgendetwas AbstractTableView.10=(Nicht verfügbar) AbstractTableView.11=Tabelle editierbar machen AboutView.7=Über Jajuk AboutView.8=Lizenz AboutView.9=System AboutView.10=Über Jajuk AboutView.11=Copyright 2003-2011
    Jajuk team" PhysicalPlaylistRepositoryView.0=Spielen PhysicalPlaylistRepositoryView.1=Editieren PhysicalPlaylistRepositoryView.2=Speichern unter PhysicalPlaylistRepositoryView.3=Löschen PhysicalPlaylistRepositoryView.4=Eigenschaften PhysicalPlaylistRepositoryView.6=Playlists PhysicalPlaylistRepositoryView.8=Smart PhysicalPlaylistRepositoryView.9=Aktuelle Wiedergabeliste PhysicalPlaylistRepositoryView.10=Aktuelle Wiedergabeliste: verwenden Sie Drag and Drop um Elemente abzuspielen PhysicalPlaylistRepositoryView.11=Neu PhysicalPlaylistRepositoryView.12=Neue Playlist: fügen Sie mit Drag and Drop Dateien hinzu PhysicalPlaylistRepositoryView.13=Bookmarks PhysicalPlaylistRepositoryView.14=Bookmark Playlist: verwenden Sie Drag and Drop um Titel hinzuzufügen PhysicalPlaylistRepositoryView.15=Best of PhysicalPlaylistRepositoryView.16=Best of Playlist: enthält Ihre Lieblingstitel PhysicalPlaylistRepositoryView.17=Neuheiten PhysicalPlaylistRepositoryView.18=Neuheiten Playlist: enthält die neuesten Titel PhysicalPlaylistRepositoryView.19=Party zusammenstellen FilesTableView.0=Dateien Tabelle FilesTableView.15=Verzeichnis spielen #Dev: do not use ID = 16, next label is FilesTableView.17 DeviceView.0=Quelle hinzufügen DeviceView.1=Quelle entfernen (es wird nichts physikalisch gelöscht) DeviceView.2=Eigenschaften der ausgewählten Quelle DeviceView.3=Ausgewählte Quelle aktivieren DeviceView.4=Ausgewählte Quelle deaktivieren DeviceView.5=Testen ob die ausgewählte Quelle verfügbar ist DeviceView.6=Ausgewählte Quelle jetzt aktualisieren DeviceView.7=Ausgewählte Quelle synchronisieren DeviceView.8=Aktivieren DeviceView.9=Deaktivieren DeviceView.10=Verfügbarkeit testen DeviceView.11=Aktualisieren erzwingen DeviceView.12=Synchronisieren DeviceView.13=Quelle entfernen DeviceView.14=Konfigurieren DeviceView.17=Neu DeviceView.18=Quelle hinzufügen DeviceView.21=Die Quelle ist verfügbar DeviceView.22=Die Quelle kann nicht erreicht werden DeviceView.23=Quellen JajukWindow.1=Ton an JajukWindow.2=Ton aus JajukWindow.3=Jajuk JajukWindow.4=Beenden JajukWindow.5=Über Jajuk JajukWindow.6=Durchgemischt spielen JajukWindow.7=Spiele die besten Titel JajukWindow.10=Pause JajukWindow.12=Spielen JajukWindow.13=Vorheriges JajukWindow.14=Nächstes JajukWindow.15=Neue Titel spielen JajukWindow.16=Album fertigspielen JajukWindow.17=Jajuk: Advanced Jukebox JajukWindow.18=Bereit zum Abspielen JajukWindow.19=[F8] Ton einn/aus
    Mit dem Mausrad kann die Lautstärke verändert werden JajukWindow.21=Beenden JajukWindow.22=Über Jajuk JajukWindow.23=Spiele durchgemischte Titel der gesamten Kollektion JajukWindow.24=Spiele die besten Titel der gesamten Kollektion JajukWindow.26=[Ctrl-p] Pause/Spielen JajukWindow.27=[Ctrl-s] Stopp JajukWindow.31=Neue Titel der gesamten Kollektion spielen JajukWindow.32=das aktuelle Album weiterspielen JajukWindow.33=[Ctrl-Auf/Ab] Lautstärke JajukWindow.34=Position JajukWindow.35=Spiele: JajukWindow.36=Aktuelle Umgebung: JajukWindow.37=Keine Umgebung aktiv #Do not use JajukWindow.38, next is JajukWindow.39 JajukWindow.39=Aktueller Titel JajukWindow.40=Extra-Tags Konfigurieren JajukWindow.41=Öffnet ein Fenster zum Einstellen der aktivierten Tags JajukDonate.1=Spenden JajukDonate.2=Das Jajuk-Projekt verursacht Kosten. Erfahren Sie mehr auf unsere Budgetseite. JajukDonate.3=Budget JajukDonate.4=Wenn Sie Jajuk unterstützen wollen, würden wir uns über eine Spende sehr freuen. ActiveTagsWizard.1=Verfügbare Tags ActiveTagsWizard.2=Aktivierte Tags ActiveTagsWizard.3=Fügen sie die Extra-Tags hinzu, die Jajuk anzeigen soll. Die Daten werden direkt aus der Muiskdatei ausgelesen. Wenn sie einen neuen Tag hinzufügen, wird ihre gesamte Kollektion gescannt, was einige Minuten dauern kann. SimpleDeviceWizard.0=Schnell eine Quelle anlegen FirstTimeWizard.0=Schnellstart FirstTimeWizard.1=Willkommen! Dieser Assistent wird Ihnen beim Erstellen Ihrer Kollektion helfen. FirstTimeWizard.2=Wählen Sie hier Ihr Musikverzeichnis FirstTimeWizard.4=Hilfe jetzt anzeigen FirstTimeWizard.5=Bitte wählen Sie ein Verzeichnis FirstTimeWizard.6=Erweiterte Einstellungen FirstTimeWizard.7=Jajuk Arbeitsverzeichnis: FirstTimeWizard.8=Gewähltes Verzeichnis: FirstTimeWizard.9=Keines HelpView.2=Hilfe DownloadManager.0=Jajuk benötigt ihr HTTP proxy Passwort um Covers zu laden
    Wenn Sie keine Covers laden möchten, ändern Sie bitte die Einstellungen in der Konfiguration
    Wenn Sie keinen Proxy verwenden möchten, ändern sie die Einstellung im Punkt Netwerk in der Konfiguration. DownloadManager.1=Passwort wird benötigt PropertiesWizard.0=Element Eigenschaften PropertiesWizard.1=Eigenschaft PropertiesWizard.2=Wert PropertiesWizard.3=Editierbar? PropertiesWizard.4=Link PropertiesWizard.6=Auswahl PropertiesWizard.7=Typ PropertiesWizard.8=Eigenschaft erfolgreich aktualisiert PropertiesWizard.9=Keine editierbare Eigenschaft für diese Auswahl PropertiesWizard.10=Eigenschaften wurden gesetzt PropertiesWizard.11=Schreibe tag nach: PropertiesWizard.12=Verknüpfung zu Einstellungsdetails des Elements NewPropertyWizard.0=Eigenschaft anlegen NewPropertyWizard.3=(*)Typ NewPropertyWizard.4=Format NewPropertyWizard.5=Standardwert CustomPropertyWizard.0=(*)Element CustomPropertyWizard.1=(*)Name der Eigenschaft RemovePropertyWizard.0=Eigenschaft entfernen QualityFeedbackWizard.20=Ein Browser-Fenster wird geöffnet, in dem Sie ein Jajuk Ticket anlegen können. Wir haben anonymisierte Debug-Informationen in Ihre Zwischenablage kopiert - wenn Sie uns einen Bug melden, fügen Sie diese Debug-Informationen bitte Ihrem neuen Ticket hinzu (so ist es für uns wesentlich einfacher Fehler aufzuspüren und zu beheben). IncRateAction.0=Bewertung des aktuellen Titels erhöhen SplashScreen.0=Initiale Checks SplashScreen.1=Lade Kollektion SplashScreen.2=Starte Music Engine SplashScreen.3=Starte Benutzeroberfläche CatalogView.0=Alben Katalog #CatalogView.2 -> darf nicht viel länger als die englische Version sein! CatalogView.2=Alben ohne Cover anzeigen CatalogView.3=Miniaturbilder neu erzeugen CatalogView.4=Miniaturbild-Größe: CatalogView.5=Erstellte Miniaturbild für: CatalogView.7=Cover auswählen CatalogView.8=Kein Cover gefunden CatalogView.9=Vorheriges CatalogView.10=Nächstes CatalogView.11=Seite: CatalogView.12=Vorherige Vorschauseite anzeigen CatalogView.13=Nächste Vorschauseite anzeigen CatalogView.14=Vorschauseite auswählen CatalogView.15=Vorschaugröße: CatalogView.16=Alben CatalogView.17=/Seite CatalogView.18=Cover Auswahl CatalogView.19=Vorschauen neu erzeugen CatalogView.20=Details anzeigen CatalogView.21=Alle Alben anzeigen CatalogView.22=Alben mit Cover anzeigen WikipediaView.0=Wikipedia WikipediaView.1=Sprachauswahl: WikipediaView.3=Keine Ergebnisse gefunden WikipediaView.5=Artist Name suchen WikipediaView.6=Album Name suchen WikipediaView.7=Titel Name suchen WikipediaView.8=Lade WikipediaView.9=Information konnte nicht von Wikipedia geladen werden WikipediaView.10=Unbekannter Artist, kann Information nicht anzeigen TipOfTheDayView.0=Tipp des Tages TipOfTheDayView.1=Haben Sie gewusst... ? TipOfTheDayView.2=Beim Start anzeigen? CDDBWizard.0=Akzeptieren CDDBWizard.1=Dateiname CDDBWizard.2=Aktueller Titelname CDDBWizard.3=Aktueller Albumname CDDBWizard.4=Vorgeschlagener Titelname CDDBWizard.5=Vorgeschlagener Albumname: CDDBWizard.6=Fertig! Habe CDDBWizard.7=mögliche Treffer gefunden CDDBWizard.12=Keine Treffer gefunden! CDDBWizard.14=Dieses Verzeichnis enthält keine Datei CDDBWizard.16=Genre: CDDBWizard.17=Exakten Treffer gefunden! CDDBWizard.18=Treffer CDDBWizard.19=Tags Online holen RefactorWizard.0=Datei verschoben: DigitalDJWizard.0=Welche Art von DJ möchten Sie erstellen? DigitalDJWizard.1=Übergänge festlegen (ROCK -> POP) DigitalDJWizard.2=Genre Anteile festlegen (20% JAZZ, 30% ROCK) DigitalDJWizard.3=Umgebungen festlegen (Soft, Party, ...) DigitalDJWizard.4=Digital DJ Wizard DigitalDJWizard.5=Allgemeine DJ Konfiguration DigitalDJWizard.6=DJ Name(*): DigitalDJWizard.8=Minimale Anzahl Sterne: DigitalDJWizard.9=Überblendung (Sekunden): DigitalDJWizard.10=Titel nur einmal spielen DigitalDJWizard.11=Entfernen DigitalDJWizard.12=Von Genres DigitalDJWizard.13=Zu Genres DigitalDJWizard.14=Genres-Auswahl (Mehrfachauswahl erlaubt) DigitalDJWizard.15=Anzahl an Titeln DigitalDJWizard.16=Welche Aktion möchten Sie ausführen? DigitalDJWizard.17=Einen neuen DJ erstellen DigitalDJWizard.18=Einen bestehenden DJ editieren DigitalDJWizard.19=Einen DJ löschen DigitalDJWizard.20=Neuer DJ mit Genre Übergängen #limited string size DigitalDJWizard.21=Entfernen #limited string size DigitalDJWizard.22=Von Genre #limited string size DigitalDJWizard.23=Nach Genre #limited string size DigitalDJWizard.24=Zahl DigitalDJWizard.26=Bitte definieren Sie zumindest einen Übergang #limited string size DigitalDJWizard.27=Genre Auswahl #limited string size DigitalDJWizard.28=% DigitalDJWizard.29=Neuer DJ mit Genre Anteilen DigitalDJWizard.30=Bitte definieren Sie zumindest einen Anteil DigitalDJWizard.31=Neuer DJ mit Umgebung DigitalDJWizard.32=Neu DigitalDJWizard.33=Eine neue Umgebung erstellen DigitalDJWizard.34=Löschen DigitalDJWizard.35=Ausgewählte Umgebungen löschen DigitalDJWizard.36=Name der Umgebung DigitalDJWizard.37=Name DigitalDJWizard.38=Bitte erstellen Sie zumindest eine Umgebung DigitalDJWizard.39=Bitte legen Sie einen Namen fest und wählen Sie Genres aus DigitalDJWizard.40=Bitte wählen Sie einen DJ DigitalDJWizard.41=Bitte legen Sie einen DJ Namen fest DigitalDJWizard.42=Es gibt bereits einen DJ mit diesem Namen DigitalDJWizard.43=Ändern eines DJs DigitalDJWizard.44=Wählen Sie einen DJ aus DigitalDJWizard.45=Auswahl einer Aktion DigitalDJWizard.46=DJ Art DigitalDJWizard.47=Bitte wählen oder erstellen Sie eine Umgebung DigitalDJWizard.48=Allgemeine Attribute DigitalDJWizard.49=Bitte füllen Sie die allgemeinen DJ Attribute aus DigitalDJWizard.50=Bitte legen Sie Verhältnisse fest DigitalDJWizard.51=DJ Löschen DigitalDJWizard.52=Bitte legen Sie Übergänge fest DigitalDJWizard.53=Minimale Anzahl an Bewertungs-Sternen der Titel (1: alle Titel) DigitalDJWizard.54=Dauer der Überblendung zwischen Titeln DigitalDJWizard.55=Wenn aktiviert, wird der DJ jeden Titel nur einmal in seine Auswahl aufnehmen DigitalDJWizard.56=Umgebungs-Wizard DigitalDJWizard.57=Umgebungen verwalten DigitalDJWizard.58=Umgebung auswählen: DigitalDJWizard.59=Die Summe aller Anteile sollte <= 100% sein DigitalDJWizard.60=Vorhandener Umgebungs-Name DigitalDJWizard.61=DJ löschen #limited string size DigitalDJWizard.62=Standard DigitalDJWizard.63=Vordefinierte Standardumgebungen einfügen DigitalDJWizard.64=Irgendeine DigitalDJWizard.66=Standard Umgebungs-Auswahl (eine Umgebung ist eine Sammlung von Genres, siehe Handbuch) DigitalDJWizard.67=Beschränke Anzahl geplanter Titel DigitalDJWizard.68=Maximale Anzahl geplanter Titel PreparePartyWizard.1=Party zusammenstellen PreparePartyWizard.2=Musikzusammenstellung auswählen PreparePartyWizard.3=Legen Sie zuerst fest, wie die Musikstücke ausgewählt werden sollen. PreparePartyWizard.4=Einschränkungen festlegen PreparePartyWizard.5=Bitte legen Sie fest, welche Einschränkungen beim Zusammenstellen der Titel gelten sollen. PreparePartyWizard.6=DJs PreparePartyWizard.7=Umgebungen PreparePartyWizard.8=Playlisten PreparePartyWizard.9=Zufällige Titel PreparePartyWizard.10=Max. Songs PreparePartyWizard.11=Legt fest, wie viele Title maximal ausgewählt werden. PreparePartyWizard.12=Max. Größe (MB) PreparePartyWizard.13=Legt fest, wie viel Speicherplatz die ausgewählten Titel beanspruchen dürfen PreparePartyWizard.14=Max. Länge (Minuten) PreparePartyWizard.15=Legt fest, wie lange die Abspieldauer der ausgewählten Titel maximal sein darf. PreparePartyWizard.16=Typ einschränken PreparePartyWizard.17=Erlaubt, nur einen bestimmten Dateityp zuzulassen. Dies ist nützlich wenn ein Abspielgerät nur wenige Dateiformate unterstützt. PreparePartyWizard.18=Ziel auswählen PreparePartyWizard.19=Wählen Sie das Verzeichnis, in das die Titel kopiert werden. Es wird darin ein neues Unterverzeichnis erstellt. PreparePartyWizard.20=Bitte wählen Sie das Verzeichnis aus PreparePartyWizard.21=Gewähltes Verzeichnis: PreparePartyWizard.22=Bitte wählen Sie das Ziel-Verzeichnis aus PreparePartyWizard.23=Dateien wurden kopiert in PreparePartyWizard.24=Best Of PreparePartyWizard.25=Neuheiten PreparePartyWizard.26=Dateinamen normalisieren PreparePartyWizard.27=Dateinamen normalisieren um Probleme mit unterschiedlichen Betriebssystemen und Zeichenkodierungen zu vermeiden PreparePartyWizard.31=Zielverzeichnis: PreparePartyWizard.32=Warteschlange PreparePartyWizard.33=Lesezeichen PreparePartyWizard.34=Versuche, andere Dateitypen zu konvertieren PreparePartyWizard.35=Verwendet das Tool 'pacpl - Perl Audio Converter' um Musikdateien wenn nötig zu konvertieren. PreparePartyWizard.36= Datei(en) konnten nicht in das ausgewählte Format umgewandelt werden. PreparePartyWizard.37=(erfordert PACPL, siehe Perl Audio Converter) PreparePartyWizard.38=Konvertierungseinstellungen PreparePartyWizard.39=Bitte legen Sie fest, wie Perl Audio Converter aufgerufen wird
    Unter Linux ist das normalerweise "pacpl", manchmal "perl <Install-Verzeichnis>/pacpl"
    Unter Windows üblicherweise "perl <Install-Verzeichnis>\pacpl" PreparePartyWizard.40=Einstellungen... #--- Tips of day --- # Left genres like in english version - difficult to translate them (can maybe be done later...) Ambience.0=Rock/Pop Ambience.1=Rap Ambience.2=HardRock Ambience.3=Techno Ambience.4=Electro Ambience.5=Classical Ambience.6=Soft Ambience.7=Party Ambience.8=Jazz Ambience.9=World Ambience.10=Others Ambience.11=Folk/Oldies Ambience.12=Inde Ambience.13=Latin DebugLogAction.0=Debug-Info Auflistung DebugLogAction.1=Aktualisieren CopyClipboardAction.0=Adresse in Zwischenablage kopieren LaunchInBrowserAction.0=Adresse im Standard-Browser öffnen ReportAction.0=Bericht erfolgreich erstellt ReportAction.1=Jajuk Musik Bericht ReportAction.2=Bitte auf die Umwelt achten und nur ausdrucken wenn unbedingt nötig ReportAction.3=Liste der Alben ReportAction.4=Titel pro Album ReportAction.5=Liste der Artisten ReportAction.6=Alben pro Artist ReportAction.7=Liste der Musikrichtungen ReportAction.8=Alben pro Musikrichtung ReportAction.9=Artisten/Alben pro Musikrichtung ReportAction.10=Liste der Verzeichnisse ReportAction.11=Dateien pro Verzeichnis ReportAction.12=Dateiname ReportAction.13=Titelname ReportAction.14=Liste der Quellen ReportAction.15=Verzeichnisse pro Quelle ReportAction.16=Verzeichnisse/Dateien ReportAction.17=Kollektion ReportAction.18=Artisten/Alben/Titel pro Musikrichtung ReportAction.19=Springe zu: ActionMove.0=Einfügen ActionRefresh.0=Aktualisieren erzwingen ActionRefresh.1=Aktualisiere Verzeichnis RenameAction.0=Umbenennen RenameAction.1=Bitte geben Sie den neuen Namen für diese Datei ein: RenameAction.2=Bitte geben Sie den neuen Namen für dieses Verzeichnis ein: NewFolderAction.0=Neues Verzeichnis NewFolderAction.1=Bitte geben Sie den Namen für das neue Verzeichnis ein: NewFolderAction.2=Das Verzeichnis mit diesem Namen existiert bereits. LyricsView.0=Lyrics LyricsView.1=Kein Liedtext vorhanden, bitte in den Einstellungen den Zugang zum Internet aktivieren LyricsView.2=Liedtext editieren LyricsView.3=Liedtext nicht mehr editieren LyricsView.4=Liedtext speichern LyricsView.5=Liedtext löschen ActionDelete.0=Dateien wurden gelöscht ActionDelete.1=Verzeichnisse wurden gelöscht FindDuplicateTracksAction.0=Keine doppelten Titel gefunden. FindDuplicateTracksAction.1=Doppelte Titel gefunden FindDuplicateTracksAction.2=Doppelte Titel finden FindDuplicateTracksAction.3=Liste der gefundenen doppelten Titel FindDuplicateTracksAction.4=Alle doppelten Titel auswählen RefreshDialog.0=Bereite Quellenaktualisierung vor... RefreshDialog.1=Aktualisiere Quelle RefreshDialog.2=Aktualisiere Quelle: RefreshDialog.3=Räume alte Dateien auf RadioWizard.0=Bitte wählen oder erstellen Sie ein Web Radio RadioWizard.1=Web Radios verwalten RadioWizard.2=Neu RadioWizard.3=Löschen RadioWizard.4=Standard RadioWizard.5=Ein Web Radio mit diesem Namen ist bereits vorhanden RadioWizard.6=Web Radio Name RadioWizard.7=Web Radio Assistent RadioWizard.8=URL RadioWizard.9=Name RadioWizard.10=Falsche URL RadioWizard.11=Name und URL sind zwingend nötig UpdateManager.0=Ein neues Jajuk Release ( UpdateManager.1=) wurde gefunden, Sie können es hier herunterladen http://jajuk.info UpdateManager.2=Kein neues Release gefunden SuggestionView.0=Vorschläge SuggestionView.1=Bevorzugte SuggestionView.2=Neueste SuggestionView.3=Andere Alben SuggestionView.4=Ähnliche Artisten SuggestionView.5=Selten gehört SuggestionView.7=Kann nichts anzeigen

    Last.FM Informationen werden angezeigt wenn:
    • Ein Titel gespielt wird
    • Der Artist des gespielten Titels bekannst ist (Tag muss korrekt sein)
    • Die Option "Last.FM Informationen laden" in der Konfigurations-Ansicht unter den Einstellungen bei Last.FM aktiviert ist
    • Die Option "Keine Verbindung mit dem Internet herstellen" in der Konfiguration im Tab "Netzwerk" ist nicht ausgewählt.
    • Eine Netzwerkverbindung besteht
    AbstractThumbnail.0=LAST.FM Webpage öffnen AlbumsTableView.0=Albumliste AlbumsTableView.1=Anzahl der Titel AlarmClock.0=Alarm setzen #Next value : 6 AlarmDialog.0=Zeit (HH24:MM:SS) AlarmDialog.1=Stunde AlarmDialog.2=Minuten AlarmDialog.3=Sekunden AlarmDialog.4=Alarmaktion AlarmDialog.5=Alarmaktion wählen #Next value : 11 ShowPropertiesAction.0=Element-Eigenschaften anzeigen QueueView.1=Wiedergabeliste leeren QueueView.2=Scrolle automatisch zum aktuell gespielten Track JajukSlimWindow.0=Schlankes Jajuk anzeigen/verstecken JajukFullscreen.0=aktiviere/deaktiviere Vollbild-Player BanSelectionAction.0=Ausschließen BanSelectionAction.1=Diesen Titel ausschließen, dadurch wird er nicht mehr automatisch ausgewählt UnBanSelectionAction.0=Entsperren UnBanSelectionAction.1=Titel entsperren so dass sie wieder vorgeschlagen werden OpenExplorerAction.0=Mit explorer öffnen OpenExplorerAction.1=Verzeichnis mit externen Explorer öffnen Preference.0=Eine persönliche Vorliebe für den Titel setzen
    Diese wird bei der endgültigen Bewertung in betracht gezogen Preference.1=Müll Preference.2=Schlecht Preference.3=Mittelmässig Preference.4=Gut Preference.5=Sehr gut Preference.6=Fantastisch Preference.7=Vorgaben... Preference.8=Geht so ArtistView.0=Künstler Notificator.NONE=Keiner Notificator.TOAST=Toast Notificator.BALLOON=Ballon Notificator.track_change.webradio_title=Internetradio gestartet: Notificator.track_change.track_title=Titel gestartet: SyncTreeTableAction.0=Baumansicht und Tabellenansicht synchronisieren SyncTreeTableAction.1=Baumansichten und Tabellenansichten synchronisieren
    Eine Auswahl in der Baumansicht wählt das gleiche Element in der Tabellenansicht aus.
    Eine Auswahl in der Tabellenansicht zweigt das gleiche Element in der Baumansicht an. # TipOfTheDay are automatically generated with the Jajuk Manual. # To change tip of the day use page: http://jajuk.info/index.php/Tip_of_the_day TipOfTheDay.0=Tip 0: Sie können mit einem schnellen [Shift]+Klick auf die Zurückspielen Schaltfläche den gerade gespielten Titel neu starten. TipOfTheDay.1=Tip 1: Sie können mit einem [Ctrl]+Klick auf die Voriges Schaltfläche zum ersten Titel des Albums zurückspringen. TipOfTheDay.2=Tip 2: Sie können einen zufälligen Titel zu Ihrer Playlist hinzufügen, indem Sie die Schaltfläche mit dem Fragezeichen und dem kleinen Plus drücken. TipOfTheDay.3=Tip 3: Sie können auch online Covers ansehen, wenn Sie über einen Proxy Server auf das Netzwerk zugreifen. Verwenden Sie dazu die Einstellungsmöglichkeiten in der Konfigurations-Ansicht unter Netzwerk. TipOfTheDay.4=Tip 4: Covers können heruntergeladen und gebuffert werden, damit diese schnell zur Verfügung stehen, wenn sie angezeigt werden sollen. Nutzen Sie dazu die Option "Covers vorausladen" in der Konfigurations-Ansicht unter Covers. TipOfTheDay.5=Tip 5: Titel können durch die Option "Nur aktive Quellen anzeigen" ausgeblendet werden. TipOfTheDay.6=Tip 6: Fast alle Funktionen können auch über die Tastatur bedient werden. TipOfTheDay.7=Tip 7: Sie können Titel per Drag and Drop (ziehen mit der Maus) von einer Tabellen- oder Baumansicht direkt in eine Playlist ziehen. TipOfTheDay.8=Tip 8: Man kann Titel kurz Anspielen ohne den ganzen Titel zu hören. Verwenden Sie dazu den Modus "Anspielen". TipOfTheDay.9=Tip 9: Man kann die Art der Überblendung zwischen zwei Titeln verändern. TipOfTheDay.10=Tip 10: Jajuk kann verkleinert gestartet werden, indem Sie rechts unten in der Taskleiste beim Jajuk Symbol die Option "Zeige Jajuk beim Starten" deaktivieren. TipOfTheDay.11=Tip 11: Alle Hauptfunktionen von Jajuk können auch ausschließlich über das Jajuk Taskleistensymbol gesteuert werden (nur Linux & Windows). TipOfTheDay.12=Tip 12: Das Design von Jajuk kann in der Konfigurations-Ansicht unter Optionen geändert werden. TipOfTheDay.13=Tip 13: Das Verhalten bei Doppelklick und Drag and Drop (ziehen mit der Maus) kann in der Konfigurations-Ansicht unter Einstellungen angepasst werden. TipOfTheDay.14=Tip 14: Jajuk spielt "geplante Titel" nach den vom Benutzer gewählten Titeln. TipOfTheDay.15=Tip 15: Die grafische Oberfläche ist veränderbar und Sie können Fenster innerhalb Jajuks verschieben. TipOfTheDay.16=Tip 16: Man kann die Gesamtzahl an Titeln sehen, wenn man den Punkt "Kollektion" im Baum der Datei oder Titel Ansicht anklickt. TipOfTheDay.17=Tip 17: Etiketten (id3 tags) für Verzeichnisse in der Datei oder Titel Ansicht können online abgerufen werden. TipOfTheDay.18=Tip 18: Die Jajuk Abspiel-Historie (Oben-Mitte im Jajuk Fenster) zeigt alle abgespielten Titel. TipOfTheDay.19=Tip 19: Man kann Titel mit der Schnellsuche einfach und schnell finden (Eingabefeld ganz unten im Jajuk Fenster). TipOfTheDay.20=Tip 20: Sie können Fehler und Ihre eigenen Verbesserungsvorschläge und Ideen für Erweiterungen einfach an das Jajuk Team schicken (Hilfe -> Problem oder Verbesserungsvorschläge melden). TipOfTheDay.21=Tip 21: Der Jajuk DJ kann itelligente Playlists erstellen, die von Ihnen festgelegte Regeln befolgen. TipOfTheDay.22=Tip 22: Jajuk lädt Song-Texte aus dem Internet und zeigt diese unter "Lyrics" an. TipOfTheDay.23=Tip 23: Unter "Vorschläge" können Informationen von LAST.FM angezeigt werden. Jajuk kann Ihnen auf diese Art andere Alben der gleichen Gruppe oder ähnliche Artisten vorstellen. TipOfTheDay.24=Tip 24: Sie können unerwünschte Titel von der automatischen Auswahl auschließen, indem sie die Option in der Slimbar oder im Hauptfenster auswählen. TipOfTheDay.25=Tip 25: Sie können nicht aktive Quellen im Menü "Modi" ein- und ausblenden. TipOfTheDay.26=Tip 26: Sie können selbst festlegen, wo Jajuk Ihre Daten speichert (auch externe Laufwerke sind möglich - ideal um Jajuk auf mehreren Computern zu verwenden). Öffnen Sie dazu den Bereich "Erweitert" im Fenster Einstellungen der Konfigurations-Ansicht. TipOfTheDay.27=Tip 27: Sie können jedes Fenster in jede Ansicht einfügen. Öffnen Sie dazu das Menü "Fenster" in der Jajuk Menüleiste. TipOfTheDay.28=Tip 28: Sie können eine Wikipedia-Seite in Ihrem Default-Web-Browser mit folgendem Icon starten Image:launch_16x16.png/ TipOfTheDay.29=Tip 29: Jajuk unterstützt Web Radios Image:webradio_32x32.png TipOfTheDay.31=Tip 30: Jajuk kann mithilfe von D-Bus ferngesteuert werden, falls die aktuelle Platform dies unterstützt (nicht unter Windows). Dies erlaubt die Verwendung von Multimedia Tasten auf der Tastatur. Das Online-Handbuch enthält weitere Hinweise zu diesem Thema. ]]> jajuk-1.9.6.orig/src/main/java/org/jajuk/i18n/jajuk_es.properties0000644000175000017500000015102311720500104024475 0ustar drazzibdrazzib Rating system page). Tus anteriores valoraciones han sido migradas a una escala de 0 a 100 pero es aconsejable resetarlas desde Preference view -> History tab (atención: todas las valoraciones se perderán) #Write confirmation so replies are: yes / no / cancel Confirmation_exit=¿ Quieres salir realmente de Jajuk ? Confirmation_delete=Atención! estás a punto de borrar físicamente el(los) siguiente(s) ficheros de tu disco: Confirmation_void_refresh=Atención! estás a punto de actualizar un dispositivo vacío el cual será limpiado. En Unix, asegurate que el dispositivo esté montado. Estás seguro ? Confirmation_remove_device=¿ Realmente quieres eliminar este dispositivo ? Confirmation_delete_cover=¿ Quieres realmente borrar definitivamente esta carátula del disco ? Confirmation_delete_files=¿ Quieres realmente borrar estos archivos del disco ? Confirmation_delete_dirs=¿ Quieres realmente borrar estos directorios del disco ? Confirmation_clear_history=¿ Quieres realmente limpiar el histórico ? Confirmation_reset_ratings=¿ Quieres realmente ? Confirmation_refactor_files=¿ Quieres realmente renombrar el(los) siguiente(s) ficheros ? Confirmation_restore_all=Una restauración de las vistas necesita reiniciar Jajuk , ¿ quieres salir ? Confirmation_defaults_radios=Se borrarán todas las emisoras de radio que has creado previamente, ¿ estás seguro ? Confirmation_delete_empty_dirs=Los siguientes directorios estan vacíos. ¿ Quieres borrarlos ? Confirmation_file_overwrite=Este archivos ya existe. ¿ Quieres sobreescribir este archivo ? Confirmation_file_number=archivo(s) seran borrados. Confirmation_alarm_stop=¿ Estás seguro que quieres parar esta alarma ? Confirmation_defaults=Esto volverá a las opciones por defecto todas las pestañas ( no solo ésta ) , ¿ estás seguro ? Confirmation_rebuild_thumbs=Esto recreará las miniaturas de todos tus albums, puede llevar varios minutos para grances colecciones. ¿ estás seguro ? Confirmation_reset_preferences=¿ Seguro que quieres resetear las preferencias de pistas ? Device_type.directory=Directorio Device_type.file_cd=CD de Ficheros Musicales Device_type.audio_cd=CD Audio Device_type.extdd=Disco Duro Externo Device_type.player=Reproductor Digital Device_type.network_drive=Unidad de red Device_type.remote=Remoto (No implementado) Perspective_Description_Files=Archivos Perspective_Description_Tracks=Pistas Perspective_Description_Configuration=Configuración Perspective_Description_Statistics=Estadísticas Perspective_Description_Help=Ayuda Perspective_Description_Display=Visualización Perspective_Description_Albums=Albums Perspective_Description_Info=Información Perspective_Description_Playlists=Playlists Item_Playlist_File=Playlist Item_Track=Pista Item_Album=Album Item_Artist=Autor Item_Genre=Estilo Item_Device=Dispositivo Item_File=Archivo Item_Directory=Directorio Property_id=Id Property_name=Nombre Property_type=Tipo Property_url=Url Property_mount_point=Punto de Montaje Property_auto_refresh=Auto Refrescar Property_auto_mount=Auto Montar Property_album=Album Property_style=Género Property_author=Artista Property_length=Longitud Property_year=Año Property_rate=Puntuación Property_files=Arxivos Property_hits=Hits Property_filename=Arxivos Property_date=Fecha Property_added=Descubrimiento Property_parent=Directorio padre Property_device=Dispositivo Property_directory=Directorio Property_track=Pista Property_size=Tamaño (Mb) Property_quality=Calidad Property_hashcode=Hashcode Property_playlist_files=playlists Property_comment=Comentario Property_order=Pista Property_path=Path Property_tracks=Pistas Property_Format_Number=Número Property_Format_String=String Property_Format_Boolean=Boolean Property_Format_Float=Float Property_Format_Date=Date Property_Format_URL=Url Property_pf=Preferencia Property_tpt=Tiempo total de reproducción (segs) Property_ban=Bloqueado Language_desc_en=Inglés Language_desc_fr=Francés Language_desc_de=Alemán Language_desc_it=Italiano Language_desc_sv=Sueco Language_desc_nl=Holandés Language_desc_zh=Chino Language_desc_es=Español Language_desc_ca=Catalán Language_desc_ko=Korean Language_desc_el=Griego Language_desc_ru=Ruso Language_desc_gl=Gallego #--- Error codes --- Error.000=Error desconocido Error.005=Error al parsear el fichero de la colección. Error.007=Error reproduciendo fichero, puede que MPlayer no empezara dentro del timeout, timeout: Error.008=Error deteniendo fichero Error.009=No se puede leer el fichero Error.010=No se puede encontrar un fichero asociado con este elemento en ningún dispositivo montado Error.011=Error técnico al montar el dispositivo o dispositivo vacío Error.012=Error técnico al desmontar el dispositivo, probablemente lo use otra aplicación Error.013=No se puede borrar el dispositivo: Está actualmente montado o actualizándose Error.016=No se puede acceder al dispositivo especificado, por favor , entra el punto de montaje. Ex: '/cdrom' en Unix,'e:' en MS Windows Error.017=Error analizando la playlist Error.018=No se encontró ninguna pista accesible Error.019=Existe un dispositivo con este nombre Error.020=Error de E/S, verifica el espacio en disco Error.021=El campo Url es obligatorio. Ej: 'd:\music' en MS Windows, '/home/foo/music' en Unix Error.022=El campo Nombre es obligatorio. Ej: 'Disco Duro', 'CD ROCK' Error.023=No se puede lanzar la pista inicial Error.024=No se puede escribir el fichero Error.025=Uno de los ficheros que quieres leer está en un dispositivo desmontado Error.026=Error registrando reproductores Error.027=Sincronización abortada Error.028=Error grabando playlist Error.029=Un dispositivo existente es un directorio padre de este dispositivo, tiene el mismo path o es un directorio hijo Error.030=Demasiadas conexiones fallidas. Jajuk ha parado de buscar carátulas en la red. Error.101=El dispositivo no existe o no está disponible Error.102=Error Error.103=Error leyendo información de tag Error.104=Error escribiendo información de tag Error.105=Resource Bundle key no encontrada Error.106=Excepción no capturada Error.107=El dispositivo ya se está refrescando o sincronizando Error.108=Error en el análisis del fichero de perspectiva Error.109=Reproductor o clase de implementación de tag no accesible Error.110=Este nombre de propiedad está reservado por Jajuk internal system, por favor escoja otro nombre Error.111=Dispositivo ya montado Error.112=No se puede montar el dispositivo Error.113=No se puede guardar la configuración del usuario Error.114=No se puede leer la configuración del usuario Error.118=Error procesando petición de evento Error.119=Error analizando fichero de historial o no existe Error.120=No se puede acceder al dispositivo : está montado, refrescándose o bien sincronizándose Error.121=El dispositivo está en uso y no puede ser desmontado Error.122=Error en FIFO Error.123=Error estableciendo tema Error.124=Otra sesión encontrada. Solo se puede lanzar una instancia de Jajuk a la vez Error.125=Dispositivo ya montado Error.126=Búsqueda no soportada por este formato de audio Error.127=No hay novedades durante tiempo especificado, puedes cambiarlo en la vista de preferencias Error.128=Esta pista es la primera de la colección, no hay pistas anteriores Error.129=Error cargando imagen de carátula Error.131=No se puede borrar el fichero Error.133=El fichero de la colección está corrupto por una razón desconocida, jajuk se encargará de restaurar un fichero de backup Error.134=No se puede renombrar el archivo Error.135=El archivo no existe Error.136=Operación fallida Error.137=Formato Erroneo Error.138=Algunos archivos referenciados por estas pistas están localizados en un dispositivos desmontado y no cambiarán Error.140=Cadena errónea: no debería contener los carácteres & ' " < o > Error.141=Esta playlistt está situada en un dispositivo desmontado, por lo que no está disponible Error.142=Esta playlist contiene algunas pistas fuera de dispositivos conocidos que serán ignoradas Error.143=La localización del dispositivo no está disponible Error.144=Error parseando DJ Error.145=No se puede hacer commit DJ Error.146=El patrón actual es incorrecto.
    Items válidos son: %artist (Artist name); %title (Track title); %album (Album name);
    %n (Track leading zero); %genre (track genre); %year (Year)
    y el patrón debe contener al menos una barra Error.147=Algunos archivos no pueden ser movidos (ver detalles para más información) Error.148=El campo Year es desconocido Error.149=El campo Album es desconocido Error.150=El campo Artist es desconocido Error.151=El campo TrackName es desconocido Error.152=El campo TrackOrder es desconocido Error.153=El campo Style es desconocido Error.154=No se puede renombrar el archivo, revisa algun carácter erróneo en el nombre o en los tags Error.155=Error al poner tags a los archivos, revisa los permisos Error.156=No hay DJ disponible para una colección vacía Error.157=DJ erróneo, por favor, selecciona o crea un DJ utilitzando el combo referenciado por este botón Error.158=Las constraints de DJ no pueden ser respetadas o ninguna pista disponible Error.159=El ambiente asociado ha sido borrado Error.160=Fichero no movido. El fuente y el destino eran el mismo Error.161=No se puede escribir al directorio, comprobar permisos Error.162=Esta propiedad de usuario ya existe Error.163=Error restaurando las vistas por defecto Error.164=No hay pistas accesibles para el ambiente : Error.165=Error en el path de la colección, el directorio o no existe o no tiene permisos de escritura Error.166=Album vacío, no se puede capturar la caràtula Error.167=No se puede crear el informe Error.168=No se han encontrado archifos duplicados Error.169=Operación con errores. Tener en cuenta que esta operación requiere una conexión a internet para obtener la lista de emisoras de radio. Error.170=Error reproduciendo webradio Error.171=No se ha definido una fuente de sincronización para este dispositivo, asignala utilizando el asistente de configuración de dispositivos (En la vista de Dispositivo, clickar sobre el dispositivo). Error.172=Se encontró un error mientras se borraba el siguiente archivos(s): Error.173=Se encontró un error mientras se borraban los siguientes directorios: Error.174=Error accediendo a la web de Freedb , revisa tu conexión de red Error.175=Operación cancelada #Warnings Warning.0=MPlayer no se encuentra. Algunos formatos de audio y video (flac, wma, aac, mpg2 ...) serán deshabilitados. Para utilizar Mplayer si está instalado, tienes que configurar manualmente elpath en la vista de Preferencias / avanzado. Warning.1=Versión de MPlayer no válida, es necesario MPlayer1.0Pre8 o superior. Algunos formatos de audio serán deshabilitados. Warning.2=Parece que alguien más está usando ahora la colección de Jajuk. El último usuario en salir sobreescribirá la configuración(opciones, valoraciones...). Warning.3=Mplayer no puede ser descargado. Si estás detrás de un proxy HTTP, configúralo en la vista de Preferencias / Pestaña de Red y reinicia Jajuk. Warning.4=Mplayer es necesario para escuchar web radios Warning.5=El directorio de destino ya existe, algunos archivos se sobreescribirán, ¿ Estás seguro ? #--- Strings by class --- ParameterView.0=Duración del histórico: ParameterView.2=Cambia el tiempo en dias que quieres guardar trazas de pistas escuchadas. Cambiar a -1 si no quieres ver ningún histórico y 0 si quieres tener histórico permanente ParameterView.3=Borrar histórico ParameterView.4=Borrar histórico ParameterView.8=Histórico/Valoraciónes ParameterView.9=Reproducir : ParameterView.10=Nada ParameterView.11=No music at all at startup ParameterView.12=La última desde el principio ParameterView.13=Reproduce la última pista de la sesión anterior ParameterView.14=Pista aleatoria ParameterView.15=Reproduce una pista aleatoria de la colección ParameterView.16=Pista : ParameterView.17=Seleccionar un fichero a reproducir al inicio ParameterView.18=Seleccionar un fichero a reproducir al inicio ParameterView.19=Inicio ParameterView.26=Confirmaciones ParameterView.27=Antes de borrar físicamente un fichero ParameterView.28=Preguntar de borrar físicamente un fichero ParameterView.29=Antes de salir de Jajuk ParameterView.30=Preguntar al salir de Jajuk ParameterView.33=Opciones ParameterView.35=Ocultar pistas situadas en dispositivos desmontados ParameterView.36=Reiniciar al llegar al fin de la colección ParameterView.37=Reinicia la coleccion completa cuando se llega al final en modo continuo ParameterView.38=Idioma: ParameterView.42=Idioma de la interfaz ParameterView.43=Tema: ParameterView.44=Seleccionar un tema

    (Puede ser necesario reiniciar jajuk para verlo correctamente) ParameterView.46=Nivel de log: ParameterView.47=Fatal ParameterView.48=Error ParameterView.49=Warning ParameterView.50=Info ParameterView.51=Debug ParameterView.52=Jajuk verbosity : Fatal:display only critical errors, Error:+display errors, Info:+display information messages, Warning:+display warnings, Debug: any message ParameterView.59=Inicio de posición de introducción (%): ParameterView.60=Posición de la introducción en la pista en %, desde 0 ( inicio de la pista ) a 99 ( final de la pista ) ParameterView.61=Longitud de la introducción (seg): ParameterView.62=Longitud de la introducción en segundos ParameterView.85=Aplicar ParameterView.86=Restaurar valores por defecto ParameterView.87=Preferencias ParameterView.98=Patrones ParameterView.99=Realizar un escaneo profundo de tags ParameterView.100=Fuerza a Jajuk to releer las id3 tags actuales.

    Esto puede ser útil para refrescar tags que se han modificado usando otro programa ParameterView.101=Usar directorio padre como nombre de álbum ParameterView.102=Jajuk usa el directorio padre como el nombre del álbum para una pista si no puede obtenerlo via id3 tags ParameterView.109=Preferencias salvadas ParameterView.110=Preferencias cambiadas a valores por defecto ParameterView.111=Tamaño de la playlist Best Of: ParameterView.112=Cambia el número de pistas en la playlist BestOf(de 1 a 100) ParameterView.113=Usar regexp en filtros ParameterView.114=Usar expresiones regulares (Formato Regexp) en los filtros de las tablas, ejemplo: .*foo.* ParameterView.115=Avanzada ParameterView.116=Hacer copia de seguridad del archivo de colección ParameterView.117=Marcar esto si quieres hacer una copia de seguridad de tu archivos de colección a ficheros collection-.xml ParameterView.118=Tamaño de Backup (Mb) ParameterView.119=Tamaño de Backup (Mb) (Mb) ParameterView.120=Charset de la colección ParameterView.121=Charset de la colección. UTF-16 está optimizado para idiomas Asiáticos y UTF-8 está optimizado para idiomas europeos. ParameterView.129=Tiempo límite de las novedades (días): ParameterView.130=Tiempo límite de las novedades en días : todas las pistas añadidas antes de este número de días son tomadas como novedades ParameterView.131=Pista BestOf ParameterView.132=Reproduce una de tus pistas favoritas al inicio ParameterView.133=Pista Nueva ParameterView.134=Reproduce una novedad de tu colección al inicio ParameterView.135=La última pista anterior ParameterView.136=Reproduce la última pista reproducida durante la sesión anterior ParameterView.139=Red ParameterView.142=Usuario del proxy ParameterView.143=Nombre de login del proxy usado para autentificación ParameterView.144=Host del proxy ParameterView.145=Nombre de host o IP del proxy ParameterView.146=Puerto del proxy ParameterView.147=Puerto TCP/IP del proxy (frecuentemente 3128) ParameterView.148=Usar auto carátulas ParameterView.149=Use auto cover to bring covers from the Internet (if required, configure your proxy in the network tab) ParameterView.150=Mínimo tamaño de carátula(Kb) ParameterView.151=Mínimo tamaño de carátula(Kb) de carátulas descargadas ParameterView.152=Máximo tamaño de carátula(Kb) ParameterView.153=Máximo tamaño de carátula(Kb) de carátulas descargadas ParameterView.155=Search accuracy. The higher is accuracy, the less you will get wrong cover images ParameterView.156=Baja ParameterView.157=Media ParameterView.158=Alta ParameterView.159=Carátulas ParameterView.160=Timeout de Conexión (seg) ParameterView.161=Timeout de Conexión in segs: la operación falla si la otra parte no contesta en este tiempo ParameterView.162=Timout de transferencia (seg). ParameterView.163=Timeout de transferencia (seg): la operación fall si los datos no se descargaron en este tiempo ParameterView.164=Antes de eliminar un dispositivo ParameterView.165=Preguntar antes de eliminar un dispositivo ParameterView.166=Barajar carátulas ParameterView.167=Mostrar una carátula aleatoria ParameterView.168=Artista ParameterView.169=Precargar carátulas ParameterView.170=Precargar todas las carátulas disponibles cuando sea posible ParameterView.171=Antes de borrar físicamente una carátula ParameterView.172=Preguntar antes de borrar físicamente una carátula ParameterView.177=Número visible de pistas planificadas ParameterView.178=El número de pistas planificadas a mostrar en la playlist ParameterView.179=Encolar la selección ParameterView.180=Encolar (y no reproducir) una pista haciendo doble click en un elemento ParameterView.181=Encolar al hacer drag & drop ParameterView.182=Encolar (y no ejecutar) una pista cuando la arrastremos. ParameterView.183=Sincronizar vistas de árbol y tabla ParameterView.184=Si está marcado la vista de tabla solo mostrará pistas seleccionadas en la vista de árbol ParameterView.185=Mostrar un popup cuando se lance una pista ParameterView.186=Inicializar puntuaciones ParameterView.187=Inicializar puntuaciones a cero para pistas ParameterView.188=Antes limpiar histórico ParameterView.189=Antes inicializar puntuaciones ParameterView.190=duración de la atenuación (segundos) ParameterView.191=El número de segundos de atenuación entre pistas ParameterView.192=Organizador de ficheros : ParameterView.193=Patrones disponibles: %artist (Nombre del artista); %title (Título de la pista); %album (Nombre del álbum); %n (Track leading zero); %genre (Género); %year (Año) ParameterView.194=Antes de organizar ficheros ParameterView.195=Vista de animación ParameterView.196=Habilitar atajos de teclado ParameterView.197=Habilitar algunas teclas como F8 para que funcionen aunque Jajuk no tenga el foco ParameterView.198=Algunos cambios serán efectivos solo en el próximo inicio de Jajuk ParameterView.199=Scrobble lo que escucho ParameterView.200=Esta opción envia informaciones a Last.fm ParameterView.201=Usuario de Last.FM ParameterView.202=El nombre de usuario usado en Last.FM ParameterView.203=Password de Last.FM ParameterView.204=El password usado en Last.FM ParameterView.205=Argumentos de MPlayer ParameterView.206=Argumetnos adicionales de MPlayer como '-ao esd' o '-ao arts' o '-novideo (para no reproducir videos)' p.e. ParameterView.207=Path base de Jajuk ParameterView.208=Cambiar el directorio que contiene la configuración de Jajuk (por defecto es el directorio home del usuario) ParameterView.209=El path de la configuración de Jajuk ha sido cambiado por el usuario actual (la colección anterior ha sido guardado en la localización anterior). Jajuk se puede reiniciar. ParameterView.210=Si el cross fade no funciona, trata de añadir <-ao esd> en Gnome o <-ao arts> en KDE en el campo de argumentos adicionales del motor de sonido (Preferencias / Avanzado). ParameterView.211=Pequeñas solo ParameterView.212=Pequeñas y medianas ParameterView.213=Medianas solo ParameterView.214=Medianas y grandes ParameterView.215=Grandes solo ParameterView.216=Buscar usando el nombre del artista ParameterView.217=Buscar usando el nombre del album ParameterView.218=Buscar usando el nombre de la pista ParameterView.219=Variables de entorno ParameterView.220=Establece la variables de entorno usadas por el reproductor de audio (ARTS_SERVER en KDE o ESPEAKER en Gnome for ie). Formato: var1=xx var2=yyy... #Respect English size for next item ParameterView.221=Tamaño página de Catálogo (0: Todo en una) ParameterView.222=Establece el número de álbumes por página en la vista de catálogo. 0: muestra todas las carátulas en una sola página ParameterView.223=Tamaño de Fuentes ParameterView.224=Establece el tamaño de la fuente de texto ParameterView.225=GUI ParameterView.226=Modos ParameterView.228=Mostrar ventanas de albums ParameterView.229=Preferencias de la vista de Catálogo ParameterView.233=El interfaz se refrescará en el próximo reinicio de jajuk ParameterView.234=Chequea actualizaciones de Jajuk ParameterView.235=Last.FM ParameterView.236=Sin Proxy ParameterView.237=proxy HTTP ParameterView.238=proxy SOCKS ParameterView.239=Proxy password ParameterView.240=Habilitar consultas de información de Last.FM ParameterView.241=Si está marcado, jajuk recogerá información de los albumes de Last.FM (ver vista de sugerencias) ParameterView.242=Path de Mplayer ParameterView.243=Cambiar aquí el path completo del ejecutable mplayer (espacio permitidos)
    Exemple: /Applications/MPlayer OSX.app/Contents/Resources/External_Binaries/mplayer_intel.app/Contents/MacOS/mplayer ParameterView.244=Forzar fecha de los archivos como fecha de descubrimiento ParameterView.245=Jajuk considera la fecha de los archivos de como la fecha de descubrimiento
    Requeire un refresco en profundidad para ser tenido en cuenta ParameterView.246=Tamanys dels icons a la barra de Perspectives (pixels) ParameterView.247=El path de destino contiene ya un workspace de Jajuk. El workspace se ha cambiado a este path para el usuario actual (el workspace anterior ha sido guardado en la anterior localización). Jajuk puede ser reiniciado. ParameterView.248=Título del marco : ParameterView.249=Resetear preferencias ParameterView.250=Resetear preferencias del usuario ParameterView.251=Histórico reseteado correctamente ParameterView.252=Valoraciones y tiempos de reproducción reseteados correctamente ParameterView.253=Preferencias resetadas correctamente Main.21=Confirmación Main.22=Descargando MPlayer Player.0=Esperando la línea de audio (ocupada) Device.21=Refrescando [ Device.22=] Entrando [ Device.25=] refrescado en Device.27= nuevos ficheros - Device.31=Sinc. [ Device.33=sincronización hecha en Device.35= ficheros creados ( Device.36= MB) Device.41=Sinc. [ Device.42=] Copiando [ Device.43= tags no legibles Device.44=Entrando FIFO.4=). ¿ Quieres montarlo ? FIFO.10=Ahora reproduciendo: FIFO.13= Kbps FIFO.14=Reproduciendo Web Radio: HistoryItem.0=yy/MM/dd HH:mm DeviceWizard.0=Configuración de dispositivo DeviceWizard.1=Tipo de dispositivo(*): DeviceWizard.2=Nombre del dispositivo(*): DeviceWizard.3=Localización del dispositivo(*): DeviceWizard.4=Directorio de montaje Unix (opcional): DeviceWizard.7=Ejecutar un refresco instantaneo DeviceWizard.8=Auto montar al inicio DeviceWizard.10=Sincronizado con : DeviceWizard.11=Sincronización unidireccional DeviceWizard.12=Todos los ficheros nuevos en el dispositivo fuente se copiarán en este dispositivo. Nada será escrito en el dispositivo fuente DeviceWizard.13=Sicronización bidireccional DeviceWizard.14=Todos los ficheros nuevos encontrados en un dispositivo se copiarán al otro DeviceWizard.43=Por favor escoge un direcorio DeviceWizard.44=Dispositivo creado DeviceWizard.45=Por favor, dale un nombre al dispositivo. Ej: CD A, Portátil ... DeviceWizard.46=Por favor, da una localización para el dispositivo. Ej: d:\music en Windows, /home/foo/music en Unix DeviceWizard.48=Marcar si quieres ejecutar un refresco inmediato del dispositivo (avisado)

    Esta operación puede tardar bastante para dispositivos grandes DeviceWizard.49=Marcar si quieres montar automáticamente el dispositivo al inicio

    especialmente para directorios en el disco duro local. Evitarlo para CDs DeviceWizard.50=Intervalo en minutos para búsqueda automática de nuevos archivos (0: deshabilitada) DeviceWizard.51=Marcar si quieres sincronizar este dispositivo con otro DeviceWizard.52=Seleccionar dispositivo fuente DeviceWizard.53=Refrescar dispositivo cada #limited string size DeviceWizard.54=min JajukJMenuBar.0=Archivo JajukJMenuBar.1=Abrir fichero JajukJMenuBar.3=Salir JajukJMenuBar.5=Propiedades JajukJMenuBar.6=Crear propiedad de usuario JajukJMenuBar.7=Borrar propiedad de usuario JajukJMenuBar.8=Vistas JajukJMenuBar.9=Modos JajukJMenuBar.10=Repetición JajukJMenuBar.11=Aleatorio JajukJMenuBar.12=Continuo JajukJMenuBar.13=Introducción JajukJMenuBar.14=Ayuda JajukJMenuBar.15=Contenido de la ayuda JajukJMenuBar.16=Sobre JajukJMenuBar.17=Restaurar vistas por defecto JajukJMenuBar.18=Asistente de Dispositivos JajukJMenuBar.19=Comunicar un problema JajukJMenuBar.20=Consejo del Día JajukJMenuBar.21=Configuración JajukJMenuBar.22=Preferencias JajukJMenuBar.23=Mostrar trazas de debug JajukJMenuBar.24=Mostrar solo pistas disponibles JajukJMenuBar.25=Mostrar vista JajukJMenuBar.26=Restaurar vistas (todas las perspectivas) JajukJMenuBar.27=Chequear actualizaciones de Jajuk JajukJMenuBar.28=Herramientas JajukJMenuBar.29=Inteligencia PlaylistFileItem.1=Novedades PlaylistFileItem.2=Nueva playlist PlaylistFileItem.3=Marcadores PlaylistFileItem.4=Lo mejor de PlaylistFileItem.5=Cola JajukFileChooser.0=Escoger Fichero SearchBox.0=Buscar entre pistas, autores, estilos, directorio ... CommandJPanel.0=Ver histórico de reproducción CommandJPanel.1=Modo repetición: Reproduce una pista en bucle CommandJPanel.2=Modo aleatorio: Reproduce aleatoriamente las pistas seleccionadas CommandJPanel.3=Modo continuo: Continua reproduciendo las pistas siguientes cuando acaba CommandJPanel.4=Modo Introducción: Reproduce un fragmento de las pistas. Inicio y tiempo pueden ser cambiados desde la vista de parámetros CommandJPanel.5=Reproducir una selección aleatoria de la colección entera CommandJPanel.6=Reproducir pistas favoritas CommandJPanel.7=Sonido off CommandJPanel.8=Reproducir pista anterior en la selección actual
    Mays+Boton Izquierdo lanza el álbum anterior CommandJPanel.9=Reproducir pista siguiente en la selección actual
    Mays+Boton Izquierdo lanza el álbum anterior CommandJPanel.10=Retroceso rápido en la pista actual
    Shift+Botón izquierdo para repetición completa CommandJPanel.11=Pausa/Reanuda pista actual CommandJPanel.12=Parar CommandJPanel.13=Avance rápido en la pista actual CommandJPanel.14=Volumen CommandJPanel.15=Click aquí para cambiar el formato de tiempo mostrado CommandJPanel.16=Lanzar selección de DJ CommandJPanel.17=Administrar DJs CommandJPanel.18=Lanzar el DJ seleccionado por defecto CommandJPanel.19=Administrar Ambientes CommandJPanel.20=Pista por pista CommandJPanel.21=Album por álbum CommandJPanel.22=Album por album CommandJPanel.23=Click para limpiar la búsqueda CommandJPanel.24=Configurar web radios CommandJPanel.25=Encender la radio InformationJPanel.5=Tiempo total de la cola a reproducir [Nb de pistas restantes] InformationJPanel.6=Bitrate de pista InformationJPanel.7=Progreso de la pista actual #song name BY artist ON album name InformationJPanel.8=%title por %artist en %album AbstractPlaylistEditorView.0=Título AbstractPlaylistEditorView.1=Localización AbstractPlaylistEditorView.2=Reproducir esta playlist AbstractPlaylistEditorView.3=Salvar esta playlist AbstractPlaylistEditorView.4=Añadir elemento a esta playlist AbstractPlaylistEditorView.5=Eliminar elemento de esta playlist AbstractPlaylistEditorView.6=Mover arriba AbstractPlaylistEditorView.7=Mover abajo AbstractPlaylistEditorView.9=Borrar esta playlist AbstractPlaylistEditorView.10=Añadir una pista aleatoria a esta playlist AbstractPlaylistEditorView.15=Playlists AbstractPlaylistEditorView.17=Estás a punto de modificar las siguientes playlists : AbstractPlaylistEditorView.18=Pista en cola AbstractPlaylistEditorView.19=Pista repetida AbstractPlaylistEditorView.20=Pista planificada AbstractPlaylistEditorView.21=Pista de playlist AbstractPlaylistEditorView.22=Playlist grabada AbstractPlaylistEditorView.27=Preparar Fiesta AbstractPlaylistEditorView.28=directorio creado con éxito StatView.0=Otros StatView.1=Géneros StatView.2=No hay datos disponibles StatView.3=Otras StatView.4=Tamaño por dispositivo (GB) StatView.5=No hay datos disponibles StatView.7=Tamaño de la colección por mes StatView.8=Meses StatView.9=Tamaño (GB) StatView.10=No hay datos disponibles StatView.12=Número total de pistas por meses StatView.13=Meses StatView.14=número de Pistas StatView.15=No hay datos disponibles StatView.16=Estadística StatView.24=Antiguas CDScanView.0=CD label : CDScanView.1=Etiqueta de CD. Ej: CD1, ROCK... CDScanView.2=Etiqueta de CD Ej: CD1, ROCK... CDScanView.3=Localización del CD : CDScanView.4=Localización donde se puede encontrar el CD. Ej: '/cdrom' en Unix, 'e:' en MS Windows... CDScanView.5=Localización donde se puede encontrar el CD. Ex: '/cdrom' on Unix, 'e:' under MS Windows... CDScanView.6=Analizar CDScanView.12=Analizar CD CDScanView.18=Analizar el CD y añadir automáticamente todos los ficheros de música a la colección CDScanView.19=Seleccionar localización del CD TracksTreeView.0=Arbol de pistas TracksTreeView.27=Colección TracksTreeView.31= pistas TracksTreeView.33=Exportar TracksTreeView.34=Obtener tags online TracksTreeView.35=Descubrir fecha TracksTreeView.36=menos de una semana TracksTreeView.37=menos de un mes TracksTreeView.38=menos de seis meses TracksTreeView.39=anterior TracksTreeView.40=menos de un año TracksTreeView.41=menos de dos años TracksTreeView.42=menos de cinco años TracksTreeView.43=menos de diez años TracksTreeView.44=menos de tres meses TracksTreeView.45=Año CoverView.2=Borrar del disco esta carátula CoverView.3=Carátula CoverView.4=Imagen anterior del disco y/o de la Web si la opción de Auto-Carátula está marcada CoverView.5=Imagen siguiente del disco y/o de la Web si la opción de Auto-Carátula está marcada CoverView.6=Grabar carátula con su nombre original CoverView.7=Grabar carátula como ... CoverView.8=Usar esta carátula como la carátula por defecto de este álbum CoverView.9=carátulas CoverView.10=Grabar carátula como CoverView.11=Carátula grabada CoverView.12=Album CoverView.13=Título AnimationView.0=Animación FilesTreeView.0=Árbol de archivos FilesTreeView.3=Copiar FilesTreeView.4=Cortar FilesTreeView.5=Pegar FilesTreeView.7=Borrar FilesTreeView.14=Desincronizar FilesTreeView.15=Resincronizar FilesTreeView.16=Crear Playlist FilesTreeView.17=Copiar FilesTreeView.18=Cortar FilesTreeView.28=Montar FilesTreeView.29=Desmontar FilesTreeView.30=Forzar Refrescar FilesTreeView.31=Sincronizar FilesTreeView.32=Probar FilesTreeView.33=Crear playlists FilesTreeView.40=Copiar FilesTreeView.41=Cortar FilesTreeView.42=Pegar FilesTreeView.47=Colección FilesTreeView.52= ficheros: FilesTreeView.53= GB FilesTreeView.54= MB FilesTreeView.55= Configurar dispositivo FilesTreeView.59=¿ Quieres ejecutar un refresco rápido o en profundidad (leer las tags otra vez) ? FilesTreeView.60=Rápido FilesTreeView.61=En profundidad FilesTreeView.62=Organizar ficheros TracksTableView.0=Tabla de pistas TracksTableView.7=Reproducir TracksTableView.8=Encolar TracksTableView.9=Reproducir aleatoriamente TracksTableView.10=Reproducir con repetición TracksTableView.11=Reproducir álbum TracksTableView.12=Reproducir autor TracksTableView.14=Propiedades TracksTableView.15=Añadir a Favoritos AbstractTableView.0=Filtro: AbstractTableView.1=Propiedad a filtrar AbstractTableView.3=Valor a ser usado por el filtro AbstractTableView.4=Aplicar filtro AbstractTableView.5=Limpiar el filtro AbstractTableView.6=Aplicar filtro avanzado AbstractTableView.7=contiene: AbstractTableView.8=Cualquiera AbstractTableView.10=(No disponible) AbstractTableView.11=Hacer editable la tabla AboutView.7=Sobre AboutView.8=Licencia AboutView.9=Sistema AboutView.10=Sobre PhysicalPlaylistRepositoryView.0=Reproducir PhysicalPlaylistRepositoryView.1=Editar PhysicalPlaylistRepositoryView.2=Guardar como PhysicalPlaylistRepositoryView.3=Borrar PhysicalPlaylistRepositoryView.4=Propiedades PhysicalPlaylistRepositoryView.6=Playlists físicas PhysicalPlaylistRepositoryView.8=Inteligentes PhysicalPlaylistRepositoryView.9=Encolar PhysicalPlaylistRepositoryView.10=Cola actual: drag and drop una pista a ella para reproducir PhysicalPlaylistRepositoryView.11=Nueva PhysicalPlaylistRepositoryView.12=Nueva playlist: drag and drop una pista a ella para añadir ficheros PhysicalPlaylistRepositoryView.13=Favoritos PhysicalPlaylistRepositoryView.14=Bookmark playlist: drag and drop una pista a ella para guardarla PhysicalPlaylistRepositoryView.15=Lo mejor de PhysicalPlaylistRepositoryView.16=Best of playlist: contiene las mejores pistas PhysicalPlaylistRepositoryView.17=Novedades PhysicalPlaylistRepositoryView.18=Playlist de Novedades: contiene las pistas más nuevas de la colección FilesTableView.0=Tabla de archivos FilesTableView.15=Reproducir un directorio #Dev: do not use ID = 16, next label is FilesTableView.17 DeviceView.0=Añadir un dispositivo DeviceView.1=Eliminar un dispositivo desmontado (no borra nada del disco) DeviceView.2=Propiedades del dispositivo seleccionado DeviceView.3=Montar dispositivo seleccionado DeviceView.4=Desmontar dispositivo seleccionado DeviceView.5=Probar disponibilidad del dispositivo seleccionado DeviceView.6=Forzar refrescar dispositivo seleccionado DeviceView.7=Sincronizar dispositivo seleccionado DeviceView.8=Montar DeviceView.9=Desmontar DeviceView.10=Probar DeviceView.11=Forzar refrescar DeviceView.12=Sincronizar DeviceView.13=Eliminar dispositivo DeviceView.14=Configurar DeviceView.17=Nuevo DeviceView.18=Añadir un dispositivo DeviceView.21=Este dispositivo está disponible DeviceView.22=No se puede acceder al dispositivo DeviceView.23=Dispositivos JajukWindow.1=Unmute JajukWindow.2=Mute JajukWindow.3=Jajuk JajukWindow.4=Salir JajukWindow.5=Sobre Jajuk JajukWindow.6=Reproducir aleatoriamente JajukWindow.7=Reproducir Lo Mejor de JajukWindow.10=Pausa JajukWindow.11=Stop JajukWindow.12=Play JajukWindow.13=Anterior JajukWindow.14=Siguiente JajukWindow.15=Reproducir Novedades JajukWindow.16=Continuar album JajukWindow.17=Jajuk: Advanced Jukebox JajukWindow.18=Preparado para reproducción JajukWindow.19=Mute/Unmute JajukWindow.21=Salir JajukWindow.22=Sobre Jajuk JajukWindow.23=Reproducir aleatoriamente pistas de la colección entera JajukWindow.24=Reproducir las mejores pistas de la colección entera JajukWindow.26=Play/Pausa JajukWindow.27=Stop JajukWindow.29=Pista o emisora anterior. Con el ratón, botón izquierdo +[Mays]: album anterior. JajukWindow.30=Pista o emisora siguiente. Con el ratón, botón izquierdo +[Mays]: album siguiente. JajukWindow.31=Reproducir novedades de la colección entera JajukWindow.32=Continuar album: acabar de reproducir este album JajukWindow.33=Volumen JajukWindow.34=Posición JajukWindow.35=Reproduciendo: JajukWindow.36=Ambiente actual: JajukWindow.37=Sin Ambiente seleccionado #Do not use JajukWindow.38, next is JajukWindow.39 SimpleDeviceWizard.0=Creación rápida de dispositivo FirstTimeWizard.0=Inicio rápido FirstTimeWizard.1=


    Bienvenido! Este asistente te ayudará en la creación de la colección.

    FirstTimeWizard.2=Selecciona la localización de la música FirstTimeWizard.3=Quieres obtener las carátulas online
    (se puede abrir una conexión a internet automàticamente) ? FirstTimeWizard.4=Mostrar la ayuda ahora ? FirstTimeWizard.5=Por favor, escoger un directorio FirstTimeWizard.6=Preferencias avanzadas FirstTimeWizard.7=Establecer directorio de area de trabajo de Jajuk : HelpView.2=Ayuda DownloadManager.0=Jajuk necesita la contraseña de tu proxy HTTP para descargar carátulas
    Si no las quieres, por favor cambia tu configuración en la pestaña Carátulas de la vista de Preferencias
    Si no tienes proxy, cambia los ajustes en la pestaña de Red de la vista de Preferencias DownloadManager.1=Contraseña requerida PropertiesWizard.0=Propiedades de ... PropertiesWizard.1=Propiedad PropertiesWizard.2=Valor PropertiesWizard.3=Editable? PropertiesWizard.4=Enlace PropertiesWizard.6=Selección PropertiesWizard.7=Tipo PropertiesWizard.8=Propiedad cambiada correctamente PropertiesWizard.9=Propiedad no editable para esta selección PropertiesWizard.10=Las propiedades se han cambiado PropertiesWizard.11=Escribiendo tag a: PropertiesWizard.12=Enlaza un elemento dado a unas propiedades dadas NewPropertyWizard.0=Crear propiedad de usuario NewPropertyWizard.3=(*)Tipo NewPropertyWizard.4=Formato NewPropertyWizard.5=Valor por defecto CustomPropertyWizard.0=(*)Item CustomPropertyWizard.1=(*)Nombre de propiedad de usuario RemovePropertyWizard.0=Borrar propiedad de usuario QualityFeedbackWizard.20=Una nueva ventana para enviar tu ticket se abrirá en el navegador externo. Tus últimas trazas anonimizadas han sido puestas en el portapapeles, Por favor pégalas en el campo descripción si es un informe de bug (esto incrementa las opciones para que podamos arreglar tu problema). IncRateAction.0=Incrementar valoración de la pista actual SplashScreen.0=Controles iniciales SplashScreen.1=Cargando Colección SplashScreen.2=Iniciando motor musical SplashScreen.3=Iniciando interfaz gráfico CatalogView.0=Catálogo de Albums #Note: CatalogView.2 label musn't be mush larger than in english for correct display in 800x600 CatalogView.2=Sin carátulas CatalogView.3=Refrescar catálogo CatalogView.4=Tamaño de miniaturas: CatalogView.5=Creada miniatura para: CatalogView.7=Seleccionar carátula CatalogView.8=Ninguna carátula encontrada CatalogView.9=Anterior CatalogView.10=Siguiente CatalogView.11=Página: CatalogView.12=Mostar página anterior de miniaturas CatalogView.13=Mostar página siguiente de miniaturas CatalogView.14=Seleccionar página de miniaturas a mostrar CatalogView.15=Tamaño de miniatura: CatalogView.16=albums CatalogView.17=/pagina CatalogView.18=Selección de carátula CatalogView.19=Rehacer miniaturas CatalogView.20=Mostrar detalles WikipediaView.0=Wikipedia WikipediaView.1=Seleccionar Idioma: WikipediaView.3=Nada encontrado WikipediaView.5=Buscar por nombre de Artista WikipediaView.6=Buscar por nombre de Album WikipediaView.7=Buscar por título TipOfTheDayView.0=Consejo del día TipOfTheDayView.1=¿ Sabías... ? TipOfTheDayView.2=¿ Mostrar al inicio ? CDDBWizard.0=Aceptar CDDBWizard.1=Archivo CDDBWizard.2=Nombre de pista actual CDDBWizard.3=Nombre de álbum actual CDDBWizard.4=Nombre de pista propuesto CDDBWizard.5=Nombre de álbum propuesto : CDDBWizard.6=Hecho ! Encontrado CDDBWizard.7=posibles coincidencias CDDBWizard.12=No encontrada coincidencia ! CDDBWizard.14=Este directorio no contiene ningún archivo CDDBWizard.16=Estilo: CDDBWizard.17=Encontrada coincidencia exacta ! CDDBWizard.18=Coincidencias CDDBWizard.19=Obtener Tags Online RefactorWizard.0=Fichero movido : DigitalDJWizard.0=Seleccionar el nuevo modo de DJ DigitalDJWizard.1=Programación basada en transiciones (ROCK -> POP) DigitalDJWizard.2=Programación basada en proporciones (20% JAZZ, 30% ROCK) DigitalDJWizard.3=Programación basada en ambientes (Suave, Fiesta, ...) DigitalDJWizard.4=Asistente de DJ Digital DigitalDJWizard.5=Configuración general del DJ DigitalDJWizard.6=Nombre del DJ (*) DigitalDJWizard.7=Usar puntuaciones DigitalDJWizard.8=Nivel de puntuación: DigitalDJWizard.9=Cross fade (sec): DigitalDJWizard.10=Pistas solo reproducidas una vez DigitalDJWizard.11=Tirar DigitalDJWizard.12=Desde Estilos DigitalDJWizard.13=A Estilos DigitalDJWizard.14=Selección de Estilos (Se puede hacer selecciones múltiples) DigitalDJWizard.15=Número de pistas DigitalDJWizard.16=¿ Quieres ? DigitalDJWizard.17=¿ Crear un nuevo DJ ? DigitalDJWizard.18=¿ Cambiar un DJ existente ? DigitalDJWizard.19=¿ Borrar un DJ ? DigitalDJWizard.20=Nuevo DJ basado en transiciones #limited string size DigitalDJWizard.21=Borrar #limited string size DigitalDJWizard.22=Origen #limited string size DigitalDJWizard.23=Destino #limited string size DigitalDJWizard.24=Nb #limited string size DigitalDJWizard.25=Empieza por: DigitalDJWizard.26=Por favor, crea almenos una transición #limited string size DigitalDJWizard.27=Selección de géneros #limited string size DigitalDJWizard.28=% DigitalDJWizard.29=DJ basado en proporciones DigitalDJWizard.30=Por favor, crea almenos una proporción DigitalDJWizard.31=DJ basado en ambiente DigitalDJWizard.32=Nuevo ambiente DigitalDJWizard.33=Crear un nuevo ambiente DigitalDJWizard.34=Borrar ambiente DigitalDJWizard.35=Borrar el ambiente seleccionado DigitalDJWizard.36=Nombre del ambiente DigitalDJWizard.37=Nombre DigitalDJWizard.38=Por favor, crea almenos un ambiente DigitalDJWizard.39=Por favor, rellena el nombre y selecciona los estilos del ambiente DigitalDJWizard.40=Por favor, selecciona un DJ DigitalDJWizard.41=Por favor, pon el nombre al DJ DigitalDJWizard.42=Un DJ con este nombre ya existe DigitalDJWizard.43=Cambiar DJ DigitalDJWizard.44=Seleccionar el DJ a configurar DigitalDJWizard.45=Selección de acción DigitalDJWizard.46=Selección del tipo de DJ DigitalDJWizard.47=Por favor, selecciona o crea un ambiente DigitalDJWizard.48=Atributos Generales DigitalDJWizard.49=Por favor, rellena los atributos generales del DJ DigitalDJWizard.50=Por favor, define proporciones DigitalDJWizard.51=Borrar DJ DigitalDJWizard.52=Por favor, define transiciones DigitalDJWizard.53=Número mínimo de estrellas de puntuación para pistas de la selección (1: todas las pistas) DigitalDJWizard.54=Duración de Cross fade entre pistas DigitalDJWizard.55=Si está marcado, la selección contendrà cada pista solo una vez DigitalDJWizard.56=Asistente de Ambientes DigitalDJWizard.57=Administrar Ambientes DigitalDJWizard.58=Selección de Ambientes: DigitalDJWizard.59=La suma de todas las proporciones tendria que ser < 100 % DigitalDJWizard.60=Nombre de ambiente existente DigitalDJWizard.61=Borrar DJ #limited string size DigitalDJWizard.62=Por defecto DigitalDJWizard.63=Añadir ambientes por defecto DigitalDJWizard.64=Cualquiera DigitalDJWizard.66=Selección de Ambiente por defecto #--- Tips of day --- Ambience.0=Rock/Pop Ambience.1=Rap Ambience.2=HardRock Ambience.3=Techno Ambience.4=Electro Ambience.5=Clásico Ambience.6=Suave Ambience.7=Fiesta Ambience.8=Jazz Ambience.9=World Ambience.10=Otros Ambience.11=Folk/Oldies Ambience.12=Indy Ambience.13=Latin DebugLogAction.0=Listar trazas de Debug DebugLogAction.1=Refrescar CopyClipboardAction.0=Copiar dirección al portapapeles LaunchInBrowserAction.0=Lanzar dirección en el navegador del sistema ReportAction.0=Informe creado satisfactoriamente ReportAction.1=Informe de Música Jajuk ReportAction.2=Por favor, por el cuidado del medio ambiente, no imprimas si no es necesario ReportAction.3=Lista de Albums ReportAction.4=Pistas por Album ReportAction.5=Lista de Artistas ReportAction.6=Álbums por artistas ReportAction.7=Lista de Géneros ReportAction.8=Albums por género ReportAction.9=Autores/ albums por género ReportAction.10=Lista de Directorios ReportAction.11=Archivos por directorio ReportAction.12=Nombre de archivo ReportAction.13=Nombre de pista ReportAction.14=Lista de Dispositivos ReportAction.15=Directorios por dispositivo ReportAction.16=Directorios/ archivos ReportAction.17=colección ReportAction.18=Autores/ albums/ pistas por estilo ReportAction.19=Ir a: ActionMove.0=Pegar ActionRefresh.0=Forzar Refrescar ActionRefresh.1=Refrescando directorio RenameAction.0=Renombrar RenameAction.1=Por favor, entra el nuevo nombre para este archivo: RenameAction.2=Por favor, entra el nuevo nombre para este directorio: NewFolderAction.0=Nueva Carpeta NewFolderAction.1=Por favor, entra el nuevo nombre para esta carpeta: NewFolderAction.2=Una carpeta con el mismo nombre ya existe. LyricsView.0=Letra ActionDelete.0=Ficheros borrados ActionDelete.1=Directorios borrados FindDuplicateFilesAction.0=No se encontraron ficheros duplicados. FindDuplicateFilesAction.1=Ficheros duplicados encontrados RefreshDialog.0=Preparando actualización de dispositivo... RefreshDialog.1=Actualizando dispositivo RefreshDialog.2=Actualizando dispositivo: RefreshDialog.3=Limpiando los archivos antiguos RadioWizard.0=Selecciona o crea una web radio RadioWizard.1=Administrarweb radios RadioWizard.2=Nueva RadioWizard.3=Borrar RadioWizard.4=Por defecto RadioWizard.5=Una web radio con este nombre ya existe RadioWizard.6=Nombre de Web Radio RadioWizard.7=Asistente de Web Radio RadioWizard.8=URL RadioWizard.9=Nombre RadioWizard.10=URL incorrecta RadioWizard.11=Nombre y URL son obligatorios UpdateManager.0=Una nueva versión de Jajuk ( UpdateManager.1=) se ha encontrado, puedes decargarla desde http://jajuk.info UpdateManager.2=No hay nueva versión por ahora LastFmManager.0=El soporte Last.FM está deshabilitado. Si quieres enviar las canciones que escuches a Last.FM, habilítalo y configura tu login y password de Last.FM en la vista de Preferencias / pestaña Last.FM. SuggestionView.0=Sugerencias SuggestionView.1=Preferidas SuggestionView.2=Nuevos SuggestionView.3=Otros albums SuggestionView.4=Artistas similares SuggestionView.5=Raramente escuchadas SuggestionView.7=Nada que mostrar

    La información de Last.FM se muestra solo si:
    • Una pista está reproduciéndos
    • El autor de la pista es conocido (tag correcta)
    • La opción "Habilitar consultas a Last.FM" está marcada en la vista de Preferencias / pestaña Last.FM
    AbstractThumbnail.0=Abrir la página LAST.FM AlbumsTableView.0=Tabla de Albums AlbumsTableView.1=No de pistas AlarmClock.0=Establecer nueva alarma AlarmClock.1=Mostrar alarmas AlarmClock.2=Sin alarmas establecidas AlarmClock.3=Alarma AlarmClock.4=Momento ya pasado ! AlarmClock.5=Recordatorio para ti: AlarmDialog.0=Tiempo (HH:MM:SS) AlarmDialog.1=Hora AlarmDialog.2=Minutos AlarmDialog.3=Segundos AlarmDialog.4=Acción de la alarma AlarmDialog.5=Seleccionar acción de la alarma AlarmDialog.6=Mensaje: AlarmDialog.7=Establecer mensaje recordatorio AlarmDialog.8=Diariamente AlarmDialog.9=Establecer la alarma diariamente. ShowPropertiesAction.0=Muestra propiedades del objeto QueueView.1=Vaciar la cola JajukSlimWindow.0=Habilitar/deshabilitar Slim Jajuk BanSelectionAction.0=Bloquear BanSelectionAction.1=Bloquear el elemento para que nunca se seleccione UnBanSelectionAction.0=Desbloquear UnBanSelectionAction.1=Desbloquear elemento(s) para volver a ser propuestos Preference.0=Asigna una preferencia personal a la pista actual
    Es tomada en cuenta para el cálculo de la valoración final Preference.1=Basura Preference.2=Pobre Preference.3=Medio Preference.4=Bueno Preference.5=Excelente Preference.6=Clásico Preference.7=Preferencias... Preference.8=Sin preferencia # TipOfTheDay are automatically generated with the Jajuk Manual. # To change tip of the day use page: http://jajuk.info/index.php/Tip_of_the_day TipOfTheDay.0=Tip 0: Qué puedes repetir la pista actual desde el inicio con [Control-Left click] o {right click] al botón de Rewind en el panel de Control o en la bandeja del sistema ? TipOfTheDay.1=Tip 1: Qué puedes repetir el álbum actual desde la primera pista con [Control-Left click] o {right click] al botón Anterior en el panel de Control o en la bandeja del sistema ? TipOfTheDay.2=Tip 2: Qué puedes añadir elementos aleatorois a la lista de reproducción (playlist) usando el botón ? en el editor de playlist ? TipOfTheDay.3=Tip 3: Qué puedes obtenerr carátulas de internet incluso detrás de un proxy usando la pestaña de Red em la vista de Configuración ? TipOfTheDay.4=Tip 4: Qué puedes guardar les carátulas obtenidas desde internet para acelerar la navegación en la vista de carátulas utilitzando la opción de precargar les carátulas en la pestaña de carátulas a la vista de configuración ? TipOfTheDay.5=Tip 5: Qué puedes ocultar las pistas no disponibles a la aplicación utilitzando la opción Mostrar solo dispositivos montados en la pestaña de opciones de la vista de configuración ? TipOfTheDay.6=Tip 6: Qué puedes reducir el tamaño de la colección para caràcteres asiáticos selecciondo UTF-16 como encodding en la Vista de Configuración / Pestaña Avanzado ? TipOfTheDay.7=Tip 7: Qué puedes arrastrar i soltar elementos de las vistas de árbol a las playlist del editor de playlist o del repositorio de playlist ? TipOfTheDay.8=Tip 8: Qué puedes escuchar el principio de las pistas usando el modo intro ? TipOfTheDay.9=Tip 9: Qué puedes configurar la duración de la atenuación en la vista de Preferencias / pestaña de Opciones ? TipOfTheDay.10=Tip 10: Qué puedes iniciar jajuk en modo reducido desmarcando la opción Mostrar jajuk al inicio en el area de noticación ? TipOfTheDay.11=Tip 11: Qué puedes controlar las principales funciones de jajuk usando solo el icono en el area de notificación (solo Linux y Windows) ? TipOfTheDay.12=Tip 12: Qué el aspecto (look and feel) de Jajuk es configurable en la vista de Preferencias / pestaña de Opciones ? TipOfTheDay.13=Tip 13: Qué puedes configurar el comportamiento del doble click y del drag & drop (push y play) en la vista de Preferencias / pestaña de Opciones ? TipOfTheDay.14=Tip 14: Qué las pistas "planificadas" de Jajuk son pistas que sonarán después de la selección actual ? TipOfTheDay.15=Tip 15: Qué la interfaz gráfica de Jajuk es completamente dockable y que se pueden reorganizar las vistas con drag and drop ? TipOfTheDay.16=Tip 16: Qué se puede obtener el número total de archivos y pistas seleccionando el nodo "colección" en las vistas física o lógica ? TipOfTheDay.17=Tip 17: Qué puedes obtener tags online con la función "Obtener tags online" en directorios de la vista física ? TipOfTheDay.18=Tip 18: Qué la barra de histórico de Jajuk (arriba de la ventana) muestra todas las pistas que sonaron anteriormente ? TipOfTheDay.19=Tip 19: Qué puedes hacer búsquedas rápidas usando el cuadro de búsqueda (arriba de la ventana) ? TipOfTheDay.20=Tip 20: Qué puedes reportar bugs o nuevas funcionalidades usando el agente de calidad (Ayuda -> Comunicar un problema) ? TipOfTheDay.21=Tip 21: Qué los DJs de Jajuk pueden crear playlists inteligentes siguiendo tus reglas ? TipOfTheDay.22=Tip 22: Qué puedes obtener las letras usando la "Vista de letras" ? TipOfTheDay.23=Tip 23: Qué la vista de Sugerencias muestra información de LAST.FM como artistas similares ? TipOfTheDay.24=Tip 24: Qué se puede añadir cualquier vista a una perspectiva usando la barra de menú de "Vistas" ? TipOfTheDay.25=Tip 25: Qué puedes establecer una imagen de fondo escogida en la vista de Preferencias / pestaña GUI ? TipOfTheDay.26=Tip 26: Qué puedes mostrar/esconder los dispositivos desmontados con un click en la barra de menu "Modos" ? TipOfTheDay.27=Tip 27: Qué puedes escoger el directorio para los datos de Jajuk (como un disco externo) para guardar tus datos y preferencias en cualquier ordenador (ver pestaña "Avanzado" en la vista de Preferencias) ? TipOfTheDay.28=Tip 28: Qué puedes añadir cualquier vista a cualquier perspectiva utilizando la barra de menu de "Vistss" ? TipOfTheDay.29=Tip 29: you can launch a web page in you default browser using this icon Image:launch_16x16.png/ TipOfTheDay.30=Tip 30: Jajuk supports web radio Image:webradio_32x32.png/ ]]>jajuk-1.9.6.orig/src/main/java/org/jajuk/i18n/jajuk.properties0000644000175000017500000015533711720500104024022 0ustar drazzibdrazzib Rating system page). Your previous ratings have been migrated to a 0 to 100 scale but we advice to reset all rates from the Preference view -> History tab (caution: all current ratings will be lost) #Write confirmation so replies are: yes / no / cancel Confirmation_exit=Do you really want to exit Jajuk? Confirmation_delete=Warning! You're about to delete the following file(s) from your disk, are you sure ? Confirmation_void_refresh=Warning! You're about to access a void device. Under Unix, make sure the device is mounted or you will loose jajuk information on this device. Are you sure? Confirmation_remove_device=Do you really want to remove this device? Confirmation_delete_cover=Do you really want to delete this cover from your disk ? Confirmation_delete_files=Do you really want to delete these files from your disk ? Confirmation_delete_dirs=Do you really want to delete these directories from your disk ? Confirmation_clear_history=Do you really want to clear the history? Confirmation_reset_ratings=Do you really want to reset all track ratings to zero ? Confirmation_refactor_files=Do you really want to rename these selected file(s) ? Confirmation_restore_all=A full views restore requires a Jajuk restart, do you want to quit now ? Confirmation_defaults_radios=This will erase all radio stations you have previously created, are you sure ? Confirmation_delete_empty_dirs=The following directories are empty. Do you want to delete them? Confirmation_file_overwrite=This file already exists. Do you want to overwrite this file? Confirmation_file_number=file(s) will be deleted. Confirmation_alarm_stop=Are you sure you want to stop this alarm? Confirmation_defaults=Note this will reset all tabs options to default values (and not only the current one), are you sure ? Confirmation_reset_preferences=Do you really want to reset tracks preferences ? Device_type.directory=Directory Device_type.file_cd=Music Files CD Device_type.audio_cd=Audio CD Device_type.extdd=External Hard Disk Device_type.player=Digital Audio Player Device_type.network_drive=Network Drive Device_type.remote=Remote (Not implemented) Perspective_Description_Simple=Simple Perspective_Description_Files=Files Perspective_Description_Tracks=Tracks Perspective_Description_Configuration=Config Perspective_Description_Statistics=Stats Perspective_Description_Help=Help Perspective_Description_Display=Display Perspective_Description_Albums=Albums Perspective_Description_Info=Information Perspective_Description_Playlists=Playlists Item_Playlist_File=Playlist Item_Track=Track Item_Album=Album Item_Artist=Artist Item_Genre=Genre Item_Device=Device Item_File=File Item_Directory=Directory Item_Year=Year Item_AlbumArtist=Album-Artist Property_id=Id Property_name=Name Property_type=Type Property_url=Url Property_mount_point=Mount Point Property_auto_refresh=Auto Refresh Property_auto_mount=Auto Mount Property_album=Album Property_style=Genre Property_author=Artist Property_album_artist=Album Artist Property_disc_number=Disc# Property_length=Length Property_year=Year Property_rate=Rate Property_files=Files Property_hits=Hits Property_filename=File Property_date=Date Property_added=Discovery date Property_parent=Parent directory Property_device=Device Property_directory=Directory Property_track=Track Property_size=Size (MB) Property_quality=Quality Property_hashcode=Hashcode Property_playlist_files=playlists Property_comment=Comment Property_order=Order Property_path=Full path Property_tracks=Tracks Property_file_date=File date Property_Format_Number=Number Property_Format_String=String Property_Format_Boolean=Boolean Property_Format_Float=Float Property_Format_Date=Date Property_Format_URL=Url Property_pf=Preference Property_tpt=Total play time (secs) Property_ban=Banned Property_disc_id=DiscID Language_desc_en=English Language_desc_fr=French Language_desc_de=German Language_desc_it=Italian Language_desc_sv=Swedish Language_desc_nl=Dutch Language_desc_zh=Chinese Language_desc_es=Spanish Language_desc_ca=Catalonian Language_desc_ko=Korean Language_desc_el=Greek Language_desc_ru=Russian Language_desc_gl=Galician Language_desc_cs=Czech Language_desc_pt=Portuguese #--- Error codes --- Error.000=Unknown error Error.005=Collection file parsing error Error.007=Error playing file, maybe MPlayer did not start playing until the timeout was reached for: Error.008=Error stopping file Error.009=Cannot read file Error.010=Cannot find a file associated with this item on a mounted device Error.011=Technical error when mounting the device or void device Error.012=Technical error when unmounting the device, it is probably being used by another application Error.013=Cannot remove the device: it is either mounted or currently refreshing Error.016=Cannot access specified device. Please enter device mount point. Ex: '/cdrom' under Unix,'e:' under MS Windows Error.017=Error parsing playlist Error.018=No accessible tracks can be found Error.019=An existing device already has this name Error.020=IO error copying file. The disk may be full Error.021=URL field is mandatory. Ex: 'd:\music' under MS Windows, '/home/foo/music' under Unix Error.022=Name field is mandatory. Ex: 'Hard drive', 'CD ROCK' Error.023=Cannot launch start-up track Error.024=Cannot write file Error.025=One of the files you want to read is on an unmounted device Error.026=Error registering players Error.027=Synchronization aborted Error.028=Error saving playlist Error.029=An existing device is a parent directory of this device, has the same path, or is a child directory Error.030=Too many connection failures. Jajuk has stopped searching for online covers Error.101=Device doesn't exist or is not reachable Error.102=Error Error.103=Error reading tag information Error.104=Error writing tag information Error.105=Resource Bundle key not found Error.106=Uncaught exception Error.107=Device already refreshing or synchronizing Error.108=Perspective file parsing error Error.109=Player or tag implementation class not reachable Error.110=This property name is reserved by the Jajuk internal system. Please choose another one Error.111=Device already mounted Error.112=Cannot mount device Error.113=Cannot store user configuration Error.114=Cannot read user configuration Error.118=Error processing event request Error.119=No history file or error parsing it Error.120=Cannot access the device: it is either not mounted, currently refreshing, or synchronizing Error.121=Device is in use and cannot be unmounted Error.122=Error in FIFO Error.123=Error setting theme Error.124=Jajuk is already running. Only one Jajuk instance can run at a time Error.125=Device already unmounted Error.126=Seeking not supported by this audio format Error.127=No novelties found within specified time limit. You can set the time limit in the preferences view Error.128=Current track is the very first one of the collection. No previous track is available Error.129=Error loading cover image Error.131=Cannot delete file Error.133=Your collection file was corrupted for an unknown reason. Jajuk managed to restore a backup file Error.134=Cannot rename file Error.135=File does not exist Error.136=Operation failed Error.137=Wrong format Error.138=Some files mapped by these tracks are located on unmounted devices and thus have not changed. Error.140=Invalid string: it should not contain & ' " < or > characters Error.141=This playlist is located on an unmounted or refreshing device and is not available Error.142=This playlist maps non-existing tracks or tracks located outside Jajuk known devices. These tracks have been ignored. Error.143=Device location not reachable Error.144=Error parsing DJ Error.145=Cannot commit DJ Error.146=The current organizer pattern is wrong.
    Valid items are: %artist (Artist name); %album_artist (Album Artist); %title (Track title); %album (Album name);
    %n (Track leading zero); %genre (track genre); %year (year); %disc (disc number)
    and the pattern must contain at least one slash Error.147=Some files could not be moved (see details for more informations) Error.148=Year field is unknown Error.149=Album field is unknown Error.150=Artist field is unknown Error.151=Track Title field is unknown Error.152=Track field is unknown Error.153=Genre field is unknown Error.154=Cannot rename file, check wrong character in file name or tags Error.155=Error in retagging files, check permissions Error.156=Void collection Error.157=Wrong DJ, please select or create a DJ from the Command view DJ button Error.158=DJ constraints cannot be respected or no track available Error.159=Associated ambience has been removed Error.160=File not moved, source and target filename are equals. Error.161=Cannot write to directory, check permissions Error.162=This custom property already exist Error.163=Error restoring default views Error.164=No accessible tracks can be found for ambience : Error.165=Wrong collection path, the directory cannot be found or is not writable Error.166=Empty album, cannot grab cover Error.167=Could not create report Error.168=No duplicate files found Error.169=Operation failed. Note that this operation requires an Internet connection to grab the radio station list. Error.170=Error playing webradio Error.171=No synchronization source yet defined for this device, set it using device configuration dialog (in Device view, click on the device). Error.172=Currently played file and its parent directories can not be deleted nor changed Error.173=Error encountered while deleting the following directories: Error.174=Error accessing Freedb website, check your network link Error.175=Operation canceled Error.176=Error generating playlist Error.177=Please enter a valid time in (HH24:MM:SS) format Error.179=Cannot open system file explorer, try to set a path to it in Preference view / Advanced tab Error.180=Error while copying files #Warnings Warning.0=MPlayer not found. Some audio and video formats (flac, wma, aac, mpg2 ... ) will be disabled. If MPlayer is already installed, please set manually its path in Preferences view/Advanced tab. Warning.1=Wrong MPlayer release, MPlayer1.0Pre8 and upper is required. Some audio formats will be disabled. Warning.2=Looks that somebody else is currently using the current jajuk collection. Last user to quit will overwrite configuration (options, rates...). Warning.3=Mplayer cannot be downloaded. If you are behind an HTTP proxy, please configure it in the Preferences view / Network tab and restart Jajuk. Warning.4=Mplayer is required to listen web radios Warning.5=Destination directory already exist, some files may be overwriten, are you sure ? Warning.6=No track available for playing (Tip: try to mount some devices or change ambience) Warning.7=Jajuk detected a need for deep refresh due to upgrade. Do you want to do it now ? (you can still do it at any time from the Devices view) #--- Strings by class --- ParameterView.0=History duration: ParameterView.2=Set the time in days to keep a history of tracks played. Enter -1 if you don't want any history and 0 if you want a permanent history. ParameterView.3=Clear history ParameterView.4=Clear history ParameterView.8=History/Ratings ParameterView.9=Play: ParameterView.10=Nothing ParameterView.11=No music will play when Jajuk starts ParameterView.12=Last track from the beginning ParameterView.13=Play the last played track from the beginning ParameterView.14=Random track ParameterView.15=Play a random track from the entire collection ParameterView.16=Track/radio : ParameterView.17=Select a file to played at start-up ParameterView.18=Select a file to played at start-up. Begin typing to see a filtered list. ParameterView.19=Start-Up ParameterView.26=Confirmations ParameterView.27=Before physically deleting a file ParameterView.28=Ask before physically deleting a file ParameterView.29=Before exiting Jajuk ParameterView.30=Ask before exiting Jajuk ParameterView.33=Options ParameterView.35=Hides tracks located on unmounted devices ParameterView.36=Restart when the end of the collection is reached ParameterView.37=Restart the entire collection when the end is reached in continue mode ParameterView.38=Language: ParameterView.42=Select the interface language ParameterView.43=Theme: ParameterView.44=Select a theme

    (May require a jajuk restart to be fully refreshed) ParameterView.46=Log level: ParameterView.47=Fatal ParameterView.48=Error ParameterView.49=Warning ParameterView.50=Info ParameterView.51=Debug ParameterView.52=Jajuk verbosity: Fatal: display only critical errors, Error: +display errors, Info: +display information messages, Warning: +display warnings, Debug: any message ParameterView.59=Intro begin position (%): ParameterView.60=Introduction position inside track in % from 0 (track beginning) to 99 (track end) ParameterView.61=Intro length (seconds): ParameterView.62=Introduction length (in seconds) ParameterView.85=Apply ParameterView.86=Restore defaults ParameterView.87=Preferences ParameterView.98=Patterns ParameterView.99=Perform a deep tag scan ParameterView.100=Force Jajuk to re-read the actual id3 tags.

    This can be useful to refresh tags modified using another program.

    ParameterView.101=Use parent directory name as album name ParameterView.102=If checked, the parent directory name will be used as the album name for tracks where the ID3 tag cannot be used. ParameterView.109=Preferences saved ParameterView.110=Preferences set to default ParameterView.111=Best of playlist size: ParameterView.112=Set the number of tracks in the best of playlist (from 1 to 100) ParameterView.113=Use regular expressions in filters ParameterView.114=Use Regular expressions (Regexp format) in table filters. Example: .*foo.* ParameterView.115=Advanced ParameterView.116=Backup collection file ParameterView.117=Check this if you want to backup your collection file to collection-.xml files ParameterView.118=Backup size (MB) ParameterView.119=Backup size (MB) ParameterView.120=Collection charset ParameterView.121=Collection charset. UTF-16 is optimized for Asian languages and UTF-8 is optimized for European languages. ParameterView.129=Time limit of novelties (days): ParameterView.130=Time limit of novelties in days: all tracks added within this number of days are shown in the novelties playlist ParameterView.131=Best of track ParameterView.132=Play one of your favorite tracks at start-up ParameterView.133=Novelty track ParameterView.134=Play a novelty from your collection at start-up ParameterView.135=Last track from the last position ParameterView.136=Play the last played track from the position it was stopped ParameterView.139=Network ParameterView.142=Proxy user name ParameterView.143=Proxy login name used for authentication ParameterView.144=Proxy host name ParameterView.145=Proxy host name or IP address ParameterView.146=Proxy port ParameterView.147=Proxy TCP-IP port (often 3128) ParameterView.148=Grab covers online ParameterView.149=Use auto cover to download album covers from the Internet (if required, configure your proxy in the network tab) ParameterView.150=Covers size ParameterView.151=Downloaded covers size ParameterView.155=Search accuracy. The higher the accuracy, the less you will get wrong cover images. ParameterView.156=Low accuracy (search all words) ParameterView.157=Medium (search grouped words) ParameterView.158=High (search mandatory grouped words) ParameterView.159=Covers ParameterView.160=Connection timeout (seconds) ParameterView.161=Connection timeout in seconds: A remote operation fails if a peer does not reply in this time. ParameterView.162=Transfer timeout (seconds) ParameterView.163=Data transfer timeout (seconds): A remote operation fails if the required data is not completely downloaded in this time. ParameterView.164=Before removing a device ParameterView.165=Ask before removing a device ParameterView.166=Shuffle covers ParameterView.167=Display a random cover ParameterView.169=Prefetch covers ParameterView.170=Prefetch all available covers when possible ParameterView.171=Before deleting a cover from disk ParameterView.172=Ask before deleting a cover from disk ParameterView.177=Number of visible planned tracks ParameterView.178=The number of planned tracks to be shown in the playlist ParameterView.179=Push on selection ParameterView.180=When checked, double clicking a track or selecting an item pushes into the queue ParameterView.181=Push on drag & drop ParameterView.182=When checked, collection tracks can be dragged and dropped into the playlist ParameterView.186=Reset ratings ParameterView.187=Reset all track ratings to zero ParameterView.188=Before clearing history ParameterView.189=Before resetting ratings ParameterView.190=Cross fade duration (seconds) ParameterView.191=The number of seconds to cross fade between tracks ParameterView.192=File organizer : ParameterView.193=Available patterns : %artist (Artist name);
    %album_artist (Album artist, if not defined artist name is used);
    %title (Track title); %album (Album name); %n (Track); %genre (track Genre);
    %year (year); %disc (disc number) ParameterView.194=Before organizing files ParameterView.195=Animation view : ParameterView.196=Enable Hotkeys ParameterView.197=Enable some keystrokes like F8 to work even when Jajuk has not the focus ParameterView.198=Some changes will be effective only at the next Jajuk start-up ParameterView.199=Scrobble my listening ParameterView.200=This option send informations to Last.fm ParameterView.201=Last.FM user name ParameterView.202=The username used on Last.FM ParameterView.203=Last.FM password ParameterView.204=The password used on Last.FM ParameterView.205=Mplayer arguments ParameterView.206=Additional MPlayer arguments like '-ao esd', '-ao arts' or '-novideo (to prevent playing videos)' for ie ParameterView.207=Jajuk configuration path ParameterView.208=Set the directory containing Jajuk configuration (default is user home directory) ParameterView.209=Jajuk configuration path has been changed for the current user (previous collection has been kept in the old location). Jajuk will now be closed and can be restarted. ParameterView.210=If cross fade doesn't work, try to add <-ao esd> under Gnome or <-ao arts> under KDE in the Sound engine additional arguments field (Preferences view / Advanced tab). ParameterView.211=Small only ParameterView.212=Small and medium ParameterView.213=Medium only ParameterView.214=Medium and large ParameterView.215=Large only ParameterView.216=Search using the artist name ParameterView.217=Search using the album name ParameterView.218=Search using the track name ParameterView.219=Environment variables ParameterView.220=Set environment variables used by the audio player (ARTS_SERVER under KDE or ESPEAKER under Gnome for ie). Format: var1=xx var2=yyy... #Respect English size for next item ParameterView.221=Catalog view page size (0: all in one) ParameterView.222=Set the number of albums per page in the catalog view. 0: show all covers in a single page. ParameterView.223=Fonts size ParameterView.224=Set text font size ParameterView.225=GUI ParameterView.226=Modes ParameterView.228=Show album popups ParameterView.229=Catalog view preferences ParameterView.233=Theme will be fully applied at next Jajuk startup ParameterView.234=Check for Jajuk updates ParameterView.235=Last.FM ParameterView.236=No Proxy ParameterView.237=HTTP proxy ParameterView.238=SOCKS proxy ParameterView.239=Proxy password ParameterView.240=Enable Last.FM information queries ParameterView.241=If checked, Jajuk will grab various information on albums and others from Last.FM website (see suggestion view) ParameterView.242=Mplayer path ParameterView.243=Set here the mplayer full path with executable (spaces allowed)
    Example: /Applications/MPlayer OSX.app/Contents/Resources/External_Binaries/mplayer_intel.app/Contents/MacOS/mplayer ParameterView.244=Discovery date = File date ParameterView.245=If checked, jajuk considers audio files system date as the discovery date
    Requires deep refreshes to be taken into account ParameterView.246=Perspective bar icons size (pixels) ParameterView.247=Destination path contains an existing Jajuk workspace. The workspace has been switched to this path for the current user (previous workspace has been kept in the old location). Jajuk will now be closed and can be restarted. ParameterView.248=Frame title : ParameterView.249=Reset preferences ParameterView.250=Reset user-defined preferences ParameterView.251=History successfully reseted ParameterView.252=Ratings and playtimes successfully reseted ParameterView.253=Preferences successfully reseted ParameterView.254=Use Windows short names ParameterView.255=[Windows 32 bits only] If checked, force mplayer to use audio file names in short windows way to fix on issue for some locales ParameterView.256=Standard cover file names ParameterView.257=Jajuk recognizes standard covers files whose filename contains this text (without extension). Several values separated by ';' can be provided. Example : "Folder;front". ParameterView.260=Save covers Windows Explorer friendly ParameterView.261=Save downloaded covers as folder.jpg/png/... so that the windows explorer uses them as directory icon. ParameterView.262=Use audio normalization ParameterView.263=Maximizes the volume without distorting the sound ParameterView.264=Disable any Internet access from Jajuk ParameterView.265=Disable any Internet access from Jajuk (LastFM, covers or lyrics download...). ParameterView.266=Drop played tracks from queue ParameterView.267=All tracks are dropped which are before the current played in the queue ParameterView.268=Proxy configuration ParameterView.269=Explorer executable path ParameterView.270=Path to the executable used as external file explorer ParameterView.271=Show Systray ParameterView.272=If checked, jajuk can be managed from the notification area (not all operating systems are supported) ParameterView.273=Mirrow Cover ParameterView.274=If checked, the cover will be tilted and mirrowed ParameterView.275=Track change notification : ParameterView.276=Select the type of notification at track change (a toast is a notification popup that appears briefly on the screen and disappears by itself) ParameterView.277=Notification pattern : ParameterView.278=This pattern set the text to be displayed by notifiers at track change ParameterView.279=Information pattern : ParameterView.280=This pattern set the text to be displayed in the information view (lower part of the screen) ParameterView.281=Minimize to tray ParameterView.282=If checked, Jajuk main main window will be shown in the systray only when minimized, no more in the taskbar Main.21=Confirmation Main.22=Checking/Downloading MPlayer Player.0=Waiting for audio line (occupied) Device.25=] refreshed in Device.27= new files Device.31=Sync. [ Device.33=Synchronization done in Device.35= created files ( Device.36= MB) Device.41=Sync. [ Device.42=] Copying [ Device.43= unreadable tags Device.44=Entering Device.45=Copying [ Device.46=Converting [ Device.47=] to [ FIFO.4=). Do you want to try to mount it ? FIFO.10=Now Playing: FIFO.13= Kbps FIFO.14=Now Playing Web Radio: HistoryItem.0=yy/MM/dd HH:mm DeviceWizard.0=Device configuration DeviceWizard.1=Device Type*: DeviceWizard.2=Device name*: DeviceWizard.3=Device location*: DeviceWizard.7=Perform an instant refresh DeviceWizard.8=Auto mount at start-up DeviceWizard.10=Synchronized with: DeviceWizard.11=Unidirectional synchronization DeviceWizard.12=All new files found on the source device are copied to this device. Nothing will be written to the source device. DeviceWizard.13=Bidirectional synchronization DeviceWizard.14=All new files found on one device are copied to the other DeviceWizard.43=Please choose a directory DeviceWizard.44=Device created DeviceWizard.45=Please give the device a name. Ex: CD A, Laptop... DeviceWizard.46=Please give device location. Ex: d:\music under Windows, /home/foo/music under Unix DeviceWizard.48=Check this if you want to perform an immediate refresh of the device (advised).

    Note this operation can take a while for large devices.

    DeviceWizard.49=Check this if you want to automatically mount the device when Jajuk starts up.

    Advised for directories on current hard disk, but not for CDs.

    DeviceWizard.50=Give interval in minutes for new files automatic search (0: no scan, 0.5 min is the minimum interval) DeviceWizard.51=Check this if you want to synchronize this device with another one DeviceWizard.52=Select a source device DeviceWizard.53=Refresh device every #limited string size DeviceWizard.54=min DeviceWizard.55=Wrong value : refreshing interval can be 0 or a number >= 0.5. JajukJMenuBar.0=File JajukJMenuBar.1=Open file JajukJMenuBar.3=Exit JajukJMenuBar.5=Properties JajukJMenuBar.6=Create custom property JajukJMenuBar.7=Remove custom property JajukJMenuBar.8=Views JajukJMenuBar.9=Modes JajukJMenuBar.10=Repeat JajukJMenuBar.11=Shuffle JajukJMenuBar.12=Continue JajukJMenuBar.13=Intro JajukJMenuBar.14=Help JajukJMenuBar.15=Help Contents JajukJMenuBar.16=About JajukJMenuBar.17=Restore views (current perspective) JajukJMenuBar.18=Device Wizard JajukJMenuBar.19=Report a bug or feature request JajukJMenuBar.20=Tip of the Day JajukJMenuBar.21=Configuration JajukJMenuBar.22=Preferences JajukJMenuBar.23=Show debug traces JajukJMenuBar.24=Only show available tracks JajukJMenuBar.25=Show view JajukJMenuBar.26=Restore views (all perspectives) JajukJMenuBar.27=Check for Jajuk updates JajukJMenuBar.28=Tools JajukJMenuBar.29=Smart JajukJMenuBar.30=Repeat all JajukJMenuBar.31=Karaoke # next two lines are only used in development/test mode, translation is therefore optional JajukJMenuBar.32=Call a full GC (test mode only) JajukJMenuBar.33=Perform a manual commit of the collection data (test mode only) PlaylistFileItem.1=Novelties PlaylistFileItem.2=New playlist PlaylistFileItem.3=Bookmarks PlaylistFileItem.4=Best Of PlaylistFileItem.5=Queue JajukFileChooser.0=File chooser SearchBox.0=Perform a search among tracks, artists, genres, directory... CommandJPanel.0=View play history CommandJPanel.1=[Ctrl-t] Repeat mode: Play tracks in a loop CommandJPanel.2=[Ctrl-h] Shuffle mode: Play randomly selected tracks CommandJPanel.3=Continue mode: Continue to play planned tracks when finished CommandJPanel.4=Intro mode: Play only a part of each track. Time and offset can be set in the Preferences view CommandJPanel.5=Play a shuffle selection from the entire collection CommandJPanel.6=Play your own favorite tracks CommandJPanel.8=[F9] Play previous track in current selection
    Right click replays current track
    Shift+click launches previous album
    Ctrl+click replays current album CommandJPanel.9=[F10] Play next track in current selection
    Shift+click launches next album CommandJPanel.10=[Alt-gr F9] Fast rewind in current track
    Shift+click for replay CommandJPanel.13=[Alt-gr F0] Fast forward in current track CommandJPanel.15=Click here to change the time display format CommandJPanel.16=Launch DJ selection CommandJPanel.17=Manage DJ CommandJPanel.18=Launch the default DJ selection CommandJPanel.19=Manage Ambiences CommandJPanel.20=Track by track CommandJPanel.21=Shuffle album by album CommandJPanel.22=Album by album CommandJPanel.23=Click to clear search CommandJPanel.24=Configure web radios CommandJPanel.25=Turn on the radio CommandJPanel.26=Repeat all mode: Play queue in a loop CommandJPanel.27=Karaoke mode, hide voices from played track (applies only to next track to be launched) InformationJPanel.5=Total queue time remaining [Nb of tracks remaining] InformationJPanel.6=Track bitrate InformationJPanel.7=Current track progression # %xxx are patterns, don't translate them ! InformationJPanel.8=%title by %artist on %album # Keep next label short InformationJPanel.9= AbstractPlaylistEditorView.0=Title AbstractPlaylistEditorView.1=Location AbstractPlaylistEditorView.2=Run this playlist AbstractPlaylistEditorView.3=Save this playlist AbstractPlaylistEditorView.4=Add an item to this playlist AbstractPlaylistEditorView.5=Remove item AbstractPlaylistEditorView.6=Move up AbstractPlaylistEditorView.7=Move down AbstractPlaylistEditorView.9=Erase this playlist AbstractPlaylistEditorView.10=Add a random track to this playlist AbstractPlaylistEditorView.15=Playlists AbstractPlaylistEditorView.17=You are about to update the following playlists: AbstractPlaylistEditorView.18=Track in queue AbstractPlaylistEditorView.19=Repeated track AbstractPlaylistEditorView.20=Planned track AbstractPlaylistEditorView.21=Playlist track AbstractPlaylistEditorView.22=Playlist saved AbstractPlaylistEditorView.27=Prepare Party AbstractPlaylistEditorView.28=folder created successfully in AbstractPlaylistEditorView.29=Playing track StatView.0=Others StatView.1=Genres StatView.2=No data available StatView.3=Others StatView.4=Size by device (GB) StatView.5=No data available StatView.7=Collection size by month StatView.8=Months StatView.9=Size (GB) StatView.10=No data available StatView.12=Total number of tracks by month StatView.13=Months StatView.14=Track number StatView.15=No data available StatView.16=Statistics StatView.24=Older CDScanView.0=CD label: CDScanView.1=CD label. Ex: CD1, ROCK... CDScanView.2=CD label. Ex: CD1, ROCK... CDScanView.3=CD Location: CDScanView.4=Location where the CD can be found. Ex: '/cdrom' under Unix, 'e:' under MS Windows... CDScanView.5=Location where the CD can be found. Ex: '/cdrom' under Unix, 'e:' under MS Windows... CDScanView.6=Scan CDScanView.12=CD Scanner CDScanView.18=Scans the CD and adds all music files into the collection CDScanView.19=Select CD location AbstractTreeView.0=Collapse all TracksTreeView.0=Tracks tree TracksTreeView.27=Collection TracksTreeView.31= tracks TracksTreeView.33=Create a report TracksTreeView.34=Get Tags Online TracksTreeView.35=Discovery date TracksTreeView.36=less than one week TracksTreeView.37=less than one month TracksTreeView.38=less than six months TracksTreeView.39=older TracksTreeView.40=less than one year TracksTreeView.41=less than two years TracksTreeView.42=less than five years TracksTreeView.43=less than ten years TracksTreeView.44=less than three months TracksTreeView.45=Year CoverView.2=Delete this cover from disk CoverView.3=Cover CoverView.4=Previous image from disk and/or the web if the auto-cover option is checked CoverView.5=Next image from the disk and/or the web if the auto-cover option is checked CoverView.6=

    Save cover with its original name

    With CTRL: Save cover as...

    CoverView.8=Use this cover as the default cover for this album CoverView.9=covers CoverView.10=Save cover as CoverView.11=Cover saved CoverView.12=Album CoverView.13=Title AnimationView.0=Animation FilesTreeView.0=Files tree FilesTreeView.3=Copy FilesTreeView.4=Cut FilesTreeView.5=Paste FilesTreeView.7=Delete FilesTreeView.14=Desynchronize FilesTreeView.15=Resynchronize FilesTreeView.16=Create Playlist FilesTreeView.17=Copy FilesTreeView.18=Cut FilesTreeView.28=Mount FilesTreeView.29=Unmount FilesTreeView.30=Force refresh FilesTreeView.31=Synchronize FilesTreeView.32=Test FilesTreeView.33=Create playlists FilesTreeView.40=Copy FilesTreeView.41=Cut FilesTreeView.42=Paste FilesTreeView.47=Collection FilesTreeView.52= files: FilesTreeView.53= GB FilesTreeView.54= MB FilesTreeView.55=Configure device FilesTreeView.59=Do you want to perform a fast or deep (read tags again) refresh ? FilesTreeView.60=Fast FilesTreeView.61=Deep FilesTreeView.62=Organize files TracksTableView.0=Tracks table TracksTableView.7=Play TracksTableView.8=Push TracksTableView.9=Play Shuffle TracksTableView.10=Play Repeat TracksTableView.11=Play Album TracksTableView.12=Play Artist TracksTableView.14=Properties TracksTableView.15=Bookmark TracksTableView.16=Push next AbstractTableView.0=Filter: AbstractTableView.1=Property to filter AbstractTableView.3=Value used by the filter AbstractTableView.4=Apply filter AbstractTableView.5=Clear the filter AbstractTableView.6=Apply an advanced filter AbstractTableView.7=contains: AbstractTableView.8=Any AbstractTableView.10=(Not available) AbstractTableView.11=Make the table editable AboutView.7=About AboutView.8=License AboutView.9=System AboutView.10=About AboutView.11=Copyright 2003-2011
    Jajuk team" PhysicalPlaylistRepositoryView.0=Play PhysicalPlaylistRepositoryView.1=Edit PhysicalPlaylistRepositoryView.2=Save as PhysicalPlaylistRepositoryView.3=Delete PhysicalPlaylistRepositoryView.4=Properties PhysicalPlaylistRepositoryView.6=Physical Playlists PhysicalPlaylistRepositoryView.8=Smart PhysicalPlaylistRepositoryView.9=Playing Queue PhysicalPlaylistRepositoryView.10=Current queue: drag and drop tracks to play PhysicalPlaylistRepositoryView.11=New PhysicalPlaylistRepositoryView.12=New playlist: drag and drop tracks add them to the playlist PhysicalPlaylistRepositoryView.13=Bookmarks PhysicalPlaylistRepositoryView.14=Bookmark playlist: drag and drop tracks to bookmark PhysicalPlaylistRepositoryView.15=Best of PhysicalPlaylistRepositoryView.16=Best of playlist: contains the most listened to tracks PhysicalPlaylistRepositoryView.17=Novelties PhysicalPlaylistRepositoryView.18=Novelties playlist: contains the newest tracks PhysicalPlaylistRepositoryView.19=Prepare Party FilesTableView.0=Files table FilesTableView.15=Play Directory #Dev: do not use ID = 16, next label is FilesTableView.17 DeviceView.0=Add a device DeviceView.1=Remove an unmounted device (does not delete anything from disk) DeviceView.2=Selected device properties DeviceView.3=Mount selected device DeviceView.4=Unmount selected device DeviceView.5=Test selected device availability DeviceView.6=Force refresh of selected device DeviceView.7=Synchronize selected device DeviceView.8=Mount DeviceView.9=Unmount DeviceView.10=Test DeviceView.11=Force refresh DeviceView.12=Synchronize DeviceView.13=Remove device DeviceView.14=Configure DeviceView.17=New DeviceView.18=Add a device DeviceView.21=This device is available DeviceView.22=This device cannot be accessed DeviceView.23=Devices JajukWindow.1=Unmute JajukWindow.2=Mute JajukWindow.3=Jajuk JajukWindow.4=Exit JajukWindow.5=About Jajuk JajukWindow.6=Play Shuffle JajukWindow.7=Play Best Of JajukWindow.10=Pause JajukWindow.12=Resume JajukWindow.13=Previous JajukWindow.14=Next JajukWindow.15=Play Novelties JajukWindow.16=Finish album JajukWindow.17=Jajuk: Advanced Jukebox JajukWindow.18=Ready to play JajukWindow.19=[F8] Mute/Unmute
    Use the mouse wheel to set the volume JajukWindow.21=Exit JajukWindow.22=About Jajuk JajukWindow.23=Play random tracks from the collection JajukWindow.24=Play the most popular tracks from the collection JajukWindow.26=[Ctrl-p] Pause/Resume JajukWindow.27=[Ctrl-s] Stop JajukWindow.31=Play the newest tracks from the collection JajukWindow.32=Finish playing the current album JajukWindow.33=[Ctrl-UP/DOWN] Volume JajukWindow.34=Position JajukWindow.35=Playing: JajukWindow.36=Current Ambience: JajukWindow.37=No Ambience set #Do not use JajukWindow.38, next is JajukWindow.39 JajukWindow.39=Now playing JajukWindow.40=Extra Tags Configuration JajukWindow.41=Opens a dialog to configure the activated extra tags JajukDonate.1=Donate JajukDonate.2=Jajuk project infrastructure needs funds, learn more on our budget page. JajukDonate.3=Budget JajukDonate.4=If you want to support Jajuk, please make a donation. ActiveTagsWizard.1=Available Tags ActiveTagsWizard.2=Activated Tags ActiveTagsWizard.3=This configures the extra-tags you want Jajuk to display. The informations are read directly from the audio files (from id3 tags for example). If you activate a new tag, a deep refresh is done. This can take some minutes depending on the size of your collection. SimpleDeviceWizard.0=Quick Device Creation FirstTimeWizard.0=Quick start FirstTimeWizard.1=


    Welcome! This wizard assists you in building your music collection

    FirstTimeWizard.2=Please select your music location FirstTimeWizard.4=Show help right now FirstTimeWizard.5=Please choose a directory FirstTimeWizard.6=Advanced preferences FirstTimeWizard.7=Set Jajuk workspace directory: FirstTimeWizard.8=Selected directory: FirstTimeWizard.9=None HelpView.2=Help DownloadManager.0=Jajuk needs your HTTP proxy password to grab covers.
    If you don't want them, please change your settings in the Covers tab of the Preferences view.
    If you don't have any proxy, please change your settings in the Network tab of the Preferences view. DownloadManager.1=Password required PropertiesWizard.0=Item properties PropertiesWizard.1=Property PropertiesWizard.2=Value PropertiesWizard.3=Editable? PropertiesWizard.4=Link PropertiesWizard.6=Selection PropertiesWizard.7=Type PropertiesWizard.8=Successfully updated property PropertiesWizard.9=No editable property for this selection PropertiesWizard.10=properties have been set PropertiesWizard.11=Writing tag to: PropertiesWizard.12=Link to given element properties details NewPropertyWizard.0=Create Custom Property NewPropertyWizard.3=(*)Type NewPropertyWizard.4=Format NewPropertyWizard.5=Default Value CustomPropertyWizard.0=(*)Item CustomPropertyWizard.1=(*)Custom Property Name RemovePropertyWizard.0=Remove Custom Property QualityFeedbackWizard.20=A new window to submit your ticket will be now opened in your external browser. Your last anonymized traces have already been pushed to your clipboard, Please paste them in the description field if it is a bug report (this will greatly increase chances for us to fix your problem). IncRateAction.0=Increase rating of the current track SplashScreen.0=Initial checkups SplashScreen.1=Loading collection SplashScreen.2=Starting music engine SplashScreen.3=Launching graphical interface CatalogView.0=Albums Catalog #Note: CatalogView.2 label musn't be much larger than in English for correct display in 800x600 CatalogView.2=Display albums without cover CatalogView.3=Refresh the catalog CatalogView.4=Thumbnail size: CatalogView.5=Created thumbnail for: CatalogView.7=Select a cover CatalogView.8=No cover found CatalogView.9=Previous CatalogView.10=Next CatalogView.11=Page: CatalogView.12=Display previous thumbnails page CatalogView.13=Display next thumbnails page CatalogView.14=Select thumbnails page to display CatalogView.15=Thumbnails size: CatalogView.16=albums CatalogView.17=/page CatalogView.18=Cover selection CatalogView.19=Rebuild thumbnails CatalogView.20=Show detail CatalogView.21=Display all albums CatalogView.22=Display albums with cover WikipediaView.0=Wikipedia WikipediaView.1=Select Language: WikipediaView.3=No result found WikipediaView.5=Search on Artist name WikipediaView.6=Search on Album name WikipediaView.7=Search on title name WikipediaView.8=Loading WikipediaView.9=Failed to load information from Wikipedia WikipediaView.10=Cannot search for unknown artist. TipOfTheDayView.0=Tip of the Day TipOfTheDayView.1=Did you know...? TipOfTheDayView.2=Show at Start-Up? CDDBWizard.0=Accept CDDBWizard.1=File name CDDBWizard.2=Current Track Title CDDBWizard.3=Current Album Title CDDBWizard.4=Proposed Track Title CDDBWizard.5=Proposed Album Name : CDDBWizard.6=Done! Found CDDBWizard.7=possible matches CDDBWizard.12=No match found! CDDBWizard.14=This directory does not contain any files CDDBWizard.16=Genre: CDDBWizard.17=Found exact match! CDDBWizard.18=Matches CDDBWizard.19=Get Tags Online RefactorWizard.0=File moved : DigitalDJWizard.0=Select the new DJ mode DigitalDJWizard.1=Programming based on transitions (ROCK -> POP) DigitalDJWizard.2=Programming based on proportions (20% JAZZ, 30% ROCK) DigitalDJWizard.3=Programming based on ambience (Soft, Party...) DigitalDJWizard.4=Digital DJ Wizard DigitalDJWizard.5=DJ general configuration DigitalDJWizard.6=DJ name (*) DigitalDJWizard.8=Minimum number of stars: DigitalDJWizard.9=Cross fade (seconds): DigitalDJWizard.10=Tracks played only once DigitalDJWizard.11=Drop DigitalDJWizard.12=From Genres DigitalDJWizard.13=To Genres DigitalDJWizard.14=Genres selection (multiple selections allowed) DigitalDJWizard.15=Number of tracks DigitalDJWizard.16=Do you want to... DigitalDJWizard.17=Create a new DJ? DigitalDJWizard.18=Change an exiting DJ? DigitalDJWizard.19=Delete a DJ? DigitalDJWizard.20=New Transition-based DJ #limited string size DigitalDJWizard.21=Remove #limited string size DigitalDJWizard.22=Origin #limited string size DigitalDJWizard.23=Destination #limited string size DigitalDJWizard.24=Nb DigitalDJWizard.26=Please create at least one transition #limited string size DigitalDJWizard.27=Genres selection #limited string size DigitalDJWizard.28=% DigitalDJWizard.29=New Proportion-based DJ DigitalDJWizard.30=Please create at least one proportion DigitalDJWizard.31=New Ambience-based DJ DigitalDJWizard.32=New DigitalDJWizard.33=Create a new ambience DigitalDJWizard.34=Delete DigitalDJWizard.35=Delete selected ambience DigitalDJWizard.36=Ambience name DigitalDJWizard.37=Name DigitalDJWizard.38=Please create at least one ambience DigitalDJWizard.39=Please fill up ambience name and select ambience genres DigitalDJWizard.40=Please select a DJ DigitalDJWizard.41=Please provide a DJ name DigitalDJWizard.42=A DJ with this name already exists DigitalDJWizard.43=DJ Change DigitalDJWizard.44=Select the DJ to configure DigitalDJWizard.45=Action selection DigitalDJWizard.46=DJ type selection DigitalDJWizard.47=Please select or create an ambience DigitalDJWizard.48=General Attributes DigitalDJWizard.49=Please fill up DJ general attributes DigitalDJWizard.50=Please define proportions DigitalDJWizard.51=DJ Removal DigitalDJWizard.52=Please define transitions DigitalDJWizard.53=Minimum number of rating stars for tracks in selection (1: all tracks) DigitalDJWizard.54=Cross fade duration between tracks DigitalDJWizard.55=If checked, selection will contain each track only once DigitalDJWizard.56=Ambiences Wizard DigitalDJWizard.57=Manage ambiences DigitalDJWizard.58=Ambience selection: DigitalDJWizard.59=Sum of all proportions should be < 100 % DigitalDJWizard.60=Existing ambience name DigitalDJWizard.61=Remove DJ #limited string size DigitalDJWizard.62=Defaults DigitalDJWizard.63=Add default ambiences DigitalDJWizard.64=Any DigitalDJWizard.66=Default Ambience Selection (an ambience is a set of genres, see manual) DigitalDJWizard.67=Limit number of tracks to queue DigitalDJWizard.68=Maximum number of tracks to queue PreparePartyWizard.1=Prepare Party PreparePartyWizard.2=Select source for tracks PreparePartyWizard.3=First define your party's tracks PreparePartyWizard.4=Select limits PreparePartyWizard.5=Please define constraints PreparePartyWizard.6=DJs PreparePartyWizard.7=Ambiences PreparePartyWizard.8=Playlists PreparePartyWizard.9=Random Tracks PreparePartyWizard.10=Max. tracks PreparePartyWizard.11=How many tracks to include at maximum. PreparePartyWizard.12=Max. size (MB) PreparePartyWizard.13=How many many megabyte of data you want to create at maximum. PreparePartyWizard.14=Max. length (Minutes) PreparePartyWizard.15=How many long the resulting party should be at maximum. PreparePartyWizard.16=Restrict type PreparePartyWizard.17=Choose to only use one type of audio files. This can be useful, if a audio player only supports certain types of media. PreparePartyWizard.18=Select location PreparePartyWizard.19=Select the location where the files for the party are stored. A subdirectory is created for the files. PreparePartyWizard.20=Please select the target location. PreparePartyWizard.21=Selected directory: PreparePartyWizard.22=Please select the target directory. PreparePartyWizard.23=Files were copied in PreparePartyWizard.24=Best Of Playlist PreparePartyWizard.25=Novelties Playlist PreparePartyWizard.26=Normalize filenames PreparePartyWizard.27=Normalize filenames to replace foreign characters so that the file is portable across operating systems and different encodings PreparePartyWizard.31=Target location: PreparePartyWizard.32=Queued files PreparePartyWizard.33=Bookmarked files PreparePartyWizard.34=Try to convert other media types PreparePartyWizard.35=Uses the external tool 'pacpl - Perl Audio Converter' for converting audio files if required PreparePartyWizard.36= file(s) could not be converted to the selected media format. PreparePartyWizard.37=(requires PACPL, see Perl Audio Converter) PreparePartyWizard.38=Configure conversion settings PreparePartyWizard.39=Please define the command to start the Perl Audio Converter.
    On Linux this is often just "pacpl" or "perl <install-location>/pacpl.
    On Windows this is usually "perl <install-location>\pacpl PreparePartyWizard.40=Configure... Ambience.0=Rock/Pop Ambience.1=Rap Ambience.2=HardRock Ambience.3=Techno Ambience.4=Electro Ambience.5=Classical Ambience.6=Soft Ambience.7=Party Ambience.8=Jazz Ambience.9=World Ambience.10=Others Ambience.11=Folk/Oldies Ambience.12=Inde Ambience.13=Latin DebugLogAction.0=Debug traces listing DebugLogAction.1=Refresh CopyClipboardAction.0=Copy address to clipboard LaunchInBrowserAction.0=Launch address in default browser ReportAction.0=Report successfully created ReportAction.1=Jajuk Music Report ReportAction.2=Please consider the environment and do not print unless absolutely necessary ReportAction.3=Albums list ReportAction.4=Tracks per Album ReportAction.5=Artists list ReportAction.6=Albums per artists ReportAction.7=Genre list ReportAction.8=Albums per genre ReportAction.9=Artists/ albums per genre ReportAction.10=Directories list ReportAction.11=Files per directory ReportAction.12=File name ReportAction.13=Track name ReportAction.14=Devices list ReportAction.15=Directories per device ReportAction.16=Directories/ files ReportAction.17=collection ReportAction.18=Artists/ albums/ tracks per style ReportAction.19=Jump to: ActionMove.0=Paste ActionRefresh.0=Force refresh ActionRefresh.1=Refreshing directory RenameAction.0=Rename RenameAction.1=Please enter the new name for this file: RenameAction.2=Please enter the new name for this directory: NewFolderAction.0=New Folder NewFolderAction.1=Please enter the new Folder Name: NewFolderAction.2=Folder with the same name already exists. LyricsView.0=Lyrics LyricsView.1=No lyrics, internet access disabled, use the Configuration menu to enable it. LyricsView.2=Enter lyrics edit mode LyricsView.3=Exit lyrics edit mode LyricsView.4=Save lyrics LyricsView.5=Delete lyrics ActionDelete.0=Files deleted ActionDelete.1=Directories deleted FindDuplicateTracksAction.0=No duplicate tracks found. FindDuplicateTracksAction.1=Duplicate tracks found FindDuplicateTracksAction.2=Find duplicate tracks FindDuplicateTracksAction.3=List of duplicate tracks found FindDuplicateTracksAction.4=Select all duplicate tracks RefreshDialog.0=Preparing device refresh... RefreshDialog.1=Refreshing device RefreshDialog.2=Refreshing device: RefreshDialog.3=Cleaning up old files RadioWizard.0=Please select or create a web radio RadioWizard.1=Manage web radios RadioWizard.2=New RadioWizard.3=Delete RadioWizard.4=Defaults RadioWizard.5=A web radio with this name already exist RadioWizard.6=Web Radio name RadioWizard.7=Web Radio Wizard RadioWizard.8=URL RadioWizard.9=Name RadioWizard.10=Wrong URL RadioWizard.11=Name and URL are mandatory UpdateManager.0=A new Jajuk release ( UpdateManager.1=) has been detected, you can download it from http://jajuk.info UpdateManager.2=No available new release found so far SuggestionView.0=Suggestions SuggestionView.1=Preferred SuggestionView.2=Newest SuggestionView.3=Others albums SuggestionView.4=Similar artists SuggestionView.5=Rarely listen SuggestionView.7=Nothing to display

    Last.FM information is displayed only if:
    • A track is playing
    • Playing track artist is known (correct tag)
    • The "Enable Last.FM information queries" option is checked in Preferences view / Last.FM tab
    • The "Disable any Internet access from Jajuk" option is not checked in Preferences view / Network tab
    • The computer running Jajuk has connectivity to the Internet
    AbstractThumbnail.0=Open LAST.FM page AlbumsTableView.0=Albums table AlbumsTableView.1=Nb of tracks AlarmClock.0=Set alarm #Next value : 6 AlarmDialog.0=Time (HH24:MM:SS) AlarmDialog.1=Hour AlarmDialog.2=Minutes AlarmDialog.3=Seconds AlarmDialog.4=Alarm action AlarmDialog.5=Select alarm action #Next value : 11 ShowPropertiesAction.0=Display item properties QueueView.1=Void the queue QueueView.2=Scroll table automatically to the current played track JajukSlimWindow.0=Show/hide Jajuk slimbar JajukFullscreen.0=Enable/Disable fullscreen player BanSelectionAction.0=Ban BanSelectionAction.1=Ban the item so it will never be selected again UnBanSelectionAction.0=Pardon UnBanSelectionAction.1=Pardon item(s) so they can be proposed again OpenExplorerAction.0=Open with explorer OpenExplorerAction.1=Open the directory using an external explorer program Preference.0=Set a personal preference for the current track
    It is taken into account for final rate computation Preference.1=Junk Preference.2=Poor Preference.3=Average Preference.4=Good Preference.5=Excellent Preference.6=Classic Preference.7=Preferences... Preference.8=No preference ArtistView.0=Artist view Notificator.NONE=None Notificator.TOAST=Toast Notificator.BALLOON=Balloon Notificator.track_change.webradio_title=Web radio launched : Notificator.track_change.track_title=Track launched : SyncTreeTableAction.0=Synchronize tree and table view SyncTreeTableAction.1=Synchronize tree and table views
    When used against a tree view, selecting an item in a table view will expand and scroll the item in tree.
    When used in a table view, selecting an item in a tree view will filter the table accordingly. TipOfTheDay.0= Tip 0: you can replay the current track from the beginning with [Shift+click] on the Rewind button TipOfTheDay.1= Tip 1: you can replay the current album from its first track with [CTRL+click] on the "Play previous" button TipOfTheDay.2= Tip 2: you can add shuffle items to playlists using the ? button in the playlist editor TipOfTheDay.3= Tip 3: you can get covers online even behind proxy server using the Network tab of Preferences view TipOfTheDay.4= Tip 4: Jajuk comes with a slimbar (button at right upper side of the menu) to control playing while taking only few desktop space TipOfTheDay.5= Tip 5: you can hide unavailable tracks by selecting the "Only show available tracks" option TipOfTheDay.6= Tip 6: you can perform almost any Jajuk function using the keyboard TipOfTheDay.7= Tip 7: you can drag and drop items from tree views to the playlist editor and playlist repository TipOfTheDay.8= Tip 8: you can listen to track introductions using intro mode TipOfTheDay.9= Tip 9: you can configure cross-fade duration in Preferences view TipOfTheDay.10= Tip 10: Jajuk can be used as an advanced alarm clock using the Alarm feature available from the Tools menu TipOfTheDay.11= Tip 11: you can control Jajuk main functions using only the tray (Linux & Windows) TipOfTheDay.12= Tip 12: the Jajuk theme is configurable in the GUI tab of Preferences view TipOfTheDay.13= Tip 13: you can configure double-click and drag and drop behavior (push and play) in the Options tab of Preferences view TipOfTheDay.14= Tip 14: Jajuk "Planned" tracks are tracks that will be played after the current track selections TipOfTheDay.15= Tip 15: Jajuk graphical interface is fully dockable and you can drag and drop views to reorganize them TipOfTheDay.16= Tip 16: you can get the total number of files and tracks by selecting the "collection" node in Files or Tracks Tree Views TipOfTheDay.17= Tip 17: you can get tags online with the "Get tags online" function on directories in the Files or Track Tree Views TipOfTheDay.18= Tip 18: the Jajuk history bar (top middle of the window) displays all tracks previously played TipOfTheDay.19= Tip 19: you can perform quick searches using the Search box (bottom of the window) TipOfTheDay.20= Tip 20: you can report bugs or feature requests using the quality agent (Help, Report an issue) TipOfTheDay.21= Tip 21: Jajuk DJ can create intelligent playlists following your rules TipOfTheDay.22= Tip 22: you can get tracks lyrics using the "Lyrics view" TipOfTheDay.23= Tip 23: the Suggestions view displays LAST.FM information like similar artists TipOfTheDay.24= Tip 24: you can ban a track you don't like from the slim bar or the control panel TipOfTheDay.25= Tip 25: you can show/hide unmounted tracks in one click in the "Configuration" menu bar TipOfTheDay.26= Tip 26: you can now choose directory for Jajuk data (like an external disk) to keep your data and preferences on any computer (see "Advanced" tab in Preference view) TipOfTheDay.27= Tip 27: you can add any view in any perspective using the "Views" menu bar TipOfTheDay.28= Tip 28: you can launch a wikipedia page in you default browser using the "Launch address in default browser" icon Image:launch_16x16.png TipOfTheDay.29= Tip 29: Jajuk supports web radios Image:webradio_32x32.png TipOfTheDay.30= Tip 30: Jajuk can be remote-controlled by using D-Bus if available on the current platform (i.e. not on Windows). This allows to use multimedia keys on the keyboard to control Jajuk. Look at the online manual for more information. ]]> jajuk-1.9.6.orig/src/main/java/org/jajuk/i18n/jajuk_ca.properties0000644000175000017500000014722311720500104024460 0ustar drazzibdrazzib Rating system page). Les teves anteriors valoracions han estat migrades a una escala de 0 a 100 però és aconsellable resetajar-les des de Preference view -> History tab (atenció: totes les valoracions es perdrà) #Write confirmation so replies are: yes / no / cancel Confirmation_exit=Vols sortir realment de Jajuk ? Confirmation_delete=Atenció ! estàs a punt d'esborrar físicament el(els) següent(s) fitxers del teu disc: Confirmation_void_refresh=Atenció ! Estàs a punt d'actualitzar un dispositiu buit que serà netejat. En Unix, fixat-hi bé que el dispositiu estigui montat. Estàs segur ? Confirmation_remove_device=Realment vols eliminar aquest dispositiu ? Confirmation_delete_cover=Vols realment esborrar definitivament aquesta caràtula del disc ? Confirmation_delete_files=Vols realmente esborrar aquests arxius del disc ? Confirmation_delete_dirs=Vols realment esborrar aquests directoris del disc ? Confirmation_clear_history=Vols realment netejar l'històric ? Confirmation_reset_ratings=Vols realment inicialitzar les puntuacions de pista a zero ? Confirmation_refactor_files=Vols realment renombrar el(els) següent(s) fitxers ? Confirmation_restore_all=Una restauració de les vistas necessita reiniciar Jajuk, vols sortir ? Confirmation_defaults_radios=S'esborraran totes les emisores de ràdio que has creat prèviament, estàs segur ? Confirmation_delete_empty_dirs=Els següents directoris estan buits. Vols esborrar-los ? Confirmation_file_overwrite=Aquest arxiu ja existeix. Vols sobreescriure aquest arxiu ? Confirmation_file_number=arxiu(s) seran esborrats. Confirmation_alarm_stop=Estàs segur que vols parar aquesta alarma ? Confirmation_defaults=Això tornarà a les opcions per defecte totes les pestanyes ( no només aquesta) , estàs segur ? Confirmation_rebuild_thumbs=Això recrearà les miniatures de tots els teus àlbums, pot durar alguns minuto per a grans col·leccions. estàs segur ? Confirmation_reset_preferences=Segur que vols resetejar les preferències de pistes ? Device_type.directory=Directori Device_type.file_cd=CD de Fitxers Musicals Device_type.audio_cd=CD Audio Device_type.extdd=Disc Dur Extern Device_type.player=Reproductor Digital Device_type.network_drive=Unitat de xarxa Device_type.remote=Remot (No implementat) Perspective_Description_Files=Arxius Perspective_Description_Tracks=Pistes Perspective_Description_Configuration=Configuració Perspective_Description_Statistics=Estadístiques Perspective_Description_Help=Ajuda Perspective_Description_Display=Visualització Perspective_Description_Albums=Àlbums Perspective_Description_Info=Informació Perspective_Description_Playlists=Playlists Item_Playlist_File=Playlist Item_Track=Pista Item_Album=Album Item_Artist=Autor Item_Genre=Estil Item_Device=Dispositiu Item_File=Arxiu Item_Directory=Directori Property_id=Id Property_name=Nom Property_type=Tipus Property_url=Url Property_mount_point=Punt de Montatge Property_auto_refresh=Auto Refrescar Property_auto_mount=Auto Montar Property_album=Album Property_style=Génere Property_author=Artista Property_length=Longitud Property_year=Any Property_rate=Puntuació Property_files=Arxius Property_hits=Hits Property_filename=Arxiu Property_date=Data Property_added=Descobriment Property_parent=Directori pare Property_device=Dispositiu Property_directory=Directori Property_track=Pista Property_size=Tamany (Mb) Property_quality=Qualitat Property_hashcode=Hashcode Property_playlist_files=playlists Property_comment=Comentari Property_order=Pista Property_path=Path Property_tracks=Pistes Property_Format_Number=Número Property_Format_String=String Property_Format_Boolean=Boolean Property_Format_Float=Float Property_Format_Date=Date Property_Format_URL=Url Property_pf=Preferència Property_tpt=Temps total de reproducció (segs) Property_ban=Bloquejat Language_desc_en=Anglés Language_desc_fr=Francés Language_desc_de=Alemany Language_desc_it=Italià Language_desc_sv=Suec Language_desc_nl=Neerlandés Language_desc_zh=Xinés Language_desc_es=Espanyol Language_desc_ca=Català Language_desc_el=Grec Language_desc_ru=Rus Language_desc_gl=Gallec #--- Error codes --- Error.000=Error desconegut Error.005=Error al parsejar el fitxer de la col·lecció. Error.007=Error reproduïnt el fitxer, pot ser que MPlayer no comencés dintre del timeout, timeout: Error.008=Error detenint fitxer Error.009=No es pot llegir el fitxer Error.010=No es pot trobar un fitxer associat amb aquest element en cap dispositiu montat Error.011=Error tècnic al montar el dispositiu o dispositiu buit Error.012=Error tècnic al desmontar el dispositiu, probablement l'utilitzi altre aplicació Error.013=No es pot esborrar el dispositiu: Està actualment montat o actualitzant-se Error.016=No es pot accedir al dispositiu especificat, si et plau, entra el punt de montatge. Ex: '/cdrom' a Unix,'e:' a MS Windows Error.017=Error analitzant la playlist Error.018=No es troba cap pista accessible Error.019=Existeix un dispossitiu amb aquest nom Error.020=Error de E/S, verifica l'espai en disc Error.021=El camp Url és obligatori. Ex: 'd:\music' a MS Windows, '/home/foo/music' a Unix Error.022=El camp Nom és obligatori. Ex: 'Disc Dur', 'CD ROCK' Error.023=No es pot llençar la pista inicial Error.024=No es pot escriure el fitxer Error.025=Un dels fitxers que vols llegir està en un dispositiu desmontat Error.026=Error registrant reproductors Error.027=Sincronització abortada Error.028=Error gravant playlist Error.029=Un dispositiu existent és un directorio para d'aquest dispositiu, te el mateix path o és un directori fill Error.030=Massa connexions fallades, Jajuk ha parat de buscar caràtulas a la xarxa Error.101=El dispossitiu no existeix o no està disponible Error.102=Error Error.103=Error llegint información de tags Error.104=Error escribint informació de tags Error.105=Resource Bundle key no trobada Error.106=Excepció no capturada Error.107=El dispositiu ja s'està refrescant o sincronitzant Error.108=Error a l'anàlisi del fitxer de perspectiva Error.109=Reproductor o classe de implementació de tag no accessible Error.110=Aquest nom de propietat està reservat per Jajuk internal system, si et plau, tria un altre nom Error.111=Dispositiu ja montat Error.112=No es pot montar el dispositiu Error.113=No es pot guardar la configuració de l'usuari Error.114=No es pot llegir la configuració de l'usuari Error.118=Error processant petició d'event Error.119=Error analitzant fitxer d' historial o no existeix Error.120=No se puede acceder al dispositivo : està montat, refrescant-se o be sincronitzant-se Error.121=El dispositiu està en us i no pot ésser desmontat Error.122=Error en FIFO Error.123=Error establint tema Error.124=Otra sessió trobada. Només es pot llençar una instància de Jajuk a la vegada Error.125=Dispositiu ja montat Error.126=Cerca no soportada per aquest format d'audio Error.127=No hi ha novetats durant temps especificat, el pots canviar a la vista de preferències Error.128=Aquesta pista és la primera de la col·lecció, no hay pistas anteriores Error.129=Error carregant imatge de caràtula Error.131=No es pot es borrar el fitxer Error.133=L'arxiu de la col.lecció està corrupte per una raó desconeguda, jajuk s'encarregarà de restaurar un fitxer de backup Error.134=No es pot renombrar l'arxiu Error.135=L'arxiu no existeix Error.136=Operació fallida Error.137=Format Erroni Error.138=Alguns arxius referenciats per aquestes pistes estàn localitzades en un despositiu desmuntat i no canviaran. Error.140=Cadena errònia: no hauria de contenir els caràcteres & ' " < o > Error.141=Aquesta playlist està situada en un dispositiu desmontat, pel que no estarà disponible Error.142=Aquesta playlist conté algunes pistes fora de dispositius coneguts que seràn ignorades Error.143=La localització del dispositiu no està disponible Error.144=Error parsejant DJ Error.145=No es pot fer commit DJ Error.146=El patró actual és incorrecte.
    Items vàlids són: %artist (Artist name); %title (Track title); %album (Album name);
    %n (Track leading zero); %genre (track genre); %year (Year)
    y el patró ha de contenir al menys una barra Error.147=Alguns arxius no poden ser moguts (veure detalls per més informació) Error.148=El camp Year és desconegut Error.149=El camp Album és desconegut Error.150=El camp Artist és desconegut Error.151=El camp TrackName és desconegut Error.152=El camp TrackOrder és desconegut Error.153=El camp Style és desconegut Error.154=No es pot renombrar l'arxiu, revisa algun caràcter erroni al nom de l'arxiu o a les tags Error.155=Error al posar tags als arxius, revisa els permisos Error.156=No hi ha DJ disponible per a una col·lecció buida Error.157=DJ erroni, si us plau, selecciona o crea un DJ utilitzant el combo referenciat per aquest botó Error.158=Les constraints de DJ no poden ser respectades o cap pista disponible Error.159=L'ambient associat ha estat esborrat Error.160=Arxiu no mogut. El font i el destí eren el mateix Error.161=No es pot escriure al directori, comprovar permisos Error.162=Aquesta propietat d'usuari ja existeix Error.163=Error restaurant les vistes per defecte Error.164=No hi ha pistes accesibles per a l'ambient : Error.165=Error al path de la col.lecció, el directori o no existeix o no te permisos d'escriptura Error.166=Album buit, no es pot capturar la caràtula Error.167=No es pot crear l'informe Error.168=No s'ha trobat arxius duplicats Error.169=Operació amb errors. Tenir en compte que aquesta operació requereix una connexió a internet per obtenir la llista d'emisores de ràdio. Error.170=Error reproduint webradio Error.171=No s'ha definit una font de sincronització per a aquest dispossitiu, assigna-la utilitzant l'assistent de configuració de dispossitius (A la vista de Dispossitiu, clickar sobre el dispossitiu). Error.172=S'ha trobat un error mentre s'esborraba el següent arxiu(s): Error.173=S'ha trobat un error mentre s'esborraba el següent directori(s): Error.174=Error accedint a la web de Freedb , revisa la teva conexió de xarxa Error.175=Operació cancelada #Warnings Warning.0=MPlayer no es troba. Alguns formats d'audio i video (flac, wma, aac, mpg2 ...) seràn deshabilitats. Per a utilitzar Mplayer si està instal·lat, has de configurar manualment el path a la vista de Preferències / avançat. Warning.1=Versió de MPlayer no vàlida, es necessari MPlayer1.0Pre8 o superior. Alguns formats d'audio serán deshabilitats. Si us plau mira les instruccions de instal.lació a http://jajuk.sourceforge.net/installation.html per a solucionar això. Warning.2=Sembla que algú més està utilitzant ara la col.lecció de Jajuk. L'últim usuari en sortir sobreescriuirà la configuració(opcions, valoracions...). Warning.3=Mplayer no es pot descarregar. Si estàs darrera d'un proxy HTTP, configúra'l a la vista de Preferències / Pestanya de Xarxa i reinicia Jajuk. Warning.4=Mplayer és necessari per a escoltar web radios Warning.5=El directori de destí ja existeix, alguns arxius es sobreescriuiràn, Estàs segur ? #--- Strings by class --- ParameterView.0=Duració d l'historial: ParameterView.2=Canvia el temps en dias que vols guardar traces de pistes escoltades. Canviar a -1 si no vols veure cap historial i 0 si vols tenir historial permanent ParameterView.3=Esborrar historial ParameterView.4=Esborrar historial ParameterView.8=Historial/Valoracions ParameterView.9=Reproduïr : ParameterView.10=Res ParameterView.11=No hi ha música a l'inici ParameterView.12=La última des del principi ParameterView.13=Reprodueix la última pista durant la sessió anterior ParameterView.14=Pista aleatòria ParameterView.15=Reprodueix una pista aleatòria de la col·lecció sencera ParameterView.16=Pista: ParameterView.17=Sel·leccionar un fitxer para reproduïr al principi ParameterView.18=Sel·leccionar un fitxer para reproduïr al principi ParameterView.19=Inici ParameterView.26=Confirmacions ParameterView.27=Abans d'esborrar físicament un fitxer ParameterView.28=Preguntar abans d'esborrar físicament un fitxer ParameterView.29=Abans de sortir de Jajuk ParameterView.30=Preguntar en sortir de Jajuk ParameterView.33=Opcions ParameterView.35=Oculta pistes situades en dispositius desmontatats ParameterView.36=Reiniciar quan s'arriba al final de la col·lecció ParameterView.37=Reinicia la col·lecció quan s'arriba al final en mode continu ParameterView.38=Idioma: ParameterView.42=Idioma de la interfaç ParameterView.43=Tema : ParameterView.44=Seleccionar un tema

    (Pot ser necessari reiniciar jajuk per veure'l correctament) ParameterView.46=Nivell de log : ParameterView.47=Fatal ParameterView.48=Error ParameterView.49=Warning ParameterView.50=Info ParameterView.51=Debug ParameterView.52=Nivell de log de Jajuk : Fatal:display only critical errors, Error:+display errors, Info:+display information messages, Warning:+display warnings, Debug: any message ParameterView.59=Intro posició d'inici (%) ParameterView.60=Posició de la introducció de la pista en %, desde 0 (inici de la pista) a 99 (final de la pista) ParameterView.61=Intro longitud (seg) : ParameterView.62=Longitud de la introducció en segons ParameterView.85=Aplicar ParameterView.86=Restaurar valors per defecte ParameterView.87=Preferències ParameterView.98=Patrons ParameterView.99=Executar un recorregut profun per les tags ParameterView.100=Forçar a Jajuk a rellegir les id3 tags actuals.

    Això pot ser util per refrescar les tags que s'hagin modificat utilitzant un altre programa ParameterView.101=Utilitzar directori pare com a nom d'àlbum ParameterView.102=Jajuk utilitza el directori pare com el nom d'un àlbum per a una pista si no pot obtenir-ho de les id3 tags ParameterView.109=Preferències gravades ParameterView.110=Preferències per defecte ParameterView.111=Tamany de la llista Best Of : ParameterView.112=Canviar numero de pistes de BestOf (de 1 a 100) ParameterView.113=Usar regexp en filtros ParameterView.114=Usar expresions regulars (Format Regexp) en los filtros de las tablas, ejemplo: .*foo.* ParameterView.115=Avançada ParameterView.116=Backup del arxiu de col·lecció ParameterView.117=Marcar si vols fer backup de la teva col.lecció a l'arxiu collection-.xml ParameterView.118=Tamany de Backup (Mb) ParameterView.119=Tamany de Backup (Mb) (Mb) ParameterView.120=Charset de la col·lecció ParameterView.121=Charset de la col·lecció. UTF-16 està optimitzat per a idiomes asiàtics y UTF-8 està optimitzat per a idiomes europeos. ParameterView.129=Temps límit de les novetats (dias): ParameterView.130=Temps límit de les novetats en dias: totes les pistes a�adidas antes de este n�mero de d�as son calificadas como novetats ParameterView.131=Bestof track ParameterView.132=Reproduïr una de les pistes favorites a l'inici ParameterView.133=Pista de novetat ParameterView.134=Reproduïr una novetat de la col·lecció a l'inici ParameterView.135=La última en la darrera posició ParameterView.136=Reproducir la darrera pista reproduïda durante la sessió anterior ParameterView.139=Xarxa ParameterView.142=Usuari del proxy ParameterView.143=Nom de login del proxy per a autentificació ParameterView.144=Host del proxy ParameterView.145=Nom de host o IP del proxy ParameterView.146=Port del proxy ParameterView.147=Port TCP/IP del proxy (normalment 3128) ParameterView.148=Utilitzar auto caràtules ParameterView.149=Utilitzar auto caràtules per a obtenir des de internet (si cal, configura el teu proxy en la pestanya de xarxa) ParameterView.150=Mínim tamany de caràtula(Kb) ParameterView.151=Mínim tamany de caràtula(Kb) de caràtules descarregades ParameterView.152=Màxim tamany de caràtula(Kb) ParameterView.153=Màxim tamany de caràtula(Kb) de caràtules descarregades ParameterView.155=Precissió de la cerca. Quan més alta és la precissió, menys caràtules errònies ParameterView.156=Baixa ParameterView.157=Mitjana ParameterView.158=Alta ParameterView.159=Caràtules ParameterView.160=Timeout de Conexió (seg) ParameterView.161=Timeout de Conexió in segons : l'operació falla si l'altre part no contesta en aquest temps ParameterView.162=Timout de transferència (seg). ParameterView.163=Timeout de transferència (seg) : l'operació falla si les dades no s'han descarregat en aquest temps ParameterView.164=Abans d'eliminar un dispositiu ParameterView.165=Preguntar abans d'eliminar un dispositiu ParameterView.166=Barrejar caràtules ParameterView.167=Mostrar una caràtula aleatòria ParameterView.168=Artista ParameterView.169=Precarregar caràtules ParameterView.170=Precarregar totes les caràtules disponibles quan sigui possible ParameterView.171=Abans d'esborrar físicament una caràtula ParameterView.172=Preguntar abans d'esborrar físicament una caràtula ParameterView.177=Número visible de pistes planificades ParameterView.178=El número de pistes planificades a mostrar a la playlist ParameterView.179=Encuar la selecció ParameterView.180=Encuar (y no Reproduïr) una pista fent doble click en un element ParameterView.181=Encuar al fer drag & drop ParameterView.182=Encuar (y no Reproduïr) una pista quan l'arrosseguem. ParameterView.183=Sincronitzar vistes d'arbre i taula ParameterView.184=Si està marcat la vista de taula només mostrarà pistes seleccionade a la vista d'arbre ParameterView.185=Mostrar un popup quan es llenci una pista ParameterView.186=Inicialtizar puntuacions ParameterView.187=Inicialitzar puntuacions a zero per a pistes ParameterView.188=Antes limpiar histórico ParameterView.189=Antes inicializar puntuaciones ParameterView.190=Duració de l'atenuació (segons) ParameterView.191=El número de segons d'atenuació entre pistes ParameterView.192=Organitzador de fitxers : ParameterView.193=Patrons disponibles: %artist (Nom de l'artista); %title (Títol de la pista); %album (Nombre del álbum); %n (Track leading zero); %genre (Género); %year (Año) ParameterView.194=Abans d'organitzar fitxers ParameterView.195=Vista d'animació ParameterView.196=Habilitar dreceres de teclat ParameterView.197=Habilitar algunes tecles com F8 per a funcionar encara que Jajuk no tengui el focus ParameterView.198=Alguns canvis seràn efectius només al pròxim inici de Jajuk ParameterView.199=Scrobble allò que escolto ParameterView.200=Aquesta opció envia informacions a Last.fm ParameterView.201=Usuari de Last.FM ParameterView.202=El nom d'usuari a Last.FM ParameterView.203=Password de Last.FM ParameterView.204=El password a Last.FM ParameterView.205=Arguments de MPlayer ParameterView.206=Arguments adiccionals de MPlayer com '-ao esd' o '-ao arts' o '-novideo (per no reproduir videos)' p.e. ParameterView.207=Path base de Jajuk ParameterView.208=Canviar el directori que conté la configuració de Jajuk (per defecte és el directori home de l'usuari) ParameterView.209=El path de la configuració de Jajuk ha estat canviat per l'usuari actual (la col.lecció anterior ha estat guardat a la localització anterior). Jajuk es pot reiniciar. ParameterView.210=Si el cross fade no funciona, mira d'afegir <-ao esd> a Gnome o <-ao arts> a KDE en el camp d'arguments adiccionals del motor de so (Preferències / Avançat). ParameterView.211=Només petites ParameterView.212=Petites i mitjanes ParameterView.213=Només mitjanes ParameterView.214=Mitjanes i grans ParameterView.215=Només grans ParameterView.216=Buscar utilitzant el nombre del artista ParameterView.217=Buscar utilitzant el nombre del album ParameterView.218=Buscar utilitzant el nombre de la pista ParameterView.219=Variables d'entorn ParameterView.220=Estableix les variables d'entorn utilitzades pel reproductor d'audio (ARTS_SERVER a KDE o ESPEAKER a Gnome p.e.). Format: var1=xx var2=yyy... #Respect English size for next item ParameterView.221=Tamany pàgina de Catàleg (0: Tot en una) ParameterView.222=Estableix el número d'àlbums per pàgina a la vista de catàleg. 0: mostra totes las caràtules a una sola pàgina ParameterView.223=Tamany de Fonts ParameterView.224=Estableix el tamany de la font de texte ParameterView.225=GUI ParameterView.226=Modes ParameterView.228=Mostrar finestres de albums ParameterView.229=Preferències de la vista de Catàleg ParameterView.233=La intefície es refrescarà al proper reinici de jajuk ParameterView.234=Chequeja actualizacions de Jajuk ParameterView.235=Last.FM ParameterView.236=Sense Proxy ParameterView.237=proxy HTTP ParameterView.238=proxy SOCKS ParameterView.239=Proxy password ParameterView.240=Habilitar consultes d'informació de Last.FM ParameterView.241=Si está marcat, Jajuk recollirà informació dels albums de Last.FM (veure vista de suggerències) ParameterView.242=Path de Mplayer ParameterView.243=Canviar aquí el path complert de l'executable mplayer (espais permesos)
    Exemple: /Applications/MPlayer OSX.app/Contents/Resources/External_Binaries/mplayer_intel.app/Contents/MacOS/mplayer ParameterView.244=Forçar data dels arxius com a data de descobrimient ParameterView.245=jajuk considera la data dels arxius d'audio com la data de descobriment
    Requereix un refresc en profunditat per ser tingut en compte ParameterView.246=Tamanys dels icons a la barra de Perspectives (pixels) ParameterView.247=El path de destí conté ja un workspace de Jajuk. El workspace s'ha canviat a aquest path per a l'usuari actual (el workspace anterior ha estat guardat a la anterior localització). Jajuk pot ser reiniciat. ParameterView.248=Títol del marc ParameterView.249=Resetejar preferències ParameterView.250=Resetejar preferències de l'usuari ParameterView.251=Històric resetejat correctament ParameterView.252=Valoracions i temps de reproducció resetejats correctament ParameterView.253=Preferències resetejades correctament Main.21=Confirmació Main.22=Descarregant MPlayer Player.0=Esperant per la línea d'audio (ocupada) Device.21=Refrescant [ Device.22=] Entrant [ Device.25=] refrescat en Device.27= nous fitxers - Device.31=Sinc. [ Device.33=sincronització feta en Device.35= fitxers creats ( Device.36= MB) Device.41=Sinc. [ Device.42=] Copiant [ Device.43= tags no legibles Device.44=Entrant FIFO.4=). El vols montar ? FIFO.10=Ara reproduïnt: FIFO.13= Kbps FIFO.14=Reproduïnt Web Radio: HistoryItem.0=yy/MM/dd HH:mm DeviceWizard.0=Configuració de dispositivo DeviceWizard.1=Tipus de dispositiu(*): DeviceWizard.2=Nom del dispositiu(*): DeviceWizard.3=Localització del dispositiu(*): DeviceWizard.4=Directori de montatge Unix (opcional): DeviceWizard.7=Executar un refresc instantani DeviceWizard.8=Auto montar a l'inici DeviceWizard.10=Sincronitzat amb : DeviceWizard.11=Sincronització unidireccional DeviceWizard.12=Tots els fitxers nous en el dispositiu font es copiaràn en aquest dispositiu. Res serà escrit en el dispositiu font DeviceWizard.13=Sicronització bidireccional DeviceWizard.14=Tots els fitxers nous trobats en un dispositiu es copiaràn a l'altre DeviceWizard.43=Si et plau, tria un directori DeviceWizard.44=Dispositiu creat DeviceWizard.45=Si et plau, dona un nom al dispositiu . Ex: CD A, Portàtil ... DeviceWizard.46=Si et plau, dona una localització per al dispositiu. Ex: d:\music a Windows, /home/foo/music a Unix DeviceWizard.48=Marcar si vols executar un refresc inmediat del dispositiu (avisat)

    Aquest operació pot trigar bastant per a dispositius grans DeviceWizard.49=Marcar si vols montar automàticament el dispositiu a l'inici

    especialment per a directoris al disc dur local. Evitar-ho per a CDs DeviceWizard.50=Interval en minuts per a cerca automàtica de nous arxius (0: deshabilitada) DeviceWizard.51=Marcar si vols sincronitzar aquest dispositiu amb un altre DeviceWizard.52=Sel·leccionar dispositiu font DeviceWizard.53=Refrescar dispositiu cada #limited string size DeviceWizard.54=min JajukJMenuBar.0=arxiu JajukJMenuBar.1=Obrir fitxer JajukJMenuBar.3=Sortir JajukJMenuBar.5=Propietats JajukJMenuBar.6=Crear propietat d'usuari JajukJMenuBar.7=Esborrar propietat d'usuari JajukJMenuBar.8=Vistes JajukJMenuBar.9=Modes JajukJMenuBar.10=Repetició JajukJMenuBar.11=Aleatori JajukJMenuBar.12=Continu JajukJMenuBar.13=Introducció JajukJMenuBar.14=Ajuda JajukJMenuBar.15=Contingut de l'ajuda JajukJMenuBar.16=Sobre JajukJMenuBar.17=Restaurar vistes per defecte JajukJMenuBar.18=Assistent de Dispositius JajukJMenuBar.19=Comunicar un problema JajukJMenuBar.20=Consell del Dia JajukJMenuBar.21=Configuració JajukJMenuBar.22=Preferències JajukJMenuBar.23=Mostrar traces de debug JajukJMenuBar.24=Mostrar pistes disponibles JajukJMenuBar.25=Mostrar vista JajukJMenuBar.26=Restaurar vistes (totes les perspectives) JajukJMenuBar.27=Chequejar actualitzacins de Jajuk JajukJMenuBar.28=Eines JajukJMenuBar.29=Inteligència PlaylistFileItem.1=Novetats PlaylistFileItem.2=Nova playlist PlaylistFileItem.3=Marcadors PlaylistFileItem.4=BestOf PlaylistFileItem.5=Cua JajukFileChooser.0=Tria la pista(s) a Reproduïr SearchBox.0=Cercar entre pistes, autors, estils, directoris ... CommandJPanel.0=Veure historial de reproducció CommandJPanel.1=Mode repetició: Reprodueix una pista en bucle CommandJPanel.2=Mode aleatori: Reprodueix aleatòriament les pistes sel·leccionades CommandJPanel.3=Mode continu: Continua reproduïnt les pistas següents quan acaba CommandJPanel.4=Mode Introducció: Reprodueix un fragment de les pistes. Inici i temps es poden canviar des de la vista de paràmetres CommandJPanel.5=Reproduïr una selecció aleatòria de la col·lecció sencera CommandJPanel.6=Reproduïr pistas favoritas CommandJPanel.7=So off CommandJPanel.8=Reproduïr pista anterior a la selecció actual
    Mays+Botó esquerra llença l'àlbum posterior CommandJPanel.9=Reproduïr pista següent a la selecció actual
    Mays+Botó esquerra llença l'àlbum anterior CommandJPanel.10=Retrocés ràpid a la pista actual
    Mays+Botó esquerra per a repetició complerta CommandJPanel.11=Pausa/Segueix pista actual CommandJPanel.12=Parar CommandJPanel.13=Avanç ràpid a la pista actual CommandJPanel.14=Volum CommandJPanel.15=Click aquí per a canviar el format de temps mostrat CommandJPanel.16=Llençar selecció de DJ CommandJPanel.17=Administrar DJs CommandJPanel.18=Llençar el DJ seleccionat per defecte CommandJPanel.19=Administrar Ambients CommandJPanel.20=Pista per pista CommandJPanel.21=Àlbum per àlbum CommandJPanel.22=Àlbum per àlbum CommandJPanel.23=Click per a netejar la cerca CommandJPanel.24=Configurar web radios CommandJPanel.25=Engegar la radio InformationJPanel.5=Temps total de la cua reproduïr [Nb de pistes restants] InformationJPanel.6=Bitrate de pista InformationJPanel.7=Progressió de pista actual #song name BY artist ON album name InformationJPanel.8=%title per %artist a %album AbstractPlaylistEditorView.0=Títol AbstractPlaylistEditorView.1=Localització AbstractPlaylistEditorView.2=Reproduïr aquesta playlist AbstractPlaylistEditorView.3=Gravar esta playlist AbstractPlaylistEditorView.4=Afegir element a aquesta playlist AbstractPlaylistEditorView.5=Esborrar element d'aquesta playlist AbstractPlaylistEditorView.6=Moure amunt AbstractPlaylistEditorView.7=Moure avall AbstractPlaylistEditorView.9=Esborrar aquesta playlist AbstractPlaylistEditorView.10=Afegir una pista aleatòria a aquesta playlist AbstractPlaylistEditorView.15=Playlists AbstractPlaylistEditorView.17=Estàs a punt de les següents playlists : AbstractPlaylistEditorView.18=Pista en cua AbstractPlaylistEditorView.19=Pista repetida AbstractPlaylistEditorView.20=Pista planificada AbstractPlaylistEditorView.21=Pista de playlist AbstractPlaylistEditorView.22=Playlist gravada AbstractPlaylistEditorView.27=Preparar Fiesta AbstractPlaylistEditorView.28=directori creat amb èxit StatView.0=Altres StatView.1=Géneres StatView.2=No hi ha dades disponibles StatView.3=Altres StatView.4=Tamany per dispositiu (GB) StatView.5=No hi ha dades disponibles StatView.7=Tamany de la col·lecció por mes StatView.8=Mesos StatView.9=Tamany (GB) StatView.10=No hi ha dades disponibles StatView.12=Número total de pistes per mesos StatView.13=Mesos StatView.14=número de Pistes StatView.15=No hi ha dades disponibles StatView.16=Estadística StatView.24=Antigues CDScanView.0=CD label : CDScanView.1=Etiqueta de CD. Ex: CD1, ROCK... CDScanView.2=Etiqueta de CD Ex: CD1, ROCK... CDScanView.3=Localització del CD : CDScanView.4=Localització on es pot trovar el CD. Ex: '/cdrom' a Unix, 'e:' a MS Windows... CDScanView.5=Localització on es pot trovar el CD. Ex: '/cdrom' a Unix, 'e:' a MS Windows... CDScanView.6=Analitzar CDScanView.12=Analitzar CD CDScanView.18=Analitzar el CD y afegir automàticament tots els fitxers de música a la col·lecció CDScanView.19=Sel·leccionar localització del CD TracksTreeView.0=Arbre de pistes TracksTreeView.27=col·lecció TracksTreeView.31= pistes TracksTreeView.33=Exportar TracksTreeView.34=Obtenir tags online TracksTreeView.35=Descobrir data TracksTreeView.36=menys d'una setmana TracksTreeView.37=menys d'un mes TracksTreeView.38=menys de sis mesos TracksTreeView.39=anterior TracksTreeView.40=menys d'un any TracksTreeView.41=menys de dos anys TracksTreeView.42=menys de cinc anys TracksTreeView.43=menys de deu anys TracksTreeView.44=menys de tres messs TracksTreeView.45=Any CoverView.2=Esborrar del disc aquesta caràtula CoverView.3=Caràtula CoverView.4=Imatge anterior del disc i/o de la Web si l'opció d'Auto-Caràtula està marcada CoverView.5=Imatge següent del disc i/o de la Web si l'opció d'Auto-Caràtula està marcada CoverView.6=Gravar caràtula amb el seu nom original CoverView.7=Gravar caràtula com ... CoverView.8=Utilitzar aquesta caràtula com la caràtula per defecte d'aquest àlbum CoverView.9=caràtules CoverView.10=Gravar caràtula com CoverView.11=Caràtula gravada CoverView.12=Àlbum CoverView.13=Títol AnimationView.0=Animació FilesTreeView.0=Arbre d'arxius FilesTreeView.3=Copiar FilesTreeView.4=Tallar FilesTreeView.5=Enganxar FilesTreeView.7=Esborrar FilesTreeView.14=Desincronitzar FilesTreeView.15=Resincronitzar FilesTreeView.16=Crear Playlist FilesTreeView.17=Copiar FilesTreeView.18=Tallar FilesTreeView.28=Montar FilesTreeView.29=Desmontar FilesTreeView.30=Forçar Refrescar FilesTreeView.31=Sincronitzar FilesTreeView.32=Provar FilesTreeView.33=Crear playlists FilesTreeView.40=Copiar FilesTreeView.41=Tallar FilesTreeView.42=Enganxar FilesTreeView.47=col·lecció FilesTreeView.52= fitxers: FilesTreeView.53= Gb FilesTreeView.54= Mb FilesTreeView.55= Configurar dispositiu FilesTreeView.59=Vols executar un refresc ràpid o en profunditat (llegir les tags una altre vegada) ? FilesTreeView.60=Rápid FilesTreeView.61=En profunditat FilesTreeView.62=Organitzar fitxers TracksTableView.0=Taula de pistes TracksTableView.7=Reproduïr TracksTableView.8=Encuar TracksTableView.9=Reproduïr aleatoriament TracksTableView.10=Reproduïr amb repetició TracksTableView.11=Reproduïr àlbum TracksTableView.12=Reproduïr autor TracksTableView.14=Propietats TracksTableView.15=Afegir a Favorits AbstractTableView.0=Filtre: AbstractTableView.1=Propietat a filtrar AbstractTableView.3=Valor utilitzat pel filtre AbstractTableView.4=Aplicar filtre AbstractTableView.5=Netejar el filtre AbstractTableView.6=Aplicar filtre avançat AbstractTableView.7=conté: AbstractTableView.8=Qualsevol AbstractTableView.10=(No disponible) AbstractTableView.11=Fer editable la taula AboutView.7=Sobre AboutView.8=Llicència AboutView.9=Sistema AboutView.10=Sobre PhysicalPlaylistRepositoryView.0=Reproduïr PhysicalPlaylistRepositoryView.1=Editar PhysicalPlaylistRepositoryView.2=Guardar com PhysicalPlaylistRepositoryView.3=Esborrar PhysicalPlaylistRepositoryView.4=Propietats PhysicalPlaylistRepositoryView.6=Playlists físiques PhysicalPlaylistRepositoryView.8=Intel.ligents PhysicalPlaylistRepositoryView.9=Encuar PhysicalPlaylistRepositoryView.10=Cua actual: drag and drop una pista cap a ella para Reproduïr PhysicalPlaylistRepositoryView.11=Nova PhysicalPlaylistRepositoryView.12=Nova playlist: drag and drop una pista cap a ella para aàadir fitxers PhysicalPlaylistRepositoryView.13=Favorits PhysicalPlaylistRepositoryView.14=Afegir playlist a Favorits: drag and drop una pista cap a ella per guardar-la PhysicalPlaylistRepositoryView.15=BestOf PhysicalPlaylistRepositoryView.16=Best of playlist : conté les millors pistes PhysicalPlaylistRepositoryView.17=Novetats PhysicalPlaylistRepositoryView.18=Playlist de Novetatas: conté les pistes més noves de la col.lecció FilesTableView.0=Taula d'arxius FilesTableView.15=Reproduïr un directori #Dev: do not use ID = 16, next label is FilesTableView.17 DeviceView.0=Afegir un dispositiu DeviceView.1=Eliminar un dispositiu desmontat (no esborra res del disc) DeviceView.2=Propietats del dispositiu sel·leccionat DeviceView.3=Montar dispositiu sel·leccionat DeviceView.4=Desmontar dispositiu sel·leccionat DeviceView.5=Probar disponibilidad del dispositiu sel·leccionat DeviceView.6=Forçar refrescar dispositiu sel·leccionat DeviceView.7=Sincronizar dispositiu sel·leccionat DeviceView.8=Montar DeviceView.9=Desmontar DeviceView.10=Provar DeviceView.11=Forçar refrescar DeviceView.12=Sincronitzar DeviceView.13=Eliminar dispositiu DeviceView.14=Configurar DeviceView.17=Nou DeviceView.18=Afegir un dispositiu DeviceView.21=Aquest dispositiu està disponible DeviceView.22=No es pot accedir al dispositiu DeviceView.23=Dispositius JajukWindow.1=Unmute JajukWindow.2=Mute JajukWindow.3=Jajuk JajukWindow.4=Salir JajukWindow.5=Sobre Jajuk JajukWindow.6=Reproduïr aleatoriament JajukWindow.7=Reproduïr BestOf JajukWindow.10=Pausa JajukWindow.11=Stop JajukWindow.12=Play JajukWindow.13=Anterior JajukWindow.14=Següent JajukWindow.15=Reproduïr Novetats JajukWindow.16=Continuar àlbum JajukWindow.17=Jajuk: Advanced Jukebox JajukWindow.18=Preparat per a reproducció JajukWindow.19=Mute/Unmute JajukWindow.21=Sortir JajukWindow.22=Sobre Jajuk JajukWindow.23=Reproduïr aleatoriamente pistas de la col·lecció entera JajukWindow.24=Reproduïr las mejores pistas de la col·lecció entera JajukWindow.26=Play/Pausa JajukWindow.27=Stop JajukWindow.29=Pista anterior. Amb el ratolí, botó esquerra +[Mays]: àlbum anterior. JajukWindow.30=Pista següent. Amb el ratolí, botó esquerra +[Mays]: àlbum següent. JajukWindow.31=Reproduïr novetats de la col·lecció entera JajukWindow.32=Continuar àlbum: acabar de reproduïr aquest àlbum JajukWindow.33=Volum JajukWindow.34=Posició JajukWindow.35=Reproduïnt: JajukWindow.36=Ambient actual: JajukWindow.37=Sense Ambient seleccionat #Do not use JajukWindow.38, next is JajukWindow.39 SimpleDeviceWizard.0=Creació ràpida de dispossitiu FirstTimeWizard.0=Inici ráapid FirstTimeWizard.1=


    Benvingut! Aquest assistent t'ajudará en la creació de la teva col.lecció.

    FirstTimeWizard.2=Selecciona la localització de la música FirstTimeWizard.3=Vols obtenir les caràtules online
    (es pot obrir una connexió a internet automàticament) ? FirstTimeWizard.4=Mostrar la ajuda ara ? FirstTimeWizard.5=Si us plau, esculliu un directori FirstTimeWizard.6=Preferències avançades FirstTimeWizard.7=Establir directori d'àrea de treball de Jajuk : HelpView.2=Ajuda DownloadManager.0=Jajuk necessita la contrasenya del teu proxy HTTP per a descarregar caràtules
    Si no las vols, si us plau, canvia la teva configuració a la pestanya Caràtules de la vista de Preferències
    Si no tens proxy, canvia els ajustos a la pestanya de Xarxa de la vista de Preferències DownloadManager.1=Contrasenya necessària PropertiesWizard.0=Propietats de ... PropertiesWizard.1=Propietat PropertiesWizard.2=Valor PropertiesWizard.3=Editable? PropertiesWizard.4=Enllaç PropertiesWizard.6=Selecció PropertiesWizard.7=Tipus PropertiesWizard.8=Propietat canviada correctament PropertiesWizard.9=Propietat no editable per aquesta selecció PropertiesWizard.10=Les propietats s' han canviat PropertiesWizard.11=Actualitzant tag a: PropertiesWizard.12=Enllaça un element donat Link a unes propietats donades NewPropertyWizard.0=Crear propietat d'usuari NewPropertyWizard.3=(*)Tipus NewPropertyWizard.4=Format NewPropertyWizard.5=Valor per defecte CustomPropertyWizard.0=(*)Item CustomPropertyWizard.1=(*)Nom de propietat d'usuari RemovePropertyWizard.0=Esborrar propietat d'usuari QualityFeedbackWizard.20=Una nova finestra per a enviar el teu ticket s'obrirà al navegador extern. Les teves darreres traces anonimitzades han estat posades al portapapers, Si us plau enganxa-les al camp descripció si és un informe de bug (això incrementa les opcions per a que poguem arreglar el teu problema). IncRateAction.0=Incrementar valoración de la pista actual SplashScreen.0=Controls inicials SplashScreen.1=Carregant col.lecció SplashScreen.2=Iniciant motor musical SplashScreen.3=Iniciant interfase gràfica CatalogView.0=Catàleg d'Àlbums #Note: CatalogView.2 label musn't be mush larger than in english for correct display in 800x600 CatalogView.2=Sense caràtules CatalogView.3=Refrescar catàleg CatalogView.4=Tamany de miniatures: CatalogView.5=Creada miniatura per: CatalogView.7=Seleccionar caràtula CatalogView.8=Cap caràtula trobada CatalogView.9=Anterior CatalogView.10=Següent CatalogView.11=Pàgina: CatalogView.12=Mostar pàgina anterior de miniatures CatalogView.13=Mostar pàgina següent de miniatures CatalogView.14=Seleccionar pàgina de miniatures a mostrar CatalogView.15=Tamany de miniatura: CatalogView.16=àlbums CatalogView.17=/pàgina CatalogView.18=Selecció de caràtula CatalogView.19=Refer miniatures CatalogView.20=Mostrar detalls WikipediaView.0=Wikipedia WikipediaView.1=Seleccionar Idioma: WikipediaView.3=Res trobat WikipediaView.5=Cercar per nom d'Artista WikipediaView.6=Cercar per nom d'Àlbum WikipediaView.7=Cercar per títol TipOfTheDayView.0=Consell del dia TipOfTheDayView.1=Sabies... ? TipOfTheDayView.2=Mostrar a l'inici ? CDDBWizard.0=Aceptar CDDBWizard.1=Arxiu CDDBWizard.2=Nom de pista actual CDDBWizard.3=Nom d'àlbum actual CDDBWizard.4=Nom de pista proposat CDDBWizard.5=Nom d'àlbum proposat : CDDBWizard.6=Fet ! Trobat CDDBWizard.7=possibles coincidències CDDBWizard.12=No trobada cap coincidència ! CDDBWizard.14=Aquest directori no conté cap arxiu CDDBWizard.16=Estil: CDDBWizard.17=Trobada coincidència exacta ! CDDBWizard.18=Coincidències CDDBWizard.19=Obtenir Tags Online RefactorWizard.0=Fitxer mogut : DigitalDJWizard.0=Seleccionar el nou mode de DJ DigitalDJWizard.1=Programació basada en transicions (ROCK -> POP) DigitalDJWizard.2=Programació basada en proporcions (20% JAZZ, 30% ROCK) DigitalDJWizard.3=Programació basada en ambients (Suau, Festa, ...) DigitalDJWizard.4=Asistent de DJ Digital DigitalDJWizard.5=Configuració general del DJ DigitalDJWizard.6=Nom del DJ (*) DigitalDJWizard.7=Utilitzar puntuacions DigitalDJWizard.8=Nivell de puntuació: DigitalDJWizard.9=Cross fade (seg): DigitalDJWizard.10=Pistes només reproduïdes una vegada DigitalDJWizard.11=Tirar DigitalDJWizard.12=Des d'Estils DigitalDJWizard.13=A Estils DigitalDJWizard.14=Selecció d'Estils (Es poden fer seleccions múltiples) DigitalDJWizard.15=Número de pistes DigitalDJWizard.16=¿ Vols ? DigitalDJWizard.17=¿ Crear un nou DJ ? DigitalDJWizard.18=¿ Canviar un DJ existent ? DigitalDJWizard.19=¿ Esborrar un DJ ? DigitalDJWizard.20=Nou DJ basat en transicions #limited string size DigitalDJWizard.21=Esborrar #limited string size DigitalDJWizard.22=Origen #limited string size DigitalDJWizard.23=Destí #limited string size DigitalDJWizard.24=Nb #limited string size DigitalDJWizard.25=Comença amb: DigitalDJWizard.26=Si us plau, crea almenys una transició #limited string size DigitalDJWizard.27=Selecció de gèneres #limited string size DigitalDJWizard.28=% DigitalDJWizard.29=DJ basat en proporcions DigitalDJWizard.30=Si us plau, crea almenys una proporció DigitalDJWizard.31=DJ basat en ambient DigitalDJWizard.32=Nou ambient DigitalDJWizard.33=Crear un nou ambient DigitalDJWizard.34=Esborrar ambient DigitalDJWizard.35=Esborrar l'ambient seleccionat DigitalDJWizard.36=Nom de l'ambient DigitalDJWizard.37=Nom DigitalDJWizard.38=Si us plau, crea almenys un ambient DigitalDJWizard.39=Si us plau, omple el nom i selecciona els estils de l'ambient DigitalDJWizard.40=Si us plau, selecciona un DJ DigitalDJWizard.41=Si us plau, posa el nom al DJ DigitalDJWizard.42=Un DJ amb aquest nom ja existeix DigitalDJWizard.43=Canviar DJ DigitalDJWizard.44=Seleccionar el DJ a configurar DigitalDJWizard.45=Selecció d'acció DigitalDJWizard.46=Selecció del tipus de DJ DigitalDJWizard.47=Si us plau, selecciona o crea un ambient DigitalDJWizard.48=Atributs Generals DigitalDJWizard.49=Si us plau, omple els atributs generals del DJ DigitalDJWizard.50=Si us plau, defineix proporcions DigitalDJWizard.51=Esborrar DJ DigitalDJWizard.52=Si us plau, defineix transicions DigitalDJWizard.53=Número mínim d'estels de puntuació per a pistes de la selecció (1: totes les pistes) DigitalDJWizard.54=Duració de Cross fade entre pistes DigitalDJWizard.55=Si està marcat, la selecció contindrà cada pista només una vegada DigitalDJWizard.56=Assistent d'Ambients DigitalDJWizard.57=Administrar Ambients DigitalDJWizard.58=Selecció d'Ambients: DigitalDJWizard.59=La suma de totes les proporcions hauria de ser < 100 % DigitalDJWizard.60=Nom d'ambient existent DigitalDJWizard.61=Esborrar DJ #limited string size DigitalDJWizard.62=Per defecte DigitalDJWizard.63=Afegir ambients per defecte DigitalDJWizard.64=Qualsevol DigitalDJWizard.66=Selecció d'Ambient per defecte #--- Tips of day --- Ambience.0=Rock/Pop Ambience.1=Rap Ambience.2=HardRock Ambience.3=Techno Ambience.4=Electro Ambience.5=Clàsic Ambience.6=Suau Ambience.7=Festa Ambience.8=Jazz Ambience.9=World Ambience.10=Altres Ambience.11=Folk/Oldies Ambience.12=Indy Ambience.13=Latin DebugLogAction.0=Llistar traces de Debug DebugLogAction.1=Refrescar CopyClipboardAction.0=Copiar adreça al portapapers LaunchInBrowserAction.0=Obrir adreça al navegador del sistema ReportAction.0=Informe creat satisfactoriament ReportAction.1=Informe de Música Jajuk ReportAction.2=Si us plau, per cura amb el medi ambient, no imprimeixis si no és necessari ReportAction.3=Llista d'Àlbums ReportAction.4=Pistes per Àlbum ReportAction.5=Llista d'Artistes ReportAction.6=Àlbums per artistes ReportAction.7=Llista de Géneres ReportAction.8=Àlbums per génere ReportAction.9=Autors/ àlbums per génere ReportAction.10=Llista de Directoris ReportAction.11=Arxius per directori ReportAction.12=Nom d'arxiu ReportAction.13=Nom de pista ReportAction.14=Llista de Dispossitius ReportAction.15=Directoris per dispossitiu ReportAction.16=Directoris/ arxius ReportAction.17=col·lecció ReportAction.18=Autors/ àlbums/ pistes per estil ReportAction.19=Anar a: ActionMove.0=Enganxar ActionRefresh.0=Forçar Refrescar ActionRefresh.1=Refrescant directori RenameAction.0=Renombrar RenameAction.1=Si et plau, entra el nou nom per a aquest arxiu: RenameAction.2=Si et plau, entra el nou nom per a aquest directori: NewFolderAction.0=Nova Carpeta NewFolderAction.1=Si et plau, entra el nou nom per a aquest carpeta: NewFolderAction.2=Una carpeta amb el mateix nom ja existeix. LyricsView.0=Letra ActionDelete.0=Fitxers eliminats ActionDelete.1=Directoris eliminats FindDuplicateFilesAction.0=No s'han trobat arxius duplicats. FindDuplicateFilesAction.1=Arxius duplicats trobats RefreshDialog.0=Preparando actualización de dispositivo... RefreshDialog.1=Actualizando dispositivo RefreshDialog.2=Actualizando dispositivo: RefreshDialog.3=Limpiando los archivos antiguos RadioWizard.0=Selecciona o crea una web radio RadioWizard.1=Administrar web radios RadioWizard.2=Nova RadioWizard.3=Esborrar RadioWizard.4=Per defecte RadioWizard.5=Una web radio amb aquest nom ja existeix RadioWizard.6=Nom de Web Radio RadioWizard.7=Assistent de Web Radio RadioWizard.8=URL RadioWizard.9=Nom RadioWizard.10=URL incorrecta RadioWizard.11=Nom i URL són obligatoris UpdateManager.0=Una nova versió de Jajuk ( UpdateManager.1=) s'ha trobat, es pot descarregar de http://jajuk.info UpdateManager.2=No hi ha nova versió per ara LastFmManager.0=El soport Last.FM està deshabilitat. Si vols enviar les cançons que escoltis a Last.FM, habilíta'l i configura el teu login i password de Last.FM a la vista de Preferències / pestanya Last.FM. SuggestionView.0=Suggerèncias SuggestionView.1=Preferides SuggestionView.2=Nous SuggestionView.3=Altres albums SuggestionView.4=Artistes similars SuggestionView.5=Rarament escoltades SuggestionView.7=Res que mostrar

    La informació de Last.FM es mostra només si:
    • Una pista està reproduïnt-se
    • L'autor de la pista és conegut(tag correcta)
    • L'opción "Habilitar consultes a Last.FM" està marcada a la vista de Preferències / pestanya Last.FM
    AbstractThumbnail.0=Obrir la pàgina LAST.FM AlbumsTableView.0=Tabla d'Àlbums AlbumsTableView.1=No de pistes AlarmClock.0=Establir nova alarma AlarmClock.1=Mostrar alarmes AlarmClock.2=Sense alarmes establertes AlarmClock.3=Alarma AlarmClock.4=Temps ja passat ! AlarmClock.5=Recordatori per a tu: AlarmDialog.0=Temps (HH:MM:SS) AlarmDialog.1=Hora AlarmDialog.2=Minuts AlarmDialog.3=Segons AlarmDialog.4=Acció de l'alarma AlarmDialog.5=Seleccionar acció de l'alarma AlarmDialog.6=Missatge: AlarmDialog.7=Establir missatge recordatori AlarmDialog.8=Diàriament AlarmDialog.9=Establir la alarma diàriament. ShowPropertiesAction.0=Mostra propietats del objecte QueueView.1=Buidar la cua JajukSlimWindow.0=Habilitar/deshabilitar Slim Jajuk BanSelectionAction.0=Bloquejar BanSelectionAction.1=Bloquejar l'element per a que mai es seleccioni UnBanSelectionAction.0=Desbloquejar UnBanSelectionAction.1=Desbloquejar element(s) per a tornar a ser proposats Preference.0=Assigna una preferència personal a la pista actual
    És presa en consideració per al càlcul de la valoració final Preference.1=Brossa Preference.2=Pobre Preference.3=Mitja Preference.4=Bo Preference.5=Excelent Preference.6=Clàsic Preference.7=Preferències... Preference.8=Sense preferència # TipOfTheDay are automatically generated with the Jajuk Manual. # To change tip of the day use page: http://jajuk.info/index.php/Tip_of_the_day TipOfTheDay.0=Tip 0: Què pots repetir la pista actual des de l'inici amb [Control-Left click] o {right click] al butó de Rewind al panel de Control o la safata del sistema ? TipOfTheDay.1=Tip 1: Què pots repetir l'àlbum actual des de la primera pista amb [Control-Left click] o {right click] al butó d'anterior al panel de Control o la safata del sistema ? TipOfTheDay.2=Tip 2: Què pots afegir elements aleatoris a la llista de reproducció using el butó ? a l'editor de playlist ? TipOfTheDay.3=Tip 3: Què pots obtenir caràtules de interenet fins i tot radera d'un proxy usant la pestanya de Xarxa a la vista de Configuració ? TipOfTheDay.4=Tip 4: Què pots guardar les caràtules obtenides des de internet per accelerar la navegació a la vista de caràtules utilitzant l'opció de precargar les caràtules a la pestanya de caràtules a la vista de configuració ? TipOfTheDay.5=Tip 5: Què pots amagar las pistes no disponibles a l'aplicació utilitzant l'opció Mostrar només dispositius montats a la pestanya d'opcions de la vista de configuració ? TipOfTheDay.6=Tip 6: Què pots reduïr el tamany de la col.lecció per caràcters asiàtics seleccionant UTF-16 com encodding a la Vista de Configuració / Pestanya Avançat ? TipOfTheDay.7=Tip 7: Què pots arrossegar i desar elements de les vistes d'arbre a les playlists a l'editor de playlist i al repository de playlist ? TipOfTheDay.8=Tip 8: Què pots escoltar el principi de les pistes amb el mode intro ? TipOfTheDay.9=Tip 9: Què pots configurar la duració de la atenuació a la vista de Preferències / pestanya d'Opcions ? TipOfTheDay.10=Tip 10: Què pots iniciar jajuk en mode reduït desmarcant l'opció Mostrar jajuk a l'inici a l'area de noticació ? TipOfTheDay.11=Tip 11: Què pots controlar las principals funcions de jajuk utilitzant només la icona a l'area de notificació (només Linux i Windows) ? TipOfTheDay.12=Tip 12: Què l'aspecte (look and feel) de Jajuk es configurable a la vista de Preferències / pestanya d'Opcions ? TipOfTheDay.13=Tip 13: Què pots configurar el comportament del doble click i del drag & drop (push i play) en la vista de Preferències / pestanya d'Opcions ? TipOfTheDay.14=Tip 14: Què les pistes "planificades" de Jajuk son pistes que sonaran després de la selecció actual ? TipOfTheDay.15=Tip 15: Què la interfaç gràfica de Jajuk és completament dockable i que es poden reorganitzar les vistes amb drag and drop ? TipOfTheDay.16=Tip 16: Què es pot obtenir el número total d'arxius i pistes seleccionant el node "col.lecció" a las vistes física o lògica ? TipOfTheDay.17=Tip 17: Què pots obtenir tags online amb la funció "Obtenir tags online" en directoris de la vista física ? TipOfTheDay.18=Tip 18: Què la barra de històric de Jajuk (a dalt de la finestra) mostra totes las pistes que han sonat anteriorment ? TipOfTheDay.19=Tip 19: Què pots fer cerques ràpides amb el quadre de cerca (a dalt de la finestra) ? TipOfTheDay.20=Tip 20: Què pots reportar bugs o noves funcionalitats amb l'agent de qualitat (Ajuda -> Comunicar un problema) ? TipOfTheDay.21=Tip 21: Què els DJs de Jajuk poden crear playlists intel.ligents seguint les teves regles ? TipOfTheDay.22=Tip 22: Què pots obtenir les lletres amb la "Vista de lletres" ? TipOfTheDay.23=Tip 23: Què la vista de Suggerències mostra informació de LAST.FM com artistas semblants ? TipOfTheDay.24=Tip 24: Què es pot afegir qualsevol vista a una perspectiva amb la barra de menú de "Vistes" ? TipOfTheDay.25=Tip 25: Què pots establir una imatge de fons escollida a la vista de Preferències / pestanya GUI ? TipOfTheDay.26=Tip 26: Què pots mostrar/amagar els dispossitius desmontats amb un click a la barra de menu "Modes" ? TipOfTheDay.27=Tip 27: Què pots escollir el directori per a les dades Jajuk (com un disc extern) per a guardar les teves dades i preferències en qualsevol ordinador (veure pestanya "Avançat" a la vista de Preferències) ? TipOfTheDay.28=Tip 28: Què pots afegir qualsevol vista a qualsevol perspectiva utilitzant la barra de menu de "Vistes" ? TipOfTheDay.29=Tip 29: you can launch a web page in you default browser using this icon Image:launch_16x16.png/ TipOfTheDay.30=Tip 30: Jajuk supports web radio Image:webradio_32x32.png/ ]]>jajuk-1.9.6.orig/src/main/java/org/jajuk/i18n/jajuk_pt.properties0000644000175000017500000020066611720500104024521 0ustar drazzibdrazzib página Rating system). As suas pontuações anteriores foram transferidas para uma escala de 0 a 100, mas recomendamos que redefina todas as pontuações desde a vista de Preferência / Histórico (atenção: todas as pontuações actuais serão perdidas). #Write confirmation so replies are: yes / no / cancel Confirmation_exit=Deseja mesmo fechar o Jajuk? Confirmation_delete=Atenção!Está prestes a eliminar o(s) seguinte(s) ficheiros do seu disco. Deseja prosseguir? Confirmation_void_refresh=Atenção! Está prestes a aceder a um dispositivo vazio. Em Unix, certifique-se que o dispositivo está montado ou perderá informação do Jajuk neste dispositivo. Deseja prosseguir? Confirmation_remove_device=Deseja mesmo remover este dispositivo? Confirmation_delete_cover=Deseja mesmo eliminar esta capa do seu disco? Confirmation_delete_files=Deseja mesmo eliminar estes ficheiros do seu disco? Confirmation_delete_dirs=Deseja mesmo eliminar estes directórios do seu disco? Confirmation_clear_history=Deseja mesmo limpar o histórico? Confirmation_reset_ratings=Deseja mesmo redefinir todas as pontuações para zero? Confirmation_refactor_files=Deseja mesmo renomear este(s) ficheiro(s)? Confirmation_restore_all=Um restauro completo das vistas requer que o Jajuk reinicie. Deseja prosseguir? Confirmation_defaults_radios=Esta acção irá eliminar todas as estações de rádio previamente criadas. Deseja prosseguir? Confirmation_delete_empty_dirs=Os directórios seguintes estão vazios. Deseja eliminá-los? Confirmation_file_overwrite=Este ficheiro já existe. Deseja reescrevê-lo? Confirmation_file_number=ficheiro(s) será(ão) eliminado(s). Confirmation_alarm_stop=Deseja mesmo parar este alarme? Confirmation_defaults=Note que esta acção irá redefinir todas as opções de separadores para os valores predefinidos. Deseja prosseguir? Confirmation_rebuild_thumbs=Esta acção irá redesenhar as miniaturas de todos os seus álbuns, poderá demorar vários minutos para colecções grandes. Deseja prosseguir? Confirmation_reset_preferences=Deseja mesmo redefinir as preferências da faixa? Device_type.directory=Directório Device_type.file_cd=CD de Ficheiros de Música Device_type.audio_cd=CD de Áudio Device_type.extdd=Disco Rígido Externo Device_type.player=Leitor de Áudio Digital Device_type.network_drive=Unidade de Rede Device_type.remote=Controlo Remoto (Não implementado) Perspective_Description_Simple=Básico Perspective_Description_Files=Ficheiros Perspective_Description_Tracks=Faixas Perspective_Description_Configuration=Configurações Perspective_Description_Statistics=Estatísticas Perspective_Description_Help=Ajuda Perspective_Description_Display=Sob Escuta Perspective_Description_Albums=Álbuns Perspective_Description_Info=Informações Perspective_Description_Playlists=Listas Item_Playlist_File=Lista de Reprodução Item_Track=Faixa Item_Album=Álbum Item_Artist=Artista Item_Genre=Género Item_Device=Dispositivo Item_File=Ficheiro Item_Directory=Directório Item_Year=Ano Item_AlbumArtist=Álbum-Artista Property_id=Identificação Property_name=Nome Property_type=Tipo Property_url=Url Property_mount_point=Ponto de Montagem Property_auto_refresh=Auto Actualização Property_auto_mount=Auto Montagem Property_album=Álbum Property_style=Género Property_author=Artista Property_album_artist=Artista do Álbum Property_disc_number=Disco Property_length=Duração Property_year=Ano Property_rate=Pontuação Property_files=Ficheiros Property_hits=N.º Reproduções Property_filename=Ficheiro Property_date=Data Property_added=Data de Adição Property_parent=Directório Superior Property_device=Dispositivo Property_directory=Directório Property_track=Tema Property_size=Tamanho (MB) Property_quality=Qualidade Property_hashcode=Código de Hash Property_playlist_files=Listas de Reprodução Property_comment=Comentário Property_order=Faixa Property_path=Caminho Total Property_tracks=Faixas Property_file_date=Data do Ficheiro Property_Format_Number=Número Property_Format_String=String Property_Format_Boolean=Boolean Property_Format_Float=Float Property_Format_Date=Data Property_Format_URL=Url Property_pf=Avaliação Property_tpt=Tempo de Reprodução (seg.s) Property_ban=Banido Property_disc_id=Identificação do Disco Language_desc_en=Inglês Language_desc_fr=Francês Language_desc_de=Alemão Language_desc_it=Italiano Language_desc_sv=Sueco Language_desc_nl=Holandês Language_desc_zh=Chinês Language_desc_es=Castelhano Language_desc_ca=Catalão Language_desc_ko=Coreano Language_desc_el=Grego Language_desc_ru=Russo Language_desc_gl=Galego Language_desc_cs=Checo Language_desc_pt=Português #--- Error codes --- Error.000=Erro desconhecido! Error.005=Erro de análise ao ficheiro da colecção. Error.007=Erro na reprodução do ficheiro, talvez o MPlayer não tenha começado a ler até se ter atingido o tempo limite para: Error.008=Erro ao parar o ficheiro. Error.009=Não é possível fazer a leitura do ficheiro. Error.010=Não é possível encontrar um ficheiro associado a este item num dispositivo montado. Error.011=Erro técnico na montagem do dispositivo ou dispositivo vazio. Error.012=Erro técnico na desmontagem do dispositivo, estará provavelmente a ser utilizado por um outro programa. Error.013=Não é possível remover o dispositivo: ou está montado ou em actualização no momento. Error.016=Não é possível aceder ao dispositivo especificado. Por favor introduza o ponto de montagem. Ex.: '/cdrom' em Unix,'e:' no MS Windows. Error.017=Erro ao analisar a lista de reprodução. Error.018=Não é possível encontrar faixas acessíveis. Error.019=Um dispositivo existente já possui este nome. Error.020=Erro de I/O copiando ficheiro. O disco poderá estar cheio. Error.021=O campo de URL é obrigatório. Ex.: '/home/foo/music' em Unix, 'd:\music' no MS Windows. Error.022=O campo do Nome é obrigatório. Ex.: 'Disco Rígido', 'CD ROCK'. Error.023=Não é possível começar a faixa de início. Error.024=Não é possível reescrever ficheiro. Error.025=Um dos ficheiros que está a tentar ler está num dispositivo desmontado. Error.026=Erro ao registar leitores. Error.027=Sincronização abortada. Error.028=Erro ao guardar lista de reprodução. Error.029=Um dispositivo existente é um directório superior deste dispositivo, tem o mesmo caminho ou é um directório inferior. Error.030=Demasiadas falhas na conexão. O Jajuk desistiu da procura das capas em linha. Error.101=O Dispositivo não existe ou não está acessível. Error.102=Erro! Error.103=Erro ao ler informações da etiqueta. Error.104=Erro ao escrever informações na etiqueta. Error.105=Chave de recursos não encontrada. Error.106=Excepção não prevista. Error.107=Dispositivo já em actualização ou sincronização. Error.108=Erro de análise ao ficheiro da Perspectiva. Error.109=Classe da implementação do leitor ou da etiqueta não acessível. Error.110=O nome desta propriedade está reservada ao sistema interno do Jajuk. Por favor escolha outro. Error.111=O dispositivo já está montado. Error.112=Não é possível proceder à montagem do dispositivo. Error.113=Não é possível guardar as configurações do utilizador. Error.114=Não é possível ler as configurações do utilizador. Error.118=Erro ao processar a acção requisitada. Error.119=Erro na análise ou ausência do ficheiro do histórico. Error.120=Não é possível aceder ao dispositivo: ou não está montado, ou está em actualização ou sincronização. Error.121=O dispositivo está em utilização e não é possível desmontá-lo. Error.122=Erro no FIFO. Error.123=Erro definindo o tema visual. Error.124=O Jajuk já está em execução. Apenas uma instância do programa pode ser executada de cada vez. Error.125=O dispositivo já está montado. Error.126=A função de pesquisa não é suportada por este formato de áudio. Error.127=Não foram encontradas Novas Entradas para a janela temporal especificada. Pode definir os limites temporais na vista das Preferências. Error.128=A faixa presente é a primeira da colecção. Não existe faixa que a anteceda. Error.129=Erro ao carregar a imagem de capa. Error.131=Não é possível eliminar o ficheiro. Error.133=O ficheiro da sua colecção ficou corrompido por razão desconhecida. O Jajuk restaurou a colecção pela cópia de segurança. Error.134=Não é possível renomear o ficheiro. Error.135=O ficheiro não existe. Error.136=A operação foi mal sucedida. Error.137=Formato errado. Error.138=Alguns ficheiros apontados por estas faixas estão localizados em dispositivos desmontados e por isso não foram alterados. Error.140=Expressão inválida: não pode conter os caracteres & ' " < > Error.141=Esta lista de reprodução está localizada num dispositivo desmontado ou em actualização e por isso não está disponível. Error.142=Esta lista de reprodução aponta para faixas não existentes ou para faixas localizadas fora dos dispositivos conhecidos pelo Jajuk. Essas faixas foram ignoradas. Error.143=A localização do dispositivo não está acessível. Error.144=Erro ao analisar o DJ. Error.145=Não é possível executar o DJ. Error.146=O presente padrão do organizador está errado.
    Os itens válidos são: %artist (Nome do Artista); %album_artist (Artista do Álbum); %title (Título da Faixa); %album (Nome do Álbum);
    %n (Zero de Referência da Faixa); %genre (Género da Faixa); %year (Ano); %disc (Número do disco)
    este padrão deve conter pelo menos uma barra. Error.147=Alguns ficheiros não puderam ser movidos (ver detalhes para mais informações). Error.148=O campo do Ano é desconhecido. Error.149=O campo do Álbum é desconhecido. Error.150=O campo do Artista é desconhecido. Error.151=O campo do Título da Faixa é desconhecido. Error.152=O campo do Faixa é desconhecido. Error.153=O campo do Género é desconhecido. Error.154=Não é possível renomear o ficheiro, verifique a presença de caracteres interditos no nome do ficheiro ou etiquetas. Error.155=Erro ao reetiquetar ficheiros, verifique permissões. Error.156=Colecção vazia. Error.157=DJ errado, por favor seleccione ou crie um DJ através do botão do DJ na vista de Comando. Error.158=As restrições do DJ não foram respeitadas ou nenhuma faixa se encontra disponível. Error.159=A ambiência associada foi removida. Error.160=O ficheiro não foi movido, os nomes de origem e destino são idênticos. Error.161=Não é possível escrever para o directório, verifique permissões. Error.162=Esta propriedade personalizada já existe. Error.163=Erro ao restaurar vistas predefinidas. Error.164=Nenhuma faixa acessível para ambiência: Error.165=Caminho errado para a colecção, o directório não pode ser encontrado ou não pode ser escrito. Error.166=Álbum vazio, não é possível requestar a capa. Error.167=Não foi possível criar o relatório. Error.168=Não foram encontrados ficheiros duplicados. Error.169=Operação mal sucedida. Note que esta operação necessita de uma ligação à Internet para poder requestar a lista de estações de rádio. Error.170=Erro ao reproduzir rádio web. Error.171=Uma fonte de sincronização ainda não foi definida para este dispositivo, defina-a através do utilitário de configuração do dispositivo na vista dos Dispositivos / Dispositivo. Error.172=Não é possível eliminar os ficheiros actualmente em reprodução: Error.173=Erro encontrado ao eliminar os seguintes directórios: Error.174=Erro ao aceder ao sítio web Freedbe, verifique a sua ligação à rede. Error.175=Operação cancelada. Error.176=Erro ao gerar a lista de reprodução. Error.177=Por favor introduza um tempo válido no formato HH(0-24):MM:SS. Error.179=Não é possível abrir o explorador de ficheiros do sistema, experimente definir-lhe um caminho na vista das Preferências / Avançadas. Error.180=Erro ao copiar os ficheiros. #Warnings Warning.0=O MPlayer não foi encontrado. Alguns formatos de áudio e de vídeo (flac, wma, aac, mpg2 ... ) serão desabilitados. Se o MPlayer já está instalado, por favor defina manualmente o seu caminho na vistas das Preferências / Avançadas. Warning.1=Versão errada do MPlayer, a versão MPlayer1.0Pre8 ou mais recente é necessária. Alguns formatos de áudio serão desabilitados. Warning.2=Parece que alguém está presentemente a utilizar a actual colecção. O derradeiro utilizador a sair irá reescrever as configurações (opções, pontuações...). Warning.3=Não é possível descarregar o Mplayer. Se está por detrás de um proxy HTTP, por favor configure-o na vista das Preferências / Rede e reinicie o Jajuk. Warning.4=o Mplayer é necessário para fazer a escuta de rádios web. Warning.5=O directório de destino já existe, alguns ficheiros serão possivelmente reescritos. Deseja prosseguir? Warning.6=Nenhuma faixa disponível para reprodução (dica: experimente montar algum dispositivo ou alterar a ambiência). Warning.7=O Jajuk precisa de realizar uma actualização exaustiva da colecção devido à instalação de uma versão mais recente. Deseja prosseguir agora? (Note que poderá fazê-lo a qualquer momento desde a vista dos Dispositivos). #--- Strings by class --- ParameterView.0=Duração do histórico: ParameterView.2=Defina o número de dias que se deve manter o registo das faixas reproduzidas. Introduza -1 se não quiser registar um histórico, e -0 se preferir registar o histórico permanentemente ParameterView.3=Limpar o histórico ParameterView.4=Limpar o histórico ParameterView.8=Histórico ParameterView.9=Reproduzir: ParameterView.10=Nenhuma ParameterView.11=Nenhuma faixa será reproduzida aquando do arranque do Jajuk ParameterView.12=A última faixa desde o início ParameterView.13=Reproduz a última faixa escutada ao momento da saída desde o seu início ParameterView.14=Uma faixa aleatória ParameterView.15=Reproduz uma faixa de toda a colecção aleatoriamente ParameterView.16=A faixa: ParameterView.17=Seleccione um ficheiro a ser reproduzido ParameterView.18=Seleccione um ficheiro a ser reproduzido no arranque. Comece a escrever para que seja apresentada uma lista filtrada ParameterView.19=Arranque ParameterView.26=Confirmações ParameterView.27=Antes de eliminar fisicamente um ficheiro ParameterView.28=Perguntar antes de eliminar fisicamente um ficheiro ParameterView.29=Antes de sair do Jajuk ParameterView.30=Perguntar antes de fechar o programa ParameterView.33=Opções ParameterView.35=Esconder faixas localizadas em dispositivos desmontados ParameterView.36=Retomar quando o final da colecção for atingido ParameterView.37=Reiniciar a colecção quando o final for atingido no modo Contínuo ParameterView.38=Língua: ParameterView.42=Seleccione a língua do interface ParameterView.43=Tema visual: ParameterView.44=Seleccione um tema

    (Pode ser necessário reiniciar o Jajuk para que este seja completamente aplicado). ParameterView.46=Nível de registo: ParameterView.47=Fatal ParameterView.48=Erro ParameterView.49=Aviso ParameterView.50=Informação ParameterView.51=Depuração ParameterView.52=Verbosidade do Jajuk: Fatal: apresentar apenas erros críticos, Erro: +apresentar erros, Informação: +apresentar mensagens informativas, Aviso: +apresentar avisos, Depuração: todas as mensagens ParameterView.59=Posição de começo da introdução (%): ParameterView.60=Posição de começo da introdução numa faixa em % de 0 (início da faixa) até 99 (fim da faixa) ParameterView.61=Duração da introdução (segundos): ParameterView.62=Duração da introdução em segundos ParameterView.85=Aplicar ParameterView.86=Restaurar predefinições ParameterView.87=Preferências ParameterView.98=Padrões ParameterView.99=Executar um rastreio exaustivo às etiquetas ParameterView.100=Forçar o Jajuk a reler as actuais etiquetas id3.

    Isto poderá ser útil na actualização de etiquetas modificadas utilizando um outro programa.

    ParameterView.101=Utilizar o directório superior como nome do álbum ParameterView.102=Quando verificado, o nome do directório superior será utilizado como o nome do álbum em faixas cuja etiqueta id3 não possa ser utilizada ParameterView.109=Preferências guardadas ParameterView.110=Preferências definidas por omissão ParameterView.111=Tamanho da lista de reprodução Favoritas: ParameterView.112=Defina o número de faixas que compõem a lista de reprodução Favoritas (de 1 até 100) ParameterView.113=Utilizar expressões comuns nos filtros ParameterView.114=Utilizar expressões comuns (formato Regexp) nos filtros de tabela. Ex.: .*foo.* ParameterView.115=Avançadas ParameterView.116=Salvaguardar ficheiro da colecção ParameterView.117=Verifique a caixa se deseja salvaguardar o ficheiro da sua colecção para ficheiros colecção-.xml ParameterView.118=Tamanho da salvaguarda (MB) ParameterView.119=Tamanho da salvaguarda (MB) ParameterView.120=Codificação da colecção ParameterView.121=Codificação de caracteres da colecção. UTF-16 está optimizado para línguas Asiáticas e UTF-8 está optimizado para línguas Europeias. ParameterView.129=Limite de tempo das novas entradas (dias): ParameterView.130=Limite de tempo das novas entradas em dias: todas as faixas adicionadas dentro deste limite serão apresentadas na lista de reprodução de Novas Entradas ParameterView.131=Uma Favorita ParameterView.132=Reproduza uma das suas faixas favoritas no arranque ParameterView.133=Uma Nova Entrada ParameterView.134=Reproduza uma Nova Entrada da sua colecção no arranque ParameterView.135=A última faixa desde a duração à saída ParameterView.136=Reproduz a última faixa escutada ao momento da saída desde a sua duração à saída ParameterView.139=Rede ParameterView.142=Nome de utilizador do Proxy ParameterView.143=Nome de utilizador do Proxy utilizado na autenticação ParameterView.144=Nome de servidor do Proxy ParameterView.145=Nome de servidor do Proxy ou endereço de IP ParameterView.146=Porta do Proxy ParameterView.147=Porta TCP-IP do Proxy (frequentemente 3128) ParameterView.148=Requestar capas em linha ParameterView.149=Utilize para descarregar automaticamente capas desde a Internet (se necessário, configure o seu proxy no separador Rede) ParameterView.150=Tamanho das capas ParameterView.151=Tamanho dos capas descarregadas ParameterView.155=Precisão da pesquisa. Quanto mais elevada for a precisão, menos provável será a obtenção de capas erradas. ParameterView.156=Baixa precisão (pesquisar por todas as palavras) ParameterView.157=Média precisão (pesquisar por palavras agrupadas) ParameterView.158=Alta precisão (pesquisar por palavras obrigatoriamente agrupadas) ParameterView.159=Capas ParameterView.160=Expiração da conexão (segundos) ParameterView.161=Tempo oferecido até à expiração da conexão em segundos: uma operação remota falhará se não se obtiver resposta neste limite de tempo ParameterView.162=Expiração da transferência (segundos) ParameterView.163=Tempo oferecido até à expiração da transferência de dados em segundos: uma operação remota falhará se os dados requisitados não forem completamente descarregados neste limite de tempo ParameterView.164=Antes de remover um dispositivo ParameterView.165=Perguntar antes da remoção de um dispositivo ParameterView.166=Capa aleatória ParameterView.167=Apresentar uma capa aleatória ParameterView.169=Pré-requisitar capas ParameterView.170=Pré-requisitar capas todas as capas disponíveis quando possível ParameterView.171=Antes de eliminar uma capa ParameterView.172=Antes da eliminação física de uma capa ParameterView.177=Número de faixas planeadas visíveis ParameterView.178=O número de faixas planeadas a serem apresentadas na lista de reprodução ParameterView.179=Colocação imediata da selecção ParameterView.180=Quando verificado, o duplo-clique numa faixa ou a selecção de itens colocá-los-á no alinhamento ParameterView.181=Colocação arrastando e largando ParameterView.182=Quando verificado, as faixas da colecção poderão ser arrastadas e largadas numa lista de reprodução ParameterView.186=Redefinir pontuações ParameterView.187=Redefinir todas as pontuações de faixas para zero ParameterView.188=Antes de limpar o histórico ParameterView.189=Antes de redefinir as pontuações ParameterView.190=Duração do cross fade (segundos) ParameterView.191=O número de segundos atribuído ao cross fade entre faixas ParameterView.192=Organizador de ficheiros: ParameterView.193=Padrões disponíveis : %artist (Nome do Artista); %album_artist (Artista do Álbum, se indefinido, o nome do artista será utilizado); %title (Título da Faixa); %album (Nome do Álbum); %n (Faixa); %genre (Género da Faixa); %year (Ano); %disc (Número do Disco) ParameterView.194=Antes de organizar ficheiros ParameterView.195=Vista da Animação: ParameterView.196=Habilitar teclas de atalho ParameterView.197=Habilitar o funcionamento de algumas teclas como F8, F9 e F10 mesmo quando o Jajuk não estiver em primeiro plano ParameterView.198=Algumas alterações só serão efectivas no próximo arranque do Jajuk ParameterView.199=Recomendar outras escutas ParameterView.200=Sugestão de outras escutas com base nos seus hábitos de escuta. Esta opção envia informações para a Last.FM ParameterView.201=Nome de utilizador Last.FM ParameterView.202=O seu nome de utilizador na conta da Last.FM ParameterView.203=Senha Last.FM ParameterView.204=A senha definida para aceder à conta da Last.FM ParameterView.205=Argumentos do Mplayer ParameterView.206=Argumentos adicionais do MPlayer '-ao esd', '-ao arts' ou '-novideo (para prevenir a reprodução de vídeos)' ParameterView.207=Caminho para a configuração do Jajuk ParameterView.208=Defina o directório que deve conter o ficheiro de configuração do Jajuk (a predefinição é a pasta pessoal do utilizador) ParameterView.209=O caminho para a configuração do Jajuk foi alterado para o presente utilizador (a colecção anterior será conservada na localização antiga). O Jajuk vai ser fechado e poderá ser reiniciado. ParameterView.210=Se o cross fade não funcionar, experimente adicionar <-ao esd> em Gnome ou <-ao arts> em KDE no campo dos argumentos adicionais do MPlayer (vista das Preferências / Avançadas). ParameterView.211=Pequenas apenas ParameterView.212=Pequenas e médias ParameterView.213=Médias apenas ParameterView.214=Médias e grandes ParameterView.215=Grandes apenas ParameterView.216=Pesquisa por nome do artista ParameterView.217=Pesquisa por nome do álbum ParameterView.218=Pesquisa por nome da faixa ParameterView.219=Variáveis do ambiente ParameterView.220=Definir as variáveis do ambiente utilizadas pelo leitor de áudio (ARTS_SERVER em KDE ou ESPEAKER em Gnome). Formato: var1=xx var2=yyy... #Respect English size for next item ParameterView.221=Tamanho da pág. Catálogo (0: todos) ParameterView.222=Defina o número de álbuns por página na vista do Catálogo de Álbuns. 0: apresentar todas as capas numa única página ParameterView.223=Tamanho da letra ParameterView.224=Defina o tamanho da letra do texto ParameterView.225=IG ParameterView.226=Modos ParameterView.228=Mostrar popups de álbuns ParameterView.229=Preferências da vista do Catálogo ParameterView.233=O tema visual será completamente aplicado no próximo arranque do Jajuk ParameterView.234=Procurar por actualizações do Jajuk ParameterView.235=Last.FM ParameterView.236=Sem Proxy ParameterView.237=Proxy HTTP ParameterView.238=Proxy SOCKS ParameterView.239=Senha do Proxy ParameterView.240=Habilitar consultas de informação da Last.FM ParameterView.241=Quando verificado, o Jajuk irá requestar ao sítio da Last.FM variada informação sobre álbuns e outras (ver vista das Sugestões) ParameterView.242=Caminho do Mplayer ParameterView.243=Defina aqui o caminho total do MPlayer incluindo o executável (espaços permitidos).
    Ex.: /Applications/MPlayer OSX.app/Contents/Resources/External_Binaries/mplayer_intel.app/Contents/MacOS/mplayer ParameterView.244=Data de adição = Data do ficheiro ParameterView.245=Quando verificado, o Jajuk passa a considerar a data dos ficheiros de áudio no sistema como a data de adição na colecção.
    Requer uma actualização exaustiva. ParameterView.246=Tamanho dos ícones da barra de Perspectivas (pixels) ParameterView.247=Caminho de destino contém um directório de trabalho já existente. O directório de trabalho foi alterado para este caminho para o utilizador presente (o espaço de trabalho anterior foi conservado na localização antiga). O Jajuk vai ser fechado e poderá ser reiniciado. ParameterView.248=Título da moldura: ParameterView.249=Redefinir preferências ParameterView.250=Redefinir preferências do utilizador ParameterView.251=Histórico redefinido com sucesso ParameterView.252=Pontuações e contagens redefinidas com sucesso ParameterView.253=Preferências redefinidas com sucesso ParameterView.254=Utilize nomes curtos do Windows ParameterView.255=[Apenas para Windows 32 bits] Quando verificado, força o MPlayer a usar nomes curtos nos ficheiros de áudio para resolver problemas com algumas localizações em Windows ParameterView.256=Nomes predefinidos para ficheiros de capa ParameterView.257=O Jajuk aceita como predefinição vários ficheiros de capa cujo nome contenha este texto (sem extensões). Vários termos separados por ';' poderão ser fornecidos. Por exemplo : "Folder;front" ParameterView.260=Guardar capas de forma compatível com o Windows Explorer ParameterView.261=Guarde as capas descarregadas como folder.jpg/png/... para que o explorador do Windows as possa usar como ícone do directório ParameterView.262=Utilizar normalização do áudio ParameterView.263=Maximiza o nível do áudio sem que ocorra distorção da onda ParameterView.264=Desabilitar todo o acesso à Internet por parte do Jajuk ParameterView.265=Desabilitar todo o acesso à Internet por parte do Jajuk (LastFM, descarga de capas ou de letras...) ParameterView.266=Deixar cair do alinhamento faixas já reproduzidas ParameterView.267=Todas as faixas que precederam a faixa sob escuta serão apagadas do alinhamento ParameterView.268=Configuração do Proxy ParameterView.269=Caminho do executável do explorador ParameterView.270=Caminho para o executável utilizado como explorador de ficheiros externo ParameterView.271=Mostrar na área de notificação ParameterView.272=Quando verificado, o Jajuk poderá ser controlado a partir da área de notificação (nem todos os sistemas operativos são suportados) ParameterView.273=Capa espelhada ParameterView.274=Quando verificado, a capa será apresentada inclinada e espelhada ParameterView.275=Notificação de mudança da faixa: ParameterView.276=Seleccione o tipo de notificação afecto à mudança da faixa (uma tosta é uma notificação em popup que aparece durante uns momentos no ecrã e que desaparece por si) ParameterView.277=Padrão de notificação: ParameterView.278=Este padrão define o texto a ser mostrado pelos notificadores aquando da mudança de faixa ParameterView.279=Padrão de informação: ParameterView.280=Este padrão define o texto a ser mostrado na vista de informação (parte inferior do ecrã) ParameterView.281=Minimizar para a área de notificação ParameterView.282=Quando verificado, a janela principal do Jajuk será mostrada na área de notificação do sistema apenas, quando minimizada, e não mais na barra de tarefas Main.21=Confirmações Main.22=Verificando/Descarregando MPlayer Player.0=Esperando por um canal de áudio (ocupado) Device.25=] actualizado em Device.27= novos ficheiros Device.31=Sincronizando [ Device.33=Sincronizado em Device.35= ficheiros criados ( Device.36= MB) Device.41=Sincronizando [ Device.42=] Copiando [ Device.43= etiquetas ilegíveis Device.44=Introduzindo Device.45=Copiando [ Device.46=Convertendo [ Device.47=] para [ FIFO.4=). Quer tentar montá-lo? FIFO.10=Sob Escuta: FIFO.13= Kbps FIFO.14=Rádio Web Sob Escuta: HistoryItem.0=yy/MM/dd HH:mm DeviceWizard.0=Configuração do dispositivo DeviceWizard.1=Tipo do dispositivo*: DeviceWizard.2=Nome do dispositivo*: DeviceWizard.3=Localização do dispositivo*: DeviceWizard.7=Realizar uma actualização imediata DeviceWizard.8=Auto-montar no arranque DeviceWizard.10=Sincronizado com: DeviceWizard.11=Sincronização unidireccional DeviceWizard.12=Todos os novos ficheiros encontrados no dispositivo de origem serão copiados para este dispositivo. Nada será gravado no dispositivo de origem DeviceWizard.13=Sincronização bidireccional DeviceWizard.14=Todos os novos ficheiros encontrados num dispositivo serão copiados para o outro dispositivo DeviceWizard.43=Por favor especifique um directório DeviceWizard.44=Dispositivo criado DeviceWizard.45=Por favor especifique um nome para o dispositivo. Ex: Laptop... DeviceWizard.46=Por favor especifique a localização do dispositivo. Ex: d:\music no Windows, /home/foo/music em Unix DeviceWizard.48=Verifique se pretender realizar uma actualização imediata no dispositivo (aconselhada).

    Note que esta operação pode demorar alguns minutos para grandes colecções.

    DeviceWizard.49=Verifique se pretender que o Jajuk monte o dispositivo automaticamente no arranque.

    Aconselhado para directórios no disco rígido interno, mas não para directórios em suportes removíveis.

    DeviceWizard.50=Especifique um intervalo em minutos para pesquisa automática de novos ficheiros (0: não pesquisar; 0,5 min.s correspondem ao intervalo mínimo). DeviceWizard.51=Verifique se pretender sincronizar este dispositivo com um outro DeviceWizard.52=Seleccione um dispositivo de origem DeviceWizard.53=Actualizar dispositivo a cada #limited string size DeviceWizard.54=min DeviceWizard.55=Valor errado: o intervalo de actualização deve ser 0 ou um número >= 0,5. JajukJMenuBar.0=Ficheiro JajukJMenuBar.1=Abrir ficheiro JajukJMenuBar.3=Sair JajukJMenuBar.5=Propriedades JajukJMenuBar.6=Criar propriedade personalizada JajukJMenuBar.7=Apagar propriedade personalizada JajukJMenuBar.8=Vistas JajukJMenuBar.9=Modos JajukJMenuBar.10=Repetitivo JajukJMenuBar.11=Aleatório JajukJMenuBar.12=Contínuo JajukJMenuBar.13=Introdutório JajukJMenuBar.14=Ajuda JajukJMenuBar.15=Tópicos da Ajuda JajukJMenuBar.16=Sobre JajukJMenuBar.17=Restaurar vistas (só esta perspectiva) JajukJMenuBar.18=Utilitário de dispositivo JajukJMenuBar.19=Requisitar depurações ou novas funcionalidades JajukJMenuBar.20=Dica do dia JajukJMenuBar.21=Configurações JajukJMenuBar.22=Preferências JajukJMenuBar.23=Mostrar vestígios para depuração JajukJMenuBar.24=Mostrar apenas as faixas disponíveis JajukJMenuBar.25=Mostrar vista JajukJMenuBar.26=Restaurar vistas (todas as perspectivas) JajukJMenuBar.27=Procurar por actualizações do Jajuk JajukJMenuBar.28=Ferramentas JajukJMenuBar.29=Programas JajukJMenuBar.30=Repetir todas JajukJMenuBar.31=Karaoke # next two lines are only used in development/test mode, translation is therefore optional JajukJMenuBar.32=Call a full GC (test mode only) JajukJMenuBar.33=Perform a manual commit of the collection data (test mode only) PlaylistFileItem.1=Novas Entradas PlaylistFileItem.2=Nova Lista de Reprodução PlaylistFileItem.3=Marcadores PlaylistFileItem.4=Favoritas PlaylistFileItem.5=Alinhamento JajukFileChooser.0=Selector de ficheiros SearchBox.0=Realize uma pesquisa entre faixas, artistas, géneros, directórios... CommandJPanel.0=Ver histórico de reproduções CommandJPanel.1=[Ctrl-t] Modo de repetição: reproduza faixas ciclicamente CommandJPanel.2=[Ctrl-h] Modo aleatório: reproduza faixas escolhidas ao acaso CommandJPanel.3=Modo contínuo: reproduza as faixas planeadas quando chegar ao final CommandJPanel.4=Modo introdutório: reproduza apenas uma parte de cada faixa. Duração e começo podem ser especificados na vista das Preferências CommandJPanel.5=Reproduz uma selecção aleatória de faixas de toda a colecção CommandJPanel.6=Reproduz as suas faixas favoritas CommandJPanel.8=[F9] Reproduz a faixa anterior da presente selecção
    Shift+clique salta para o álbum anterior
    CTRL+clique reinicia o presente álbum CommandJPanel.9=[F10] Reproduz a faixa seguinte da presente selecção
    Shift+clique salta para o álbum seguinte CommandJPanel.10=[Alt-gr F9] Rebobinar rapidamente a presente faixa
    Shift+clique para reproduzir novamente CommandJPanel.13=[Alt-gr F0] Bobinar rapidamente a presente faixa CommandJPanel.15=Clique para alterar o formato do cronómetro CommandJPanel.16=Iniciar uma selecção do DJ CommandJPanel.17=Gerir o DJ CommandJPanel.18=Iniciar a selecção predefinida do DJ CommandJPanel.19=Gerir as Ambiências CommandJPanel.20=Faixa por Faixa CommandJPanel.21=Baralhar álbum por álbum CommandJPanel.22=Álbum por Álbum CommandJPanel.23=Clique para limpar a pesquisa CommandJPanel.24=Configurar rádios web CommandJPanel.25=Ligar o rádio CommandJPanel.26=Modo de repetição total: reproduza todo o alinhamento ciclicamente CommandJPanel.27=Modo de Karaoke: retire as vozes da faixa sob escuta (apenas se activa no início da próxima faixa) InformationJPanel.5=Duração remanescente no alinhamento [Nº de faixas remanescentes] InformationJPanel.6=Taxa de bits da faixa InformationJPanel.7=Progressão da faixa sob escuta # %xxx are patterns, don't translate them ! InformationJPanel.8=%title por %artist de %album # Keep next label short InformationJPanel.9= AbstractPlaylistEditorView.0=Título AbstractPlaylistEditorView.1=Localização AbstractPlaylistEditorView.2=Reproduzir esta lista AbstractPlaylistEditorView.3=Guardar esta lista AbstractPlaylistEditorView.4=Adicionar um item nesta lista AbstractPlaylistEditorView.5=Remover um item desta lista AbstractPlaylistEditorView.6=Mover acima AbstractPlaylistEditorView.7=Mover abaixo AbstractPlaylistEditorView.9=Apagar esta lista AbstractPlaylistEditorView.10=Adicionar uma faixa nesta lista AbstractPlaylistEditorView.15=Listas de reprodução AbstractPlaylistEditorView.17=Está prestes a actualizar as seguintes listas: AbstractPlaylistEditorView.18=Faixa no alinhamento AbstractPlaylistEditorView.19=Faixa repetida AbstractPlaylistEditorView.20=Faixa planeada AbstractPlaylistEditorView.21=Faixa de lista de reprodução AbstractPlaylistEditorView.22=Lista de reprodução guardada AbstractPlaylistEditorView.27=Preparar festa AbstractPlaylistEditorView.28=Pasta criada com sucesso em StatView.0=Outros StatView.1=Géneros StatView.2=Sem dados disponíveis StatView.3=Outros StatView.4=Tamanho por dispositivo (GB) StatView.5=Sem dados disponíveis StatView.7=Tamanho da colecção por mês StatView.8=Meses StatView.9=Tamanho (GB) StatView.10=Sem dados disponíveis StatView.12=Número total de faixas por mês StatView.13=Meses StatView.14=Número de faixas StatView.15=Sem dados disponíveis StatView.16=Estatísticas StatView.24=Mais antigo CDScanView.0=Etiqueta do CD: CDScanView.1=Etiqueta do CD. Ex: CD1, ROCK... CDScanView.2=Etiqueta do CD. Ex: CD1, ROCK... CDScanView.3=Localização do CD: CDScanView.4=Localização onde se encontra o CD. Ex: '/cdrom' em Unix, 'e:' no MS Windows... CDScanView.5=Localização onde se encontra o CD. Ex: '/cdrom' em Unix, 'e:' no MS Windows... CDScanView.6=Rastrear CDScanView.12=Rastreio de CD CDScanView.18=Rastreia o CD e adiciona todas os ficheiros musicais à colecção CDScanView.19=Seleccione a localização do CD AbstractTreeView.0=Colapsar tudo TracksTreeView.0=Árvore de faixas TracksTreeView.27=Colecção TracksTreeView.31= faixas TracksTreeView.33=Criar um relatório TracksTreeView.34=Obter etiquetas em linha TracksTreeView.35=Data da adição TracksTreeView.36=menor do que uma semana TracksTreeView.37=menor do que um mês TracksTreeView.38=menor do que seis meses TracksTreeView.39=mais antigo TracksTreeView.40=menor do que um ano TracksTreeView.41=menor do que dois anos TracksTreeView.42=menor do que cinco anos TracksTreeView.43=menor do que dez anos TracksTreeView.44=menor do que três meses TracksTreeView.45=Ano CoverView.2=Apagar esta capa do disco CoverView.3=Capa CoverView.4=Imagem anterior no disco e/ou da Web se a opção de baixar as capas automaticamente estivar verificada CoverView.5=Imagem seguinte no disco e/ou da Web se a opção de baixar as capas automaticamente estivar verificada CoverView.6=

    Guardar a capa com o seu nome original

    Com CTRL: Guardar capa como...

    CoverView.8=Utilizar esta capa como a capa predefinida deste álbum CoverView.9=capas CoverView.10=Guardar capa como... CoverView.11=Capa guardada CoverView.12=Álbum CoverView.13=Título AnimationView.0=Animação FilesTreeView.0=Árvore de Ficheiros FilesTreeView.3=Copiar FilesTreeView.4=Cortar FilesTreeView.5=Colar FilesTreeView.7=Eliminar FilesTreeView.14=Dessincronizar FilesTreeView.15=Ressincronizar FilesTreeView.16=Criar Lista de Reprodução FilesTreeView.17=Copiar FilesTreeView.18=Cortar FilesTreeView.28=Montar FilesTreeView.29=Desmontar FilesTreeView.30=Forçar actualização FilesTreeView.31=Sincronizar FilesTreeView.32=Testar FilesTreeView.33=Criar Listas de Reprodução FilesTreeView.40=Copiar FilesTreeView.41=Cortar FilesTreeView.42=Colar FilesTreeView.47=Colecção FilesTreeView.52= ficheiros: FilesTreeView.53= GB FilesTreeView.54= MB FilesTreeView.55=Configurar dispositivo FilesTreeView.59=Deseja efectuar uma actualização rápida ou exaustiva (relendo etiquetas)? FilesTreeView.60=Rápida FilesTreeView.61=Exaustiva FilesTreeView.62=Organizar ficheiros TracksTableView.0=Tabela de Faixas TracksTableView.7=Reproduzir TracksTableView.8=Colocar no alinhamento TracksTableView.9=Reprodução Aleatória TracksTableView.10=Reprodução em Repetição TracksTableView.11=Reproduzir Álbum TracksTableView.12=Reproduzir Artista TracksTableView.14=Propriedades TracksTableView.15=Marcador TracksTableView.16=Colocar no alinhamento já a seguir AbstractTableView.0=Filtro: AbstractTableView.1=Propriedade a filtrar AbstractTableView.3=Termos utilizados pelo filtro AbstractTableView.4=Aplicar filtro AbstractTableView.5=Limpar filtro AbstractTableView.6=Fazer uma filtragem avançada AbstractTableView.7=contém: AbstractTableView.8=Qualquer AbstractTableView.10= AbstractTableView.11=Tornar a tabela editável AboutView.7=Sobre AboutView.8=Licença AboutView.9=Sistema AboutView.10=Sobre AboutView.11=Copyright 2003-2011
    equipa Jajuk" PhysicalPlaylistRepositoryView.0=Reproduzir PhysicalPlaylistRepositoryView.1=Editar PhysicalPlaylistRepositoryView.2=Guardar como PhysicalPlaylistRepositoryView.3=Eliminar PhysicalPlaylistRepositoryView.4=Propriedades PhysicalPlaylistRepositoryView.6=Listas de Reprodução Físicas PhysicalPlaylistRepositoryView.8=Inteligente PhysicalPlaylistRepositoryView.9=Alinhamento PhysicalPlaylistRepositoryView.10=Alinhamento actual: arraste faixas para as reproduzir PhysicalPlaylistRepositoryView.11=Nova Lista PhysicalPlaylistRepositoryView.12=Nova Lista de Reprodução: arraste faixas para as adicionar à lista PhysicalPlaylistRepositoryView.13=Marcadores PhysicalPlaylistRepositoryView.14=Marcar Lista de Reprodução: arraste faixas para as marcar PhysicalPlaylistRepositoryView.15=Favoritas PhysicalPlaylistRepositoryView.16=Lista de Reprodução de Favoritas: apresenta a selecção das faixas mais ouvidas PhysicalPlaylistRepositoryView.17=Novas Entradas PhysicalPlaylistRepositoryView.18=Lista das Novas Entradas: apresenta a selecção das faixas mais recentes PhysicalPlaylistRepositoryView.19=Preparar Lista de Reprodução para Festa FilesTableView.0=Tabela de Ficheiros FilesTableView.15=Directório da Reprodução #Dev: do not use ID = 16, next label is FilesTableView.17 DeviceView.0=Adicionar dispositivo DeviceView.1=Remover um dispositivo desmontado (não elimina nada do disco) DeviceView.2=Seleccionar propriedades do dispositivo DeviceView.3=Montar dispositivo seleccionado DeviceView.4=Desmontar dispositivo seleccionado DeviceView.5=Testar a disponibilidade do dispositivo seleccionado DeviceView.6=Forçar a actualização do dispositivo seleccionado DeviceView.7=Sincronizar dispositivo seleccionado DeviceView.8=Montar DeviceView.9=Desmontar DeviceView.10=Testar DeviceView.11=Forçar actualização DeviceView.12=Sincronizar DeviceView.13=Remover dispositivo DeviceView.14=Configurar DeviceView.17=Novo DeviceView.18=Adicionar dispositivo DeviceView.21=Este dispositivo está disponível DeviceView.22=Este dispositivo não pôde ser acedido DeviceView.23=Dispositivos JajukWindow.1=Sonorizar JajukWindow.2=Silenciar JajukWindow.3=Jajuk JajukWindow.4=Sair JajukWindow.5=Sobre o Jajuk JajukWindow.6=Reprodução Aleatória JajukWindow.7=Reproduzir Favoritas JajukWindow.10=Pausa JajukWindow.12=Reproduzir JajukWindow.13=Anterior JajukWindow.14=Seguinte JajukWindow.15=Reproduzir Novas Entradas JajukWindow.16=Finalizar álbum JajukWindow.17=Jajuk: A Jukebox Avançada JajukWindow.18=Pronto a Reproduzir JajukWindow.19=[F8] Silenciar/Sonorizar
    Utilize a roda do rato para definir o volume JajukWindow.21=Sair JajukWindow.22=Sobre o Jajuk JajukWindow.23=Reproduzir aleatoriamente faixas da colecção JajukWindow.24=Reproduzir as faixas mais populares da colecção JajukWindow.26=[Ctrl-p] Pausar/Reproduzir JajukWindow.27=[Ctrl-s] Parar JajukWindow.31=Reproduzir as faixas mais recentes da colecção JajukWindow.32=Finalizar a reprodução do álbum actual JajukWindow.33=[Ctrl-Cima/Baixo] Volume JajukWindow.34=Posição JajukWindow.35=Reproduzindo: JajukWindow.36=Ambiência actual: JajukWindow.37=Nenhuma ambiência definida #Do not use JajukWindow.38, next is JajukWindow.39 JajukWindow.39=Sob Escuta JajukWindow.40=Configuração de etiquetas adicionais JajukWindow.41=Abre caixa para configuração das etiquetas adicionais activadas JajukDonate.1=Doar JajukDonate.2=A infraestrutura do projecto Jajuk precisa de financiamento, saiba mais na nossa página do orçamento JajukDonate.3=Orçamento JajukDonate.4=Se deseja apoiar o Jajuk, por favor faça uma doação ActiveTagsWizard.1=Etiquetas disponíveis ActiveTagsWizard.2=Etiquetas activadas ActiveTagsWizard.3=Isto configura as etiquetas adicionais que deseja ver apresentadas. As informações são lidas directamente dos ficheiros de áudio (etiquetas id3 por exemplo). Se activar uma nova etiqueta será efectuada uma actualização exaustiva. Isto poderá demorar vários minutos dependendo do tamanho da colecção. SimpleDeviceWizard.0=Criação rápida de dispositivo FirstTimeWizard.0=Começo rápido FirstTimeWizard.1=


    Bem-vindo! Este utilitário assisti-lo-á na elaboração da sua colecção musical

    FirstTimeWizard.2=Por favor especifique a localização da sua música FirstTimeWizard.4=Auxiliar-me imediatamente FirstTimeWizard.5=Por favor seleccione um directório FirstTimeWizard.6=Preferências avançadas FirstTimeWizard.7=Definir o directório de trabalho do Jajuk FirstTimeWizard.8=Directório seleccionado: FirstTimeWizard.9=Nenhum HelpView.2=Ajuda DownloadManager.0=O Jajuk precisa da senha do seu Proxy HTTP para requestar capas.
    Se não as desejar, pode mudar as suas definições no separador de Capas na vista das Preferências.
    Se não dispõe de um proxy, pode mudar as suas definições no separador de Rede na vista das Preferências. DownloadManager.1=Senha requisitada PropertiesWizard.0=Propriedades do item PropertiesWizard.1=Propriedade PropertiesWizard.2=Valor PropertiesWizard.3=Editável? PropertiesWizard.4=Ligação PropertiesWizard.6=Selecção PropertiesWizard.7=Tipo PropertiesWizard.8=Propriedade actualizada com sucesso PropertiesWizard.9=Nenhuma propriedade é editável nesta selecção PropertiesWizard.10=propriedades foram definidas PropertiesWizard.11=Escrevendo etiqueta para: PropertiesWizard.12=Ligação aos detalhes das propriedades do campo em causa NewPropertyWizard.0=Criar propriedade personalizada NewPropertyWizard.3=(*)Tipo NewPropertyWizard.4=Formatar NewPropertyWizard.5=Valor predefinido CustomPropertyWizard.0=(*)Item CustomPropertyWizard.1=(*)Nome da propriedade personalizada RemovePropertyWizard.0=Remover propriedade personalizada QualityFeedbackWizard.20=Uma nova janela será aberta no seu navegador para a submissão de retorno. Os seus traços anónimos de utilização já foram colocados na sua área de transferência. Por favor cole-os no campo da descrição se se tratar de uma questão de depuração (assim, as hipóteses de resolução do problema sairão melhoradas). IncRateAction.0=Incrementar a pontuação da faixa actual. SplashScreen.0=Verificações iniciais SplashScreen.1=Carregando a colecção SplashScreen.2=Inicializando o MPlayer SplashScreen.3=Desenhando o interface gráfico CatalogView.0=Catálogo de Álbuns #Note: CatalogView.2 label musn't be much larger than in English for correct display in 800x600 CatalogView.2=Apresentar álbuns sem capa CatalogView.3=Actualizar o catálogo CatalogView.4=Tamanho da miniatura: CatalogView.5=Criada miniatura para: CatalogView.7=Seleccionar uma capa CatalogView.8=Nenhuma capa encontrada CatalogView.9=Anterior CatalogView.10=Seguinte CatalogView.11=Página: CatalogView.12=Apresentar a página de miniaturas anterior CatalogView.13=Apresentar a página de miniaturas seguinte CatalogView.14=Seleccionar a página de miniaturas a apresentar CatalogView.15=Tamanho das miniaturas: CatalogView.16=Álbuns CatalogView.17=/página CatalogView.18=Selecção de capa CatalogView.19=Redesenhar miniaturas CatalogView.20=Mostrar detalhes CatalogView.21=Apresentar todos os álbuns CatalogView.22=Apresentar álbuns com capa WikipediaView.0=Wikipedia WikipediaView.1=Seleccione a língua: WikipediaView.3=Sem resultados WikipediaView.5=Pesquisa acerca do nome do artista WikipediaView.6=Pesquisa acerca do nome do álbum WikipediaView.7=Pesquisa acerca do título da faixa WikipediaView.8=Carregando WikipediaView.9=Falha ao carregar a informação da Wikipedia WikipediaView.10=Não é possível pesquisar por artista desconhecido TipOfTheDayView.0=Dica do dia TipOfTheDayView.1=Sabia que...? TipOfTheDayView.2=Mostrar no arranque? CDDBWizard.0=Aceitar CDDBWizard.1=Nome do ficheiro CDDBWizard.2=Título da faixa actual CDDBWizard.3=Título do álbum actual CDDBWizard.4=Título da faixa proposto: CDDBWizard.5=Nome do álbum proposto: CDDBWizard.6=Pronto! Encontrado CDDBWizard.7=equivalências possíveis CDDBWizard.12=Nenhuma equivalência encontrada! CDDBWizard.14=Este directório não contém nenhum ficheiro CDDBWizard.16=Género: CDDBWizard.17=Encontrada equivalência exacta! CDDBWizard.18=Equivalências CDDBWizard.19=Obter etiquetas em linha RefactorWizard.0=Ficheiro movido: DigitalDJWizard.0=Seleccione o novo modo DJ DigitalDJWizard.1=Programação baseada em transições (ROCK -> POP) DigitalDJWizard.2=Programação baseada em proporções (20% JAZZ, 30% ROCK) DigitalDJWizard.3=Programação baseada em ambiência (Suave, Festa...) DigitalDJWizard.4=Utilitário DJ Digital DigitalDJWizard.5=Configurações gerais DJ DigitalDJWizard.6=Nome do DJ (*) DigitalDJWizard.8=Número mínimo de estrelas: DigitalDJWizard.9=Cross fade (segundos): DigitalDJWizard.10=Faixas reproduzidas apenas uma vez DigitalDJWizard.11=Queda DigitalDJWizard.12=Dos géneros DigitalDJWizard.13=Para géneros DigitalDJWizard.14=Selecção de géneros (múltipla selecção permitida) DigitalDJWizard.15=Número de faixas DigitalDJWizard.16=Pretende... DigitalDJWizard.17=Criar um novo DJ? DigitalDJWizard.18=Alterar um DJ existente? DigitalDJWizard.19=Eliminar um DJ? DigitalDJWizard.20=Novo DJ baseado em transições #limited string size DigitalDJWizard.21=Remover #limited string size DigitalDJWizard.22=Origem #limited string size DigitalDJWizard.23=Destino #limited string size DigitalDJWizard.24=Nº DigitalDJWizard.26=Por favor crie pelo menos uma transição #limited string size DigitalDJWizard.27=Selecção de Género #limited string size DigitalDJWizard.28=% DigitalDJWizard.29=Novo DJ baseado em proporções DigitalDJWizard.30=Por favor crie pelo menos uma proporção DigitalDJWizard.31=Novo DJ baseado em ambiências DigitalDJWizard.32=Novo DigitalDJWizard.33=Crie uma nova ambiência DigitalDJWizard.34=Eliminar DigitalDJWizard.35=Eliminar ambiência seleccionada DigitalDJWizard.36=Nome da ambiência DigitalDJWizard.37=Nome DigitalDJWizard.38=Por favor crie pelo menos uma ambiência DigitalDJWizard.39=Por favor preencha o nome da ambiência e seleccione géneros de ambiências DigitalDJWizard.40=Por favor seleccione um DJ DigitalDJWizard.41=Por favor atribua um nome ao DJ DigitalDJWizard.42=Um DJ com este nome já existe DigitalDJWizard.43=Edição de DJ DigitalDJWizard.44=Seleccione um DJ para configurar DigitalDJWizard.45=Tomada de Acção DigitalDJWizard.46=Selecção do tipo de DJ DigitalDJWizard.47=Por favor seleccione ou crie uma ambiência DigitalDJWizard.48=Atributos Gerais DigitalDJWizard.49=Por favor preencha os atributos gerais do DJ DigitalDJWizard.50=Por favor defina as proporções DigitalDJWizard.51=Remoção de um DJ DigitalDJWizard.52=Por favor defina as transições DigitalDJWizard.53=Número mínimo de estrelas para selecção de faixas (1: todas as faixas) DigitalDJWizard.54=Duração do cross fade entre faixas DigitalDJWizard.55=Quando marcado, a selecção irá conter cada faixa apenas uma vez DigitalDJWizard.56=Utilitário de Ambiências DigitalDJWizard.57=Gerir ambiências DigitalDJWizard.58=Selecção de Ambiências: DigitalDJWizard.59=O somatório de todas as proporções tem ser < 100 % DigitalDJWizard.60=Nome da presente ambiência DigitalDJWizard.61=Remover o DJ #limited string size DigitalDJWizard.62=Pré-definições DigitalDJWizard.63=Adicionar ambiências predefinidas DigitalDJWizard.64=Qualquer DigitalDJWizard.66=Selecção da ambiência predefinida (uma ambiência consiste num conjunto de géneros, veja o manual) DigitalDJWizard.67=Limitar o número de faixas no alinhamento DigitalDJWizard.68=Número máximo de faixas no alinhamento PreparePartyWizard.1=Preparar uma festa PreparePartyWizard.2=Seleccione a fonte de faixas PreparePartyWizard.3=Em primeiro lugar defina quais as faixas da sua festa PreparePartyWizard.4=Seleccione os limites PreparePartyWizard.5=Por favor defina as restrições PreparePartyWizard.6=DJs PreparePartyWizard.7=Ambiências PreparePartyWizard.8=Listas de Reprodução PreparePartyWizard.9=Faixas aleatórias PreparePartyWizard.10=Máx. n.º de faixas PreparePartyWizard.11=Qual o número máximo de faixas a incluir PreparePartyWizard.12=Tamanho máx. (MB) PreparePartyWizard.13=Qual o tamanho máximo em MB a criar PreparePartyWizard.14=Duração máx. (minutos) PreparePartyWizard.15=Qual a duração máxima da lista de festa PreparePartyWizard.16=Tipo de restrição PreparePartyWizard.17=Escolher utilizar apenas um tipo de ficheiros. Isto poderá ser útil se um leitor de áudio apenas suportar certos tipos de média. PreparePartyWizard.18=Seleccionar localização PreparePartyWizard.19=Seleccione a localização onde os ficheiros serão guardados. Um sub-directório para os ficheiros será criado. PreparePartyWizard.20=Por favor seleccione a localização de destino PreparePartyWizard.21=Directório seleccionado: PreparePartyWizard.22=Por favor seleccione o directório de destino PreparePartyWizard.23=Os ficheiros foram copiados em PreparePartyWizard.24=Lista de Reprodução Favoritas PreparePartyWizard.25=Lista de Reprodução Novas Entradas PreparePartyWizard.26=Normalizar nomes de ficheiros PreparePartyWizard.27=Normalizar nomes de ficheiros com a substituição de caracteres especiais a fim de melhorar a portabilidade entre sistemas operativos. PreparePartyWizard.31=Localização pretendida: PreparePartyWizard.32=Ficheiros alinhados PreparePartyWizard.33=Ficheiros marcados PreparePartyWizard.34=Ensaiar a conversão de outros formatos de média PreparePartyWizard.35=Utilizar a ferramenta externa 'pacpl - Perl Audio Converter' para a conversão de ficheiros se necessário PreparePartyWizard.36= ficheiro(s) não puderam ser convertidos para o formato pretendido. PreparePartyWizard.37=(requer PACPL, ver Perl Audio Converter) PreparePartyWizard.38=Configurar definições de conversão PreparePartyWizard.39=Por favor defina qual o comando para arrancar com o Perl Audio Converter.
    Em Unix "pacpl" ou "perl <install-location>/pacpl.
    No Windows "perl <install-location>\pacpl PreparePartyWizard.40=Configurar... Ambience.0=Rock/Pop Ambience.1=Rap Ambience.2=HardRock Ambience.3=Techno Ambience.4=Electro Ambience.5=Clássica Ambience.6=Suave Ambience.7=Festa Ambience.8=Jazz Ambience.9=Mundo Ambience.10=Outros Ambience.11=Tradicional Ambience.12=Indie Ambience.13=Latina DebugLogAction.0=Listagem dos traços de depuração DebugLogAction.1=Actualizar CopyClipboardAction.0=Copiar morada para a área de transferência LaunchInBrowserAction.0=Ir para a morada no navegador predefinido ReportAction.0=Relatório criado com sucesso. ReportAction.1=Relatório de Música do Jajuk ReportAction.2=Por favor tenha apreço pelo ambiente e só imprima se absolutamente necessário. ReportAction.3=Listagem de Álbuns ReportAction.4=Faixas por Álbuns ReportAction.5=Listagem de Artistas ReportAction.6=Álbuns por Artistas ReportAction.7=Listagem de Géneros ReportAction.8=Álbuns por Géneros ReportAction.9=Artistas por Álbuns por Género ReportAction.10=Listagem de Directórios ReportAction.11=Ficheiros por Directórios ReportAction.12=Nome do Ficheiro ReportAction.13=Nome da Faixa ReportAction.14=Listagem de Dispositivos ReportAction.15=Directórios por Dispositivo ReportAction.16=Directórios por Ficheiros ReportAction.17=Colecção ReportAction.18=Artistas por Álbuns por Faixas por Estilo ReportAction.19=Saltar para: ActionMove.0=Colar ActionRefresh.0=Forçar actualização ActionRefresh.1=Actualizando directório RenameAction.0=Renomear RenameAction.1=Por favor introduza um novo nome para este ficheiro: RenameAction.2=Por favor introduza um novo nome para este directório: NewFolderAction.0=Nova pasta NewFolderAction.1=Por favor introduza o nome da pasta: NewFolderAction.2=Já existe uma pasta com o mesmo nome. LyricsView.0=Letra LyricsView.1=Sem letra, acesso à Internet desligado, use o menu de Configurações para o ligar. LyricsView.2=Entrar no modo de edição de letra LyricsView.3=Sair do modo de edição de letra LyricsView.4=Guardar letra LyricsView.5=Eliminar letra ActionDelete.0=Ficheiros eliminados ActionDelete.1=Directórios eliminados FindDuplicateTracksAction.0=Não foram encontradas faixas duplicadas. FindDuplicateTracksAction.1=Foram encontradas faixas duplicadas. FindDuplicateTracksAction.2=Procurar faixas duplicadas FindDuplicateTracksAction.3=Lista de faixas duplicadas encontrada FindDuplicateTracksAction.4=Seleccionar todas as faixas duplicadas RefreshDialog.0=Preparando actualização de dispositivo... RefreshDialog.1=Actualizando dispositivo RefreshDialog.2=Actualizando dispositivo: RefreshDialog.3=Limpando ficheiros antigos RadioWizard.0=Por favor seleccione ou crie um rádio web RadioWizard.1=Gerir rádios web RadioWizard.2=Novo RadioWizard.3=Eliminar RadioWizard.4=Pré-definições RadioWizard.5=Um rádio web com este nome já existe RadioWizard.6=Nome do rádio web RadioWizard.7=Utilitário Rádio Web RadioWizard.8=URL RadioWizard.9=Nome RadioWizard.10=URL errado RadioWizard.11=O nome e URL são obrigatórios UpdateManager.0=Uma nova versão do Jajuk ( UpdateManager.1=) foi detectada, pode transferi-la desde http://jajuk.info UpdateManager.2=Nenhuma nova versão encontrada até agora. LastFmManager.0=Por favor note que o seu suporte à Last.FM encontra-se desactivado. Se pretender fazer a audição de músicas pela Last.FM, terá de activar o serviço Last.FM e introduzir o seu nome de utilizador e senha na vista das Preferências / Last.FM. SuggestionView.0=Sugestões SuggestionView.1=Preferidos SuggestionView.2=Recentes SuggestionView.3=Restantes álbuns SuggestionView.4=Artistas semelhantes SuggestionView.5=Raramente escutados SuggestionView.7=Nada a mostrar

    as informações da Last.FM são mostradas apenas quando:
    • Uma faixa está sob escuta
    • O artista da faixa sob escuta é conhecido (etiqueta correcta)
    • A opção "Habilitar consultas de informação da Last.FM" está activa na vista das Preferências / Last.FM
    • A opção "Desabilitar todo o acesso à Internet pelo Jajuk" não está activa na vista das Preferências / separador da Rede
    • O computador correndo o Jajuk apresenta conectividade à Internet.
    AbstractThumbnail.0=Abrir página da LAST.FM AlbumsTableView.0=Tabela de Álbuns AlbumsTableView.1=N.º de faixas AlarmClock.0=Definir alarme #Next value : 6 AlarmDialog.0=Horas HH(0-24):MM:SS AlarmDialog.1=Horas AlarmDialog.2=Minutos AlarmDialog.3=Segundos AlarmDialog.4=Acção do Alarme AlarmDialog.5=Seleccionar a acção do alarme #Next value : 11 ShowPropertiesAction.0=Apresentar as propriedades do item QueueView.1=Limpar o alinhamento QueueView.2=Rolar a tabela automaticamente até à faixa sob escuta JajukSlimWindow.0=Mostrar/esconder a barra fina do Jajuk JajukFullscreen.0=Habilitar/desabilitar o leitor de tela preenchida BanSelectionAction.0=Banir BanSelectionAction.1=Banir o(s) item(ns) por forma a que jamais volte(m) a ser seleccionado(s) UnBanSelectionAction.0=Perdoar UnBanSelectionAction.1=Perdoar o(s) item(ns) por forma a que possa(m) voltar a ser proposto(s) OpenExplorerAction.0=Abrir no explorador OpenExplorerAction.1=Abrir o directório utilizando um explorador de ficheiros externo Preference.0=Definir a preferência pessoal para a faixa sob escuta
    Será tomada em consideração no cálculo da pontuação final. Preference.1=Lixo Preference.2=Fraco Preference.3=Razoável Preference.4=Bom Preference.5=Excelente Preference.6=Genial Preference.7=Avaliação... Preference.8=Indiferente ArtistView.0=Vista do Artista Notificator.NONE=Nenhum Notificator.TOAST=Tosta Notificator.BALLOON=Balão Notificator.track_change.webradio_title=Rádio Web iniciado: Notificator.track_change.track_title=Faixa iniciada: SyncTreeTableAction.0=Sincronizar vistas de árvore e tabela SyncTreeTableAction.1=Sincronizar vistas em árvore e em tabela
    Quando usado em função de uma vista em árvore, a selecção de um item na tabela fará com que a árvore se expanda e role.
    Quando usado em função de uma vista em tabela, a selecção de um item na vista em árvore fará a respectiva filtragem na tabela. TipOfTheDay.0= Tip 0: pode reproduzir a faixa sob escuta desde o seu início fazendo [Shift+clique] no botão de Rebobinar TipOfTheDay.1= Tip 1: pode reproduzir o álbum sob escuta desde o seu início fazendo [CTRL+click] no botão "Reproduzir Anterior" TipOfTheDay.2= Tip 2: pode adicionar itens aleatórios a listas de reprodução utilizando o botão ? no editor de listas de reprodução TipOfTheDay.3= Tip 3: pode obter capas em linha mesmo por detrás de um servidor proxy recorrendo ao separador da Rede na vista das Preferências TipOfTheDay.4= Tip 4: o Jajuk vem com uma função de barra fina (botão no canto superior direito da barra de menu) permitindo controlar a reprodução sem ocupar espaço no ambiente de trabalho TipOfTheDay.5= Tip 5: pode esconder as faixas indisponíveis seleccionando a opção "Apresentar apenas as faixas disponíveis" TipOfTheDay.6= Tip 6: pode executar quase todas as funções do Jajuk recorrendo apenas ao teclado TipOfTheDay.7= Tip 7: pode arrastar e largar itens desde as vistas em árvore até ao editor de listas de reprodução e até ao repositório de listas de reprodução TipOfTheDay.8= Tip 8: pode escutar as introduções de cada faixa recorrendo ao modo introdutório TipOfTheDay.9= Tip 9: pode configurar a duração do cross fade entre faixas na vista das Preferências TipOfTheDay.10= Tip 10: o Jajuk pode ser utilizado como um despertador avançado utilizando o utilitário de Alarme disponível no menu das Ferramentas TipOfTheDay.11= Tip 11: pode controlar as principais funções do Jajuk através do ícone na área de notificação (Linux & Windows) TipOfTheDay.12= Tip 12: o tema visual do Jajuk é configurável no separador do Interface Gráfico na vista das Preferências TipOfTheDay.13= Tip 13: pode configurar o o comportamento do duplo-clique e do arrastamento (alinhando as faixas para reprodução) no separador das Opções na vista das Preferências TipOfTheDay.14= Tip 14: as faixas "planeadas" do Jajuk são faixas que serão reproduzidas após a actual selecção de faixas TipOfTheDay.15= Tip 15: o interface gráfico do Jajuk é completamente adaptável, pelo que pode arrastar e largar as diversas vistas reorganizando-as de acordo com a sua preferência TipOfTheDay.16= Tip 16: pode obter o número total de de ficheiros e de faixas seleccionando o nódulo "colecção" nas vistas de ficheiros ou de faixas em árvore TipOfTheDay.17= Tip 17: pode obter etiquetas em linha através da função "Obter etiquetas em linha" nos directórios das vistas de ficheiros ou de faixas em árvore TipOfTheDay.18= Tip 18: a barra de histórico do Jajuk (na parte superior central da janela) apresenta todas as faixas reproduzidas anteriormente TipOfTheDay.19= Tip 19: pode executar pesquisas rápidas utilizando a caixa de Pesquisa (na parte superior direita da janela) TipOfTheDay.20= Tip 20: pode reportar depurações necessárias ou fazer pedidos de novas funcionalidades através do agente de qualidade (Ajuda, Reportar um problema) TipOfTheDay.21= Tip 21: a funcionalidade de DJ do Jajuk cria listas de reprodução inteligentes seguindo as suas directivas TipOfTheDay.22= Tip 22: pode obter as letras para as suas músicas através da vista de Letras TipOfTheDay.23= Tip 23: a vista de Sugestões apresenta informação da LAST.FM como, por exemplo, artistas semelhantes TipOfTheDay.24= Tip 24: pode banir uma faixa que não aprecie através da barra fina ou do painel de controlo TipOfTheDay.25= Tip 25: pode mostrar/esconder faixas desmontadas num clique recorrendo ao menu das Configurações TipOfTheDay.26= Tip 26: já pode escolher um directório para os dados do Jajuk (como um disco externo) para preservar as suas configurações e as suas preferências em qualquer computador (ver o separador "Avançadas" na vista das Preferências) TipOfTheDay.27= Tip 27: pode adicionar qualquer vista a qualquer perspectiva recorrendo ao menu das Vistas TipOfTheDay.28= Tip 28: pode abrir uma página da Wikipedia no seu navegador pré-definido através do botão "Abrir endereço no navegador pré-definido" Image:launch_16x16.png TipOfTheDay.29= Tip 29: o Jajuk suporta rádio web Image:webradio_32x32.png TipOfTheDay.30= Tip 30: o Jajuk pode ser controlado via remoto através do D-Bus se disponível na presente plataforma (Unix). Isto permite a utilização das teclas de atalho multimédia no seu teclado para controlar o comportamento do Jajuk. Consulte o manual em linha para mais informações. ]]>jajuk-1.9.6.orig/src/main/java/org/jajuk/i18n/jajuk_zh.properties0000644000175000017500000005155311720500104024516 0ustar drazzibdrazzib 强制Jajuk重新读取实际id3格式标签。

    当您在读取被其他应用程序修改过的标签时,该功能非常有用 ParameterView.101=使用上层目录名作为专辑名称U ParameterView.102=当Jajuk不能读取id3格式标签时,使用上层目录名作为专辑名称 ParameterView.103=语言包将在重启Jajuk后生效L ParameterView.104=外观和感觉将在重启Jajuk后生效 ParameterView.109=设置已保存 ParameterView.110=设置还原为默认值 ParameterView.111=最佳播放表长度: ParameterView.112=设置最佳播放表长度(从 1 到 100) ParameterView.113=在过滤器中使用regexp ParameterView.114=在过滤器中使用规范表达式(Regexp 格式), 例如: .*foo.* ParameterView.115=高级 ParameterView.116=备份收藏文件 ParameterView.117=选择,如果您希望备份收藏文件至 collection-.xml ParameterView.118=备份大小 (Mb) ParameterView.119=备份大小 (Mb) ParameterView.120=收藏字符格式 ParameterView.121=收藏字符格式。 UTF-16对亚洲及欧洲字符进行了优化。 ParameterView.122=视图 ParameterView.123=读取默认设置 ParameterView.124=读取Jajuk默认视图、视角位置及尺寸 ParameterView.125=读取默认设置 ParameterView.126=视图修改将在重启Jajuk后生效 ParameterView.127=仅在安装的设备中查找 ParameterView.128=仅在安装的设备中查找(显示在搜索框中) ParameterView.129=新歌时间限制(天): ParameterView.130=新歌时限天数:在这个天数之内添加的音轨将作为新歌 ParameterView.131=最好的音轨 ParameterView.132=启动时播放一首您最爱的歌曲 ParameterView.133=新歌 ParameterView.134=启动时播放一首收藏中的新歌 ParameterView.135=最后一首最后播放 ParameterView.136=上次最后播放的歌放在最后播放 ParameterView.139=网络 ParameterView.140=使用HTTP代理 ParameterView.141=使用HTTP代理,如果您使用局域网需通过代理服务器连接网络,这个选项将非常有用 ParameterView.142=代理用户名 ParameterView.143=代理用户名用来获得授权 ParameterView.144=代理服务器名 ParameterView.145=代理服务器名或IP地址 ParameterView.146=代理端口 ParameterView.147=代理TCP-IP端口(通常为 3128) ParameterView.148=使用自动封面 ParameterView.149=使用自动封面从互联网下载封面 (如果需要,请在网络选项中设置代理) ParameterView.150=最小封面尺寸(Kb) ParameterView.151=从网络下载的最小封面尺寸(Kb) ParameterView.152=最大封面尺寸(Kb) ParameterView.153=从网络下载的最大封面尺寸(Kb) ParameterView.154=精确搜索 ParameterView.155=精确搜索。搜索越精确,您将越可能找到正确的封面。 ParameterView.156=低 ParameterView.157=中 ParameterView.158=高 ParameterView.159=封面 ParameterView.160=连接超时(sec) ParameterView.161=连接超时(sec) : 在此时间内未获应答将视为操作失败 ParameterView.162=下载超时(sec) ParameterView.163=下载超时(sec) : 在此时间内未下载指定文件将视为操作失败 Main.12=这是您的第一个Jajuk片断, 您需要首先在设备视角中添加至少一个设备 Main.13=Jajuk成功启动 Main.21=确认 Device.21=刷新 [ Device.22=] 确定 [ Device.25=] 已刷新 Device.26= 秒 - Device.27= 新文件 - Device.28= 已删除的参考信息 Device.31=同步. [ Device.33=同步完成 Device.34= 秒 - Device.35= 创建文件 ( Device.36= MB) Device.41=同步. [ Device.42=] 正在拷贝 [ FIFO.4=). 您希望安装该设备吗 ? FIFO.10=正在播放: FIFO.13= kbps HistoryItem.0=年-月-日 小时:分钟 DeviceWizard.0=设备向导 DeviceWizard.1=设备类型 : DeviceWizard.2=设备名称 : DeviceWizard.3=设备位置 : DeviceWizard.4=Unix 设备安装点 (可选): DeviceWizard.7=进行即时刷新 DeviceWizard.8=启动时自动安装 DeviceWizard.9=启动时自动刷新 DeviceWizard.10=与……同步 : DeviceWizard.11=Unidirectional synchronization DeviceWizard.12=All new files found on the source device are copied into this device. Nothing will be written to source device DeviceWizard.13=Bidirectional synchronization DeviceWizard.14=All new files found on one device are copied to the other one DeviceWizard.33=OK DeviceWizard.34=Cancel DeviceWizard.43=Please choose a directory DeviceWizard.44=Device created DeviceWizard.45=Please give device name. Ex: CD A, Laptop... DeviceWizard.46=Please give device location. Ex: d:\mp3 under Windows, /home/foo/mp3 under Unix DeviceWizard.47=Please give device Unix mount point. Ex:/media/cdrom DeviceWizard.48=Check this if you want to perform an immediate refresh of the device (advised)

    Note this operation can take a while for large devices DeviceWizard.49=Check this if you want to mount automatically the device at jajuk start

    Especially for directories on current hard disk. Avoid it for CDs DeviceWizard.50=Check this if you want to perform a refresh at each Jajuk start

    (Use it only for small devices) DeviceWizard.51=Check this if you want to synchronize this device with another one DeviceWizard.52=Select a source device JajukJMenuBar.0=File JajukJMenuBar.1=Open file JajukJMenuBar.3=Exit JajukJMenuBar.5=Properties JajukJMenuBar.6=New property JajukJMenuBar.7=Delete a property JajukJMenuBar.8=Views JajukJMenuBar.9=Mode JajukJMenuBar.10=Repeat JajukJMenuBar.11=Shuffle JajukJMenuBar.12=Continue JajukJMenuBar.13=Intro JajukJMenuBar.14=Help JajukJMenuBar.15=Help contents JajukJMenuBar.16=About PlaylistFileItem.2=New playlist PlaylistFileItem.3=Bookmarks PlaylistFileItem.4=Best-of PlaylistFileItem.5=Current Queue JajukFileChooser.0=Please choose track(s) to play SearchBox.0=Perform a search among tracks, artists, genres, directory... CommandJPanel.0=View play history CommandJPanel.1=Repeat mode: play tracks in a loop CommandJPanel.2=Shuffle mode: play randomly selected tracks CommandJPanel.3=Continue mode: continue to play next tracks when finished CommandJPanel.4=Intro mode: play only a part of each track. Offset and time can be set in the parameters view CommandJPanel.5=Play a shuffle selection from the entire collection CommandJPanel.6=Play your own favourite tracks CommandJPanel.7=Turn sound off CommandJPanel.8=Play previous track in current selection CommandJPanel.9=Play next track in current selection CommandJPanel.10=Fast rewind in current track CommandJPanel.11=Pause/Resume current track CommandJPanel.12=Stop CommandJPanel.13=Fast forward in current track CommandJPanel.14=Volume CommandJPanel.15=Go to this position in the played track CommandJPanel.16=Play novelties, age option can be set in the parameter view CommandJPanel.17=Continue in current album InformationJPanel.5=Total music time to be played InformationJPanel.6=Track bitrate InformationJPanel.7=Current track progression AbstractPlaylistEditorView.0=Track AbstractPlaylistEditorView.1=Location AbstractPlaylistEditorView.2=Run this playlist AbstractPlaylistEditorView.3=Save this playlist AbstractPlaylistEditorView.4=Add an item to this playlist AbstractPlaylistEditorView.5=Remove an item from this playlist AbstractPlaylistEditorView.6=Set item position higher AbstractPlaylistEditorView.7=Set item position lower AbstractPlaylistEditorView.8=Display current played playlist AbstractPlaylistEditorView.9=Erase this playlist AbstractPlaylistEditorView.15=Playlist editor AbstractPlaylistEditorView.17=You are about to update on disk all following playlists : StatView.0=Others StatView.1=Styles repartition StatView.2=No data available StatView.3=Others StatView.4=Size by device (Gb) StatView.5=No data available StatView.7=Collection size by month StatView.8=Months StatView.9=Size (Gb) StatView.10=No data available StatView.12=Total number of tracks by month StatView.13=Months StatView.14=Track number StatView.15=No data available StatView.16=Statistics StatView.24=older CDScanView.0=CD label : CDScanView.1=Enter CD label. Ex: CD1, ROCK... CDScanView.2=Enter CD label. Ex: CD1, ROCK... CDScanView.3=CD Location : CDScanView.4=CD Location where CD can be found. Ex: '/cdrom' under Unix, 'e:' under MS Windows... CDScanView.5=CD Location where CD can be found. Ex: '/cdrom' on Unix, 'e:' under MS Windows... CDScanView.6=Scan CDScanView.12=CD Scanner CDScanView.18=Scans the CD and adds automatically all music files into the collection CDScanView.19=Select CD location TracksTreeView.0=Logical tree TracksTreeView.1=Play TracksTreeView.2=Push TracksTreeView.3=Play shuffle TracksTreeView.4=Play repeat TracksTreeView.5=Delete TracksTreeView.6=Set a property TracksTreeView.7=Properties TracksTreeView.8=Play TracksTreeView.9=Push TracksTreeView.10=Play shuffle TracksTreeView.11=Play repeat TracksTreeView.12=Delete TracksTreeView.13=Set a property TracksTreeView.14=Properties TracksTreeView.15=Play TracksTreeView.16=Push TracksTreeView.17=Play shuffle TracksTreeView.18=Play repeat TracksTreeView.19=Delete TracksTreeView.20=Set a property TracksTreeView.21=Properties TracksTreeView.22=Play TracksTreeView.23=Push TracksTreeView.24=Delete TracksTreeView.25=Set a property TracksTreeView.26=Properties TracksTreeView.27=Collection TracksTreeView.31= tracks LogicalPlaylistRepositoryView.0=Playlists CoverView.3=Cover CoverView.4=Previous image from the disk and/or the web if auto-cover option is checked CoverView.5=Next image from the disk and/or the web if auto-cover option is checked CoverView.6=Save cover with its original name CoverView.7=Save cover as... CoverView.8=Use this cover as default cover for this album CoverView.9=covers CoverView.10=Save cover as CoverView.11=Cover saved AnimationView.0=Animation FilesTreeView.0=Physical tree FilesTreeView.1=Play FilesTreeView.2=Push FilesTreeView.3=Copy FilesTreeView.4=Cut FilesTreeView.5=Paste FilesTreeView.6=Rename FilesTreeView.7=Delete FilesTreeView.8=Set a property FilesTreeView.9=Properties FilesTreeView.10=Play FilesTreeView.11=Push FilesTreeView.12=Play Shuffle FilesTreeView.13=Play repeat FilesTreeView.14=Desynchronize FilesTreeView.15=Resynchronize FilesTreeView.16=Create playlist FilesTreeView.17=Copy FilesTreeView.18=Cut FilesTreeView.19=Paste FilesTreeView.20=Rename FilesTreeView.21=Delete FilesTreeView.22=Set a property FilesTreeView.23=Properties FilesTreeView.24=Play FilesTreeView.25=Push FilesTreeView.26=Play Shuffle FilesTreeView.27=Play repeat FilesTreeView.28=Mount FilesTreeView.29=Unmount FilesTreeView.30=Refresh FilesTreeView.31=Synchronize FilesTreeView.32=Test FilesTreeView.33=Create playlists FilesTreeView.34=Set a property FilesTreeView.35=Properties FilesTreeView.36=Play FilesTreeView.37=Push FilesTreeView.38=Play Shuffle FilesTreeView.39=Play Repeat FilesTreeView.40=Copy FilesTreeView.41=Cut FilesTreeView.42=Paste FilesTreeView.43=Rename FilesTreeView.44=Delete FilesTreeView.45=Set a property FilesTreeView.46=Properties FilesTreeView.47=Collection FilesTreeView.52= files : FilesTreeView.53= Gb FilesTreeView.54= Mb TracksTableView.0=Logical table TracksTableView.1=Track TracksTableView.2=Album TracksTableView.3=Artist TracksTableView.4=Length TracksTableView.5=Style TracksTableView.6=Rate AbstractTableView.0=Filter: AbstractTableView.1=Property to filter AbstractTableView.3=Value to be used by the filter AbstractTableView.4=Apply filter AbstractTableView.5=Clear the filter AbstractTableView.6=Apply an advanced filter AbstractTableView.7=contains : AboutView.7=About AboutView.8=License AboutView.9=System AboutView.10=About PhysicalPlaylistRepositoryView.0=Play PhysicalPlaylistRepositoryView.1=Edit PhysicalPlaylistRepositoryView.2=Save as PhysicalPlaylistRepositoryView.3=Delete PhysicalPlaylistRepositoryView.4=Properties PhysicalPlaylistRepositoryView.6=Playlists PhysicalPlaylistRepositoryView.8=Specials PhysicalPlaylistRepositoryView.9=Queue PhysicalPlaylistRepositoryView.10=Current queue: drag and drop to it for playing PhysicalPlaylistRepositoryView.11=New PhysicalPlaylistRepositoryView.12=New playlist: drag and drop to it for adding files PhysicalPlaylistRepositoryView.13=Bookmarks PhysicalPlaylistRepositoryView.14=Bookmark playlist: drag and drop to it for keeping it PhysicalPlaylistRepositoryView.15=Best of PhysicalPlaylistRepositoryView.16=Best of playlist : contains top tracks FilesTableView.0=Physical table物理桌面 FilesTableView.1=Play播放 FilesTableView.2=Push FilesTableView.3=Play shuffle FilesTableView.4=Play repeat FilesTableView.5=Set a property FilesTableView.6=Properties FilesTableView.7=Track FilesTableView.8=Album FilesTableView.9=Artist FilesTableView.10=Length FilesTableView.11=Style FilesTableView.12=Device FilesTableView.13=File FilesTableView.14=Rate DeviceView.0=Add a device DeviceView.1=Remove an unmounted device (doesn't remove anything physically from disk) DeviceView.2=Selected device properties DeviceView.3=Mount selected device DeviceView.4=Unmount selected device DeviceView.5=Test selected device availability DeviceView.6=Refresh selected device DeviceView.7=Synchronize selected device DeviceView.8=Mount DeviceView.9=Unmount DeviceView.10=Test DeviceView.11=Refresh DeviceView.12=Synchronize DeviceView.13=Remove unmounted device DeviceView.14=Get properties DeviceView.17=New DeviceView.18=Add a device DeviceView.21=The device is available DeviceView.22=The device cannot be accessed DeviceView.23=Devices JajukWindow.3=Jajuk advanced jukebox JajukWindow.4=Exit JajukWindow.5=About JajukWindow.6=Play Shuffle JajukWindow.7=Play Best of JajukWindow.8=Show Jajuk at startup JajukWindow.9=Hide Jajuk at startup JajukWindow.10=Pause || JajukWindow.11=Stop [] JajukWindow.12=Play > JajukWindow.13=Previous <-- JajukWindow.14=Next --> JajukWindow.15=Play novelties JajukWindow.16=Continue album JajukWindow.17=Jajuk : Advanced Jukebox JajukWindow.18=Ready to play HelpView.2=Help DownloadManager.0=Jajuk needs your HTTP proxy password to grab covers
    If you don't want them, please change your settings in the Covers tab of Parameter view
    If you don't have any proxy, please change your settings in the Network tab of the Parameter view DownloadManager.1=Password required ]]>jajuk-1.9.6.orig/src/main/java/org/jajuk/i18n/jajuk_nl.properties0000644000175000017500000010216111720500104024476 0ustar drazzibdrazzib zijn niet toegelaten. Error.141=Deze afspeellijst bevindt zich op een afgekoppeld apparaat of het apparaat is aan het verversen. Daarom is het bestand momenteel niet beschikbaar. Error.142=Deze afspeellijst bevat enkele genegeerde nummers die zich buiten de gekende apparaten bevinden. #Strings from a class ParameterView.0=Lengte van de geschiedenis: ParameterView.2=Stel hier het aantal dagen in dat u bij wilt houden wat u geluisterd heeft. Stel -1 in als u niets wilt bijhouden en 0 als u het permanent wilt bewaren. ParameterView.3=Wis geschiedenis ParameterView.4=Wis geschiedenis ParameterView.8=Geschiedenis ParameterView.9=Speel: ParameterView.10=Niets ParameterView.11=Geen muziek bij opstarten ParameterView.12=Laatste vanaf het begin ParameterView.13=Speel het laatste nummer van de vorige sessie ParameterView.14=Willekeurige volgorde ParameterView.15=Speel een willekeurig nummer uit de hele verzameling ParameterView.16=Nummer: ParameterView.17=Kies een bestand om te spelen bij het opstarten ParameterView.18=Kies een bestand om te spelen bij het opstarten ParameterView.19=Opstarten ParameterView.26=Bevestigingen ParameterView.27=Voordat een bestand fysiek wordt gewist ParameterView.28=Vraag voordat een bestand fysiek wordt gewist ParameterView.29=Voordat Jajuk gestopt wordt ParameterView.30=Vraag voordat Jajuk gestopt wordt ParameterView.33=Opties ParameterView.34=Laat alleen verbonden apparaten zien ParameterView.35=Verberg nummers op niet verbonden apparaten ParameterView.36=Begin opnieuw aan het einde van de verzameling ParameterView.37=Begin opnieuw met de hele verzameling als het einde wordt bereikt bij continu spelen ParameterView.38=Taal: ParameterView.42=Taal instelling voor de interface ParameterView.43=Uiterlijk en gedrag: ParameterView.44=Instelling voor het uiterlijk en gedrag ParameterView.45=Instelling voor het uiterlijk en gedrag ParameterView.46=Niveau van het log: ParameterView.47=Fataal ParameterView.48=Fout ParameterView.49=Waarschuwing ParameterView.50=Ter info ParameterView.51=Debuggen ParameterView.52=Jajuk boodschappen: Fataal :laat alleen kritieke fouten zien, Fout:+laat fouten zien, Ter info:+laat informatie zien, Waarschuwing:+laat waarschuwingen zien, Debuggen: alle boodschappen ParameterView.59=Begin van intro (%) : ParameterView.60=Begin van het intro in het nummer in %, van 0 (begin van het nummer) tot 99 (eind van het nummer) ParameterView.61=Intro lengte (sec) : ParameterView.62=Lengte van het intro in seconden ParameterView.71=P2P ParameterView.72=Deze nummers delen? ParameterView.73=Selecteer dit om anderen toe te staan nummers in uw vak te delen ParameterView.74=Wachtwoord: ParameterView.75=Stel het wachtwoord voor uw vak in. Als u geen wachtwoord instelt heeft niemand toegang. ParameterView.76=Laat de instellingen van de ander zien ParameterView.77=Selecteer dit om de persoonlijke instellingen in het vak van de ander te zien. ParameterView.78=Verberg lokale instellingen ParameterView.79=Selecteer dit om anderen uw eigen instellingen niet te laten zien. ParameterView.85=Pas toe ParameterView.86=Herstel standaardinstellingen ParameterView.87=Parameters ParameterView.98=Labels ParameterView.99=Doe een grondige scan voor labels. ParameterView.100=Dwing Jajuk de huidige id3 labels te lezen.

    Dit kan nuttig zijn om labels te verversen die u in een ander programma hebt aangepast. ParameterView.101=Gebruik de bovenliggende map als album naam ParameterView.102=Gebruik de bovenliggende map als album naam als die naam niet met id3 labels wordt gevonden. ParameterView.103=De taal wordt veranderd nadat Jajuk opnieuw is opgestart. ParameterView.109=De opties zijn bewaard. ParameterView.110=De standaardinstellingen zijn hersteld. ParameterView.111=Grootte van de favorieten speellijst: ParameterView.112=Stel het aantal nummers in op de favorieten speellijst (van 1 tot 100) ParameterView.113=Gebruik regexp in filters ParameterView.114=Gebruik Reguliere expressies (Regexp formaat) in filters voor tabellen, voorbeeld: .*foo.* ParameterView.115=Geavanceerd ParameterView.116=Reservekopie verzameling bestand ParameterView.117=Selecteer dit als je een reservekopie van je verzameling bestand collection-.xml bestanden wil maken. ParameterView.118=Grootte reservekopie (MB) ParameterView.119=Grootte reservekopie (MB) ParameterView.120=Tekenset verzameling ParameterView.121=Tekenset verzameling. UTF-16 is optimaal voor Aziatische talen en UTF-8 is optimaal voor Europese talen. ParameterView.129=Tijdslimiet voor nieuwe nummers (dagen): ParameterView.130=Tijdslimiet voor nieuwe nummers in dagen : alle nummers toegevoegd sinds het aangegeven aantal dagen worden beschouwd als nieuw. ParameterView.131="Best of" nummer ParameterView.132=Speel één van je favoriete nummers bij het opstarten. ParameterView.133=Nieuw nummer ParameterView.134=Speel een "nieuw" nummer uit je verzameling bij het opstarten. ParameterView.135=Laatste op laatste positie ParameterView.136=Speel het laatste nummer op de laatste positie gespeeld tijdens vorige sessie. ParameterView.139=Netwerk ParameterView.140=Gebruik een HTTP proxy ParameterView.141=Gebruik een HTTP proxy, dit is nuttig als je Jajuk gebruikt op een bedrijfsnetwerk en een proxy moet gebruiken om met het internet te verbinden. ParameterView.142=Proxy gebruikers naam ParameterView.143=Proxy gebruikers naam gebruikt voor authenticatie. ParameterView.144=Proxy hostnaam ParameterView.145=Proxy hostnaam or IP adres. ParameterView.146=Proxy poort ParameterView.147=Proxy TCP-IP poort (vaak 3128) ParameterView.148=Automatische omslagen ParameterView.149=Gebruik automatische omslagen om de omslagen van de afgespeelde albums van het internet te halen (indien nodig, doe proxy instellingen in de netwerk tab). ParameterView.150=Minimum omslag grootte (KB) ParameterView.151=Minimum grootte (KB) voor de omslagen binnengehaald van het internet. ParameterView.152=Maximum omslag grootte (KB) ParameterView.153=Maximum grootte (KB) voor de omslagen binnengehaald van het internet. ParameterView.155=Zoek nauwkeurigheid. Des te hoger de nauwkeurigheid, des te kleiner de kans op verkeerde omslagen. ParameterView.156=Laag ParameterView.157=Gemiddeld ParameterView.158=Hoog ParameterView.159=Omslagen ParameterView.160=Tijdslimiet verbinding (sec) ParameterView.161=Tijdslimiet voor de verbinding in seconden: de bewerking mislukt als een externe computer geen antwoord geeft binnen deze limiet. ParameterView.162=Tijdslimiet overdracht (sec). ParameterView.163=Tijdslimiet voor de gegevens overdracht in seconden: de bewerking mislukt als de benodigde gegevens niet volledig binnen gehaald zijn binnen deze limiet. ParameterView.164=Voor het verwijderen van een apparaat ParameterView.165=Vragen voor het verwijderen van een apparaat. ParameterView.166=Omslagen in willekeurige volgorde ParameterView.167=Toon een willekeurige omslag. ParameterView.168=Auteur ParameterView.169=Omslagen vooraf laden ParameterView.170=Laad alle beschikbare omslagen op voorhand indien mogelijk. ParameterView.171=Alvorens een omslag fysiek te verwijderen ParameterView.172=Vragen voor het fysiek verwijderen van een omslag. ParameterView.175=Laad omslag bij elk nummer ParameterView.176=Selecteer dit als je een andere omslag wil laden bij elk nummer (enkel beschikbaar bij willekeurige volgorde). ParameterView.177=Aantal zichtbare geplande nummers ParameterView.178=Aantal zichtbare geplande nummers ParameterView.179=Push bij dubbel klik ParameterView.180=Push (niet afspelen) een nummer wanneer een dubbel klik wordt uitgevoerd. ParameterView.181=Push bij slepen ParameterView.182=Push (niet afspelen) een nummer wanneer het gespleept wordt naar de afspeellijst. ParameterView.183=Synchronizeren van boom en tabel structuur ParameterView.184=Wanneer dit geselecteerd is toont de tabel enkel geselecteerde bestanden in de boom. ParameterView.185=Toon een dialoog bij het starten van een nummer ParameterView.186=Waarderingen wissen ParameterView.187=Wis de ingestelde waarderingen voor nummers ParameterView.188=Alvorens de geschiedens te wissen ParameterView.189=Alvorens de waarderingen te wissen ParameterView.190=Duur Cross-Fade (sec) ParameterView.191=Duur van de cross-fade tussen twee nummers in seconden Main.21=Bevestiging Player.0=Wachten op audio kanaal (bezet) Device.21=Verversen [ Device.22=] Openen [ Device.25=] ververst in Device.27= nieuwe bestanden - Device.31=Synchr. [ Device.33=Synchronisatie gedaan in Device.35= bestanden gemaakt ( Device.36= MB) Device.41=Synchr. [ Device.42=] Copying [ Device.43= onleesbare labels FIFO.4=). Wilt u proberen het te verbinden? FIFO.10=Nu speelt: FIFO.13= kbps HistoryItem.0=dd-mm-yyyy HH:mm DeviceWizard.0=Apparaat instellen DeviceWizard.1=Type apparaat: DeviceWizard.2=Naam apparaat: DeviceWizard.3=Locatie apparaat: DeviceWizard.4=Unix mount punt (optioneel): DeviceWizard.7=Ververs direct DeviceWizard.8=Verbinden bij opstarten DeviceWizard.10=Gesynchroniseerd met: DeviceWizard.11=Eenweg synchronisatie DeviceWizard.12=Elk nieuw bestand van het bron apparaat worden op dit apparaat gekopieerd. Niets wordt toegevoegd aan het bron apparaat. DeviceWizard.13=Tweeweg synchronisatie DeviceWizard.14=Elk nieuw bestand op een apparaat wordt gekopieerd op het andere apparaat. DeviceWizard.43=Kies een map DeviceWizard.44=Apparaat is aangemaakt DeviceWizard.45=Geef het apparaat een naam. Bijv: CD A, Laptop... DeviceWizard.46=Geef de locatie van het apparaat. Bijv: d:\mp3 in Windows, /home/foo/mp3 in Unix DeviceWizard.47=Geef het Unix mount punt van dit apparaat. Bijv:/media/cdrom DeviceWizard.48=Selecteer dit om dit apparaat nu te verversen (aanbevolen)

    Dit kan op grote apparaten lang duren DeviceWizard.49=Selecteer dit om bij het opstarten van Jajuk te verbinden met dit apparaat

    Speciaal voor mappen op de hadre schijf. Doe dit niet bij CD's. DeviceWizard.50=Selecteer dit als u wilt verversen bij het opstarten van Jajuk.

    (Voor kleine apparaten) DeviceWizard.51=Selecteer dit als u dit apparaat wilt synchroniseren met een ander apparaat. DeviceWizard.52=Kies een bron apparaat DeviceWizard.53=Ververs apparaat elke DeviceWizard.54=min JajukJMenuBar.0=Bestand JajukJMenuBar.1=Open bestand JajukJMenuBar.3=Stop JajukJMenuBar.5=Eigenschappen JajukJMenuBar.6=Nieuwe eigenschap JajukJMenuBar.7=Wis een eigenschap JajukJMenuBar.8=Beeld JajukJMenuBar.9=Mode JajukJMenuBar.10=Herhaal JajukJMenuBar.11=Willekeurig JajukJMenuBar.12=Continu JajukJMenuBar.13=Intro JajukJMenuBar.14=Help JajukJMenuBar.15=Help inhoud JajukJMenuBar.16=Over JajukJMenuBar.17=Herstel standaard beeld posities JajukJMenuBar.18=Apparaat assistent JajukJMenuBar.19=Rapporteer fout JajukJMenuBar.20=Tip van de Dag PlaylistFileItem.1=Nieuwigheden PlaylistFileItem.2=Nieuwe speellijst PlaylistFileItem.3=Gemarkeerd PlaylistFileItem.4=Favorieten PlaylistFileItem.5=Huidige wachtrij JajukFileChooser.0=Kies nummer(s) om te spelen SearchBox.0=Zoek tussen nummers, artiesten, stijlen, mappen... CommandJPanel.0=Laat speel geschiedenis zien CommandJPanel.1=Herhaling: blijf nummers herhalen CommandJPanel.2=Willekeurig: speel willekeurig gekozen nummers CommandJPanel.3=Continu: speel nieuwe nummers na afronding CommandJPanel.4=Intro: speel een deel van elk nummer. Begin en duur kunnen ingesteld worden bij Instellingen CommandJPanel.5=Speel een willekeurige selectie van de hele verzameling CommandJPanel.6=Speel uw favoriete nummers CommandJPanel.7=Geluid uit CommandJPanel.8=Speel vorige nummer van huidige selectie CommandJPanel.9=Speel volgende nummer van huidige selectie CommandJPanel.10=Huidig nummer snel terugspoelen CommandJPanel.11=Huidig nummer afspelen/pauzeren CommandJPanel.12=Stop CommandJPanel.13=Huidig nummer snel vooruitspoelen CommandJPanel.14=Volume CommandJPanel.15=Ga naar dit moment in het huidige nummer InformationJPanel.5=Totale tijd nog te spelen InformationJPanel.6=Bitrate van dit nummer InformationJPanel.7=Voortgang van dit nummer AbstractPlaylistEditorView.0=Nummer AbstractPlaylistEditorView.1=Locatie AbstractPlaylistEditorView.2=Speel deze speellijst AbstractPlaylistEditorView.3=Bewaar deze speellijst AbstractPlaylistEditorView.4=Voeg toe aan deze speellijst AbstractPlaylistEditorView.5=Verwijder van deze speellijst AbstractPlaylistEditorView.6=Positie van dit onderdeel hoger AbstractPlaylistEditorView.7=Positie van dit onderdeel lager AbstractPlaylistEditorView.9=Wis deze speellijst AbstractPlaylistEditorView.10=Voeg een willekeurig nummer toe aan deze afspeellijst AbstractPlaylistEditorView.15=Speellijst aanpassen AbstractPlaylistEditorView.17=U zult nu op schijf deze speellijsten updaten: AbstractPlaylistEditorView.18=Nummer in de wachtrij AbstractPlaylistEditorView.19=Nummer herhaald AbstractPlaylistEditorView.20=Nummer gepland AbstractPlaylistEditorView.21=Nummer in afspeellijst AbstractPlaylistEditorView.22=Afspeellijst bewaard AbstractPlaylistEditorView.23=Afspelen AbstractPlaylistEditorView.24=Push AbstractPlaylistEditorView.25=Voeg toe aan favorieten AbstractPlaylistEditorView.26=Eigenschappen StatView.0=Andere StatView.1=Herverdeling stijlen StatView.2=Geen gegevens beschikbaar StatView.3=Andere StatView.4=Grootte per apparaat (Gb) StatView.5=Geen gegevens beschikbaar StatView.7=Grootte van de verzameling per maand StatView.8=Maanden StatView.9=Grootte (Gb) StatView.10=Geen gegevens beschikbaar StatView.12=Totaal aantal nummers per maand StatView.13=Maanden StatView.14=Nummer StatView.15=Geen gegevens beschikbaar StatView.16=Statistieken StatView.24=ouder CDScanView.0=CD label: CDScanView.1=Kies CD label. Bijv: CD1, ROCK... CDScanView.2=Kies CD label. Bijv: CD1, ROCK... CDScanView.3=CD locatie: CDScanView.4=Locatie van de CD. Bijv: '/cdrom' in Unix, 'e:' in MS Windows... CDScanView.5=Locatie van de CD. Bijv: '/cdrom' in Unix, 'e:' in MS Windows... CDScanView.6=Scan CDScanView.12=CD scanner CDScanView.18=Scant de CD en voegt alle muziek bestanden toe aan de verzameling CDScanView.19=Kies de locatie van de CD TracksTreeView.0=Logische boom TracksTreeView.1=Speel TracksTreeView.2=Dwing TracksTreeView.3=Speel willekeurig TracksTreeView.4=Speel en herhaal TracksTreeView.5=Wis TracksTreeView.7=Eigenschappen TracksTreeView.8=Speel TracksTreeView.9=Dwing TracksTreeView.10=Speel willekeurig TracksTreeView.11=Speel en herhaal TracksTreeView.12=Wis TracksTreeView.14=Eigenschappen TracksTreeView.15=Speel TracksTreeView.16=Dwing TracksTreeView.17=Speel willekeurig TracksTreeView.18=Speel en herhaal TracksTreeView.19=Wis TracksTreeView.21=Eigenschappen TracksTreeView.22=Speel TracksTreeView.23=Dwing TracksTreeView.24=Wis TracksTreeView.26=Eigenschappen TracksTreeView.27=verzameling TracksTreeView.31= nummers TracksTreeView.32=Voeg toe aan favorieten LogicalPlaylistRepositoryView.0=Afspeellijsten CoverView.2=Verwijder deze omslag CoverView.3=Omslag CoverView.4=Vorige afbeelding vanaf de schijf en/of het internet als de "vooraf laden" optie ingesteld is CoverView.5=Volgende afbeelding vanaf de schijf en/of het internet als de "vooraf laden" optie ingesteld is CoverView.6=Bewaar omslag met de origele naam CoverView.7=Bewaar omslag als... CoverView.8=Gebruik deze omslag als de standaard omslag voor dit album CoverView.9=omslagen CoverView.10=Bewaar omslag als CoverView.11=Omslag bewaard CoverView.12=Album CoverView.13=Nummer AnimationView.0=Animatie FilesTreeView.0=Fysieke boom FilesTreeView.1=Speel FilesTreeView.2=Dwing FilesTreeView.3=Kopieer FilesTreeView.4=Knip FilesTreeView.5=Plak FilesTreeView.7=Wis FilesTreeView.9=Eigenschappen FilesTreeView.10=Speel FilesTreeView.11=Dwing FilesTreeView.12=Speel willekeurig FilesTreeView.13=Speel en herhaal FilesTreeView.14=Herstel synchroniseren FilesTreeView.15=Synchroniseer opnieuw FilesTreeView.16=Maak speellijst FilesTreeView.17=Kopieer FilesTreeView.18=Knip FilesTreeView.19=Plak FilesTreeView.21=Wis FilesTreeView.23=Eigenschappen FilesTreeView.24=Speel FilesTreeView.25=Dwing FilesTreeView.26=Speel willekeurig FilesTreeView.27=Speel en herhaal FilesTreeView.28=Verbind FilesTreeView.29=Verbreek verbinding FilesTreeView.30=Ververs FilesTreeView.31=Synchroniseer FilesTreeView.32=Test FilesTreeView.33=Maak afspeellijsten FilesTreeView.35=Eigenschappen FilesTreeView.36=Speel FilesTreeView.37=Dwing FilesTreeView.38=Speel willekeurig FilesTreeView.39=Speel en herhaal FilesTreeView.40=Kopieer FilesTreeView.41=Knip FilesTreeView.42=Plak FilesTreeView.44=Wis FilesTreeView.46=Eigenschappen FilesTreeView.47=Verzameling FilesTreeView.52= bestanden: FilesTreeView.53= Gb FilesTreeView.54= Mb FilesTreeView.55=Instellen FilesTreeView.56=Toevoegen aan Favorieten FilesTreeView.57=Zoek labels online TracksTableView.0=Logische tabel TracksTableView.7=Afspelen TracksTableView.8=Push TracksTableView.9=Willekeurig afspelen TracksTableView.10=Afspelen herhalen TracksTableView.11=Album afspelen album TracksTableView.12=Auteur afspelen TracksTableView.14=Eigenschappen TracksTableView.15=Toevoegen aan Favorieten AbstractTableView.0=Filter: AbstractTableView.1=Eigenschap van filter AbstractTableView.3=Waarde gebruikt door de filter AbstractTableView.4=Pas filter toe AbstractTableView.5=Wis het filter AbstractTableView.6=Pas geavanceerd filter toe AbstractTableView.7=bevat: AbstractTableView.8=Alles AbstractTableView.10=(Niet beschikbaar) AboutView.7=Over AboutView.8=Licentie AboutView.9=Systeem AboutView.10=Over PhysicalPlaylistRepositoryView.0=Speel PhysicalPlaylistRepositoryView.1=Wijzig PhysicalPlaylistRepositoryView.2=Bewaar als PhysicalPlaylistRepositoryView.3=Wis PhysicalPlaylistRepositoryView.4=Eigenschappen PhysicalPlaylistRepositoryView.6=Speellijsten PhysicalPlaylistRepositoryView.8=Speciaal PhysicalPlaylistRepositoryView.9=Wachtrij PhysicalPlaylistRepositoryView.10=Huidige wachtrij: selecteer en sleep erin om af te spelen PhysicalPlaylistRepositoryView.11=Nieuw PhysicalPlaylistRepositoryView.12=Nieuwe afspeellijst: selecteer en sleep erin om nummers toe te voegen PhysicalPlaylistRepositoryView.13=Gemarkeerd PhysicalPlaylistRepositoryView.14=Gemarkeerde afspeellijst: selecteer en sleep erin om bij te houden PhysicalPlaylistRepositoryView.15=Favorieten PhysicalPlaylistRepositoryView.16=Favorieten afspeellijst: de beste nummers PhysicalPlaylistRepositoryView.17=Niewigheden PhysicalPlaylistRepositoryView.18=Niewigheden afspeellijst: bevat de nieuwste nummer uit de vezameling FilesTableView.0=Fysieke tabel FilesTableView.1=Speel FilesTableView.2=Dwing FilesTableView.3=Speel willekeurig FilesTableView.4=Speel en herhaal FilesTableView.6=Eigenschappen FilesTableView.15=Afspeel map FilesTableView.16=Toevoegen aan Favorieten DeviceView.0=Voeg een apparaat toe DeviceView.1=Verwijder apparaat (verwijdert niets van schijf) DeviceView.2=Kies apparaat eigenschappen DeviceView.3=Verbind met gekozen apparaat DeviceView.4=Verbreek verbinding met gekozen apparaat DeviceView.5=Test beschikbaarheid van gekozen apparaat DeviceView.6=Ververs gekozen apparaat DeviceView.7=Synchroniseer gekozen apparaat DeviceView.8=Verbind DeviceView.9=Verbreek verbinding DeviceView.10=Test DeviceView.11=Ververs DeviceView.12=Synchroniseer DeviceView.13=Wis apparaat DeviceView.14=Bekijk eigenschappen DeviceView.17=Nieuw DeviceView.18=Voeg een apparaat toe DeviceView.21=Het apparaat is beschikbaar DeviceView.22=Geen toegang tot dit apparaat DeviceView.23=Apparaten JajukWindow.1=Dempen uit JajukWindow.2=Dempen JajukWindow.3=Jajuk JajukWindow.4=Stop JajukWindow.5=Over Jajuk JajukWindow.6=Speel willekeurig JajukWindow.7=Speel favorieten JajukWindow.8=Maak Jajuk zichtbaar bij opstarten JajukWindow.10=Pauze JajukWindow.11=Stop JajukWindow.12=Afspelen JajukWindow.13=Vorige JajukWindow.14=Volgende JajukWindow.15=Speel nieuwigheden JajukWindow.16=Vervolg album JajukWindow.17=Jajuk: Advanced Jukebox JajukWindow.18=Klaar om af te spelen JajukWindow.19=Dempen/Dempen Uit JajukWindow.21=Afsluiten JajukWindow.22=Over Jajuk JajukWindow.23=Speel willekeurige nummers uit de volledige verzameling JajukWindow.24=Speel favoriete nummers uit de volledige verzameling JajukWindow.25=Toon Jajuk bij het opstarten: indien niet geselecteerd start jajuk geminimalizeerd op JajukWindow.26=Afspelen/Pauze JajukWindow.27=Stop JajukWindow.29=Vorig nummer - [SHIFT] + linker muisknop : vorig album. JajukWindow.30=Volgend nummer - [SHIFT] + linker muisknop : volgend album. JajukWindow.31=Speel nieuwe nummers uit de volledige verzameling JajukWindow.32=Vervolg album: speel huidig album volledig af JajukWindow.33=Volume JajukWindow.34=Positie JajukWindow.35=Nu speelt : FirstTimeWizard.0=Snelstart FirstTimeWizard.1=Welkom! Deze assistent zal je helpen om je eerste collectie aan te maken. FirstTimeWizard.2=Kies de locatie van je muziek bestanden (bijvoorbeeld ~/music of d:\music): FirstTimeWizard.3=Wil je dat Jajuk omslagen op het internet zoekt?
    (een verbinding met internet wordt automatisch gemaakt indien nodig) ? FirstTimeWizard.4=Toon extra hulp onmiddellijk ? FirstTimeWizard.5=Kies een map HelpView.2=Help DownloadManager.0=Jajuk heeft je HTTP-proxy wachtwoord nodig om de omslagen op te halen.
    Als je dit niet wil, verander dan je instellingen in de "Omslagen" tab van het parameter beeld.
    Als je geen proxy hebt, verander dan je instellingen in de "Netwerk" tab van het Parameter beeld. DownloadManager.1=Wachtwoord nodig PropertiesWizard.0=Item eigenschappen PropertiesWizard.1=Eigenschap PropertiesWizard.2=Waarde PropertiesWizard.3=Aanpasbaar? PropertiesWizard.4=Koppeling PropertiesWizard.6=Selectie PropertiesWizard.7=Type PropertiesWizard.8=Eigenschap bijgewerkn gelukt PropertiesWizard.9=Geen aanpasbare eigenschap voor deze selectie PropertiesWizard.10=eigenschappen zijn ingesteld PropertiesWizard.11=Schrijft label naar: PropertiesWizard.12=Koppeling naar eigenschap details van het gegeven element NewPropertyWizard.0=Maak eigenschap NewPropertyWizard.3=(*)Type NewPropertyWizard.4=Formaat NewPropertyWizard.5=Standaard waarde CustomPropertyWizard.0=(*)Item CustomPropertyWizard.1=(*)Eigenschap naam RemovePropertyWizard.0=Verwijder eigenschap QualityFeedbackWizard.1=Van: QualityFeedbackWizard.2=Voer je naam of alias in QualityFeedbackWizard.3=(*)Onderwerp: QualityFeedbackWizard.4=Geef een omschrijving van je probleem QualityFeedbackWizard.5=Details: QualityFeedbackWizard.6=Geef meer details over het probleem SplashScreen.0=Initiële controle SplashScreen.1=Laden van de verzameling SplashScreen.2=Starten van de muziek machine SplashScreen.3=Lanceren van grafische interface CatalogView.0=Omslagen Catalogus CatalogView.2=Zonder omslagen CatalogView.3=Forceer opnieuw aanmaken van miniaturen CatalogView.4=Grootte miniaturen: CatalogView.5=Aanmaken van miniatuur voor: CatalogView.7=Haal omslagen online CatalogView.8=Geen omslagen gevonden CatalogView.9=Vorige CatalogView.10=Volgende WikipediaView.0=Wikipedia WikipediaView.1=Kies taal: TipOfTheDayView.0=Tip van de Dag TipOfTheDayView.1=Wist je dat ... ? TipOfTheDayView.2=Toon bij opstarten? CDDBWizard.0=Accepteren CDDBWizard.1=Bestandsnaam CDDBWizard.2=Naam huidig nummer CDDBWizard.3=Titel huidig album CDDBWizard.4=Voorgestelde naam voor nummer CDDBWizard.5=Voorgestelde naam voor album CDDBWizard.6=Klaar ! CDDBWizard.7=mogelijke overeenkomsten gevonden CDDBWizard.11=Vragen aan Freedb Servers ... CDDBWizard.12=Geen overeenkomst gevonden ! CDDBWizard.13=Mogelijke overeenkomsten gevonden ! CDDBWizard.14=Deze map bevat geen enkel bestand CDDBWizard.16=Stijl: CDDBWizard.17=Precieze overeenkomst gevonden ! CDDBWizard.18=Match(es) #--- Tips of day --- TipOfTheDay.0=Dat je het huidig nummer opnieuw kunt afspelen vanaf het begin met [Shift+klik] op de "terugspoel" knop in het controle paneel of het icoon in het systeemvak ? TipOfTheDay.1=Dat je het huidig album vanaf het eerste nummer opnieuw kan spelen met [Shift+click] op de "vorig nummer" knop in het controle paneel of het icoon in het systeemvak ? TipOfTheDay.2=Dat je willekeurige nummers kan toevoegen aan de afspeel lijst door de "?" knop te gebruiken in de afspeellijst bewerker ? TipOfTheDay.3=Dat je omslagen vanaf het internet kan halen, zelfs achter een bedrijfs-proxy door dit in te stellen in de "Netwerk" tab in het Parameter beeld ? TipOfTheDay.4=Dat je alle gevonden omslagen kan bufferen om de navigatie in het omslag beeld te versnellen met de Vooraf laden optie in de "Omslag" tab in het Parameter beeld ? TipOfTheDay.5=Dat je onbeschikbare nummers kan verstoppen via de "Laat alleen verbonden apparaten zien" optie in parameter beeld / opties tab ? TipOfTheDay.6=Dat je bijna alle functies ook kunt uitvoeren met het toetsenbord ? TipOfTheDay.7=Dat je items kan slepen van de boom structuur naar de afspeellijsten in de bewerker en repository ? TipOfTheDay.8=Dat je naar de inleiding van nummer kan luisteren met behulp van de intro mode ? TipOfTheDay.9=Dat je de cross-fade duur kan instellen in Parameter beeld / Opties tab ? TipOfTheDay.10=Dat je Jajuk geminimalizeerd kan opstarten door de "Maak Jajuk zichtbaar bij opstarten" optie uit te vinken in het systemvak icoon menu ? TipOfTheDay.11=Dat je de belangrijkste functies van Jajuk kunt uitvoeren via en icoon in het systemvak (enkel Linux & Windows) ? TipOfTheDay.12=Dat het uiterlijk en gedrag van Jajuk in te stellen is het in Parameter beeld / Opties tab ? TipOfTheDay.13=Dat je het gedrag van dubbel klik en slepen (push of afspelen) kan instellen in het Parameter beeld / Opties tab ? TipOfTheDay.14=Dat "geplande" tracks afgespeeld worden na het afspelen van de huidige selectie ? TipOfTheDay.15=Dat de grafische interface volledig "dockable" is en dat je de verschillende "views" kan verplaatsen door ze te verslepen ? TipOfTheDay.16=Dat je het totale aantal bestanden en nummers kan zien via "collectie" node in de fysieke of logische boom structuur te selecteren ? TipOfTheDay.17=Dat je labels van het internet kan laden met de "Zoek labels online" functie op mappen in de fysieke boom structuur ? TipOfTheDay.18=Dat de Jajuk geschiedenis balk (boven aan het venster) alle gespeelde nummers bevat ? TipOfTheDay.19=Dat je kan snelzoeken met het Zoek veld (boven aan het venster) ? ]]> jajuk-1.9.6.orig/src/main/java/org/jajuk/i18n/jajuk_sv.properties0000644000175000017500000004431111720500104024517 0ustar drazzibdrazzib Tvinga Jajuk att läsa om id3-metadata.

    Detta kan vara användbart för att uppdatera metadata som du ändrat via ett annat program ParameterView.101=ANvänd katalognamnet som albumnamn ParameterView.102=Låt Jajuk använda katalognamnet som albumnamn till en låt om det intekan fås via id3-metadata ParameterView.103=Språkbyte träder i kraft nästa gång Jajuk startas ParameterView.104=Utseendet uppdateras nästa gång Jajuk startas ParameterView.109=Egenskaper sparade ParameterView.110=Egenskaper satt till ursprungsläge ParameterView.111=Storlek på spellistan 'Best-of' : ParameterView.112=Sätt antal spår i 'Best-of'-spellistan (från 1 to 100) Main.10=Jajuk : Advanced Jukebox Main.12=Detta är din första Jajuk-session, för att använda den måste du först skapa minst en enhet i enhetsvyn Main.13=Jajuk korrekt uppstartad Main.21=Bekräftelse Device.21=Uppdaterar [ Device.22=] Går in i [ Device.25=] uppdaterad om Device.26= sek - Device.27= nya filer - Device.28= raderade referenser Device.31=Synk. [ Device.33=synkronisering klar om Device.34= sek - Device.35= skapade filer ( Device.36= MB) Device.41=Synk. [ Device.42=] Kopierar [ FIFO.4=). Vill du försöka montera den ? FIFO.10=Nu Spelar: FIFO.13= kbps FIFO.16=Klar att spela FIFO.18=Jajuk : Just Another Jukebox | Java Jukebox HistoryItem.0=yy-MM-dd HH:mm DeviceWizard.0=Enhetsassistent DeviceWizard.1=Enhetstyp : DeviceWizard.2=Enhetsnamnnamn : DeviceWizard.3=Enhetsposition : DeviceWizard.4=Unix monteringspunkt (ej nödvändig): DeviceWizard.7=Genomför omedelbar uppdatering DeviceWizard.8=Automatisk monteringspunkt vid start DeviceWizard.9=Automatisk uppdatering vid start DeviceWizard.10=Synkroniserad med : DeviceWizard.11=Enkelriktad synkronisering DeviceWizard.12=Alla nya filer som hittas på källenheten kopieras till denna enhet. Inget skrivs till källenheten DeviceWizard.13=Dubbelriktad synkronisering DeviceWizard.14=Alla nya filer som hittas på ena enheten kopieras till den andra DeviceWizard.33=OK DeviceWizard.34=Avbryt DeviceWizard.43=Vänligen välj en katalog DeviceWizard.44=Enhet skapad DeviceWizard.45=Vänligen namnge enheten. Ex: CD A, Laptop... DeviceWizard.46=Vänligen specificera enhetens plats. Ex: d:\mp3 under Windows, /home/foo/mp3 under Unix DeviceWizard.47=Vänligen specificera Unix monteringspunkt. Ex:/media/cdrom DeviceWizard.48=Kryssa i här om du vill göra en omedelbar uppdatering av enheten (rekommenderas)

    Att notera, detta kan ta tid på stora enheter DeviceWizard.49=Kryssa i här om du vill montera enheten automatiskt vid Jajuks uppstart

    Speciellt för kataloger på hårddiskar, undvik detta för CD DeviceWizard.50=Kryssa i här om du vill uppdatera vid varje start av Jajuk

    (Endast för små enheter) DeviceWizard.51=Kryssa i här om du vill synkronisera denna enhet med en annan DeviceWizard.52=Välj källenhet JajukJMenuBar.0=Fil JajukJMenuBar.1=Öppna fil JajukJMenuBar.3=Avsluta JajukJMenuBar.5=Egenskaper JajukJMenuBar.6=Ny egenskap JajukJMenuBar.7=Radera en egenskap JajukJMenuBar.8=Vyer JajukJMenuBar.9=Läge JajukJMenuBar.10=Repetera JajukJMenuBar.11=Blanda JajukJMenuBar.12=Fortsätt JajukJMenuBar.13=Intro JajukJMenuBar.14=Hjälp JajukJMenuBar.15=Innehåll i hjälp JajukJMenuBar.16=Om PlaylistFileItem.2=Ny spellista PlaylistFileItem.3=Bokmärken PlaylistFileItem.4=Best-of PlaylistFileItem.5=Aktuell kö JajukFileChooser.0=Vänligen välj spår att spela SearchBox.0=Sök bland spår, författare, stilar, kataloger... CommandJPanel.0=Visa historia över spelade spår CommandJPanel.1=Repetitionsläge : spela spår i en loop CommandJPanel.2=Blandningsläge : spela slumpvis valda spår CommandJPanel.3=Fortsättningsläge : fortsätt spela nästa spår efter det aktuella CommandJPanel.4=Introläge : spela bara en bit av varje spår. Position och längd kan sättas i parametervyn CommandJPanel.5=Spela en blandning från hela samlingen CommandJPanel.6=Spela dina egna favoritspår CommandJPanel.7=Stäng av ljudet CommandJPanel.8=Spela föregående spår i aktuellt urval CommandJPanel.9=Spela nästa låt i aktuellt urval CommandJPanel.10=Snabbspola bakåt i aktuellt spår CommandJPanel.11=Spela/Pausa aktuellt spår CommandJPanel.12=Stopp CommandJPanel.13=Snabbspola framåt i aktuellt spår CommandJPanel.14=Volym CommandJPanel.15=Gå till denna position i aktuellt spår InformationJPanel.5=Total återstående speltid InformationJPanel.6=Spårets bitrate InformationJPanel.7=Position i aktuellt spår AbstractPlaylistEditorView.0=Spår AbstractPlaylistEditorView.1=Position AbstractPlaylistEditorView.2=Kör denna spellista AbstractPlaylistEditorView.3=Spara denna spellista AbstractPlaylistEditorView.4=Lägg till i denna spellista AbstractPlaylistEditorView.5=Ta bort från denna spellista AbstractPlaylistEditorView.6=Flytta till högre position i listan AbstractPlaylistEditorView.7=Flytta till lägre position i listan AbstractPlaylistEditorView.8=Visa spellista som spelas AbstractPlaylistEditorView.9=Radera denna spellista AbstractPlaylistEditorView.15=Spellisteredigerare AbstractPlaylistEditorView.17=Du kommer att uppdatera följande spellistor tillsammans till skiva : StatView.0=Andra StatView.1=Uppdelning i stilar StatView.2=Ingen data tillgänglig StatView.3=Andra StatView.4=Storlek räknat per enhet (GB) StatView.5=Ingen data tillgänglig StatView.7=Samlingsstorlek räknat per månad StatView.8=Månad StatView.9=Storlek (GB) StatView.10=Ingen data tillgänglig StatView.12=Totalt antal spår per månad StatView.13=Månader StatView.14=Spårnummer StatView.15=Ingen data tillgänglig StatView.16=Statistik StatView.24=äldre CDScanView.0=CD-etikett : CDScanView.1=Skriv CD-etikett. Ex: CD1, ROCK... CDScanView.2=Skriv CD-etikett. Ex: CD1, ROCK... CDScanView.3=CD Plats : CDScanView.4=CD Plats där CD finns. Ex: '/cdrom' i Unix, 'e:' i MS Windows... CDScanView.5=CD Plats där CD finns. Ex: '/cdrom' i Unix, 'e:' i MS Windows... CDScanView.6=Avsökning CDScanView.12=CD-avsökare CDScanView.18=Söker av CD och lägger automatiskt till alla musikfiler till samlingen CDScanView.19=Välj plats där CD'n finns TracksTreeView.0=Logiskt träd TracksTreeView.1=Spela TracksTreeView.2=Tryck TracksTreeView.3=Spela blandat TracksTreeView.4=Spela upprepat TracksTreeView.5=Radera TracksTreeView.6=Sätt en egenskap TracksTreeView.7=Egenskaper TracksTreeView.8=Spela TracksTreeView.9=Tryck TracksTreeView.10=Spela blandat TracksTreeView.11=Spela upprepat TracksTreeView.12=Radera TracksTreeView.13=Sätt en egenskap TracksTreeView.14=Egenskaper TracksTreeView.15=Spela TracksTreeView.16=Tryck TracksTreeView.17=Spela blandat TracksTreeView.18=Spela upprepat TracksTreeView.19=Radera TracksTreeView.20=Sätt en egenskap TracksTreeView.21=Egenskaper TracksTreeView.22=Spela TracksTreeView.23=Tryck TracksTreeView.24=Radera TracksTreeView.25=Sätt en egenskap TracksTreeView.26=Egenskaper TracksTreeView.27=Samling TracksTreeView.31= spår LogicalPlaylistRepositoryView.0=Spellistor CoverView.3=Omslag FilesTreeView.0=Fysiskt träd FilesTreeView.1=Spela FilesTreeView.2=Tryck FilesTreeView.3=Kopiera FilesTreeView.4=Klipp ut FilesTreeView.5=Klistra in FilesTreeView.6=Döp om FilesTreeView.7=Radera FilesTreeView.8=Sätt en egenskap FilesTreeView.9=Egenskaper FilesTreeView.10=Spela FilesTreeView.11=Tryck FilesTreeView.12=Spela blandat FilesTreeView.13=Spela upprepat FilesTreeView.14=Avsynkronisera FilesTreeView.15=Återsynkronisera FilesTreeView.16=Skapa spellista FilesTreeView.17=Kopiera FilesTreeView.18=Klipp ut FilesTreeView.19=Klistra in FilesTreeView.20=Döp om FilesTreeView.21=Radera FilesTreeView.22=Sätt en egenskap FilesTreeView.23=Egenskaper FilesTreeView.24=Spela FilesTreeView.25=Tryck FilesTreeView.26=Spela blandat FilesTreeView.27=Spela upprepat FilesTreeView.28=Montera FilesTreeView.29=Avmontera FilesTreeView.30=Uppdatera FilesTreeView.31=Synkronisera FilesTreeView.32=Test FilesTreeView.33=Skapa spellistor FilesTreeView.34=Sätt en egenskap FilesTreeView.35=Egenskaper FilesTreeView.36=Spela FilesTreeView.37=Tryck FilesTreeView.38=Spela blandat FilesTreeView.39=Spela upprepat FilesTreeView.40=Kopiera FilesTreeView.41=Klipp ut FilesTreeView.42=Klistra in FilesTreeView.43=Döp om FilesTreeView.44=Radera FilesTreeView.45=Sätt en egenskap FilesTreeView.46=Egenskaper FilesTreeView.47=Samling FilesTreeView.52= filer : FilesTreeView.53= GB FilesTreeView.54= MB TracksTableView.0=Logisk tabell TracksTableView.1=Spår TracksTableView.2=Album TracksTableView.3=Författare TracksTableView.4=Längd TracksTableView.5=Stil TracksTableView.6=Betygsätt AbstractTableView.0=Filter: AbstractTableView.1=Filteregenskap AbstractTableView.3=Värde att användas av filtret AbstractTableView.4=Använd filter AbstractTableView.5=Rensa filtret AbstractTableView.6=Använd ett avancerat filter AbstractTableView.7=innehåller : AboutView.7=Om AboutView.8=Licens AboutView.9=System AboutView.10=Om PhysicalPlaylistRepositoryView.0=Spela PhysicalPlaylistRepositoryView.1=Ändra PhysicalPlaylistRepositoryView.2=Spara som PhysicalPlaylistRepositoryView.3=Radera PhysicalPlaylistRepositoryView.4=Egenskaper PhysicalPlaylistRepositoryView.6=Spellistor PhysicalPlaylistRepositoryView.8=Special PhysicalPlaylistRepositoryView.9=Kö PhysicalPlaylistRepositoryView.10=Aktuell kö : dra-och-släpp in i den för att spela PhysicalPlaylistRepositoryView.11=Ny PhysicalPlaylistRepositoryView.12=Ny spellista : dra-och-släpp in i den för att lägga till filer PhysicalPlaylistRepositoryView.13=Bokmärken PhysicalPlaylistRepositoryView.14=Bokmärk spellista : dra-och-släpp in i den för att lägga till PhysicalPlaylistRepositoryView.15=Best-of PhysicalPlaylistRepositoryView.16=Best-of-spelllista : innehåller toppspår FilesTableView.0=Fysisk tabell FilesTableView.1=Spela FilesTableView.2=Tryck FilesTableView.3=Spela blandat FilesTableView.4=Spela upprepat FilesTableView.5=Sätt en egenskap FilesTableView.6=Egenskaper FilesTableView.7=Spår FilesTableView.8=Album FilesTableView.9=Författare FilesTableView.10=Längd FilesTableView.11=Stil FilesTableView.12=Enhet FilesTableView.13=Fil FilesTableView.14=Betygsätt DeviceView.0=Lägg till en enhet DeviceView.1=Ta bort en enhet (tar inte bort något fysiskt från disken) DeviceView.2=Valda enhetsegenskaper DeviceView.3=Montera vald enhet DeviceView.4=Avmontera vald enhet DeviceView.5=Testa vald enhets tillgänglighet DeviceView.6=Uppdatera vald enhet DeviceView.7=Synkronisera vald enhet DeviceView.8=Montera DeviceView.9=Avmontera DeviceView.10=Testa DeviceView.11=Uppdatera DeviceView.12=Synkronisera DeviceView.13=Radera enhet DeviceView.14=Hämta egenskaper DeviceView.17=Ny DeviceView.18=Lägg till en ny enhet DeviceView.21=Enheten är tillgänglig DeviceView.22=Enheten kan inte nås DeviceView.23=Enheter JajukWindow.3=Jajuk avancerad jukebox JajukWindow.4=Avsluta JajukWindow.5=Om JajukWindow.6=Spela blandat JajukWindow.7=Spela Best-of JajukWindow.8=Visa Jajuk vid uppstart JajukWindow.9=Dölj Jajuk vid uppstart JajukWindow.10=Paus || JajukWindow.11=Stopp [] JajukWindow.12=SPela > JajukWindow.13=Föregående <-- JajukWindow.14=Nästa --> HelpView.2=Hjälp ]]>jajuk-1.9.6.orig/src/main/java/org/jajuk/i18n/jajuk_gl.properties0000644000175000017500000015655611720500104024510 0ustar drazzibdrazzib Rating system page). As túas puntuacións previas migraron a unha escala de 0 a 100 pero tamén dicirche que se reseteas tódalas puntuacións dende a xanela Preferencias -> Borrar histórico (coidado: tódalas puntuaciób serían eliminadas) #Write confirmation so replies are: yes / no / cancel Confirmation_exit=¿Queres realmente saír de Jajuk? Confirmation_delete=Atención! estás a punto de borrar fisicamente o(s) seguinte(s) arquivos do teu disco duro: Confirmation_void_refresh=Atención! estás a punto de acceder a un dispositivo vacío. Baixo Unix, asegurate de que o dispositivo estea conectado ou perdera-la información que teña jajuk neste e deste dispositivo. ¿Estás seguro? Confirmation_remove_device=¿Realmente queres eliminar este dispositivo? Confirmation_delete_cover=¿Queres realmente borrar definitivamente esta carátula do disco? Confirmation_delete_files=¿Queres realmente borrar estes arquivos do teu disco duro? Confirmation_delete_dirs=¿Queres realmente borrar estes directorios do teu disco duro? Confirmation_clear_history=¿Queres realmente limpia-lo histórico? Confirmation_reset_ratings=¿Queres realmente resetear tódolas puntuacións das cancións a cero? Confirmation_refactor_files=¿Queres realmente renomea-lo(s) seguinte(s) arquivos(s)? Confirmation_restore_all=Unha restauración das vistas require reiniciar Jajuk , ¿queres saír? Confirmation_defaults_radios=Borraranse tódalas emisoras de radio que creaches previamente, ¿estás seguro? Confirmation_delete_empty_dirs=Os seguintes directorios están vacíos. ¿Quere-los borrar? Confirmation_file_overwrite=Este arquivo xa existe. ¿Queres sobreescribir este arquivo? Confirmation_file_number=o(s) arquivo(s) será(n) borrado(s). Confirmation_alarm_stop=Estás seguro de queres parar esta alerta? Confirmation_defaults=Nota: esto reseteará tódalas opcións das cellas ós valores por defecto (e non só os actualmente en curso), ¿estás seguro? Confirmation_rebuild_thumbs=Esto reconstruirá tódalas iconas de tódolos teus álbumes, pode levar bastantes minutos nas colecións grandes. Estás seguro de facelo? Confirmation_reset_preferences=Queres reseta-las preferencias das cancións ? Device_type.directory=Directorio Device_type.file_cd=CD de Arquivos Musicais Device_type.audio_cd=CD de Audio Device_type.extdd=Disco Duro Externo Device_type.player=Reproductor Díxital Device_type.network_drive=Unidade de rede Device_type.remote=Remoto (Non implementado) Perspective_Description_Simple=Simple Perspective_Description_Files=Arquivos Perspective_Description_Tracks=Pistas Perspective_Description_Configuration=Configuración Perspective_Description_Statistics=Estatísticas Perspective_Description_Help=Axuda Perspective_Description_Display=Visualización Perspective_Description_Albums=Álbumes Perspective_Description_Info=Información Perspective_Description_Playlists=Listas de reprodución Item_Playlist_File=Lista de Reprodución Item_Track=Pista Item_Album=Álbume Item_Artist=Autor Item_Genre=Estilo Item_Device=Dispositivo Item_File=Arquivo Item_Directory=Directorio Item_Year=Ano Property_id=Id Property_name=Nome Property_type=Tipo Property_url=Url Property_mount_point=Punto de Montaxe Property_auto_refresh=Auto Refresco Property_auto_mount=Auto Montaxe Property_album=Álbume Property_style=Xénero Property_author=Artista Property_album_artist=Album Artist Property_disc_number=Disc Property_length=Lonxitude Property_year=Ano Property_rate=Puntuación Property_files=Arquivos Property_hits=Hits Property_filename=Arquivos Property_date=Data Property_added=Data do Descubrimento Property_parent=Directorio Pai Property_device=Dispositivo Property_directory=Directorio Property_track=Pista Property_size=Tamaño (Mb) Property_quality=Calidade Property_hashcode=HashCode Property_playlist_files=Listas de Reprodución Property_comment=Comentario Property_order=Pista Property_path=Ruta completa Property_tracks=Pistas Property_file_date=Data do Arquivo Property_Format_Number=Número Property_Format_String=String Property_Format_Boolean=Boolean Property_Format_Float=Float Property_Format_Date=Data Property_Format_URL=Url Property_pf=Preferencias Property_tpt=Tempo de reprodución total (segs) Property_ban=Baneado Language_desc_en=Inglés Language_desc_fr=Francés Language_desc_de=Alemán Language_desc_it=Italiano Language_desc_sv=Sueco Language_desc_nl=Holandés Language_desc_zh=Chino Language_desc_es=Español Language_desc_ca=Catalán Language_desc_ko=Koreano Language_desc_el=Grego Language_desc_ru=Ruso Language_desc_gl=Galego Language_desc_cs=Checo #--- Error codes --- Error.000=Erro descoñecido Error.005=Erro ó verifica-lo arquivo da colección. Error.007=Erro reproducindo o arquivo Error.008=Erro detendo o arquivo Error.009=Non se pode le-lo arquivo Error.010=Non se pode atopar un arquivo asociado con esta pista en ningún dispositivo instalado Error.011=Erro técnico ó instala-lo dispositivo ou dispositivo baleiro Error.012=Erro técnico ó desinstala-lo dispositivo, probablemente estao usando outra aplicación Error.013=Non se pode borra-lo dispositivo: Está actualmente instalado ou actualizándose Error.016=Non se pode acceder ó dispositivo especificado, por favor insire un dispositivo instalado. Ex: '/cdrom' baixo Unix,'e:' baixo MS Windows Error.017=Erro analizando a lista de reprodución Error.018=Non se atopou ningunha pista accesible Error.019=Xa existe un dispositivo con este nome Error.020=Erro de E/S. O disco pode que estea cheo Error.021=O campo Url é obrigatorio. Ex: 'd:\music' en MS Windows, '/home/foo/music' en Unix Error.022=O campo Nome é obrigatorio. Ex: 'Disco Duro', 'CD ROCK' Error.023=Non se pode inicia-la pista inicial Error.024=Non se pode escribi-lo arquivo Error.025=Un dos arquivos que queres ler está nun dispositivo desinstalado Error.026=Erro rexistrando reproductores Error.027=Sincronización abortada Error.028=Erro gardando a lista de reprodución Error.029=Un dispositivo existente é un directorio pai deste dispositivo, ten a mesma ruta ou é un directorio fillo Error.030=Demasiadas conexións erradas. Jajuk parou de buscar carátulas na rede. Error.101=O dispositivo non existe ou non está dispoñible Error.102=Erro Error.103=Erro lendo a información do tag Error.104=Erro escribindo a información do tag Error.105=Código de Empaquetado non atopado Error.106=Excepción non capturada Error.107=Xa se está actualizando ou sincronizando Error.108=Erro na verificación do arquivo de vistas Error.109=Reproductor ou clase de implementación do tag non accesible Error.110=Este nome de propiedade está reservado polo sistema interno de Jajuk, por favor escolla outro nome Error.111=Dispositivo xa instalado Error.112=Non se pode instala-lo dispositivo Error.113=Non se pode garda-la configuración do usuario Error.114=Non se pode le-la configuración do usuario Error.118=Erro procesando a petición de evento Error.119=Non existe arquivo do histórico ou erro verificando o mesmo Error.120=Non se pode acceder o dispositivo : aínda non está instalado, está actualizandose ou sincronizándose Error.121=O dispositivo está en uso e non pode ser desinstalado Error.122=Erro en FIFO Error.123=Erro escollendo sobreplanta Error.124=Outra sesión de Jajuk atopada. Só se pode lanzar unha instancia de Jajuk á vez Error.125=Dispositivo xa desinstalado Error.126=Búsqueda no soportada por este formato de audio Error.127=Non hai novedades durante o tempo especificado, podes cambia-lo valor para o tempo límite na vista de preferencias Error.128=Esta pista é a primeira da colección, non hai pistas anteriores dispoñibles Error.129=Erro cargando a imaxe de carátula Error.131=Non se pode borra-lo arquivo Error.133=O arquivo da colección está corrupto por unha razón descoñecida, jajuk encargarase de restaurar dende un arquivo de respaldo Error.134=Non se pode renomea-lo arquivo Error.135=O arquivo non existe Error.136=Operación fallida Error.137=Formato Erróneo Error.138=Algúns arquivos referenciados por estas pistas están localizados nuns dispositivos desinstalados e esto non pode ser cambiado Error.140=Cadea errónea: non debería conte-los carácteres & ' " < o > Error.141=Esta lista de reprodución está situada nun dispositivo desinstalado, polo que non está dispoñible Error.142=Esta lista de reprodución contén algunhas pistas fora de dispositivos coñecidos que serán ignorados Error.143=A localización do dispositivo non está dispoñible Error.144=Erro verificando o DJ Error.145=No se pode asigna-lo DJ Error.146=O patrón actual é incorrecto.
    Os elementos válidos son: %artist (Nome do Autor); %title (Título da Pista); %album (Nome do Álbume);
    %n (Pista a partires de cero); %genre (xénero da pista); %year (Ano)
    e o patrón debe conter coma mínimo unha barra invertida Error.147=Alguns arquivos non poden ser movidos (ver detalles para máis información) Error.148=O campo Ano é descoñecido Error.149=O campo Álbume é descoñecido Error.150=O campo Artista é descoñecido Error.151=O campo Título de Pista é descoñecido Error.152=O campo Pista é descoñecido Error.153=O campo Xénero é descoñecido Error.154=Non se pode renomea-lo arquivo, revisa algun carácter erróneo no mome ou nos tags Error.155=Erro ó polos tags ós arquivos, revisa os permisos Error.156=colección baleira Error.157=DJ erróneo, por favor, selecciona o crea un DJ dende a Vista de Comandos de DJ Error.158=As restriccións de DJ non poden ser respetadas ou ningunha pista dispoñible Error.159=O ambiente asociado foi borrado Error.160=Arquivo non movido. A fonte e a orixe eran os mesmos Error.161=Non se pode escribir no directorio, comprobar permisos Error.162=Esta caracteristica de usuario xa existe Error.163=Erro restaurando as vistas por defecto Error.164=Non hai pistas accesibles para o ambiente : Error.165=Erro na ruta, o directorio ou non existe ou non ten permisos de escritura Error.166=Álbume baleiro, non se pode captura-la caràtula Error.167=Non se pode crea-lo informe Error.168=Non se atoparon arquivos duplicados Error.169=Operación con erros. Ter en conta que esta operación require unha conexión a internet para obte-la lista de emisoras de radio. Error.170=Erro reproducindo webradio Error.171=Non se definiu unha fonte de sincronización para este dispositivo, asinala utilizando o asistente de configuración de dispositivos (Na vista de Dispositivo, pulsar sobre o dispositivo). Error.172=Erro atopado mentres se borrabán os seguintes arquivos: Error.173=Erro atopado mentres se borrabán os seguintes directorios: Error.174=Erro ó acceder ó sitio web de Freedb, revisa a túa conexión Error.175=Operación cancelada Error.176=Erro ó xenera-la lista de reprodución Error.177=Por favor insire unha hora válida no formato (HH24:MM:SS) Error.179=Non se pode abri-o exlorador do sistemas, tenta escoller unha ruta na vista Preferencias / Avanzadas #Warnings Warning.0=MPlayer non foi atopado na ruta, alguns formatos de audio (flac, wma, aac, mpg2 e algunhas características de ogg) serán deshabilitados. Para poder usar Mplayer, se este está instalado, debes escoller manualmente a súa ruta na cella Preferencias / avanzadas. Warning.1=Versión de MPlayer incorrecta, é necesario MPlayer1.0Pre8 ou superior. Algúns formatos de audio serán deshabilitados. Warning.2=Asemella que alguén máis está usando agora a área de traballo de Jajuk. O último usuario en sair sobreescribirá a configuración(opcións, valoracións...). Warning.3=Mplayer non pode ser descargado. Se estás detrás dun proxy HTTP, configúrao na vista de Preferencias / Cella de Rede e reinicia Jajuk. Warning.4=Mplayer é necesario para escoita-las radios web Warning.5=O directorio de destino xa existe, alguos arquivos sobreescribiranse, ¿Estás seguro? #--- Strings by class --- ParameterView.0=Duración do histórico: ParameterView.2=Escolle o tempo en dias que queres garda-la historia das pistas escoitadas. Escolle -1 se non queres ver ningún histórico e 0 se queres ter un histórico permanente ParameterView.3=Borrar histórico ParameterView.4=Borrar histórico ParameterView.8=Histórico ParameterView.9=Reproducir : ParameterView.10=Ningún ParameterView.11=Non se reproducirá música no comezo de Jajuk ParameterView.12=A última dende o comezo ParameterView.13=Reproduce a última pista da sesión anterior ParameterView.14=Pista aleatoria ParameterView.15=Reproduce unha pista aleatoria da colección ParameterView.16=Pista ParameterView.17=Seleccionar un arquivo para reproducir ó comezo ParameterView.18=Seleccionar un arquivo para reproducir ó comezo. Comeza a escribir para ver unha lista filtrada. ParameterView.19=Inicio ParameterView.26=Confirmacións ParameterView.27=Antes de borrar físicamente un arquivo ParameterView.28=Preguntar antes de borrar físicamente un arquivo ParameterView.29=Antes de sair de Jajuk ParameterView.30=Preguntar ó sair de Jajuk ParameterView.33=Opcións ParameterView.35=Ocultar pistas situadas en dispositivos desinstalados ParameterView.36=Reiniciar ó chegar ó fin da colección ParameterView.37=Reinicia-la colección completa cando se chega ó final no modo continuo ParameterView.38=Idioma: ParameterView.42=Idioma da interface ParameterView.43=Faciana: ParameterView.44=Seleccionar unha faciana

    (Pode que sexa necesario reiniciar jajuk para ve-la correctamente) ParameterView.46=Nivel de log: ParameterView.47=Fatal ParameterView.48=Erro ParameterView.49=Aviso ParameterView.50=Info ParameterView.51=Depurar ParameterView.52=Contexto de Jajuk : Fatal: amosa só os erros críticos, Erro: + erros de visualización, Info: +amosar mensaxes de info, Aviso:+ amosar alertas, Depurar: tódalas mensaxes ParameterView.59=Inicio de posición de introdución (%): ParameterView.60=Posición de introdución dentro da pista en %, dende 0 ( inicio da pista ) a 99 ( final da pista ) ParameterView.61=Lonxitude da introdución (seg): ParameterView.62=Lonxitude da introdución (en segundos) ParameterView.85=Aplicar ParameterView.86=Restaurar valores por defecto ParameterView.87=Preferencias ParameterView.98=Tags ParameterView.99=Realizar un escaneo profundo dos tags ParameterView.100=Forzar a Jajuk a re-ler os tags id3 actuais.

    Esto pode ser útil para actualiza-los tags que fosen modificados usando outro programa ParameterView.101=Usar directorio pai coma nome de álbume ParameterView.102=Jajuk usará o directorio pai coma o nome do álbume para as pistas se non pode obte-lo vía tags id3 ParameterView.109=Preferencias gardadas ParameterView.110=Preferencias restauradas a valores por defecto ParameterView.111=Tamaño da lista de reprodución O Mellor de: ParameterView.112=Escolle o número de pistas na lista de reprodución O Mellor de (de 1 a 100) ParameterView.113=Usar expresións regulares nos filtros ParameterView.114=Usar expresións regulares (Formato Regexp) nos filtros das tabóass, exemplo: .*foo.* ParameterView.115=Avanzada ParameterView.116=Facer unha copia de seguridade do arquivo de colección ParameterView.117=Marcar esto se queres facer unha copia de seguridade do teu arquivo de colección a arquivos collection-.xml ParameterView.118=Tamaño do Backup (Mb) ParameterView.119=Tamaño do Backup (Mb) ParameterView.120=Tipo de caracteres da colección ParameterView.121=Tipo de caracteres da colección. UTF-16 está optimizado para idiomas Asiáticos e UTF-8 está optimizado para idiomas europeos. ParameterView.129=Tempo límite das novidades (días): ParameterView.130=Tempo límite das novidades en días : tódalas pistas engadidas dentro dese número de días son amosadas coma novidades ParameterView.131=Pista O Mellor de ParameterView.132=Reproduce unha das túas pistas favoritas ó comezo ParameterView.133=Pista Novidade ParameterView.134=Reproduce unha novidade da túa colección ó comezo ParameterView.135=A última pista dende a última posición ParameterView.136=Reproduce a última pista reproducida dende a posición na que foi parada ParameterView.139=Rede ParameterView.142=Nome do usuario do proxy ParameterView.143=Nome de identificación no proxy ParameterView.144=Nome do host do proxy ParameterView.145=Nome do host ou da IP do proxy ParameterView.146=Porto do proxy ParameterView.147=Porto TCP/IP do proxy (a míudo 3128) ParameterView.148=Grava-las carátulas obtidas en liña ParameterView.149=Usa-la descarga automática de carátulas dende internet (se é requirido, configura o teu proxy na cella da rede) ParameterView.150=Tamaño das carátulas ParameterView.151=Tamaño das carátulas descargadas ParameterView.155=Precisión nas buscas. Canta máis precisión menos erros obterás coas carátulas ParameterView.156=Precisión Baixa (buscar tódalas palabras) ParameterView.157=Media (busca-las palabras agrupadas) ParameterView.158=Precisión Alta (busca-las palabras agrupadas obrigratoriamente) ParameterView.159=Carátulas ParameterView.160=Tempo sen Conexión (seg) ParameterView.161=Tempo sen Conexión en segs: a operación falla se a outra parte non resposta nese tempo ParameterView.162=Tempo sen transferencia (seg). ParameterView.163=Tempo sen transferencia (seg): a operación falla se os datos non se descargaron nese tempo ParameterView.164=Antes de desinstalar un dispositivo ParameterView.165=Preguntar antes de desinstalar un dispositivo ParameterView.166=Mesturar carátulas ParameterView.167=Amosar unha carátula aleatoria ParameterView.169=Precargar carátulas ParameterView.170=Precargar tódalas carátulas dispoñibles cando sexa posible ParameterView.171=Antes de borrar físicamente unha carátula ParameterView.172=Preguntar antes de borrar físicamente unha carátula ParameterView.177=Número visible de pistas escollidas ParameterView.178=O número de pistas escollidas a amosar na lista de reprodución ParameterView.179=Pulsar sobre a selección ParameterView.180=Cando se marquen, se puse unha pista cun dobre click ou se seleccione unha pista, estas serán inserida na cola ParameterView.181=Inserir ó facer un arrastar e pegar ParameterView.182=Cando se marquen, as cancións dunha colección seran arrastardas e pegadas dentro da lista de reprodución. ParameterView.183=Sincroniza-las vistas de árbore e tabóa ParameterView.184=Se está marcado, a vista de tabóa só amosará as pistas seleccionadas na vista de árbore ParameterView.185=Amosa-los globos ParameterView.186=Resetear puntuacións ParameterView.187=Resetea-las puntuacións de tódalas pistas a cero ParameterView.188=Antes limpa-lo histórico ParameterView.189=Antes resetea-las puntuacións ParameterView.190=Duración da propiedade de atenuación (segundos) ParameterView.191=Número de segundos de atenuación entre pistas ParameterView.192=Patrón de organizador de arquivos ParameterView.193=Patróns dispoñibles :%artist (Nome do artista); %title (Título da pista); %album (Nome do álbume); %n (Pista Principal dende cero); %genre (Xénero); %year (Ano) ParameterView.194=Antes de organizar arquivos ParameterView.195=Patrón de animación: ParameterView.196=Habilitar atallos de teclado ParameterView.197=Habilitar alguhnas teclas como F8 para que funcionen aínda que Jajuk non teña o foco ParameterView.198=Este cambio só terá efecto cando Jajuk sexa reiniciado ParameterView.199=Scrobble my listening ParameterView.200=Esta opción envia as informacións a Last.fm ParameterView.201=Nome de Usuario en Last.FM ParameterView.202=O nome de usuario usado en Last.FM ParameterView.203=Seña en Last.FM ParameterView.204=A seña usada en Last.FM ParameterView.205=Argumentos de Mplayer ParameterView.206=Argumentos adicionais de MPlayer coma '-ao esd', '-ao arts' ou '-novideo (para non reproducir videos)' para ie ParameterView.207=Ruta raíz de Jajuk ParameterView.208=Escolle-lo directorio que conten a configuración de Jajuk (por defecto é o directorio raíz do usuario) ParameterView.209=A ruta da configuración de Jajuk foi cambiada polo usuario actual (a área de traballo anterior foi gardada na localización anterior). Jajuk será reiniciado. ParameterView.210=Se a propiedade de atenuación non funciona, trata de engadir <-ao esd> en Gnome ou <-ao arts> en KDE no campo de argumentos adicionais do reprodutor de son (Preferencias / Avanzado). ParameterView.211=Pequenas só ParameterView.212=Pequenas e medianas ParameterView.213=Só medianas ParameterView.214=Medianas e grandes ParameterView.215=Grandes só ParameterView.216=Buscar usando o nome do artista ParameterView.217=Buscar usando o nome do álbume ParameterView.218=Buscar usando o nome da pista ParameterView.219=Variables de entorno ParameterView.220=Establece as variables de entorno usadas polo reprodutor de audio (ARTS_SERVER en KDE ou ESPEAKER en Gnome para ie). Formato: var1=xx var2=yyy... #Respect English size for next item ParameterView.221=T. da páxina do Catálogo (0: Todo nunha) ParameterView.222=Establece o número de álbumes por páxina na vista de catálogo. 0: amosa tódalas carátulas nunha soa páxina ParameterView.223=Tamaño das Fontes ParameterView.224=Establece o tamaño da fonte de texto ParameterView.225=GUI ParameterView.226=Modos ParameterView.228=Amosa-las xanelas emerxentes dos álbumes ParameterView.229=Preferencias da vista de Catálogo ParameterView.233=A interface refrescarse no próximo reinicio de jajuk ParameterView.234=Buscar actualizacións de Jajuk ParameterView.235=Last.FM ParameterView.236=Sen Proxy ParameterView.237=proxy HTTP ParameterView.238=proxy SOCKS ParameterView.239=Seña do Proxy ParameterView.240=Habilitar consultas de información en Last.FM ParameterView.241=Se está marcado, jajuk recollerá información dos álbumes dende a web de Last.FM (ver vista de suxerencias) ParameterView.242=Ruta de Mplayer ParameterView.243=Escolle aquí a ruta completa do mplayer có executable (espazos permitidos)
    Exemplo: /Applications/MPlayer OSX.app/Contents/Resources/External_Binaries/mplayer_intel.app/Contents/MacOS/mplayer ParameterView.244=Forza-las datas dos arquivos coma datas de descubrimento ParameterView.245=Se está marcado, jajuk considerará o sistema de datas dos arquivos coma datas de descubrimento
    Require un refresco profundo para que teñan efecto ParameterView.246=Tamaño das iconas da barra de Perspectivas (pixels) ParameterView.247=A ruta de destino xa contén un espazo de traballo de Jajuk. O espazo de traballo será cambiado a esta ruta para o usuario actualmente en curso (o espazo de traballo anterior será mantido na vella localización). Jajuk pode ser reiniciado agora. ParameterView.248=Patrón do título dos fotogramas: ParameterView.249=Resetear preferencias ParameterView.250=Resetear preferencias definidas polo usuario ParameterView.251=Histórico reseteado con éxito ParameterView.252=Puntuación e número de veces reproducida reseteadas con éxito ParameterView.253=Preferencias reseteadas con éxito ParameterView.254=Usar nomes cutos de Windows ParameterView.255=[Só Windows 32 bits] Se está marcado, forzar a mplayer a usa-los nomes dos arquivos de audio ó estilo dos nomes curtos de windows para fixar algún inconveniente con algún idioma (locale) ParameterView.256=Nomes dos arquivos das caratulas por defecto ParameterView.257=Jajuk toma por defecto ós nomes das caratulas a partir do nome do arquivo da caratula (sen a extensión). Pode ser que moitos valores esteán separados por ';'. Exemplo : "Fronte,contraportada". ParameterView.260=Gardar caratulas de xeito "amistoso" co Windows Explorer ParameterView.261=Garda-las caratulas descargadas coma cartafol.jpg/png/... así o explorador de windows pode usa-las coma iconas de directorio. ParameterView.262=Usar normalización de audio ParameterView.263=Maximiza-lo volume sen distorsiona-lo son ParameterView.264=Desactivar calquera acceso a Internet dende Jajuk ParameterView.265=Desactivar calquera acceso a Internet dende Jajuk (LastFM, caratulas ou descarga de letras...). ParameterView.266=Vacia-las cancións reproducidas da cola ParameterView.267=Tódalas cancións que esteán antes da canción en curso na cola serán descartadas ParameterView.268=Configuración do Proxy ParameterView.269=Ruta do executable do explorador ParameterView.270=Ruta do executable usado coma explorador de arquivos externo ParameterView.271=Amosa-la bandexa de iconas ParameterView.272=Se está marcado, jajuk pode ser manexado dende a area de notificación (non está dispoñible para tódolos sistemas operativos) Main.21=Confirmación Main.22=Descargando MPlayer Player.0=Esperando la línea de audio (ocupada) Device.25=] refrescado en Device.27= novos arquivos - Device.31=Sinc. [ Device.33=Sincronización feita en Device.35= arquivos creados ( Device.36= MB) Device.41=Sinc. [ Device.42=] Copiando [ Device.43= tags non lexibles Device.44=Entrando FIFO.4=). ¿ Queres instalalo ? FIFO.10=Reproducindo nestes intres: FIFO.13= Kbps FIFO.14=Reproducindo Web Radio: HistoryItem.0=yy/MM/dd HH:mm DeviceWizard.0=Configuración de dispositivo DeviceWizard.1=Tipo de dispositivo(*): DeviceWizard.2=Nome do dispositivo(*): DeviceWizard.3=Localización do dispositivo(*): DeviceWizard.7=Executar un refresco instantaneo DeviceWizard.8=Auto instalar ó comezo DeviceWizard.10=Sincronizado con : DeviceWizard.11=Sincronización unidireccional DeviceWizard.12=Tódolos arquivos novos no dispositivo fonte serán copiados neste dispositivo. Nada voltará a ser escrito no dispositivo fonte DeviceWizard.13=Sicronización bidireccional DeviceWizard.14=Tódolos arquivos novos atopados nun dispositivo copiaranse ó outro DeviceWizard.43=Por favor escolle un direcorio DeviceWizard.44=Dispositivo creado DeviceWizard.45=Por favor, dalle un nome o dispositivo. Ex: CD A, Portátil ... DeviceWizard.46=Por favor, da unha localización para o dispositivo. Ex: d:\music en Windows, /home/foo/music en Unix DeviceWizard.48=Marca esto se queres executar un refresco inmediato do dispositivo (avisado)

    Esta operación pode tardar bastante para dispositivos grandes DeviceWizard.49=Marca esto se queres instalar automáticamente o dispositivo ó inicio.

    Aconsellado para directorios no disco duro actual. Evitalo para CDs DeviceWizard.50=Intervalo en minutos para búsca automática de novos arquivos (0: deshabilitada, 0.5 min é o intervalo mínimo) DeviceWizard.51=Marca esto se queres sincronizar este dispositivo con outro DeviceWizard.52=Seleccionar un dispositivo fonte DeviceWizard.53=Refrescar dispositivo cada #limited string size DeviceWizard.54=min JajukJMenuBar.0=Arquivo JajukJMenuBar.1=Abrir arquivo JajukJMenuBar.3=Sair JajukJMenuBar.5=Propiedades JajukJMenuBar.6=Crear propiedade personalizada JajukJMenuBar.7=Borrar propiedade personalizada JajukJMenuBar.8=Vistas JajukJMenuBar.9=Modos JajukJMenuBar.10=Repetición JajukJMenuBar.11=Aleatorio JajukJMenuBar.12=Continuo JajukJMenuBar.13=Intro JajukJMenuBar.14=Axuda JajukJMenuBar.15=Contidos da axuda JajukJMenuBar.16=Acerca de JajukJMenuBar.17=Restaurar vistas (actual perpectiva) JajukJMenuBar.18=Asistente de Dispositivos JajukJMenuBar.19=Comunicar un problema JajukJMenuBar.20=Consello do Día JajukJMenuBar.21=Configuración JajukJMenuBar.22=Preferencias JajukJMenuBar.23=Mostra-las trazas da depuración JajukJMenuBar.24=Mostrar só as pistas dispoñibles JajukJMenuBar.25=Mostrar vista JajukJMenuBar.26=Restaurar vistas (tódalas perspectivas) JajukJMenuBar.27=Comprobar actualizacións de Jajuk JajukJMenuBar.28=Ferramentas JajukJMenuBar.29=Pequeno JajukJMenuBar.30=Repetir todo JajukJMenuBar.31=Karaoke PlaylistFileItem.1=Lista de Novidades PlaylistFileItem.2=Nova lista de reprodución PlaylistFileItem.3=Favoritos PlaylistFileItem.4=O Mellor de PlaylistFileItem.5=Cola JajukFileChooser.0=Escoller Arquivo SearchBox.0=Executar unha busca entre pistas, autores, estilos, directorio ... CommandJPanel.0=Ver histórico de reproducción CommandJPanel.1=[Ctrl-t] Modo repetición: Reproduci-las pistas nun bucle CommandJPanel.2=[Ctrl-h] Modo aleatorio: Reproducir aleatoriamente as pistas seleccionadas CommandJPanel.3=Modo continuo: Voltar a reproduci-las pistas escollidas unha vez escoitada a lista CommandJPanel.4=Modo introducción: Reproducir un fragmento de cada pista. Inicio e duración poden ser cambiados dende a vista de Preferencias CommandJPanel.5=Reproducir unha selección aleatoria da colección enteira CommandJPanel.6=Reproduci-las túas pistas favoritas CommandJPanel.8=[F9] Reproduci-la pista anterior na selección actual
    Shift+ click lanza o álbume anterior
    CTRL+click para reproducir de novo ó álbume actual CommandJPanel.9=[F10] Reproduci-la pista siguinte na selección actual
    Shift+click lanza o álbume anterior CommandJPanel.10=[Alt-gr F9] Retroceso rápido na pista actual
    Shift+click para repetición completa CommandJPanel.13=[Alt-gr F0] Avance rápido na pista actual CommandJPanel.15=Preme aqui para cambia-lo formato da hora CommandJPanel.16=Lanza-la selección de DJ CommandJPanel.17=Administrar DJ CommandJPanel.18=Lanza-la seleción de DJ por defecto CommandJPanel.19=Administrar Ambientes CommandJPanel.20=Pista por pista CommandJPanel.21=Aleatoriamente álbume por álbume CommandJPanel.22=Álbume por álbume CommandJPanel.23=Clica para limpia-la busca CommandJPanel.24=Configurar web radios CommandJPanel.25=Encende-la radio CommandJPanel.26=Modo repetir todo: Reproduci-la cola en bucle CommandJPanel.27=Modo Karaoke, oculta as voces na canción reproducida (aplicaranse os cambios á seguinte canción en ser reproducida) InformationJPanel.5=Tempo total da list a reproducir [Nb de pistas restantes] InformationJPanel.6=Taxa de Bits da pista InformationJPanel.7=Progreso de la pista actual #song name BY artist ON album name InformationJPanel.8=%title de %artist do %album # Keep next label short InformationJPanel.9= AbstractPlaylistEditorView.0=Título AbstractPlaylistEditorView.1=Localización AbstractPlaylistEditorView.2=Reproducir esta lista de reprodución AbstractPlaylistEditorView.3=Salvar esta lista de reprodución AbstractPlaylistEditorView.4=Engadir un elemento a esta lista de reprodución AbstractPlaylistEditorView.5=Eliminar un elemento desta lista de reprodución AbstractPlaylistEditorView.6=Move-la pista seleccionada arriba AbstractPlaylistEditorView.7=Move-la pista seleccionada abaixo AbstractPlaylistEditorView.9=Borrar esta lista de reprodución AbstractPlaylistEditorView.10=Engadir unha pista aleatoria a esta lista de reprodución AbstractPlaylistEditorView.15=Editor de listas de reprodución AbstractPlaylistEditorView.17=Estás a punto de actualiza-las seguintes listas de reprodución : AbstractPlaylistEditorView.18=Pista en cola AbstractPlaylistEditorView.19=Pista repetida AbstractPlaylistEditorView.20=Pista seleccionada AbstractPlaylistEditorView.21=Pista da lista de reprodución AbstractPlaylistEditorView.22=Lista de reprodución gardada AbstractPlaylistEditorView.27=Preparar Festa AbstractPlaylistEditorView.28=Cartafol creado con éxito en StatView.0=Outros StatView.1=Xéneros StatView.2=Non hai datos dispoñibles StatView.3=Outras StatView.4=Tamaño por dispositivo (GB) StatView.5=Non hai datos dispoñibles StatView.7=Tamaño de la colección por mes StatView.8=Meses StatView.9=Tamaño (GB) StatView.10=Non hai datos dispoñibles StatView.12=Número total de pistas por meses StatView.13=Meses StatView.14=Número das Pistas StatView.15=Non hai datos dispoñibles StatView.16=Estatísticas StatView.24=Antigas CDScanView.0=Etiqueta de CD : CDScanView.1=Etiqueta de CD. Ex: CD1, ROCK... CDScanView.2=Etiqueta de CD Ejx CD1, ROCK... CDScanView.3=Localización do CD : CDScanView.4=Localización onde se pode atopa-lo CD. Ex: '/cdrom' en Unix, 'e:' en MS Windows... CDScanView.5=Localización onde se pode atopa-lo CD. Ex: '/cdrom' en Unix, 'e:' baixo MS Windows... CDScanView.6=Analizar CDScanView.12=Analizar CD CDScanView.18=Analiza-lo CD e engadir automáticamente tódolos arquivos de música á colección CDScanView.19=Selecciona-la localización do CD TracksTreeView.0=Árbore de pistas TracksTreeView.27=Colección TracksTreeView.31= pistas TracksTreeView.33=Crear un informe TracksTreeView.34=Obter tags en liña TracksTreeView.35=Data de Descubrimento TracksTreeView.36=menos dunha semana TracksTreeView.37=menos dun mes TracksTreeView.38=menos de seis meses TracksTreeView.39=anterior TracksTreeView.40=menos dun ano TracksTreeView.41=menos de dous anos TracksTreeView.42=menos de cinco anos TracksTreeView.43=menos de 10 anos TracksTreeView.44=menos de tres meses TracksTreeView.45=Ano CoverView.2=Borrar do disco esta carátula CoverView.3=Carátula CoverView.4=Imaxe anterior obtida do disco e/ou da Web se a opción de Auto-Carátula está marcada CoverView.5=Imaxe seguinte obtida do disco e/ou da Web se a opción de Auto-Carátula está marcada CoverView.6=

    Garda-la carátula co seu nome orixinal

    Con CTRL: Gardar carátula coma...

    CoverView.8=Usar esta carátula coma a carátula por defecto deste álbume CoverView.9=carátulas CoverView.10=Gardar carátula coma CoverView.11=Carátula gardada CoverView.12=Álbume CoverView.13=Título AnimationView.0=Animación FilesTreeView.0=Árbore de arquivos FilesTreeView.3=Copiar FilesTreeView.4=Cortar FilesTreeView.5=Pegar FilesTreeView.7=Borrar FilesTreeView.14=Desincronizar FilesTreeView.15=Resincronizar FilesTreeView.16=Crear Lista de Reprodución FilesTreeView.17=Copiar FilesTreeView.18=Cortar FilesTreeView.28=Instalar FilesTreeView.29=Desinstalar FilesTreeView.30=Forzar Refrescar FilesTreeView.31=Sincronizar FilesTreeView.32=Probar FilesTreeView.33=Crear listas de reprodución FilesTreeView.40=Copiar FilesTreeView.41=Cortar FilesTreeView.42=Pegar FilesTreeView.47=Colección FilesTreeView.52= arquivos: FilesTreeView.53= GB FilesTreeView.54= MB FilesTreeView.55= Configurar FilesTreeView.59=¿Queres executar un refresco rápido ou profundo (le-los tags outra vez)? FilesTreeView.60=Rápido FilesTreeView.61=Profundo FilesTreeView.62=Organizar arquivos TracksTableView.0=Tabóa de pistas TracksTableView.7=Reproducir TracksTableView.8=Inserir TracksTableView.9=Reproducir aleatoriamente TracksTableView.10=Reproducir con repetición TracksTableView.11=Reproducir álbume TracksTableView.12=Reproducir autor TracksTableView.14=Propiedades TracksTableView.15=Engadir a Favoritos TracksTableView.16=Ir ó seguinte AbstractTableView.0=Filtro: AbstractTableView.1=Propiedade a filtrar AbstractTableView.3=Valor usado polo filtro AbstractTableView.4=Aplicar filtro AbstractTableView.5=Limpia-lo filtro AbstractTableView.6=Aplicar un filtro avanzado AbstractTableView.7=contén: AbstractTableView.8=Calquera AbstractTableView.10=(Non dispoñible) AbstractTableView.11=Face-la tabóa editable AboutView.7=Acerca de AboutView.8=Licenza AboutView.9=Sistema AboutView.10=Acerca de AboutView.11=Copyright 2003-2011
    Jajuk team" PhysicalPlaylistRepositoryView.0=Reproducir PhysicalPlaylistRepositoryView.1=Editar PhysicalPlaylistRepositoryView.2=Gardar como PhysicalPlaylistRepositoryView.3=Borrar PhysicalPlaylistRepositoryView.4=Propiedades PhysicalPlaylistRepositoryView.6=Listas de Reprodución físicas PhysicalPlaylistRepositoryView.8=Intelixente PhysicalPlaylistRepositoryView.9=Reproducir Cola PhysicalPlaylistRepositoryView.10=Lista actual: arrastra e solta as pistas para engadilas á lista de reprodución PhysicalPlaylistRepositoryView.11=Nova PhysicalPlaylistRepositoryView.12=Nova lista de reprodución: arrastra e solta as pista a engadir a favoritos PhysicalPlaylistRepositoryView.13=Favoritos PhysicalPlaylistRepositoryView.14=Lista de reprodución de favoritos: arrastra e solta as pistas a engadir a favoritos PhysicalPlaylistRepositoryView.15=O Mellor de PhysicalPlaylistRepositoryView.16=Lista de reprodución de O Mellor de: contén as mellores pistas PhysicalPlaylistRepositoryView.17=Novidades PhysicalPlaylistRepositoryView.18=Lista de reprodución de novidades: contén as pistas máis novas da colección PhysicalPlaylistRepositoryView.19=Preparara Festa FilesTableView.0=Tabóa de arquivos FilesTableView.15=Reproducir un directorio #Dev: do not use ID = 16, next label is FilesTableView.17 DeviceView.0=Engadir un dispositivo DeviceView.1=Eliminar un dispositivo desinstalado (non borra nada do disco) DeviceView.2=Propiedades do dispositivo seleccionado DeviceView.3=Instala-lo dispositivo seleccionado DeviceView.4=Desinstala-lo dispositivo seleccionado DeviceView.5=Probar disponibilidade do dispositivo seleccionado DeviceView.6=Forza-lo refresco do dispositivo seleccionado DeviceView.7=Sincronizar dispositivo seleccionado DeviceView.8=Instalar DeviceView.9=Desinstalar DeviceView.10=Probar DeviceView.11=Forzar refresco DeviceView.12=Sincronizar DeviceView.13=Eliminar dispositivo DeviceView.14=Configurar DeviceView.17=Novo DeviceView.18=Engadir un dispositivo DeviceView.21=Este dispositivo está dispoñible DeviceView.22=Non se pode acceder ó dispositivo DeviceView.23=Dispositivos JajukWindow.1=Non silenciar JajukWindow.2=Silenciar JajukWindow.3=Jajuk JajukWindow.4=Sair JajukWindow.5=Acerca de Jajuk JajukWindow.6=Reproducir aleatoriamente JajukWindow.7=Reproducir O Mellor de JajukWindow.10=Pausa JajukWindow.12=Resume JajukWindow.13=Anterior JajukWindow.14=Seguinte JajukWindow.15=Reproducir Novidades JajukWindow.16=Continuar co álbume JajukWindow.17=Jajuk: Jukebox Avanzada JajukWindow.18=Preparado para a reproducción JajukWindow.19=[F8] Silenciar/Non silenciar
    Usa a rodiña do rato para escolle-lo volume JajukWindow.21=Sair JajukWindow.22=Acerca de Jajuk JajukWindow.23=Reproducir aleatoriamente pistas da colección enteira JajukWindow.24=Reproduci-las mellores pistas da colección enteira JajukWindow.26=[Ctrl-p] Reproducir/Pausar JajukWindow.27=[Ctrl-s] Parar JajukWindow.31=Reproducir novidades da colección enteira JajukWindow.32=Rematar de reproducir este álbume JajukWindow.33=[Ctrl-UP/DOWN] Volume JajukWindow.34=Posición JajukWindow.35=Reproducindo: JajukWindow.36=Ambiente actual: JajukWindow.37=Sen Ambiente seleccionado #Do not use JajukWindow.38, next is JajukWindow.39 SimpleDeviceWizard.0=Creación rápida de dispositivo FirstTimeWizard.0=Comezo rápido FirstTimeWizard.1=


    Benvido! Este asistente ayudarache na creación da colección.

    FirstTimeWizard.2=Selecciona o directorio onde está situada a música

    (O primeiro refresco levará un bó anaco) FirstTimeWizard.4=Amosa-la axuda agora FirstTimeWizard.5=Por favor, escolle un directorio FirstTimeWizard.6=Preferencias avanzadas FirstTimeWizard.7=Establece-lo directorio da área de traballo de Jajuk : HelpView.2=Axuda DownloadManager.0=Jajuk necesita a seña do teu proxy HTTP para descargar carátulas
    Se non as queres, por favor cambia a túa configuración na cella Carátulas da vista de Preferencias
    Se non tes proxy, cambia os axustes na cella de Rede da vista de Preferencias DownloadManager.1=Seña requirida PropertiesWizard.0=Propiedades de ... PropertiesWizard.1=Propiedade PropertiesWizard.2=Valor PropertiesWizard.3=Editable? PropertiesWizard.4=Enlace PropertiesWizard.6=Selección PropertiesWizard.7=Tipo PropertiesWizard.8=Propiedade cambiada correctamente PropertiesWizard.9=Propiedade non editable para esta selección PropertiesWizard.10=as propiedades forón escollidas PropertiesWizard.11=Escribindo tag en: PropertiesWizard.12=Enlazar cuns detalles de propiedades dun elemento dado NewPropertyWizard.0=Crear propiedade de usuario NewPropertyWizard.3=(*)Tipo NewPropertyWizard.4=Formato NewPropertyWizard.5=Valor por defecto CustomPropertyWizard.0=(*)Elemento CustomPropertyWizard.1=(*)Nome de propiedade de usuario RemovePropertyWizard.0=Borrar propiedade de usuario QualityFeedbackWizard.20=Unha nova xanela abrirase no navegador para envia-lo teu informe. Os teus últimos rastros anónimos foron colocados no portapapeis, por favor pégaos no campo descrición se é un informe de bug (esto incrementa as opcións de que poidamos arranxa-lo teu problema). IncRateAction.0=Incrementa-la valoración da pista actual SplashScreen.0=Controis iniciais SplashScreen.1=Cargando Colección SplashScreen.2=Iniciando reprodutor musical SplashScreen.3=Iniciando interface gráfica CatalogView.0=Catálogo de álbumes #Note: CatalogView.2 label musn't be mush larger than in english for correct display in 800x600 CatalogView.2=Sen carátulas CatalogView.3=Refresca-lo catálogo CatalogView.4=Tamaño das miniaturas: CatalogView.5=Creada miniatura para: CatalogView.7=Seleccionar unha carátula CatalogView.8=Ningunha carátula atopada CatalogView.9=Anterior CatalogView.10=Seguinte CatalogView.11=Páxina: CatalogView.12=Amosa-la páxina anterior de miniaturas CatalogView.13=Amosa-la páxina seguinte de miniaturas CatalogView.14=Selecciona-la páxina de miniaturas a amosar CatalogView.15=Tamaño da miniatura: CatalogView.16=álbumes CatalogView.17=/páxina CatalogView.18=Selección de carátula CatalogView.19=Refacer miniaturas CatalogView.20=Amosar detalle CatalogView.21=Amosar tódolos álbumes CatalogView.22=Amosa-lod álbumes con caratula WikipediaView.0=Wikipedia WikipediaView.1=Seleccionar Idioma: WikipediaView.3=Nada atopado WikipediaView.5=Buscar por nome de Artista WikipediaView.6=Buscar por nome de Álbume WikipediaView.7=Buscar por título WikipediaView.8=Cargando WikipediaView.9=Non foi posible carga-la información dende a Wikipedia TipOfTheDayView.0=Consello do día TipOfTheDayView.1=¿Sabías...? TipOfTheDayView.2=¿Amosar ó comezo? CDDBWizard.0=Aceptar CDDBWizard.1=Nome do Arquivo CDDBWizard.2=Título da Pista Actual CDDBWizard.3=Título do Álbume Actual CDDBWizard.4=Título de Pista Proposto CDDBWizard.5=Título de Álbume Proposto: CDDBWizard.6=Feito! Atopado CDDBWizard.7=posibles coincidencias CDDBWizard.12=Non foi atopada coincidencia algunha ! CDDBWizard.14=Este directorio non contén arquivo algún CDDBWizard.16=Xénero: CDDBWizard.17=Atopada coincidencia exacta ! CDDBWizard.18=Coincidencias CDDBWizard.19=Obter Tags en liña RefactorWizard.0=Arquivo movido : DigitalDJWizard.0=Selecciona-lo novo modo de DJ DigitalDJWizard.1=Programación baseada en transicións (ROCK -> POP) DigitalDJWizard.2=Programación baseada en proporcións (20% JAZZ, 30% ROCK) DigitalDJWizard.3=Programación baseada en ambientes (Suave, Festa, ...) DigitalDJWizard.4=Asistente de DJ Digital DigitalDJWizard.5=Configuración xeral do DJ DigitalDJWizard.6=Nome do DJ (*) DigitalDJWizard.8=Número mínimo de estrelas: DigitalDJWizard.9=Atenuación (seg): DigitalDJWizard.10=Pistas somentes reproducidas unha vez DigitalDJWizard.11=Tirar DigitalDJWizard.12=Dende Xéneros DigitalDJWizard.13=A Xéneros DigitalDJWizard.14=Selección de Xéneros (seleccións múltiples permitidas) DigitalDJWizard.15=Número de pistas DigitalDJWizard.16=¿Queres.... DigitalDJWizard.17=Crear un novo DJ ? DigitalDJWizard.18=Configurar un DJ existente ? DigitalDJWizard.19=Borrar un DJ ? DigitalDJWizard.20=Novo DJ baseado en transicións #limited string size DigitalDJWizard.21=Borrar #limited string size DigitalDJWizard.22=Orixe #limited string size DigitalDJWizard.23=Destino #limited string size DigitalDJWizard.24=Nb DigitalDJWizard.26=Por favor crea al menos unha transición #limited string size DigitalDJWizard.27=Selección de xéneros #limited string size DigitalDJWizard.28=% DigitalDJWizard.29=Novo DJ baseado en proporcións DigitalDJWizard.30=Por favor, crea almenos una proporción DigitalDJWizard.31=Novo DJ baseado en ambientes DigitalDJWizard.32=Novo DigitalDJWizard.33=Crear un novo ambiente DigitalDJWizard.34=Borrar DigitalDJWizard.35=Borra-lo ambiente seleccionado DigitalDJWizard.36=Nome do ambiente DigitalDJWizard.37=Nome DigitalDJWizard.38=Por favor crea al menos un ambiente DigitalDJWizard.39=Por favor insire o nome e selecciona os xéneros do ambiente DigitalDJWizard.40=Por favor selecciona un DJ DigitalDJWizard.41=Por favor pon un nome ó DJ DigitalDJWizard.42=Xa existe un DJ con este nome DigitalDJWizard.43=Cambiar DJ DigitalDJWizard.44=Selecciona-lo DJ a configurar DigitalDJWizard.45=Selección de acción DigitalDJWizard.46=Selección do tipo de DJ DigitalDJWizard.47=Por favor, selecciona ou crea un ambiente DigitalDJWizard.48=Atributos Xerais DigitalDJWizard.49=Por favor insire os atributos xerais do DJ DigitalDJWizard.50=Por favor define as proporcións DigitalDJWizard.51=Borrar DJ DigitalDJWizard.52=Por favor define as transicións DigitalDJWizard.53=Número mínimo de estrelas de puntuación para pistas na selección (1: tódalas pistas) DigitalDJWizard.54=Duración da atenuación entre pistas DigitalDJWizard.55=Se está marcado, a selección conterà cada pista só unha vez DigitalDJWizard.56=Asistente de Ambientes DigitalDJWizard.57=Xestor de Ambientes DigitalDJWizard.58=Selección de Ambientes: DigitalDJWizard.59=A suma de tódalas proporcións tería que ser < 100 % DigitalDJWizard.60=O nome do ambiente xa existe DigitalDJWizard.61=Borrar DJ #limited string size DigitalDJWizard.62=Por defecto DigitalDJWizard.63=Engadir ambientes por defecto DigitalDJWizard.64=Calquera DigitalDJWizard.66=Selección de Ambiente por defecto #--- Tips of day --- Ambience.0=Rock/Pop Ambience.1=Rap Ambience.2=HardRock Ambience.3=Techno Ambience.4=Electro Ambience.5=Clásico Ambience.6=Soft Ambience.7=Party Ambience.8=Jazz Ambience.9=World Ambience.10=Otros Ambience.11=Folk/Oldies Ambience.12=Indy Ambience.13=Latino DebugLogAction.0=Lista-los rastros da Depuración DebugLogAction.1=Refrescar CopyClipboardAction.0=Copiar dirección ó portapapeis LaunchInBrowserAction.0=Lanza-la dirección no navegador por defecto ReportAction.0=Informe creado satisfactoriamente ReportAction.1=Informe de Música de Jajuk ReportAction.2=Por favor, para coidar do medio ambiente, non imprimas se non é necesario ReportAction.3=Lista de Álbumes ReportAction.4=Pistas por Álbume ReportAction.5=Lista de Artistas ReportAction.6=Álbumes por artistas ReportAction.7=Lista de Xéneros ReportAction.8=Álbumes por xénero ReportAction.9=Autores/ álbumes por xénero ReportAction.10=Lista de Directorios ReportAction.11=Arquivos por directorio ReportAction.12=Nome do arquivo ReportAction.13=Nome da pista ReportAction.14=Lista de Dispositivos ReportAction.15=Directorios por dispositivo ReportAction.16=Directorios/arquivos ReportAction.17=colección ReportAction.18=Autores/ álbumes/ cancións por estilo ReportAction.19=Ir a: ActionMove.0=Pegar ActionRefresh.0=Forzar refresco ActionRefresh.1=Refresca-lo diretorio RenameAction.0=Renomear RenameAction.1=Por favor insire un novo nome para este arquivo: RenameAction.2=Por favor insire un novo nome para este cartafol: NewFolderAction.0=Crear un Novo Cartafol NewFolderAction.1=Por favor insire un novi Nome de Cartafol: NewFolderAction.2=Xa existe un cartafol con ese mesmo nome. LyricsView.0=Letras LyricsView.1=Non hai letras, o acesso a internet foi desactivado, usa o menu de Configuración para activa-lo. ActionDelete.0=Arquivos borrados ActionDelete.1=Directorios borrados FindDuplicateFilesAction.0=Non se atoparon arquivos duplicados. FindDuplicateFilesAction.1=Atoparonse arquivos duplicados FindDuplicateTracksAction.2=Atopar pistas duplicadas FindDuplicateTracksAction.3=Lista de pistas duplicadas atopadas FindDuplicateTracksAction.4=Seleccionar tódalas pistas duplicadas RefreshDialog.0=Preparando actualización de dispositivo... RefreshDialog.1=Actualizando dispositivo RefreshDialog.2=Actualizando dispositivo: RefreshDialog.3=Limpando os arquivos antigos RadioWizard.0=Selecciona ou crea unha web radio RadioWizard.1=Xestionar web radios RadioWizard.2=Nova RadioWizard.3=Borrar RadioWizard.4=Por defecto RadioWizard.5=Xa existe unha web radio con ese nome RadioWizard.6=Nome da Web Radio RadioWizard.7=Asistente de Web Radio RadioWizard.8=URL RadioWizard.9=Nome RadioWizard.10=URL incorrecta RadioWizard.11=O nome e a URL son obrigatorios UpdateManager.0=Unha nova versión de Jajuk ( UpdateManager.1=) foi atopada, podes descargala dende http://jajuk.info UpdateManager.2=Non hai unha nova versión polo de agora LastFmManager.0=O soporte Last.FM está deshabilitado. Se queres envia-las cancións que escoites a Last.FM, habilítao e configura o teu alcume e seña de Last.FM na cella Last.FM da vista de Preferencias. SuggestionView.0=Suxerencias SuggestionView.1=Preferidas SuggestionView.2=Os Máis Novos SuggestionView.3=Outros álbumes SuggestionView.4=Artistas similares SuggestionView.5=Raramente escoitadas SuggestionView.7=Nada que amosar

    A información de Last.FM só se amosará se:

    • Unha pista está sendo reproducida
    • O autor da pista é coñecido (tag correcto)
    • A opción "Habilitar consultas a Last.FM" está marcada na cella Last.FM da vista de Preferencias
    AbstractThumbnail.0=Abri-la páxina LAST.FM AlbumsTableView.0=Tabóa de Álbumes AlbumsTableView.1=Nº de pistas AlarmClock.0=Escoller unha nova alarma #Next value : 6 AlarmDialog.0=Hora (HH24:MM:SS) AlarmDialog.1=Hora AlarmDialog.2=Minutos AlarmDialog.3=Segundos AlarmDialog.4=Acción de alarma AlarmDialog.5=Selección acción de alarma #Next value : 11 ShowPropertiesAction.0=Amosa-las propiedades do elemento QueueView.1=Baleira-la cola QueueView.2=Moverse na táboa automaticamente cara a canción en reprodución JajukSlimWindow.0=Amosar/Ocultar-la barra de deslizamento de Jajuk JajukFullscreen.0=Des/Habilita-lo reproductor a pantalla completa BanSelectionAction.0=Banear BanSelectionAction.1=Banea-lo elemento, así nunca poderá ser escollido de novo UnBanSelectionAction.0=Desbanear UnBanSelectionAction.1=Desbanea-lo(s) elemento(s), así poderá ser escollido de novo OpenExplorerAction.0=Abrir co explorador OpenExplorerAction.1=Abri-lo directorio usando un programa explorador externo Preference.0=Escolle unha preferencia persoal para a actual canción
    Será tida en conta para o computo de puntuación final Preference.1=Desastrosa Preference.2=Pobre Preference.3=Regular Preference.4=Boa Preference.5=Excelente Preference.6=Clásico Preference.7=Preferencias... Preference.8=Sen preferencias ArtistView.0=Artist view # TipOfTheDay are automatically generated with the Jajuk Manual. # To change tip of the day use page: http://jajuk.info/index.php/Tip_of_the_day TipOfTheDay.0=Consello 0: podes repeti-la pista actual dende o comezo con [Shift+click] no botón de Rebobinado TipOfTheDay.1=Consello 1: podes repeti-lo álbume actual dende a primera pista con [Shift+click] TipOfTheDay.2=Consello 2: podes engadir elementos aleatorios á lista de reprodución usando o botón ? no editor da lista de reprodución TipOfTheDay.3=Consello 3: podes obter carátulas de internet incluso detrás dun proxy usando a cella de Rede na vista de Preferencias TipOfTheDay.4=Consello 4: podes garda-las carátulas obtidas dende internet para acelera-la navegación na vista de carátulas utilizando a opción de precargar de carátulas na cella de carátulas na vista de Preferencias TipOfTheDay.5=Consello 5: Qué podes oculta-las pistas non disponibles utilizando a opción "Amosar só dispositivos instalados" na cella de opcións da vista de Preferencias TipOfTheDay.6=Consello 6: podes executar case tódalas funcións de Jajuk usando o teclado TipOfTheDay.7=Consello 7: podes arrastrar e soltar elementos dende as vistas de árbore ó editor das listas de reprodución e ó reposorio das listas de reprodución TipOfTheDay.8=Consello 8: podes escoita-lo principio das pistas usando o modo intro TipOfTheDay.9=Consello 9: podes configura-la duración da atenuación na cella de Modos da vista de Preferencias TipOfTheDay.10=Consello 10: podes comezar con jajuk en modo reducido desmarcando a opción "Amosar Jajuk ó comezo" na bandexa do escritorio TipOfTheDay.11=Consello 11: podes controla-las principais funcións de Jajuk usando só o icono da bandexa (Linux e Windows) TipOfTheDay.12=Consello 12: a faciana de Jajuk é configurable na cella de GUI na vista de Preferencias TipOfTheDay.13=Consello 13: podes configura-lo comportamento do doble-click e do arrastar e soltar (push & play) na cella de Opcións da vista de Preferencias TipOfTheDay.14=Consello 14: as pistas "programadas" de Jajuk son pistas que soarán despois da selección actual TipOfTheDay.15=Consello 15: a interface gráfica de Jajuk é completamente acoplable e podese reorganiza-las vistas arrastrando e soltando TipOfTheDay.16=Consello 16: podes obte-lo número total de arquivos e pistas seleccionando o nodo "colección" nas vistas de árbore de arquivos e pistas TipOfTheDay.17=Consello 17: podes obter tags en liña coa función "Obter tags en liña" nos directorios ou nas vistas de árbore de arquivos e pistas TipOfTheDay.18=Consello 18: a barra de histórico de Jajuk (arriba da fiestra) amosa tódalas pistas reproducidas con anterioridade TipOfTheDay.19=Consello 19: podes executar bucas rápidas usando a caixa de busca (arriba da fiestra) TipOfTheDay.20=Consello 20: podes informar sobre ou pedir novas propiedades usando o axente de calidade (Axuda,Comunicar un problema) TipOfTheDay.21=Consello 21: os DJs de Jajuk poden crear listas de reprodución intelixentes seguindo as túas reglas TipOfTheDay.22=Consello 22: podes obte-las letras usando a "Vista de letras" TipOfTheDay.23=Consello 23: a vista de Suxerencias amosa a información de LAST.FM coma artistas semellantes TipOfTheDay.24=Consello 24: podes establecer unha imaxe de fondo do teu gusto na cella GUI da vista de Preferencias TipOfTheDay.25=Consello 25: podes amosar/oculta-los dispositivos desinstalados nun só click na barra do menú de Modos TipOfTheDay.26=Consello 26: podes escolle-lo directorio para os datos de Jajuk (coma un disco externo) para garda-los teus datos e preferencias en calquer ordenador (ver cella "Avanzado" na vista de Preferencias) TipOfTheDay.27=Consello 27: podes engadir calquera perspectiva usando a barra de menú de "Vistas" TipOfTheDay.28=Consello 28: podes ir a unha páxina web co teu navegador por defecto usando esta icona Image:launch_16x16.png/ TipOfTheDay.29=Consello 29: Jajuk soporta radios web Image:webradio_32x32.png/ ]]> jajuk-1.9.6.orig/src/main/java/org/jajuk/i18n/jajuk_ko.properties0000644000175000017500000011236711720500104024507 0ustar drazzibdrazzib 는 포함될 수 없습니다. Error.141=이 재생목록은 마운트되지 않았거나 새로 갱신중인 장치에 있어서 사용할 수 없습니다. Error.142=이 재생목록은 알려진 외부 장치에 있는 일부 무시된 트랙들을 포함하고 있습니다. #--- Strings by class --- ParameterView.0=히스토리 기간: ParameterView.2=청취했던 트랙을 기록하는 히스토리 기간을 하루 단위로 정하십시오. history 기능을 사용하고 싶지 않다면 1을 입력하고 영구적으로 설정하려면 0을 입력하십시오 ParameterView.3=히스토리 기록 제거 : ParameterView.4=히스토리 기록 제거 : ParameterView.8=히스토리 기록 ParameterView.9=재생 : ParameterView.10=아무것도 없습니다 ParameterView.11=시작시 재생되는 음악이 없습니다. ParameterView.12=시작시 마지막 곡부터 ParameterView.13=이전 세션에 재생된 마지막 트랙부터 재생 ParameterView.14=트랙을 무작위로 섞습니다. ParameterView.15=전체 컬렉션에서 임의로 트랙을 재생합니다. ParameterView.16=트랙: ParameterView.17=시작시 재생될 파일을 선택하십시오. ParameterView.18=시작시 재생될 파일을 선택하십시오. ParameterView.19=시작 ParameterView.26=확정 ParameterView.27=실제로 화일을 지우기 전 ParameterView.28=실제로 화일을 지우기 전 물어봅니다. ParameterView.29=Jajuk을 끝내기 전 ParameterView.30=Jajuk을 끝내기 전 물어봅니다 ParameterView.33=옵션 ParameterView.34=오직 마운트된 장치들만 표시합니다 ParameterView.35=마운트되지 않은 장치에 있는 트랙들을 숨깁니다. ParameterView.36=컬렉션의 끝 트랙에 도달했을 때 재시작합니다. ParameterView.37=현재 모드에서 가장 마지막 트랙에 도달했을 때 모든 컬렉션을 재시작합니다. ParameterView.38=언어: ParameterView.42=인터페이스 언어 설정 ParameterView.43=룩앤필: ParameterView.44=룩앤필 설정 ParameterView.45=룩앤필 설정 ParameterView.46=로그 레벨: ParameterView.47=치명적인 ParameterView.48=에러 ParameterView.49=경고 ParameterView.50=정보 ParameterView.51=디버그 ParameterView.52=Jajuk 에러 수준: 치명적: 치명적 에러 발생시에만 표시됩니다. 에러: 에러 발생시 표시됩니다. 정보: 정보 메시지가 표시됩니다., 경고: 경고 메시지가 표시됩니다. 디버그: 어떤 메시지가 표시됩니다. ParameterView.59=인트로 시작 위치(%): ParameterView.60=트랙의 인트로 포지션 (%), 0 (시작)부터 99(마지막)까지 선택가능 ParameterView.61=인트로 길이 (초 단위) : ParameterView.62=인트로 길이 (초 단위) ParameterView.71=P2P ParameterView.72=트랙을 공유하겠습니까? ParameterView.73=다른 사용자가 당신의 박스로부터 음악을 읽을 수 있게 하려면 이곳에 체크하십시오 ParameterView.74=패스워드 : ParameterView.75=당신의 박스에 접근할 수 있도록 패스워드를 설정하십시오. 패스워드를 설정하지 않는다면 아무도 박스로부터 아무것도 읽을 수 없습니다. . ParameterView.76=원격 프로퍼티를 추가하십시오 ParameterView.77=이곳에 체크한다면, 당신은 다른 사람들의 박스로부터 당신이 읽는 트랙에 대한 개인 원격 프로퍼티를 얻을 것입니다. ParameterView.78=지역 프로퍼티를 숨깁니다. ParameterView.79=이곳에 체크한다면, 다른 사람들은 트랙에 대한 당신의 개인 프로퍼티를 볼 수 없습니다. ParameterView.85=적용 ParameterView.86=디폴트로 복구합니다. ParameterView.87=파라미터 ParameterView.98=태그 ParameterView.99=보다 상세한 태그 스캔을 수행합니다. ParameterView.100= Jajuk이 실제 id3 태그를 다시 읽도록 강제시킵니다.

    이는 당신이 다른 프로그램을 사용하여 tag를 수정한 후 새로 갱신할 때 유용합니다. ParameterView.101=앨범 이름으로 부모 디렉토리를 사용하십시오 ParameterView.102=id3 태그에 의해 앨범 이름을 얻을 수 없다면 Jajuk에게 부모 디렉토리를 사용하도록 하십시오 ParameterView.103=언어 변환은 다음 Jajuk 실행시 적용됩니다. ParameterView.109=옵션이 저장되었습니다. ParameterView.110=옵션이 디폴트로 설정됩니다. ParameterView.111=베스트 재생목록 크기 ParameterView.112=베스트 재생목록에 들어갈 트랙 수를 정하십시오 (1-100) ParameterView.113=필터에서 정규식 표현을 사용하십시오 ParameterView.114=테이블 필터에서 정규식 표현을 사용하십시오 (Regexp format) . 예) .*foo.* ParameterView.115=고급 ParameterView.116=컬렉션 화일을 복구합니다. ParameterView.117=컬렉션 화일을 .xml 화일로 백업하려면 여기에 체크하십시오 ParameterView.118=백업 사이즈 (MB) ParameterView.119=백업 사이즈 (MB) ParameterView.120=컬렉션 문자셋 ParameterView.121=컬렉션 문자셋. UTF-16은 아시아 국가 언어에 최적화되어있고, UTF-8은 유럽언어에 최적화되어 있습니다. ParameterView.129=노벨티 기능 기간 제한 (일 단위): ParameterView.130=노벨티 기능 기간 제한 (일 단위), 모든 트랙은 노벨티 기능에 기간 제한이 적용되기전 추가되어야 합니다. ParameterView.131=베스트 트랙 ParameterView.132=시작시 사용자 선호 트랙을 재생합니다. ParameterView.133=노벨티(Novelty) 트랙 ParameterView.134=시작시 사용자 컬렉션으로부터 노벨티 트랙을 재생합니다. ParameterView.135=지난 세션의 마지막 위치에서 마지막 트랙 ParameterView.136=지난 세션의 마지막 위치에서의 마지막 트랙을 재생합니다. ParameterView.139=네트웍 ParameterView.140=HTTP 프락시를 사용합니다. ParameterView.141=프락시를 이용하여 웹에 연결된 공용 네트웍에 연결되어 있다면 HTTP 프락시를 사용합니다. ParameterView.142=사용자 이름을 위임합니다. ParameterView.143=인증을 위해 사용되는 로그인 이름을 위임합니다. ParameterView.144=호스트 이름을 위임합니다. ParameterView.145=호스트 이름이나 IP 주소를 위임합니다. ParameterView.146=포트를 위임합니다. ParameterView.147=TCP-IP포트를 위임합니다. (주로 3128 포트) ParameterView.148=자동 커버 기능을 사용합니다. ParameterView.149=인터넷으로부터 커버를 갖고 오기 위해 자동 커버 기능을 사용합니다 (필요하다면, 옵션에서 네트웍 탭에서 proxy를 설정하십시오) ParameterView.150=최소 커버 사이즈 (KB) ParameterView.151=인터넷으로부터 가져올 커버의 최소 사이즈 (KB) ParameterView.152=최대 커버 사이즈 (KB) ParameterView.153=인터넷으로부터 가져올 커버의 최대 사이즈 (KB) ParameterView.155=정확도로 이미지를 검색합니다. 수치가 높을 수록 더 정확한 커버를 찾을 것이고 수치가 낮다면 잘못된 커버 이미지를 찾을 것입니다. ParameterView.156=낮음 ParameterView.157=중간 ParameterView.158=높음 ParameterView.159=커버 ParameterView.160=커넥션 타임아웃 (초 단위) ParameterView.161=커넥션 타임아웃 (초 단위): 설정 시간동안 반응이 없다면 명령은 완수되지 않은 것입니다. ParameterView.162=전송 타임 아웃 (초 단위): ParameterView.163=데이터 전송 타임 아웃 (초 단위): 설정 시간동안 필요로 하는 데이터가 완전히 다운로드 되지 않는 다면 명령은 완수되지 않은 것입니다. ParameterView.164=장치를 제거하기 전 ParameterView.165=장치를 제거하기 전 물어봅니다. ParameterView.166=커버를 섞습니다. ParameterView.167=무작위로 커버를 표시합니다. ParameterView.168=저자 ParameterView.169=커버를 미리 로드합니다. ParameterView.170=가능하다면 모든 가능한 커버들을 미리 로드합니다. ParameterView.171=실제로 커버를 제거하기 전 ParameterView.172=실제로 커버를 제거하기 전 물어봅니다. ParameterView.175=각 트랙마다 커버를 로드합니다. ParameterView.176=만약 각 트랙마다 서로 다른 커버를 로드하고자 한다면 체크하십시오 (단, 셔플 모드에서만 적용됨) ParameterView.177=가시적인 예정된 트랙의 수 ParameterView.178=가시적인 예정된 트랙의 수 ParameterView.179=더블클릭시 다음 곡 재생 ParameterView.180=더블클릭시 현재곡 재생하지 않고 다음 곡 재생 ParameterView.181=드래그&드랍시 다음 곡 재생 ParameterView.182=드래그&드랍시 다음 곡 재생 ParameterView.183=트리 & 테이블 뷰를 동기화합니다. ParameterView.184=테이블뷰가 체크가 되어 있다면,오직 트리뷰에서 선택된 트랙들만 보여집니다. ParameterView.185=트랙이 시작된다면 팝업이 보여집니다. ParameterView.186=rating을 초기화합니다. ParameterView.187=트랙들에 대한 rating을 0으로 초기화합니다. ParameterView.188=히스토리 기록을 지우기 전 ParameterView.189=rating을 초기화하기 전 ParameterView.190=크로스 페이드 간격 (초 단위) ParameterView.191=트랙간 크로스 페이드 간격 (초 단위) Main.21=결정 Player.0=오디오 라인을 기다립니다.(점유되어진 라인) Device.21=Refreshing [ Device.22=] Entering [ Device.25=] refreshed in Device.27= new files Device.31=Sync. [ Device.33=Synchronization done in Device.35= created files ( Device.36= MB) Device.41=Sync. [ Device.42=] Copying [ Device.43= unreadable tags FIFO.4=). 마운트를 시도하고자 합니까 ? FIFO.10=현재 재생 중: FIFO.13= kbps HistoryItem.0=yy/MM/dd HH:mm DeviceWizard.0=장치 마법사 DeviceWizard.1=장치 유형: DeviceWizard.2=장치 유형: DeviceWizard.3=장치 위치: DeviceWizard.4=유닉스 마운트 위치(선택사항): DeviceWizard.7=즉각의 새로고침을 수행합니다. DeviceWizard.8=시작시 자동 마운트를 합니다. DeviceWizard.10=동기화합니다.: DeviceWizard.11=일정방향의 동기화: DeviceWizard.12=소스 장치에서 발견된 모든 새로운 파일들은 이 장치로 복사됩니다. 소스 장치에는 아무것도 쓰여지지 않습니다. DeviceWizard.13=쌍방향 동기화 DeviceWizard.14=한 장치에서 발견된 모든 새로운 파일들은 다른 장치로 복사됩니다. DeviceWizard.43=디렉토리를 선택하십시오 DeviceWizard.44=장치가 생성되었습니다. DeviceWizard.45=장치 이름을 정하십시오. 예) CD A, Laptop DeviceWizard.46=장치 위치를 정하십시오. 예) d:\music under Windows, /home/foo/music under Unix DeviceWizard.47=장치 Unix 마운트 위치를 정하십시오. 예) /media/cdrom DeviceWizard.48=즉각적인 장치의 새로 고침을 원한다면 선택하십시오

    이 명령어는 용량이 큰 장치에서는 더 많은 시간이 소요될 수 있습니다. DeviceWizard.49=jajuk 시작시 자동적으로 장치를 마운트하고자 한다면 선택하십시오.

    마운트는 CD가 아닌 현 하드디스크의 디렉토리가 선택되어져야 합니다. DeviceWizard.50=새로 추가된 파일을 위한 자동 스캔시 인터벌 시간 (분 단위, 0: 스캔 없음) DeviceWizard.51=다른 장치와 동기화를 하고자 한다면 체크하십시오 DeviceWizard.52=소스 장치를 선택하십시오 DeviceWizard.53=장치를 새로 고침하십시오. DeviceWizard.54=분 JajukJMenuBar.0=파일 JajukJMenuBar.1=열기 JajukJMenuBar.3=끝내기 JajukJMenuBar.5=속성 JajukJMenuBar.6=사용자 프로퍼티 생성 JajukJMenuBar.7=사용자 프로퍼티 제거 JajukJMenuBar.8=뷰 JajukJMenuBar.9=모드 JajukJMenuBar.10=반복 JajukJMenuBar.11=섞기 JajukJMenuBar.12=계속 JajukJMenuBar.13=인트로 JajukJMenuBar.14=도움말 JajukJMenuBar.15=도움말 목차 JajukJMenuBar.16=About JajukJMenuBar.17=초기화 뷰 포지션 복구 JajukJMenuBar.18=장치 마법사 JajukJMenuBar.19=이슈를 보고합니다. JajukJMenuBar.20=오늘의 팁 PlaylistFileItem.1=노벨티 큐(Novelties) PlaylistFileItem.2=새 재생목록 PlaylistFileItem.3=북마크 PlaylistFileItem.4=베스트 PlaylistFileItem.5=현재 큐(Queue) JajukFileChooser.0=파일 선택기 SearchBox.0=트랙, 저자, 스타일, 디렉토리상에서 검색을 수행합니다. CommandJPanel.0=재생 히스토리 기록을 봅니다. CommandJPanel.1=반복 모드: 반복적으로 트랙을 재생합니다. CommandJPanel.2=셔플 모드: 선택된 트랙들을 무작위로 재생합니다. CommandJPanel.3=계속 모드: 트랙 재생이 끝나면 다음곡을 재생합니다. CommandJPanel.4=인트로 모드: 각 트랙마다 일정 시간동안만 재생합니다. 오프셋과 시간은 파라미터 뷰에서 설정할 수 있습니다. CommandJPanel.5=전체 컬렉션에서 선택된 곡들을 무작위로 재생합니다. CommandJPanel.6=사용자 선호 트랙들을 재생합니다. CommandJPanel.7=소리를 제거합니다. CommandJPanel.8= 현 선택에서 이전 트랙을 재생합니다.
    Shift+click을 누르면 이전 앨범을 시작합니다. CommandJPanel.9= 현 선택에서 다음 트랙을 재생합니다.
    Shift+click을 누르면, 다음 앨범을 시작합니다. CommandJPanel.10=현재 재생중인 트랙에서 Fast Rewind를 합니다.
    Shift+click을 누르면 재생을 반복합니다. CommandJPanel.11=현재 재생중인 트랙의 일시멈춤 / 재생 CommandJPanel.12=멈춤 CommandJPanel.13=현재 재생중인 트랙에서의 Fast Forward CommandJPanel.14=볼륨 CommandJPanel.15=재생중인 트랙에서의 이 위치로 이동 InformationJPanel.5=총 재생시간 InformationJPanel.6=트랙의 비트율 InformationJPanel.7=현 트랙의 진행상황 AbstractPlaylistEditorView.0=트랙 AbstractPlaylistEditorView.1=위치 AbstractPlaylistEditorView.2=현 재생목록을 실행합니다. AbstractPlaylistEditorView.3=현 재생목록을 저장합니다. AbstractPlaylistEditorView.4=선택 곡을 재생목록에 추가합니다. AbstractPlaylistEditorView.5=현 재생목록으로부터 선택 곡을 제거합니다. AbstractPlaylistEditorView.6=선택 곡의 목록 위치를 높게 설정합니다. AbstractPlaylistEditorView.7=선택 곡의 목록 위치를 낮게 설정합니다. AbstractPlaylistEditorView.9=현 재생목록을 제거합니다. AbstractPlaylistEditorView.10=셔플트랙을 재생목록에 추가합니다. AbstractPlaylistEditorView.15=재생목록 에디터 AbstractPlaylistEditorView.17=다음의 모든 재생목록들을 모두 디스크에 업데이트하려고 합니다. AbstractPlaylistEditorView.18=큐에 있는 트랙 AbstractPlaylistEditorView.19=반복되는 트랙 AbstractPlaylistEditorView.20=(재생) 예정 중인 트랙 AbstractPlaylistEditorView.21=재생목록 트랙 AbstractPlaylistEditorView.22=저장된 재생목록 AbstractPlaylistEditorView.23=재생 AbstractPlaylistEditorView.24=다음 AbstractPlaylistEditorView.25=선호목록에 추가 AbstractPlaylistEditorView.26=속성 StatView.0=Others StatView.1=스타일 재구분 StatView.2=가능 데이터 없음 StatView.3=Others StatView.4=장치별 용량 (gb) StatView.5=가능 데이터 없음 StatView.7=컬렉션 사이즈 (월 단위) StatView.8=월 StatView.9=크기 (gb) StatView.10=가능 데이터 없음 StatView.12=총 트랙 수 (월 단위) StatView.13=월 StatView.14=트랙 번호 StatView.15=가능 데이터 없음 StatView.16=통계 StatView.24=older CDScanView.0=CD 라벨 : CDScanView.1=CD 라벨을 입력하시오. 예) CD1, ROCK... CDScanView.2=CD 라벨을 입력하시오. 예) CD1, ROCK... CDScanView.3=CD 위치 : CDScanView.4=CD가 발견된 위치. 예) '/cdrom' under Unix, 'e:' under MS Windows... CDScanView.5=CD가 발견된 위치. 예) '/cdrom' on Unix, 'e:' under MS Windows... CDScanView.6=스캔 CDScanView.12=CD 스캐너 CDScanView.18=CD를 스캔하고 자동적으로 컬렉션에 모든 음악화일들을 추가합니다. CDScanView.19=CD 위치를 선택합니다. TracksTreeView.0=논리적 트리 TracksTreeView.1=재생 TracksTreeView.2=다음곡 TracksTreeView.3=무작위 재생 TracksTreeView.4=반복 재생 TracksTreeView.5=제거 TracksTreeView.7=속성 TracksTreeView.8=재생 TracksTreeView.9=다음곡 TracksTreeView.10=무작위 재생 TracksTreeView.11=반복 재생 TracksTreeView.12=제거 TracksTreeView.14=속성 TracksTreeView.15=재생 TracksTreeView.16=다음곡 TracksTreeView.17=무작위재생 TracksTreeView.18=반복재생 TracksTreeView.19=제거 TracksTreeView.21=속성 TracksTreeView.22=재생 TracksTreeView.23=다음곡 TracksTreeView.24=제거 TracksTreeView.26=속성 TracksTreeView.27=컬렉션 TracksTreeView.31= 트랙 TracksTreeView.32=선호목록에 추가 LogicalPlaylistRepositoryView.0=재생목록 CoverView.2=실제로 현 커버를 제거 CoverView.3=커버 CoverView.4=자동 커버이미지 옵션이 체크되어 있다면 디스크나 웹에서의 이전 커버 이미지 CoverView.5=자동 커버이미지 옵션이 체크되어 있다면 디스크나 웹에서의 다음 커버 이미지 CoverView.6=원래 이름과 함께 커버 이미지 저장 CoverView.7=커버 이미지를 새 이름으로. 저장 CoverView.8=현 커버를 현 앨범의 기본 커버 이미지로 사용 CoverView.9=커버 CoverView.10=현 커버를 새 이름으로 저장 CoverView.11=저장된 커버 CoverView.12=앨범 CoverView.13=트랙 AnimationView.0=애니메이션 FilesTreeView.0=물리적 트리 FilesTreeView.1=재생 FilesTreeView.2=다음곡 FilesTreeView.3=복사 FilesTreeView.4=잘라내기 FilesTreeView.5=붙여넣기 FilesTreeView.7=제거 FilesTreeView.9=속성 FilesTreeView.10=재생 FilesTreeView.11=다음곡 FilesTreeView.12=무작위 재생 FilesTreeView.13=반복 재생 FilesTreeView.14=비동기화 FilesTreeView.15=재동기화 FilesTreeView.16=재생목록 생성 FilesTreeView.17=복사 FilesTreeView.18=잘라내기 FilesTreeView.19=붙여넣기 FilesTreeView.21=제거 FilesTreeView.23=속성 FilesTreeView.24=재생 FilesTreeView.25=다음곡 FilesTreeView.26=무작위 재생 FilesTreeView.27=반복 재생 FilesTreeView.28=마운트 FilesTreeView.29=마운트 제거 FilesTreeView.30=강제 새로고침 FilesTreeView.31=동기화 FilesTreeView.32=테스트 FilesTreeView.33=재생목록 생성 FilesTreeView.35=속성 FilesTreeView.36=재생 FilesTreeView.37=다음곡 FilesTreeView.38=무작위 재생 FilesTreeView.39=반복 재생 FilesTreeView.40=복사 FilesTreeView.41=잘라내기 FilesTreeView.42=붙여넣기 FilesTreeView.44=제거 FilesTreeView.46=속성 FilesTreeView.47=컬렉션 FilesTreeView.52= 파일: FilesTreeView.53= Gb FilesTreeView.54= Mb FilesTreeView.55=설정 FilesTreeView.56=재생목록에 추가 FilesTreeView.57=온라인상에서 태그 수집 TracksTableView.0=논리적 테이블 TracksTableView.7=재생 TracksTableView.8=다음 곡 TracksTableView.9=무작위 재생 TracksTableView.10=반복 재생 TracksTableView.11=앨범 재생 TracksTableView.12=저자별 재생 TracksTableView.14=속성 TracksTableView.15=선호목록에 추가 AbstractTableView.0=필터링: AbstractTableView.1=필터링에 대한 속성 AbstractTableView.3=필터링에 의해 사용되는 값 AbstractTableView.4=필터링 적용 AbstractTableView.5=필터링 초기화 AbstractTableView.6=고급 필터링 적용 AbstractTableView.7=포함: AbstractTableView.8=any AbstractTableView.10=(Not available) AboutView.7=About AboutView.8=License AboutView.9=System AboutView.10=About PhysicalPlaylistRepositoryView.0=재생 PhysicalPlaylistRepositoryView.1=에디트 PhysicalPlaylistRepositoryView.2=새 이름으로 PhysicalPlaylistRepositoryView.3=제거 PhysicalPlaylistRepositoryView.4=속성 PhysicalPlaylistRepositoryView.6=재생목록 PhysicalPlaylistRepositoryView.8=Specials PhysicalPlaylistRepositoryView.9=큐 PhysicalPlaylistRepositoryView.10=현재 큐: 재생되는 동안 드래그&드랍 가능 PhysicalPlaylistRepositoryView.11=New PhysicalPlaylistRepositoryView.12=새 재생목록: 화일 추가하기 위해 드래그&드랍 가능 PhysicalPlaylistRepositoryView.13=북마크 PhysicalPlaylistRepositoryView.14=재생목록 북마크: 북마크에 추가하기 위해 드래그&드랍 가능 PhysicalPlaylistRepositoryView.15=베스트 PhysicalPlaylistRepositoryView.16=베스트 재생목록: top 트랙 포함. PhysicalPlaylistRepositoryView.17=Novelties PhysicalPlaylistRepositoryView.18=Novelties 재생목록: 새로 추가된 트랙들 포함 FilesTableView.0=물리적 테이블 FilesTableView.1=재생 FilesTableView.2=다음 곡 FilesTableView.3=무작위 재생 FilesTableView.4=반복재생 FilesTableView.6=속성 FilesTableView.15=디렉토리 재생 FilesTableView.16=재생목록에 추가 DeviceView.0=장치 추가 DeviceView.1=마운트되지 않은 장치 제거 (디스크에서 물리적으로는 어떤 장치도 제거되지 않습니다.) DeviceView.2=선택된 장치 속성 DeviceView.3=선택된 장치 마운트 DeviceView.4=선택된 장치 마운트 해제 DeviceView.5=선택된 장치 사용가능성 테스트 DeviceView.6=선택 장치의 새로고침 강제 DeviceView.7=선택된 장치 동기화 DeviceView.8=마운트 DeviceView.9=마운트 해제 DeviceView.10=테스트 DeviceView.11=새로고침 강제 DeviceView.12=동기화 DeviceView.13=장치 제거 DeviceView.14=설정 DeviceView.17=New DeviceView.18=장치 추가 DeviceView.21=장치는 사용가능합니다. DeviceView.22=장치에 접근할 수 없습니다. DeviceView.23=장치들 JajukWindow.1=소리 제거 해제 JajukWindow.2=소리 제거 JajukWindow.3=Jajuk JajukWindow.4=끝내기 JajukWindow.5=Jajuk에 대해서.. JajukWindow.6=임의 재생 JajukWindow.7=Play Best of JajukWindow.8=시작시 Jajuk 표시 JajukWindow.10=일시멈춤 JajukWindow.11=멈춤 JajukWindow.12=재생 JajukWindow.13=이전 JajukWindow.14=다음 JajukWindow.15=novelties 재생 JajukWindow.16=앨범 계속 재생 JajukWindow.17=Jajuk: Advanced Jukebox JajukWindow.18=재생 준비 됨 JajukWindow.19=소리 제거 / 해제 JajukWindow.21=끝내기 JajukWindow.22=Jajuk에 대해서... JajukWindow.23=전체 컬렉션에서 임의 트랙 재생 JajukWindow.24=전체 컬렉션에서 베스트 트랙 재생 JajukWindow.25=시작시 Jajuk 표시: 만약 체크되지 않았다면, jajuk은 트레이에서 최소화되어 시작됩니다. JajukWindow.26=재생 / 일시멈춤 JajukWindow.27=멈춤 JajukWindow.29=이전 트랙 - left-click+[SHIFT]: 이전 앨범 JajukWindow.30=다음 트랙 - left-click+[SHIFT]: 다음 앨범 JajukWindow.31=전체 컬렉션에서 novelties 목록 재생 JajukWindow.32=Continue album: finish to play current album JajukWindow.33=볼륨 JajukWindow.34=위치 JajukWindow.35=현 재생 : FirstTimeWizard.0=빠른 시작 FirstTimeWizard.1=환영합니다! Jajuk 마법사는 당신의 컬렉션을 생성하는 데 도움을 줄 것입니다. FirstTimeWizard.2=음악 디렉토리 위치를 선택하십시오 FirstTimeWizard.3=Jajuk이 온라인에서 커버 이미지를 얻기를 원하십니까
    (자동적으로 인터넷을 연결할 것입니다) ? FirstTimeWizard.4=바로 도움말을 보시겠습니까 ? FirstTimeWizard.5=디렉토리를 선택하십시오 HelpView.2=도움말 DownloadManager.0=온라인에서 커버를 얻기 위해 당신의 HTTP proxy 패스워드가 필요합니다, Parameter의 네트웍 탭에서 설정을 변경하십시오. DownloadManager.1=패스워드가 필요합니다. PropertiesWizard.0=아이템 속성 PropertiesWizard.1=속성 PropertiesWizard.2=값 PropertiesWizard.3=수정가능? PropertiesWizard.4=링크 PropertiesWizard.6=Selection PropertiesWizard.7=유형 PropertiesWizard.8=속성을 성공적으로 업데이트했습니다. PropertiesWizard.9=현 선택에 대해 속성을 변경할 수 없습니다. PropertiesWizard.10=속성이 변경되었습니다. PropertiesWizard.11=Writing tag to: PropertiesWizard.12=Link to given element properties details NewPropertyWizard.0=사용자 속성 생성 NewPropertyWizard.3=(*)유형 NewPropertyWizard.4=포맷 NewPropertyWizard.5=초기값 CustomPropertyWizard.0=(*)아이템 CustomPropertyWizard.1=(*)사용자 속성 이름 RemovePropertyWizard.0=사용자 속성 제거 QualityFeedbackWizard.1=From: QualityFeedbackWizard.2=사용자의 이름이나 별칭을 입력하시오 QualityFeedbackWizard.3=(*)주제: QualityFeedbackWizard.4=당신의 문제에 대해 기술하시오: QualityFeedbackWizard.5=세부사항: QualityFeedbackWizard.6=당신의 문제에 대해 세부적으로 기술하시오. SplashScreen.0=초기 체크업 SplashScreen.1=컬렉션 로딩 SplashScreen.2=음악 엔진 시작 SplashScreen.3=그래픽 인터페이스 시작 CatalogView.0=커버 카탈로그 #CatalogView.2 라벨은 800x600 label musn't be mush larger than in english for correct display in 800x600 CatalogView.2=커버 없이 CatalogView.3=강제 썸네일 재생성 CatalogView.4=썸네일 크기: CatalogView.5=썸네일 생성: CatalogView.7=온라인상에서 커머 이미지 수집 CatalogView.8=발견된 커버 이미지가 없습니다. CatalogView.9=이전 CatalogView.10=다음 WikipediaView.0=Wikipedia WikipediaView.1=언어를 선택하십시오: TipOfTheDayView.0=Tip of the Day TipOfTheDayView.1=알고 있습니까... ? TipOfTheDayView.2=시작시 표시? CDDBWizard.0=수락 CDDBWizard.1=파일 이름 CDDBWizard.2=현재 트랙 이름 CDDBWizard.3=현재 앨범 이름 CDDBWizard.4=Proposed Track Name CDDBWizard.5=Proposed Album Name CDDBWizard.6=검색하였습니다. CDDBWizard.7=가능한 검색 결과 CDDBWizard.11=가능한 데이터베이스 서버에 요청하고 있습니다. CDDBWizard.12=검색 결과가 없습니다. CDDBWizard.13=가능한 검색 결과입니다. CDDBWizard.14=이 디렉토리는 어떤 파일도 포함하고 있지 않습니다. CDDBWizard.16=스타일: CDDBWizard.17=요구사항과 정확하게 맞는 결과를 검색하였습니다. Found exact match ! CDDBWizard.18=Match(es) #--- Tips of day --- TipOfTheDay.0=컨트롤 패널이나 트레이에서 Rewind 버튼 위에 [Shift+click]을 누름으로써 현재 트랙을 처음부터 다시 재생할 수 있다 ? TipOfTheDay.1=컨트롤 패널이나 트레이에서 Previous 버튼 위에 [Shift+click]을 누름으로써 앨범의 첫 번째 트랙부터 다시 재생할 수 있다 ? TipOfTheDay.2=재생목록 에디터의 ? 버튼을 누름으로써 재생목록의 무작위 아이템을 추가할 수 있다 ? TipOfTheDay.3=Parameter 뷰의 네트웍 탭을 사용하는 공용 proxy 서버 뒤에서 일지라도 온라인 상에서 커버 이미지를 얻을 수 있다 ? TipOfTheDay.4=Parameter 뷰의 커버 탭에서 '커버 이미지 미리 적재(prefetch covers) 옵션을 선택하면, 커버 뷰의 네비게이션 기능을 빠르게 하기 위해 온라인 상에서 발견한 모든 커버 이미지들을 저장할 수 있다 ? TipOfTheDay.5=Parameter 뷰 / 옵션 탭의 '마운트된 장치만 보여주기' 옵션을 사용하면 사용가능하지 않은 트랙을 숨길 수 있다 ? TipOfTheDay.6=키보드만을 사용해도 jajuk의 대부분의 기능들을 다룰 수 있다 ? TipOfTheDay.7=재생목록 에디터와 재생목록 저장소 (Playlist repository)에서의 free 뷰로부터 재생목록까지 언제나 아이템들을 드래그&드랍할 수 있다 ? TipOfTheDay.8=인터로 모드를 사용하면 트랙의 일정 앞부분을 청취할 수 있다 ? TipOfTheDay.9=Parameter 뷰 / 옵션 탭에서 크로스-페이드 간격을 설정할 수 있다 ? TipOfTheDay.10=트레이 팝업내의 윈도우 시작시 jajuk 보이기 옵션을 해제함으로써 jajuk을 reduced mode로 시작할 수 있다 ? TipOfTheDay.11=오직 트레이(Linux & Window only)를 사용하여 jajuk의 주 기능들을 사용할 수 있다 ? TipOfTheDay.12=Jajuk의 룩&필(Look and Feel)은 Parameter 뷰 / 옵션 탭에서 설정 가능하다 ? TipOfTheDay.13=더블클릭과 드래그&드랍 (push & play) 기능을 Parameter 뷰 / 옵션 탭에서 설정 가능하다 ? TipOfTheDay.14=Jajuk의 '예정된' 트랙들은 현재 유저에 의해 선택된 트랙들이 모두 재생된 후에 재생될 트랙들이다 ? TipOfTheDay.15=Jajuk의 그래픽 인터페이스는 완벽히 조작 가능하고 드래그&드랍 기능을 사용하여 뷰들을 재배치할 수 있다 ? TipOfTheDay.16=물리적 / 논리적 트리 뷰의 '컬렉션' 노드를 선택함으로써 파일과 트랙의 총 개수를 알 수 있다 ? TipOfTheDay.17=물리적 트리 뷰의 디렉토리에 대한 '온라인에서 태그 수집' 기능을 통해 태그 정보를 얻을 수 있다 ? TipOfTheDay.18=Jajuk 윈도우의 윗 부분에 있는 재생 기록 막대(history bar)에서 이전에 재생된 모든 트랙 목록들을 볼 수 있다 ? TipOfTheDay.19=Jajuk 윈도우의 윗 부분에 있는 Search box를 이용하여 빠른 검색을 수행할 수 있다 ? ]]>jajuk-1.9.6.orig/src/main/java/org/jajuk/i18n/jajuk_it.properties0000644000175000017500000004670311720500104024512 0ustar drazzibdrazzib Forza Jajuk la rilettura dei tags id3 .

    Questo puo' essere utile per rileggere le meta-informazioni che hai modificato con altri programmi ParameterView.101=Usa il nome della directory come nome dell'album ParameterView.102=Usa il nome della directory come nome dell'album per i brani che non hanno meta-informazioni ParameterView.103=Il cambio di linguaggio sara' attivo al prossimo riavvio di Jajuk ParameterView.104=Il tema sara' aggiornato al prossimo riavvio di Jajuk ParameterView.109=Opzioni salvate ParameterView.110=Opzioni settate con i valori di default ParameterView.111=Dimensione della playlist bestof : ParameterView.112=Setta il numero di brani per la playlist bestof (da 1 a 100) Main.10=Jajuk : Advanced Jukebox Main.12=E' la tua prima sessione di Jajuk, come prima cosa devi creare un dispositivo nella vista dei dispositivi Main.13=Jajuk partito correttamente Main.21=Conferme Device.21=Aggiornamento [ Device.22=] Entering [ Device.25=] Aggiornato in Device.26= sec - Device.27= nuovo files - Device.28= riferimenti cancellati Device.31=Sync. [ Device.33=Sincronizzazione fatta in Device.34= sec - Device.35= files creati ( Device.36= MB) Device.41=Sync. [ Device.42=] Copiando [ FIFO.4=). Vuoi provare a montarlo ? FIFO.10=Leggendo: FIFO.13= kbps FIFO.16=Pronto a leggere FIFO.18=Jajuk : Just Another Jukebox | Java Jukebox HistoryItem.0=dd-MM-yy HH:mm DeviceWizard.0=Assistente alla configurazione dei dispositivi DeviceWizard.1=Tipo di dispositivo : DeviceWizard.2=Nome del dispositivo : DeviceWizard.3=Locazione del dispositivo : DeviceWizard.4=Punto di mount per sistemi Unix (opzionale): DeviceWizard.7=Fai un aggiornamento immediato DeviceWizard.8=Monta automaticamente alla partenza DeviceWizard.9=Aggiorna automaticamente alla partenza DeviceWizard.10=Sincronizzato con : DeviceWizard.11=Sincronizzazione unidirezionale DeviceWizard.12=Tutti i nuovi file trovati nel dispositivo sorgente sono copiati in questo dispositivo. Nulla sara' scritto nel dispositivo sorgente. DeviceWizard.13=Sincronizzazione bidirezionale DeviceWizard.14=Tutti i nuovi file trovati su un dispositivo sono copiati sull'altro DeviceWizard.33=OK DeviceWizard.34=Annulla DeviceWizard.43=Prego scegliere una cartella DeviceWizard.44=Dispositivo creato DeviceWizard.45=Dare un nome al dispositivo. Es: CD A, Laptop... DeviceWizard.46=Dare la locazione del dispositivo. Es: d:\mp3 sotto Windows, /home/foo/mp3 sotto Unix DeviceWizard.47=dare ai dispositivo sotto unix un punto di montaggio. Es:/media/cdrom DeviceWizard.48=Seleziona questo se vuoi fare un immediato aggiornamento del dispositivo (avviso)

    Nota questa operazione puo' metterci del tempo su dispositivi molto capienti DeviceWizard.49=Seleziona questo se vuoi montare automaticamente il dispositivo alla partenza di Jajuk

    Specialmente per directory sul disco locale. Evitare per i CD DeviceWizard.50=Seleziona questo se vuoi fare un aggiornamento alla partenza di ogni Jajuk

    (Solo per piccoli dispositivi) DeviceWizard.51=Seleziona questo se vuoi sincronizzare questo dispositivo con un altro DeviceWizard.52=Seleziona un dispositivo sorgente JajukJMenuBar.0=File JajukJMenuBar.1=Apri file JajukJMenuBar.3=Esci JajukJMenuBar.5=Proprieta JajukJMenuBar.6=Nuovo attributo JajukJMenuBar.7=Cancella un attributo JajukJMenuBar.8=Viste JajukJMenuBar.9=Modalità JajukJMenuBar.10=Ripeti JajukJMenuBar.11=Casuale JajukJMenuBar.12=Continuo JajukJMenuBar.13=Introduzione JajukJMenuBar.14=Aiuto JajukJMenuBar.15=Aiuto sui contenuti JajukJMenuBar.16=A proposito PlaylistFileItem.2=Nuova playlist PlaylistFileItem.3=Segnalibri PlaylistFileItem.4=Best-of PlaylistFileItem.5=Coda corrente JajukFileChooser.0=Scegli dei brani da leggere SearchBox.0=Esegui una ricerca sui brani, autori, stili, directory ... CommandJPanel.0=Guarda lo storico CommandJPanel.1=Ripeti : Leggi i brani in un ciclo CommandJPanel.2=Casuale : Leggi in sequenza casuale i brani selezionati CommandJPanel.3=Continuo : Continua aleggere i brani quando la selezione e' terminata CommandJPanel.4=Introduzione : Leggi solo una parte di ogni brano. Il punto di partenza e la durata possono essere settati nella configurazione CommandJPanel.5=Leggi in modalita casuale dall'intera collezione CommandJPanel.6=Leggi i tuoi brani preferiti CommandJPanel.7=Spegni il sonoro CommandJPanel.8=Leggi il brano precedente nella selezione corrente CommandJPanel.9=Leggi il brano successivo nella selezione corrente CommandJPanel.10=Riavvolgi velocemente il brano corrente CommandJPanel.11=Leggi/metti in pausa il brano corrente CommandJPanel.12=Stop CommandJPanel.13=Avanza rapidamente nel brano corrente CommandJPanel.14=Volume CommandJPanel.15=Vai in questa posizione nel brano suonato InformationJPanel.5=Tempo totale rimasto di musica da leggere InformationJPanel.6=Qualita' (bitrate) del brano InformationJPanel.7=Posizione nel brano corrente AbstractPlaylistEditorView.0=Brano AbstractPlaylistEditorView.1=Locazione AbstractPlaylistEditorView.2=Leggi questa playlist AbstractPlaylistEditorView.3=Salva questa playlist AbstractPlaylistEditorView.4=Aggiungi un oggetto a questa playlist AbstractPlaylistEditorView.5=Togli un oggetto da questa playlist AbstractPlaylistEditorView.6=Sposta piu' in alto l'oggetto nella playlist AbstractPlaylistEditorView.7=Sposta piu' in basso l'oggetto nella playlist AbstractPlaylistEditorView.8=Mostra la playlist corrente AbstractPlaylistEditorView.9=cancella questa playlist AbstractPlaylistEditorView.15=Edita la Playlist AbstractPlaylistEditorView.17=Tu stai per aggiornare su disco le seguenti playlist: StatView.0=Altro StatView.1=Divisione per genere StatView.2=Informazione non disponibile StatView.3=Altro StatView.4=Dimensione per dispositivi (Gb) StatView.5=Nessuna informazione disponibile StatView.7=Dimensione della collezione per mesi StatView.8=Mesi StatView.9=Dimensione (Gb) StatView.10=Nessuna informazione disponibile StatView.12=Numero totale di brani per mese StatView.13=Mesi StatView.14=Numero del brano StatView.15=Nessuna informazione disponibile StatView.16=Statistiche StatView.24=vecchi CDScanView.0=Nome del CD : CDScanView.1=Nome del CD. Es: CD1, ROCK... CDScanView.2=Nome del CD. Es: CD1, ROCK... CDScanView.3=Locazione del CD : CDScanView.4=Locazione del CD. Es: '/cdrom' su Unix, 'e:' sotto MS Windows... CDScanView.5=Locazione del CD. Es: '/cdrom' su Unix, 'e:' sotto MS Windows... CDScanView.6=Scansiona CDScanView.12=Leggi il CD CDScanView.18=Leggi il CD ed aggiungi automaticamente tutti i file musicali nella collezione CDScanView.19=Seleziona la locazione del CD TracksTreeView.0=Albero Logico TracksTreeView.1=Leggi TracksTreeView.2=Aggiungi TracksTreeView.3=Leggi casualmente TracksTreeView.4=Leggi ciclicamente TracksTreeView.5=Cancella TracksTreeView.6=Setta un attributo TracksTreeView.7=Attributo TracksTreeView.8=Leggi TracksTreeView.9=Aggiungi TracksTreeView.10=Leggi casualmente TracksTreeView.11=Leggi ciclicamente TracksTreeView.12=Cancella TracksTreeView.13=Setta un attributo TracksTreeView.14=Attributo TracksTreeView.15=Leggi TracksTreeView.16=Aggiungi TracksTreeView.17=Leggi casualmente TracksTreeView.18=Leggi ciclicamente TracksTreeView.19=Cancella TracksTreeView.20=Setta un attributo TracksTreeView.21=Attributo TracksTreeView.22=Leggi TracksTreeView.23=Aggiungi TracksTreeView.24=Cancella TracksTreeView.25=Setta un attributo TracksTreeView.26=Attributo TracksTreeView.27=Collezione TracksTreeView.31= Brani LogicalPlaylistRepositoryView.0=Playlists CoverView.3=Copertina FilesTreeView.0=Albero fisico FilesTreeView.1=Leggi FilesTreeView.2=Aggiungi FilesTreeView.3=Copia FilesTreeView.4=Taglia FilesTreeView.5=Incolla FilesTreeView.6=Renomina FilesTreeView.7=Cancella FilesTreeView.8=Setta un attributo FilesTreeView.9=Attributo FilesTreeView.10=Leggi FilesTreeView.11=Aggiungi FilesTreeView.12=Leggi casualmente FilesTreeView.13=Leggi ciclicamente FilesTreeView.14=Desincronizza FilesTreeView.15=Risincronizza FilesTreeView.16=Crea una playlist FilesTreeView.17=Copia FilesTreeView.18=Taglia FilesTreeView.19=Incolla FilesTreeView.20=Renomina FilesTreeView.21=Cancella FilesTreeView.22=Setta un attributo FilesTreeView.23=Attributo FilesTreeView.24=Leggi FilesTreeView.25=Aggiungi FilesTreeView.26=Leggi casualmente FilesTreeView.27=Leggi ciclicamente FilesTreeView.28=Monta FilesTreeView.29=Smonta FilesTreeView.30=Aggiorna FilesTreeView.31=Sincronizza FilesTreeView.32=Testa FilesTreeView.33=Cre una playlists FilesTreeView.34=Setta un attributo FilesTreeView.35=Attributo FilesTreeView.36=Leggi FilesTreeView.37=Aggiungi FilesTreeView.38=Leggi casualmente FilesTreeView.39=Leggi ciclicamente FilesTreeView.40=Copia FilesTreeView.41=Taglia FilesTreeView.42=Incolla FilesTreeView.43=Rinomina FilesTreeView.44=Cancella FilesTreeView.45=Setta un attributo FilesTreeView.46=Attributo FilesTreeView.47=Collezione FilesTreeView.52= files : FilesTreeView.53= Gb FilesTreeView.54= Mb TracksTableView.0=Tabella Logica TracksTableView.1=Brani TracksTableView.2=Album TracksTableView.3=Autore TracksTableView.4=Durata TracksTableView.5=Genere TracksTableView.6=Rate AbstractTableView.0=Filtro: AbstractTableView.1=Attributo da filtrare AbstractTableView.3=Valore da utilizzare per il filtro AbstractTableView.4=Applica filtro AbstractTableView.5=Annula i filtri AbstractTableView.6=Applica un filtro avanzato AbstractTableView.7=contiene : AboutView.7=A proposito AboutView.8=Licenza AboutView.9=Sistema AboutView.10=A proposito PhysicalPlaylistRepositoryView.0=Leggi PhysicalPlaylistRepositoryView.1=Modifica PhysicalPlaylistRepositoryView.2=Salva come PhysicalPlaylistRepositoryView.3=Cancella PhysicalPlaylistRepositoryView.4=Propieta' PhysicalPlaylistRepositoryView.6=Playlists PhysicalPlaylistRepositoryView.8=Speciali PhysicalPlaylistRepositoryView.9=Coda PhysicalPlaylistRepositoryView.10=Coda corrente : sposta/lascia per leggere i file PhysicalPlaylistRepositoryView.11=Nuovo PhysicalPlaylistRepositoryView.12=Nuova playlist : sposta/lascia per aggiungere i file alla playlist PhysicalPlaylistRepositoryView.13=Segnalibri PhysicalPlaylistRepositoryView.14=Segnalibri playlist : sposta/lascia per aggiungere un segnalibro PhysicalPlaylistRepositoryView.15=Best of PhysicalPlaylistRepositoryView.16=Best of playlist : contiene i migliori brani FilesTableView.0=Tabella Fisica FilesTableView.1=Leggi FilesTableView.2=Aggiungi FilesTableView.3=Leggi casualmente FilesTableView.4=Leggi ciclicamente FilesTableView.5=Setta un attributo FilesTableView.6=Attributi FilesTableView.7=Brani FilesTableView.8=Album FilesTableView.9=Autore FilesTableView.10=Durata FilesTableView.11=Genere FilesTableView.12=Dispositivo FilesTableView.13=File FilesTableView.14=Qualita' DeviceView.0=Aggiungi un dispositivo DeviceView.1=Cancella un dispositivo (non cancella nulla fisicamente dal disco) DeviceView.2=Propieta' del dispositivo selezionato DeviceView.3=Monta il dispositivo selezionato DeviceView.4=Smonta il dispositivo selezionato DeviceView.5=Testa la disponibilita' del dispositivo selezionato DeviceView.6=Aggiorna il dispositivo selezionato DeviceView.7=Sincronizza il dispositivo selezionato DeviceView.8=Monta DeviceView.9=Smonta DeviceView.10=Testa DeviceView.11=Aggiorna DeviceView.12=Sincronizza DeviceView.13=Cancella un dispositivo DeviceView.14=Propieta' DeviceView.17=Nuovo DeviceView.18=Aggiungi un dispositivo DeviceView.21=Il dispositivo e' disponibile DeviceView.22=Il dispositivo non puo' essere acceduto DeviceView.23=Dispositivi JajukWindow.3=Jajuk advanced jukebox JajukWindow.4=Esci JajukWindow.5=A proposito JajukWindow.6=Leggi casualmente JajukWindow.7=Leggi il Best of JajukWindow.8=Mostra Jajuk alla partenza JajukWindow.9=Nascondi Jajuk alla partenza JajukWindow.10=Pausa || JajukWindow.11=Ferma [] JajukWindow.12=Leggi > JajukWindow.13=Precedente <-- JajukWindow.14=Successivo --> HelpView.2=Aiuto ]]> jajuk-1.9.6.orig/src/main/java/org/jajuk/i18n/jajuk_cs.properties0000644000175000017500000016706411720500104024507 0ustar drazzibdrazzib Stránka Systém hodnocení). Vaše předchozí hodnocení bylo převedeno na stupnici od 0 do 100, ale doporučujeme všechna hodnocení vynulovat v okně Předvolby -> záložka Historie (upozornění: všechna současná odnocení budou ztracena) #Write confirmation so replies are: yes / no / cancel Confirmation_exit=Opravdu ukončit Jajuk? Confirmation_delete=Varování! Opravdu chcete odstranit následující soubor(y) z Vašeho disku? Confirmation_void_refresh=Upozornění! Pokoušíte se přistupovat na neplatné zařízení. V Unixu se ujistěte, že je zařízení připojeno, nebo Jajuk ztratí informace o tomto zařízení. Jste si jist? Confirmation_remove_device=Opravdu chcete odstranit toto zařízení ? Confirmation_delete_cover=Opravdu chcete odstranit tento obal z Vašeho disku ? Confirmation_delete_files=Opravdu chcete odstranit tyto soubory z Vašeho disku ? Confirmation_delete_dirs=Opravdu chcete odstranit tyto adresáře z Vašeho disku ? Confirmation_clear_history=Opravdu chcete odstranit historii? Confirmation_reset_ratings=Opravdu chcete nastavit hodnocení všech skladeb na nulu ? Confirmation_refactor_files=Opravdu chcete přejmenovat vybraný soubor(y) ? Confirmation_restore_all=Kompletní obnovení náhledů vyžaduje restart Jajuku. Chcete aplikaci ukončit ? Confirmation_defaults_radios=Budou odstraněny všechny dříve vytvořené stanice rádia. Jste si jist ? Confirmation_delete_empty_dirs=Následující adresář je prázdný. Chcete jej odstranit ? Confirmation_file_overwrite=Tento soubor již existuje. Chcete jej přepsat ? Confirmation_file_number=soubor(y) bude odstraněn. Confirmation_alarm_stop=Opravdu chcete zastavit tento alarm? Confirmation_defaults=Nastavení všech voleb záložek bude změněno na výchozí hodnoty (nikoliv pouze aktuálních). Jste si jist ? Confirmation_rebuild_thumbs=Budou obnoveny všechny miniatury všech Vašich alb, což může u velké kolekce chvíli trvat. Jste si jist ? Confirmation_reset_preferences=Opravdu obnovit předvolby skladeb ? Device_type.directory=Adresář Device_type.file_cd=Hudební soubory CD Device_type.audio_cd=Audio CD Device_type.extdd=Externí harddisk Device_type.player=Digital Audio přehrávač Device_type.network_drive=Síťový disk Device_type.remote=Vzdálené zařízení (neni implementováno) Perspective_Description_Simple=Jednoduché Perspective_Description_Files=Soubory Perspective_Description_Tracks=Skladby Perspective_Description_Configuration=Nastavení Perspective_Description_Statistics=Statistiky Perspective_Description_Help=Nápověda Perspective_Description_Display=Zobrazit Perspective_Description_Albums=Alba Perspective_Description_Info=Informace Perspective_Description_Playlists=Playlisty Item_Playlist_File=playlist Item_Track=Název Item_Album=Album Item_Artist=Umělec Item_Genre=Žánr Item_Device=Zařízení Item_File=Soubor Item_Directory=Adresář Item_Year=rok Item_AlbumArtist=Album-Umělec Property_id=Id Property_name=Název Property_type=Typ Property_url=Url Property_mount_point=Bod připojení Property_auto_refresh=Automaticky obnovit Property_auto_mount=Automaticky připojit Property_album=Album Property_style=Žánr Property_author=Umělec Property_album_artist=Umělec alba Property_disc_number=Disk Property_length=Délka Property_year=Rok Property_rate=Hodnocení Property_files=Soubory Property_hits=Hity Property_filename=Soubor Property_date=Datum Property_added=Datum objevení Property_parent=Nadřazený adresář Property_device=Zařízení Property_directory=Adresář Property_track=Název Property_size=Velikost (MB) Property_quality=Kvalita Property_hashcode=Hashcode Property_playlist_files=playlisty Property_comment=Komentář Property_order=Skladba Property_path=Celá cesta Property_tracks=Skladby Property_file_date=Datum souboru Property_Format_Number=Číslo Property_Format_String=Řetězec Property_Format_Boolean=Boolean Property_Format_Float=Float Property_Format_Date=Datum Property_Format_URL=Url Property_pf=Předvolby Property_tpt=Celkový hrací čas (sek.) Property_ban=Zakázané Property_disc_id=ID disku Language_desc_en=Angličtina Language_desc_fr=Francoužština Language_desc_de=Němčina Language_desc_it=Italština Language_desc_sv=Švédština Language_desc_nl=Holandština Language_desc_zh=Čínština Language_desc_es=Španělština Language_desc_ca=Katalánština Language_desc_ko=Korejšina Language_desc_el=Řečtina Language_desc_ru=Ruština Language_desc_gl=Galicijština Language_desc_cs=Čeština #--- Error codes --- Error.000=Neznámá chyba Error.005=Syntaktická chyba souboru kolekce Error.007=Chyba přehrávání souboru. Možná MPlayer nespustil přehrávání v časovém limitu: Error.008=Chyba zastavení souboru Error.009=Soubor nelze přečíst Error.010=Nemohu nalézt soubor přidružený k položce na připojeném zařízení Error.011=Technická chyba při připojování zřízení, nebo neplatné zařízení Error.012=Technická chyba při podpojování zřízení, možná je používáno jinou aplikací Error.013=Zařízení nelze odstranit: buď je připojeno, nebo je právě obnovováno Error.016=Ke zvolenému zařízení nelze přistupovat. Zvolte prosím přípojný bod. Např: '/cdrom' v Unixu,'e:' v MS Windows Error.017=Chyba analýzy playlistu Error.018=Nelze nalézt dostupné skladby Error.019=Existující zařízení tento název již má Error.020=IO chyba kopírování souboru. Možná je plný disk Error.021=URL pole je povinné. Např: 'd:\music' v MS Windows, '/home/foo/music' v Unixu Error.022=Pole Název je povinné. Např: 'Hard drive', 'CD ROCK' Error.023=Nelze přehrát skladbu po spuštění Error.024=Nelze zapisovat do souboru Error.025=Jeden ze souborů, který chcete načíst je na odpojeném zařízení Error.026=Chyba registrace přehrávačů Error.027=Synchronizace přerušena Error.028=Chyba uložení playlistu Error.029=Existující zařízení je nadřazený adresář tohoto zařízení, má stejnou cestu, nebo je podřízený adresář Error.030=Příliš mnoho spojení selhalo. Jajuk přerušil online hledání obalů Error.101=Zařízení neexistuje, nebo je nedostupné Error.102=Chyba Error.103=Chyba načítání informací tagu Error.104=Chyba zápisu informací tagu Error.105=Klíč Resource Bundle nenalezen Error.106=Neznámá vyjímka Error.107=Zařízení se již obnovuje, nebo synchronizuje Error.108=Chyba analýzy prohlíženého souboru Error.109=Přehrávač, nebo implementační třída tagu je nedostupná Error.110=Tento název vlastnosti je vyhrazen interním systémem Jajuku. Zvolte prosím jiný Error.111=Zařízení je již připojeno Error.112=Zařízení nelze připojit Error.113=Nemohu uložit uživatelské nastavení Error.114=Nemohu načíst uživatelské nastavení Error.118=Chyba zpracování požadavku události Error.119=Soubor historie neexistuje, nebo chyba syntaxe Error.120=K zařízení nelze přistupovat: buď není připojeno, právě se obnovuje nebo synchronizuje Error.121=Zařízení je používáno a nelze jej odpojit Error.122=Chyba FIFO Error.123=Chyba nastavení tématu Error.124=Jajuk je již spuštěn. Současně může být spuštěna pouze jedna instance programu Error.125=Zařízení je již odpojeno Error.126=Hledání s tímto audio formátem není podporováno Error.127=Pro zadaný časový úsek nebyly nalezeny žádné novinky. Časový limit můžete nastavit v okně Předvolby Error.128=Aktuální skladba je vůbec první v kolekci. Předchozí skladba není dostupná Error.129=Chyba načítání obrázku obalu Error.131=Soubor nelze odstranit Error.133=Soubor s Vaší kolekcí byl poškozen z neznámého důvodu. Jajuk zajistil obnovení ze záložního souboru Error.134=Soubor nelze přejmenovat Error.135=Soubor neexistuje Error.136=Úloha selhala Error.137=Neplatný formát Error.138=Některé soubory mapované těmito skladbami jsou umístěné na odpojeném zařízení a proto nebyly změněny. Error.140=Neplatný řetězec: nesmí obsahovat znaky & ' " < nebo > Error.141=Tento playlist je umístěn na odpojeném nebo obnovujícím se zařízení a proto je nedostupný Error.142=Tento playlist odkazuje na neexistující skladby, nebo na skladby umístěné na Jajuku neznámé zařízení. Tyto skladby budou ignorovány. Error.143=Nedosažitelné umístění zařízení Error.144=Syntaktická chyba DJ Error.145=DJ nelze uložit Error.146=Aktuální šablona organizátoru je neplatná.
    Platné položky jsou: %artist (jméno autora); %title (název skladby); %album (název alba);
    %n (skladba začínající od nuly); %genre (žánr skladby); %year (rok)
    a šablona musí obsahovat nejméně jedno lomítko Error.147=Některé soubory nelze přesunout (pro více informací si přečtěte detaily) Error.148=Pole Rok je neznámé Error.149=Pole Album je neznámé Error.150=Pole Umělec je neznámé Error.151=Název skladby je neznámý Error.152=Pole Skladba je neznámé Error.153=Pole Žánr je neznámé Error.154=Soubor nelze přejmenovat. Zkontrolujte zakázané znaky v názvu souboru nebo tagu. Error.155=Chyba při úpravě tagů, zkontrolujte oprávnění. Error.156=Přázdná kolekce Error.157=Neplatný DJ. Vyberte, nebo jej vytvořte tlačítkem DJ (ikona gramofonu) v příkazové části Jajuku Error.158=Omezení DJ nelze respektovat, nebo není skladba dostupná Error.159=Přidružené hudební styly byly odstraněny Error.160=Soubor nebyl přesunut. Název zdrojového a cílového souboru jsou shodné. Error.161=Do adresáře nelze zapisovat, zkontrolujte oprávnění. Error.162=Tato uživatelská vlastnost již existuje Error.163=Chyba obnovení výchozího vzhledu Error.164=Pro tento hudební styl nelze nalézt dostupné skladby : Error.165=Neplatná cesta kolekce. Adresář nelze nalézt, nebo do něj nelze zapisovat Error.166=Prázdné album, obal nelze získat Error.167=Zprávu nelze vytvořit Error.168=Nenalezeny žádné duplicitní soubory Error.169=Úloha selhala. Pozor, tato úloha potřebuje pro získání seznamu stanic rádia připojení k internetu. Error.170=Chyba přehrávání webového rádia Error.171=Pro toto zařízení není momentálně nastaven zdroj synchronizace. Nastavte jej pomocí průvodce nastavením zařízení (v okně Zařízení klikněte na Nové zařízení). Error.172=Při odstraňování následujících souborů se vyskytla chyba: Error.173=Při odstraňování následujících adresářů se vyskytla chyba: Error.174=Chyba přístupu na webovou stránku Freedb. Ověřte Vaše síťové připojení Error.175=Úloha zrušena Error.176=Chyba při vytváření playlistu Error.177=Zadejte prosím platný čas ve formátu (HH24:MM:SS) Error.179=Systémový správce souborů nelze otevřít, zkuste nastavit cestu v okně Předvolby na záložce Pokročilé Error.180=Chyba při kopírování souborů #Warnings Warning.0=MPlayer nenalezen. Některé audio a video formáty (flac, wma, aac, mpg2 ... ) byly zakázány. Pokud je již MPlayer nainstalován, nastavte prosím ručně cestu v okně Předvolby na záložce Pokročilé. Warning.1=Chybné vydání MPlayer, je požadována verze MPlayer1.0Pre8 a vyšší. Některé audio formáty byly zakázány. Warning.2=Vypadá, že jiný uživatel právě používá aktuální kolekci jajuku. Poslední uživatel při ukončení přepíše nastavení (Možnosti, Hodnocení...). Warning.3=Mplayer nelze stáhnout. Pokud používáte HTTP proxy, nastavte jej prosím v okně Předvolby na záložce Síť a restartujte Jajuk. Warning.4=Pro poslech webových rádií je požadován Mplayer Warning.5=Cílový adresář již existuje. Některé soubory mohou být přepsány. Jste si jist? Warning.6=Pro přehrávání nejsou dostupné žádné stopy (Tip: pokuste se připojit nějaké zařízení, nebo změnit hudební styl) Warning.7=Jajuk zjistil, že je potřeba obnovit zařízení kvůli aktualizaci. Chcete jej provést nyní? (obnovení lze provést kdykoliv v okně Zařízení) #--- Strings by class --- ParameterView.0=Délka historie: ParameterView.2=Nastavení počtu dnů zachování historie přehrávaných skladeb. Zadejte -1 pokud nechcete historii žádnou, nebo 0 pokud má být historie stálá. ParameterView.3=Smazat historii ParameterView.4=Smazat historii ParameterView.8=Historie / Hodnocení ParameterView.9=Přehrát: ParameterView.10=Nic ParameterView.11=Po spuštění Jajuku nic nepřehrávat ParameterView.12=Poslední skladbu od začátku ParameterView.13=Přehraje naposledy přehrávanou skladbu od začátku ParameterView.14=Náhodnou skladbu ParameterView.15=Přehraje náhodnou skladbu z celé kolekce ParameterView.16=Skladbu : ParameterView.17=Vyberte skladbu, která bude po spuštění přehrána ParameterView.18=Vyberte skladbu, která bude po spuštění přehrána. Začněte psát a uvidíte filtrovaný seznam. ParameterView.19=Po spuštění ParameterView.26=Potvrzení ParameterView.27=Před fyzickým smazáním souboru ParameterView.28=Dotázat se před fyzickým smazáním souboru ParameterView.29=Před ukončením Jajuku ParameterView.30=Dotázat se před ukončením Jajuku ParameterView.33=Možnosti ParameterView.35=Nezobrazí skladby na odpojených zařízeních ParameterView.36=Obnovit po dosažení konce kolekce ParameterView.37=Po dosažení konce obnoví celou kolekci v módu Opakovat ParameterView.38=Jazyk: ParameterView.42=Vyberte jazykové rozhraní ParameterView.43=Téma: ParameterView.44=Zvolte téma

    (Může vyžadovat restart Jajuku) ParameterView.46=Úroveň zprávy: ParameterView.47=Závažná ParameterView.48=Chyba ParameterView.49=Upozornění ParameterView.50=Informace ParameterView.51=Ladění ParameterView.52=Oznámení Jajuku : Závažná: zobrazí pouze kritické chyby, Chyba: +zobrazí chyby, Informace: +zobrazí informační zprávy, Upozornění: +zobrazí upozornění, Ladění: všechna hlášení ParameterView.59=Pozice začátku úryvku (%): ParameterView.60=Pozice začátku ve skladbě v % od 0 (začátek skladby) do 99 (konec skladby) ParameterView.61=Délka úryvku (sekund): ParameterView.62=Délka úryvku (v sekundách) ParameterView.85=Použít ParameterView.86=Obnovit výchozí ParameterView.87=Předvolby ParameterView.98=Předlohy ParameterView.99=Provést důkladné skenování tagů ParameterView.100=Přinutí Jajuk znovu načíst aktuální id3 tagy.

    To může být užitečné k aktualizaci tagů upravených jiným programem.

    ParameterView.101=Použít název nadřazeného adresáře jako název alba ParameterView.102=Pokud je volba vybrána, název nadřazeného adresáře bude použit jako název alba pro skladby, které nepoužívají ID3 tag. ParameterView.109=Předvolby uloženy ParameterView.110=Nastavit Předvolby na výchozí hodnoty ParameterView.111=Velikost playlistu Nejlepší: ParameterView.112=Nastaví počet skladeb v playlistu Nejlepší (od 1 do 100) ParameterView.113=Použít regulární výrazy ve filtrech ParameterView.114=Používání regulárních výrazů (formát Regexp) v tabulce filtrů. Příklad: .*foo.* ParameterView.115=Pokročilé ParameterView.116=Zálohovat soubor kolekce ParameterView.117=Vyberte, pokud si přejete zálohovat Vaší kolekci do souboru Kolekce-.xml ParameterView.118=Velikost zálohy (MB) ParameterView.119=Velikost zálohy (MB) ParameterView.120=Znaková sada kolekce ParameterView.121=Znaková sada kolekce. UTF-16 je optimalizovaná pro Asijské jazyky a UTF-8 pro Evropské jazyky. ParameterView.129=Časový limit pro novinky (dnů): ParameterView.130=Časový limit pro novinky v počtu dnů: všechny skladby přidané během počtu dnů udaných tímto číslem jsou zobrazeny v playlistu novinek ParameterView.131=Nejlepší skladbu ParameterView.132=Po spuštění přehraje jednu z Vašich oblíbených skladeb ParameterView.133=Nejnovější skladbu ParameterView.134=Po spuštění přehraje nejnovější skladbu z Vaší kolekce ParameterView.135=Poslední skladbu od poslední pozice ParameterView.136=Přehraje posledně přehrávanou skladbu od pozice, kde byla zastavena ParameterView.139=Síť ParameterView.142=Uživatelské jméno proxy ParameterView.143=Přihlašovací jméno proxy použité pro autentizaci ParameterView.144=Jméno proxy host ParameterView.145=Jméno proxy host nebo IP adresa ParameterView.146=Proxy port ParameterView.147=Proxy TCP-IP port (většinou 3128) ParameterView.148=Získat obaly online ParameterView.149=Použijte pro automatické stahování obalů alb z internetu (pokud je vyžadováno, nastavte Vaše proxy na záložce Síť) ParameterView.150=Velikost obalů ParameterView.151=Velikost stažených obalů ParameterView.155=Přesnost hledání. Vyšší přesnost může způsobit získání chybného obalu. ParameterView.156=Malá přesnost (hledá všechna slova) ParameterView.157=Střední (hledá slovní spojení) ParameterView.158=Vysoká (hledá přesné slovní spojení) ParameterView.159=Obaly ParameterView.160=Časový limit spojení (sekund) ParameterView.161=Časový limit spojení v sekundách: Vzdálená úloha selhala, pokud druhá strana v této době neodpoví. ParameterView.162=Časový limit přenosu (sekund) ParameterView.163=Časový limit přenosu (sekund): Vzdálená úloha selhala, pokud nejsou požadovaná data v této době kompletně stažena. ParameterView.164=Před odstraněním zařízení ParameterView.165=Dotáže se před odstraněním zařízení ParameterView.166=Náhodné obaly ParameterView.167=Zobrazí náhodný obal ParameterView.169=Načíst obaly ParameterView.170=Pokud možno, načte s předstihem všechny dostupné obaly ParameterView.171=Před odstraněním obalu z disku ParameterView.172=Dotáže se před odstraněním obalu z disku ParameterView.177=Počet viditelných plánovaných skladeb ParameterView.178=Počet viditelných plánovaných skladeb zobrazených v playlistu ParameterView.179=Vložit do výběru ParameterView.180=Pokud je volba vybrána, dvojklikem na skladbu nebo výběrem položky bude zařazena do fronty ParameterView.181=Vybrat přetažením ParameterView.182=Pokud je volba vybrána, skladby kolekce mohou být přetaženy do playlistu ParameterView.186=Vynulovat hodnocení ParameterView.187=Nastaví hodnocení všech skladeb na nulu ParameterView.188=Před smazáním historie ParameterView.189=Před vynulování hodnocení ParameterView.190=Délka prolínání (sekund) ParameterView.191=Počet sekund prolínání mezi skladbami ParameterView.192=Organizátor souborů : ParameterView.193=Dostupné předlohy : %artist (Jméno autora); %title (Název skladby); %album (Název alba); %n (Skladba); %genre (Zánr skladby); %year (Rok) ParameterView.194=Před uspořádáním souborů ParameterView.195=Náhled animace : ParameterView.196=Používat klávesové zkratky ParameterView.197=Umožní použití některých kláves, jako např. F8, ikdyž není okno Jajuku aktivní ParameterView.198=Některé změny se projeví až po příštím spuštění programu Jajuk ParameterView.199=Informovat o tom co poslouchám ParameterView.200=Tato volba odesílá informace do Last.FM ParameterView.201=Uživatelské jméno Last.FM ParameterView.202=Uživatelské jméno používané pro Last.FM ParameterView.203=Heslo Last.FM ParameterView.204=Heslo používané pro Last.FM ParameterView.205=Argumenty Mplayer ParameterView.206=Dodatečné argumenty MPlayeru jako např. '-ao esd', '-ao arts' nebo '-novideo (pro zamezení přehrávání videa)' ParameterView.207=Cesta nastavení Jajuku ParameterView.208=Zadejte adresář obsahující nastavení programu Jajuk (obvykle je to home adresář uživatele) ParameterView.209=Cesta ke konfiguraci Jajuku byla pro aktuálního uživatele změněna (předchozí kolekce byla zachována ve starém umístění). Jajuk bude nyní ukončen a může být znovu spuštěn. ParameterView.210=Pokud prolínání nefunguje, zkuste přidat <-ao esd> pod Gnome nebo <-ao arts> pod KDE v dodatkovém poli pro zvukové zařízení Argumenty MPlayer (v okně Předvolby na záložce Pokročilé). ParameterView.211=pouze malé ParameterView.212=malé a střední ParameterView.213=pouze střední ParameterView.214=střední a velké ParameterView.215=pouze velké ParameterView.216=Pro hledání použije jméno umělce ParameterView.217=Pro hledání použije název alba ParameterView.218=Pro hledání použije název skladby ParameterView.219=Proměnné prostředí ParameterView.220=Nastaví proměnné prostředí použité audio přehrávačem (ARTS_SERVER pod KDE nebo ESPEAKER pod Gnome). Formát: var1=xx var2=yyy... #Respect English size for next item ParameterView.221=Velikost stránky katalogu (0: vše na jedné) ParameterView.222=Nastavení počtu alb na stránku v Katalogu alb. 0: zobrazí všechny obaly na jedné stránce. ParameterView.223=Velikost písma ParameterView.224=Nastaví velikost písma textů ParameterView.225=GUI ParameterView.226=Módy ParameterView.228=Zobrazovat vysunovací informace o albu ParameterView.229=Předvolby Katalogu ParameterView.233=Téma bude změněno při příštím spuštění Jajuku ParameterView.234=Vyhledat aktualizace Jajuku ParameterView.235=Last.FM ParameterView.236=Žádné Proxy ParameterView.237=HTTP proxy ParameterView.238=SOCKS proxy ParameterView.239=Heslo proxy ParameterView.240=Povolit informační dotazy Last.FM ParameterView.241=Pokud je volby vybrána, Jajuk bude získávat různé informace o albech z webové stránky Last.FM ParameterView.242=Cesta k Mplayeru ParameterView.243=Zde zadejte celou cestu ke spustitelnému souboru mplayer (může zůstat prázdné)
    Příklad: /Applications/MPlayer OSX.app/Contents/Resources/External_Binaries/mplayer_intel.app/Contents/MacOS/mplayer ParameterView.244=Datum objevení = datum souboru ParameterView.245=Pokud je volba vybrána, považuje Jajuk systémové datum audio-souboru za Datum objevení
    Aby se změny projevily, vyžaduje kompletní obnovení ParameterView.246=Velikost ikon panelu pohledů (pixely) ParameterView.247=Cílová cesta obsahuje existující pracovní oblast Jajuku. Pracovní oblast pro aktuálního uživatele byla přepnuta na na tuto cestu (předchozí pracovní oblast byla zachována ve starém umístění). Jajuk bude nyní ukončen a je možno ho znovu spustit. ParameterView.248=Základní název : ParameterView.249=Obnovit předvolby ParameterView.250=Obnoví uživatelsky definované předvolby ParameterView.251=Historie úspěšně obnovena ParameterView.252=Hodnocení a čas přehrávání úspěšně obnoveny ParameterView.253=Předvolby úspěšně obnoveny ParameterView.254=Použít zkratky Windows ParameterView.255=[Pouze Windows 32 bit] Pokud je volby vybrána, vynutí mplayer použití názvů souborů ve zkrácené cestě Windows k pevnému určení některého umístění ParameterView.256=Výchozí názvy souborů obalů ParameterView.257=Jajuk vyhledá soubor s obrázkem obalu jejihož název obsahuje tento text jako výchozí obal (;;...) ParameterView.260=Uložit obaly vhodně pro průzkumník Windows ParameterView.261=Uloží stažené obaly jako složka.jpg/png/... tak, že je průzkumník Windows použije jako ikonu složky. ParameterView.262=Normalizovat audio ParameterView.263=Maximalizovat hlasitost bez zkreslení zvuku ParameterView.264=Zakázat Jajuku přístup k internetu ParameterView.265=Zakáže Jajuku přístup k internetu, například k příslušenství. ParameterView.266=Vyřadit přehrávanou skladbu z fronty ParameterView.267=Všechny skladby ve frontě před právě přehrávanou skladbou budou vyřazeny. ParameterView.268=Nastavení proxy ParameterView.269=Cesta ke správci souborů ParameterView.270=Cesta k aplikaci používané jako správce souborů ParameterView.271=Zobrazit systémovou lištu ParameterView.272=Pokud je volba vybrána, Jajuk může být ovládán z oznamovací oblasti (nepodporují všechny operační systémy) ParameterView.273=Zrcadlit obal ParameterView.274=Pokud je volba vybrána, bude obal skloněn a zrcadlen ParameterView.275=Oznámit změnu stopy : ParameterView.276=Zvolte typ oznámení při změně stopy (toast je vyskakovací okno, které se krátce objeví na obrazovce a samo se uzavře) ParameterView.277=Šablona bubliny : ParameterView.278=Tato šablona nastavuje text zobrazený ve vyskakovacím bublině při změně stopy ParameterView.279=Šablona informací : ParameterView.280=Tato šablona nastavuje text zobrazený v informačním okně (ve spodní části obrazovky) ParameterView.281=Minimalizovat na systémový panel ParameterView.282=Pokud je volba vybrána, bude minimalizované hlavní okno Jajuku zobrazeno v systémové části panelu, nikoliv na panelu úloh Main.21=Potvzení Main.22=Stahuji MPlayer Player.0=Čekám na linku audio (je obsazená) Device.25=] obnoveno za Device.27= nové soubory Device.31=Sync. [ Device.33=Synchronizace bude dokončena za Device.35= vytvořené soubory ( Device.36= MB) Device.41=Sync. [ Device.42=] Kopíruji [ Device.43= nečitelné tagy Device.44=Přistupování Device.45=Kopíruji [ FIFO.4=). Přejete si ho zkusit připojit ? FIFO.10=Právě přehrávám: FIFO.13= Kbps FIFO.14=Právě přehrávám Web Radio: HistoryItem.0=yy/MM/dd HH:mm DeviceWizard.0=Nastavení zařízení DeviceWizard.1=Typ zařízení*: DeviceWizard.2=Název zařízení*: DeviceWizard.3=Umístění zařízení*: DeviceWizard.7=Provést okamžité obnovení DeviceWizard.8=Automaticky připojit při spuštění DeviceWizard.10=Synchronizovat s: DeviceWizard.11=Jednosměrná synchronizace DeviceWizard.12=Všechny nové soubory na zdrojovém zařízení bodou zkopírovány na toto zařízení. Na zdrojové zařízení nebude nic kopírováno. DeviceWizard.13=Obousměrná synchronizace DeviceWizard.14=Všechny nové soubory na jednom zařízení budou zkopírovány na jiné DeviceWizard.43=Vyberte prosím adresář DeviceWizard.44=Zařízení vytvořeno DeviceWizard.45=Zadejte prosím název zařízení. Např.: CD A, Laptop... DeviceWizard.46=Zadejte prosím umístění zařízení. Např.: d:\hudba ve Windows, /home/foo/hudba v Unixu DeviceWizard.48=Zaškrtněte položku, pokud si přejete okamžité obnovení zařízení (doporučeno).

    Uvědomte si, že úlocha může chvíli trvat v závislosti na velikosti zařízení.

    DeviceWizard.49=Zaškrtněte položku, pokud si přejete, aby Jajuk po spuštění automaticky připojil zařízení.

    Doporučeno pro adresáře ne aktuálním harddisku, nikoliv pro CD.

    DeviceWizard.50=Zadejte interval v minutách pro automatické vyhledávání nových souborů (0: nevyhledávat, 0.5 min je minimální interval) DeviceWizard.51=zvolte, pokud chcete synchronizovat toto zařízení s jiným DeviceWizard.52=Vybrat zdroj zařízení DeviceWizard.53=Obnovit zařízení po #limited string size DeviceWizard.54=min DeviceWizard.55=Neplatná hodnota : interval obnovení může být 0 nebo číslo >= 0.5. JajukJMenuBar.0=Soubor JajukJMenuBar.1=Otevřít soubor JajukJMenuBar.3=Konec JajukJMenuBar.5=Vlastnosti JajukJMenuBar.6=Vytvořit uživatelskou vlastnost JajukJMenuBar.7=Odstranit uživatelskou vlastnost JajukJMenuBar.8=Náhledy JajukJMenuBar.9=Módy JajukJMenuBar.10=Opakovat JajukJMenuBar.11=Náhodně JajukJMenuBar.12=Pokračovat JajukJMenuBar.13=Úryvky JajukJMenuBar.14=Nápověda JajukJMenuBar.15=Obsah nápovědy JajukJMenuBar.16=O programu JajukJMenuBar.17=Obnovit náhledy (aktuální pohled) JajukJMenuBar.18=Průvodce zařízením JajukJMenuBar.19=Nahlásit chybu nebo požadavky na funkce JajukJMenuBar.20=Tip dne JajukJMenuBar.21=Nastavení JajukJMenuBar.22=Předvolby JajukJMenuBar.23=Zobrazit ladicí informace JajukJMenuBar.24=Zobrazit pouze dostupné skladby JajukJMenuBar.25=Zobrazit náhled JajukJMenuBar.26=Obnovit náhledy (všechny pohledy) JajukJMenuBar.27=Vyhledat aktualizace Jajuku JajukJMenuBar.28=Nástroje JajukJMenuBar.29=Přehrávání JajukJMenuBar.30=Opakovat vše JajukJMenuBar.31=Karaoke JajukJMenuBar.32=Volání Full GC (pouze testovací režim) PlaylistFileItem.1=Novinky PlaylistFileItem.2=Nový playlist PlaylistFileItem.3=Záložky PlaylistFileItem.4=Nejlepší PlaylistFileItem.5=Fronta JajukFileChooser.0=Výběr souborů SearchBox.0=Vyhledává podle skladeb, umělců, žánrů,adresáře... CommandJPanel.0=Zobrazit historii přehrávání CommandJPanel.1=[Ctrl-t] Opakovat: Přehrává skladby ve smyčce CommandJPanel.2=[Ctrl-h] Náhodně: Přehrává náhodně vybrané skladby CommandJPanel.3=Pokračovat: Přehrává plánované skladby až do konce CommandJPanel.4=Úryvky: Přehraje pouze část z každé skladby. Čas a začátek lze nastavit v náhledu Nastavení CommandJPanel.5=Přehraje náhodný výběr z celé kolekce CommandJPanel.6=Přehraje Vaše oblíbené skladby CommandJPanel.8=[F9] Předchozí: přehraje předchozí skladbu ve výběru
    Shift + kliknutí spustí předchozí album
    Ctrl + kliknutí znovu přehraje aktuální album CommandJPanel.9=[F10] Další: přehraje další skladbu ve výběru
    Shift + kliknutí spustí další album CommandJPanel.10=[Alt-gr F9] Zpět: rychle zpět v aktuální skladbě
    Shift + kliknutí pro opakování CommandJPanel.13=[Alt-gr F0] Vpřed: rychle dopředu v aktuální skladbě CommandJPanel.15=Zde klikněte pro změnu formátu zobrazení času CommandJPanel.16=Spustit výběr DJ CommandJPanel.17=Spravovat DJs CommandJPanel.18=Spustí výchozí výběr DJ CommandJPanel.19=Spravovat hudební styly CommandJPanel.20=Skladbu za skladbou CommandJPanel.21=Náhodně album za albem CommandJPanel.22=Album za albem CommandJPanel.23=Klikněte pro smazání vyhledávání CommandJPanel.24=Nastavit webová rádia CommandJPanel.25=Zapnout rádio CommandJPanel.26=Režim Opakovat vše: Přehrává frontu ve smyčce CommandJPanel.27=Režim Karaoke, utlumí hlasy z přehrávané skladby (použít lze pouze na skladbu následují po přehrávané) InformationJPanel.5=Celkový zbývající čas fronty [počet zbývajících skladeb] InformationJPanel.6=Bitový tok skladby InformationJPanel.7=Průběh aktuální skladby # %xxx are patterns, don't translate them ! InformationJPanel.8=%title z %artist v %album # Keep next label short InformationJPanel.9=<Žádný výběr> AbstractPlaylistEditorView.0=Název AbstractPlaylistEditorView.1=Umístění AbstractPlaylistEditorView.2=Spustit tento playlist AbstractPlaylistEditorView.3=Uložit tento playlist AbstractPlaylistEditorView.4=Přidat položku do playlistu AbstractPlaylistEditorView.5=Odstranit položku z playlistu AbstractPlaylistEditorView.6=Nahoru AbstractPlaylistEditorView.7=Dolů AbstractPlaylistEditorView.9=Smazat tento playlist AbstractPlaylistEditorView.10=Přidat náhodnou skladbu do playlistu AbstractPlaylistEditorView.15=Playlisty AbstractPlaylistEditorView.17=Chystáte se aktualizovat následující playlisty: AbstractPlaylistEditorView.18=Skladba ve frontě AbstractPlaylistEditorView.19=Opakovaná skladba AbstractPlaylistEditorView.20=Plánovaná skladba AbstractPlaylistEditorView.21=Název Playlistu AbstractPlaylistEditorView.22=Playlist uložen AbstractPlaylistEditorView.27=Připravit párty AbstractPlaylistEditorView.28=adresář vytvořen v StatView.0=Ostatní StatView.1=Žánry StatView.2=Data nejsou dostupná StatView.3=Ostatní StatView.4=Velikost podle zařízení (GB) StatView.5=Data nejsou dostupná StatView.7=Velikost kolekce podle měsíce StatView.8=Měsíce StatView.9=Velikost (GB) StatView.10=Data nejsou dostupná StatView.12=Celkový počet skladeb podle měsíce StatView.13=Měsíce StatView.14=Číslo skladby StatView.15=Data nejsou dostupná StatView.16=Statistiky StatView.24=Starší CDScanView.0=Název CD: CDScanView.1=Název CD. Např: CD1, ROCK... CDScanView.2=Název CD. Např: CD1, ROCK... CDScanView.3=Umístění CD: CDScanView.4=Umístění, kde je možno CD nalézt. Např: '/cdrom' v Unixu, 'e:' v MS Windows... CDScanView.5=Umístění, kde je možno CD nalézt. Např: '/cdrom' v Unixu, 'e:' v MS Windows... CDScanView.6=Prohledat CDScanView.12=Prohledávač CD CDScanView.18=Prohledá CD a přidá všechny hudební soubory do kolekce CDScanView.19=Vybrat umístění CD AbstractTreeView.0=Rozbalit vše TracksTreeView.0=Strom skladeb TracksTreeView.27=Kolekce TracksTreeView.31= skladby TracksTreeView.33=Vytvořit zprávu TracksTreeView.34=Získat tagy online TracksTreeView.35=Datum objevení TracksTreeView.36=méně než týden TracksTreeView.37=méně než měsíc TracksTreeView.38=méně než 6 měsíců TracksTreeView.39=starší TracksTreeView.40=méně než rok TracksTreeView.41=méně než 2 roky TracksTreeView.42=méně než 5 let TracksTreeView.43=méně než 10 let TracksTreeView.44=méně než 3 měsíce TracksTreeView.45=Rok CoverView.2=Odstranit obal z disku CoverView.3=Obal CoverView.4=Předchozí obrázek z disku a/nebo webu, pokud je vybrána volba Automatický obal CoverView.5=Další obrázek z disku a/nebo webu, pokud je vybrána volba Automatický obal CoverView.6=

    Uložit obal s původním názvem

    S CTRL: Uložit obal jako...

    CoverView.8=Použít tento obal jako výchozí pro toto album CoverView.9=obaly CoverView.10=Uložit obal jako CoverView.11=Obal uložen CoverView.12=Album CoverView.13=Název AnimationView.0=Animace FilesTreeView.0=Strom souborů FilesTreeView.3=Kopírovat FilesTreeView.4=Vyjmout FilesTreeView.5=Vložit FilesTreeView.7=Odstranit FilesTreeView.14=Desynchronizovat FilesTreeView.15=Znovu synchronizovat FilesTreeView.16=Vytvořit playlist FilesTreeView.17=Kopírovat FilesTreeView.18=Vyjmout FilesTreeView.28=Připojit FilesTreeView.29=Odpojit FilesTreeView.30=Vynutit obnovení FilesTreeView.31=Synchronizovat FilesTreeView.32=Testovat FilesTreeView.33=Vytvořit playlisty FilesTreeView.40=Kopírovat FilesTreeView.41=Vyjmout FilesTreeView.42=Vložit FilesTreeView.47=Kolekce FilesTreeView.52= soubor(ů): FilesTreeView.53= GB FilesTreeView.54= MB FilesTreeView.55=Nastavit zařízení FilesTreeView.59=Přejete si spustit rychlé nebo důkladné (opětovné načtení tagů) obnovení? FilesTreeView.60=Rychlé FilesTreeView.61=Důkladné FilesTreeView.62=Uspořádat soubory TracksTableView.0=Seznam skladeb TracksTableView.7=Přehrát TracksTableView.8=Vložit nakonec TracksTableView.9=Přehrát náhodně TracksTableView.10=Přehrát opakovaně TracksTableView.11=Přehrát album TracksTableView.12=Přehrát umělce TracksTableView.14=Vlastnosti TracksTableView.15=Záložka TracksTableView.16=Přehrát další AbstractTableView.0=Filtr: AbstractTableView.1=Vlastnosti filtrování AbstractTableView.3=Hodnota použitá filtrem AbstractTableView.4=Použít filtr AbstractTableView.5=Odstranit filtr AbstractTableView.6=Použít pokročilý filtr AbstractTableView.7=Obsahuje: AbstractTableView.8=Žádný AbstractTableView.10=(Nedostupné) AbstractTableView.11=Seznam s možností úprav AboutView.7=O programu AboutView.8=Licence AboutView.9=Systém AboutView.10=O programu AboutView.11=Copyright 2003-2011
    Jajuk team" PhysicalPlaylistRepositoryView.0=Přehrát PhysicalPlaylistRepositoryView.1=Upravit PhysicalPlaylistRepositoryView.2=Uložit jako PhysicalPlaylistRepositoryView.3=Odstranit PhysicalPlaylistRepositoryView.4=Vlastnosti PhysicalPlaylistRepositoryView.6=Fyzické playlisty PhysicalPlaylistRepositoryView.8=Přehrávání PhysicalPlaylistRepositoryView.9=Přehrávání fronty PhysicalPlaylistRepositoryView.10=Aktuální fronta: přetáhněte skladby k přehrávání PhysicalPlaylistRepositoryView.11=Nový PhysicalPlaylistRepositoryView.12=Nový playlist: přetáhněte skladby pro přidání do playlistu PhysicalPlaylistRepositoryView.13=Záložky PhysicalPlaylistRepositoryView.14=Playlist záložek: přetáhněte skladby do záložky PhysicalPlaylistRepositoryView.15=Nejlepší od PhysicalPlaylistRepositoryView.16=Nejlepší z playlistu: obsahuje nejposlouchanější skladby PhysicalPlaylistRepositoryView.17=Novinky PhysicalPlaylistRepositoryView.18=Playlist novinek: obsahuje nejnovější skladby PhysicalPlaylistRepositoryView.19=Připravit párty FilesTableView.0=Tabulka souborů FilesTableView.15=Přehrát adresář #Dev: do not use ID = 16, next label is FilesTableView.17 DeviceView.0=Přidat zařízení DeviceView.1=Odstranit nepřipojené zařízení (z disku nic nemazat) DeviceView.2=Vlastnosti vybraného zařízení DeviceView.3=Připojit vybrané zařízení DeviceView.4=Odpojit vybrané zařízení DeviceView.5=Testovat dostupnost vybraného zařízení DeviceView.6=Vynutit obnovení vybraného zařízení DeviceView.7=Synchronizovat vybrané zařízení DeviceView.8=Připojit DeviceView.9=Odpojit DeviceView.10=Testovat DeviceView.11=Vynutit obnovení DeviceView.12=Synchronizovat DeviceView.13=Odstranit zařízení DeviceView.14=Nastavit DeviceView.17=Nové zařízení DeviceView.18=Přidat zařízení DeviceView.21=Toto zařízení je dostupné DeviceView.22=K zařízení nelze přistupovat DeviceView.23=Zařízení JajukWindow.1=Obnovit zvuk JajukWindow.2=Ztišit JajukWindow.3=Jajuk JajukWindow.4=Konec JajukWindow.5=O programu Jajuk JajukWindow.6=Přehrát náhodně JajukWindow.7=Přehrát nejlepší JajukWindow.10=Pozastavit JajukWindow.12=Pokračovat JajukWindow.13=Předchozí JajukWindow.14=Další JajukWindow.15=Přehrát novinky JajukWindow.16=Dokončit album JajukWindow.17=Jajuk: Pokročilý Jukebox JajukWindow.18=Připraven přehrávat JajukWindow.19=[F8] Ztišit / obnovit zvuk
    Hlasitost můžete nastavit kolečkem myši JajukWindow.21=Konec JajukWindow.22=O programu Jajuk JajukWindow.23=Přehraje náhodné skladby z kolekce JajukWindow.24=Přehraje nejoblíbenější skladby z kolekce JajukWindow.26=[Ctrl-p] Pozastavit/Pokračovat JajukWindow.27=[Ctrl-s] Zastavit JajukWindow.31=Přehraje nejnovější skladby z kolekce JajukWindow.32=Dokončí přehrávání aktuálního alba JajukWindow.33=[Ctrl-UP/DOWN] Hlasitost JajukWindow.34=Pozice JajukWindow.35=Přehrávání: JajukWindow.36=Aktuální hudební styl: JajukWindow.37=Žádný hudební styl #Do not use JajukWindow.38, next is JajukWindow.39 JajukWindow.39=Právě přehrávám JajukWindow.40=Nastavení dodatečných tagů JajukWindow.41=Otevře dialog pro nastavení aktivovaných dodatečných tagů JajukDonate.1=Dar JajukDonate.2=Infrastruktura projektu Jajuk potřebuje finanční prostředky. Další info na naší stránce o rozpočtu. JajukDonate.3=Rozpočet JajukDonate.4=Pokud chcete Jajuk podporovat, věnujte nám prosím dar. ActiveTagsWizard.1=Dostupné tagy ActiveTagsWizard.2=Aktivované tagy ActiveTagsWizard.3=Zde se nastavují dodatečné tagy, které chcete aby Jajuk zobrazil v tabulce stop. Informace jsou načítány přímo z audio souborů (např. z id3 tagů). Pokud aktivujete nový tag, bude provedeno celkové obnovení. To může trvat několik minut v závislosti na velikosti vaší kolekce. SimpleDeviceWizard.0=Rychlé vytvoření zařízení FirstTimeWizard.0=Rychlý start FirstTimeWizard.1=


    Vítejte! Tento průvodce Vám pomůže sestavit Vaši hudební kolekci

    FirstTimeWizard.2=Zvolte prosím umístění vašich hudebních souborů FirstTimeWizard.4=Zobrazit nápovědu nyní FirstTimeWizard.5=Vyberte prosím adresář FirstTimeWizard.6=Pokročilé předvolby FirstTimeWizard.7=Nastavit pracovní adresář Jajuku: FirstTimeWizard.8=Vybraný adresář: FirstTimeWizard.9=Žádný HelpView.2=Nápověda DownloadManager.0=Jajuk potřebuje Vaše heslo HTTP proxy, aby mohl získat obaly.
    Pokud si to nepřejete, změňte Vaše nastavení na záložce Obaly v okně Předvolby.
    Pokud nemáte proxy, změňte Vaše nastavení na záložce Síť v okně Předvolby. DownloadManager.1=Požadováno heslo PropertiesWizard.0=Vlastnosti položky PropertiesWizard.1=Vlastnost PropertiesWizard.2=Hodnota PropertiesWizard.3=Upravitelné? PropertiesWizard.4=Odkaz PropertiesWizard.6=Výběr PropertiesWizard.7=Typ PropertiesWizard.8=Vlastnost aktualizována PropertiesWizard.9=Vlastnost výběru nelze upravit PropertiesWizard.10=vlastnosti byly nastaveny PropertiesWizard.11=Zapisuji tag do: PropertiesWizard.12=Odkaz pro zadání základních detailů vlastností NewPropertyWizard.0=Vytvořit uživatelskou vlastnost NewPropertyWizard.3=(*)Typ NewPropertyWizard.4=Formát NewPropertyWizard.5=Výchozí hodnota CustomPropertyWizard.0=(*)Položka CustomPropertyWizard.1=(*)Název uživatelské vlastnosti RemovePropertyWizard.0=Odstranit uživatelskou vlastnost QualityFeedbackWizard.20=Ve Vašem externím prohlížeči bude nyní otevřeno nové okno k odeslání Vašeho oznámení. Vaše poslední anonymní informace již byly vloženy do schránky. Pokud je to chybové hlášení, vložte je prosím do pole pro popis (to nám velmi zvýší možnost opravit Váš problém). IncRateAction.0=Zvýšit hodnocení aktuální skladby SplashScreen.0=Spouštím kontroly SplashScreen.1=Načítám kolekci SplashScreen.2=Spouštím hudební zařízení SplashScreen.3=Spouštím grafické rozhranní CatalogView.0=Katalog alb #Note: CatalogView.2 label musn't be much larger than in English for correct display in 800x600 CatalogView.2=Zobrazit i alba bez obalu CatalogView.3=Obnovit katalog CatalogView.4=Velikost miniatur: CatalogView.5=Miniatury vytvořeny pro: CatalogView.7=Vybrat obal CatalogView.8=Žádný obal nenalezen CatalogView.9=Předchozí CatalogView.10=Další CatalogView.11=Stránka: CatalogView.12=Zobrazit předchozí stránku miniatur CatalogView.13=Zobrazit další stránku miniatur CatalogView.14=Vybrat stránku miniatur pro zobrazení CatalogView.15=Velikost miniatur: CatalogView.16=alba CatalogView.17=/stránka CatalogView.18=Výběr obalu CatalogView.19=Obnovit miniatury CatalogView.20=Zobrazit detail CatalogView.21=Zobrazit všechna alba CatalogView.22=Zobrazit alba s obalem WikipediaView.0=Wikipedia WikipediaView.1=Vybrat jazyk: WikipediaView.3=Žádný výsledek nenalezen WikipediaView.5=Hledat ve jménu umělce WikipediaView.6=Hledat v názvu alba WikipediaView.7=Hledat v názvu skladby WikipediaView.8=Načítám WikipediaView.9=Načítání informací z Wikipedie selhalo WikipediaView.10=Nelze hledat neznámého umělce. TipOfTheDayView.0=Tip dne TipOfTheDayView.1=Věděli jste...? TipOfTheDayView.2=Zobrazit po spuštění? CDDBWizard.0=Přijmout CDDBWizard.1=Název souboru CDDBWizard.2=Název aktuální skladby CDDBWizard.3=Název aktuálního alba CDDBWizard.4=Navrhovaný název skladby CDDBWizard.5=Navrhovaný název alba : CDDBWizard.6=Hotovo! Nalezeno CDDBWizard.7=možných shod CDDBWizard.12=Žádná shoda nenalezena! CDDBWizard.14=Tento adresář neobsahuje žádné soubory CDDBWizard.16=Žánr: CDDBWizard.17=Nalezena přesná shoda! CDDBWizard.18=Shody CDDBWizard.19=Získat tagy online RefactorWizard.0=Soubor přesunut : DigitalDJWizard.0=Zvolte nový mód DJ DigitalDJWizard.1=Programování založené na přechodu (ROCK -> POP) DigitalDJWizard.2=Programování založené na složení (20% JAZZ, 30% ROCK) DigitalDJWizard.3=Programování založené na hudebním stylu (Soft, Party...) DigitalDJWizard.4=Digitální průvodce DJ DigitalDJWizard.5=Obecné nastavení DJ DigitalDJWizard.6=Název DJ (*) DigitalDJWizard.8=Minimální počet hvězdiček: DigitalDJWizard.9=Prolnutí (sekund): DigitalDJWizard.10=Skladby přehrát pouze jednou DigitalDJWizard.11=Zrušit DigitalDJWizard.12=Od žánru DigitalDJWizard.13=Po žánr DigitalDJWizard.14=Výběr žánrů (vícenásobný výběr povolen) DigitalDJWizard.15=Počet skladeb DigitalDJWizard.16=Přejete si... DigitalDJWizard.17=Vytvořit nový DJ? DigitalDJWizard.18=Upravit existující DJ? DigitalDJWizard.19=Odstranit DJ? DigitalDJWizard.20=Nový DJ dle složení #limited string size DigitalDJWizard.21=Odstranit #limited string size DigitalDJWizard.22=Zdroj #limited string size DigitalDJWizard.23=Cíl #limited string size DigitalDJWizard.24=Počet DigitalDJWizard.26=Vytvořte prosím alespoň jedno složení #limited string size DigitalDJWizard.27=Výběr žánrů #limited string size DigitalDJWizard.28=% DigitalDJWizard.29=Nový DJ dle složení DigitalDJWizard.30=Vytvořte prosím alespoň jedno složení DigitalDJWizard.31=Nový DJ založený na hudebním stylu DigitalDJWizard.32=Nový DigitalDJWizard.33=Vytvoří nový hudební styl DigitalDJWizard.34=Odstranit DigitalDJWizard.35=Odstraní vybraný hudební styl DigitalDJWizard.36=Název hudebního stylu DigitalDJWizard.37=Název DigitalDJWizard.38=Vytvořte prosím nejméně jeden hudební styl DigitalDJWizard.39=Vyplňte prosím název hudebního stylu a zvolte jeho žánr DigitalDJWizard.40=Vyberte prosím DJ DigitalDJWizard.41=Vyplňte prosím název DJ DigitalDJWizard.42=DJ s tímto názvem jež existuje DigitalDJWizard.43=Změnit DJ DigitalDJWizard.44=Zvolte DJ pro nastavení DigitalDJWizard.45=Výběr úlohy DigitalDJWizard.46=Výběr typu DJ DigitalDJWizard.47=Vyberte, nebo vytvořte hudební styl DigitalDJWizard.48=Obecné atributy DigitalDJWizard.49=Vyplňte prosím obecné atributy DJ DigitalDJWizard.50=Zadejte prosím složení DigitalDJWizard.51=Odstranění DJ DigitalDJWizard.52=Zadejte prosím přechody DigitalDJWizard.53=Minimální počet hvězdiček hodnocení pro skladby ve výběru (1: všechny skladby) DigitalDJWizard.54=Délka prolínání mezi skladbami DigitalDJWizard.55=Pokud je volba vybrána, výběr bude obsahovat každou skladbu pouze jednou DigitalDJWizard.56=Průvodce hudebními styly DigitalDJWizard.57=Spravovat hudební styly DigitalDJWizard.58=Výběr hudebního stylu: DigitalDJWizard.59=Součet všech částí musí být < 100 % DigitalDJWizard.60=Název existujícího hudebního stylu DigitalDJWizard.61=Odstranit DJ #limited string size DigitalDJWizard.62=Výchozí DigitalDJWizard.63=Přidat výchozí hudební styl DigitalDJWizard.64=Všechny DigitalDJWizard.66=Výchozí výběr hudebního stylu (hudební styl je soubor žánrů, viz manuál) DigitalDJWizard.67=Omezit počet skladeb ve frontě DigitalDJWizard.68=Maximální počet skladeb ve frontě PreparePartyWizard.1=Připravit párty PreparePartyWizard.2=Zvolit zdroj skladeb PreparePartyWizard.3=Nejdříve určete, ja mají být skladby pro vaše párty vybrány. PreparePartyWizard.4=Vyberte omezení PreparePartyWizard.5=Zvolte prosím omezení skladby / čas / velikost na disku, nebo typ skladby. PreparePartyWizard.6=DJs PreparePartyWizard.7=Hudební styly PreparePartyWizard.8=Playlisty PreparePartyWizard.9=Náhodné skladby PreparePartyWizard.10=Max. skladeb PreparePartyWizard.11=Kolik skladeb má být maximálně zadáno. PreparePartyWizard.12=Max. velikost (MB) PreparePartyWizard.13=Kolik megabajtů dat maximálně chcete vytvořit. PreparePartyWizard.14=Max. délka (minuty) PreparePartyWizard.15=Jaká má být celková maximální délka párty. PreparePartyWizard.16=Omezení typu PreparePartyWizard.17=Vyberte použití pouze jednoho typu hudebních souborů. Volba může být užitečná, pokud například přehrávač podporuje pouze určité typy médií. PreparePartyWizard.18=Vybrat umístění PreparePartyWizard.19=Vyberte umístění souborů, které mají být použity pro párty. Pro soubory bude vytvořen podadresář. PreparePartyWizard.20=Vyberte prosím umístění cíle. PreparePartyWizard.21=Vybraný adresář: PreparePartyWizard.22=Vyberte prosím cílový adresář. PreparePartyWizard.23=Soubory budou kopírovány do PreparePartyWizard.24=Nejlepší z Playlistu PreparePartyWizard.25=Novinky v Playlistu PreparePartyWizard.26=Normalizovat názvy souborů PreparePartyWizard.27=Normalizuje názvy souborů nahrazením cizích znaků tak, aby byly soubory přenositelné na ostatní operační systémy i kódování PreparePartyWizard.31=Umístění cíle: PreparePartyWizard.32=Soubory ve frontě PreparePartyWizard.33=Soubory se záložkami PreparePartyWizard.34=Vyzkoušet ostatní typy médií PreparePartyWizard.35=Pokud je potřeba, použije pro převedení souborů externí nástroj 'pacpl - Perl Audio Converter'. PreparePartyWizard.36= soubor(y) nelze do zvoleného formátu převést. PreparePartyWizard.37=(vyžaduje PACPL, viz Perl Audio Converter) PreparePartyWizard.38=Konfigurovat nastavení převodu PreparePartyWizard.39=definujte prosím příkaz pro spuštění Perl Audio Converter.
    Na Linuxu je to nejčastěji právě "pacpl", někdy "perl <install-location>/pacpl.
    Ve Windows je to obvykle "perl <install-location>\pacpl PreparePartyWizard.40=Konfigurovat... #--- Tips of day --- Ambience.0=Rock/Pop Ambience.1=Rap Ambience.2=HardRock Ambience.3=Techno Ambience.4=Electro Ambience.5=Classical Ambience.6=Soft Ambience.7=Party Ambience.8=Jazz Ambience.9=World Ambience.10=Ostatní Ambience.11=Folk/Oldies Ambience.12=Inde Ambience.13=Latin DebugLogAction.0=Seznam informací o ladění DebugLogAction.1=Obnovit CopyClipboardAction.0=Zkopírovat adresu do schránky LaunchInBrowserAction.0=Otevřít adresu ve výchozím prohlížeči ReportAction.0=Hlášení úspěšně vytvořeno ReportAction.1=Hlášení Jajuk Music ReportAction.2=Pamatujte prosím na životní prostředí a tiskněte, jen když je nezbytně nutné ReportAction.3=Seznam alb ReportAction.4=Skladeb v albu ReportAction.5=Seznam umělců ReportAction.6=Alb na umělce ReportAction.7=Seznam žánrů ReportAction.8=Alb na žánr ReportAction.9=Autoři/ alba na žánr ReportAction.10=Seznam adresářů ReportAction.11=Souborů v adresáři ReportAction.12=Název souboru ReportAction.13=Název skladby ReportAction.14=Seznam zařízení ReportAction.15=Adresářů v zařízení ReportAction.16=Adresáře/ soubory ReportAction.17=kolekce ReportAction.18=Autoři/ alba/ písně na styl ReportAction.19=Přejít na: ActionMove.0=Vložit ActionRefresh.0=Vynutit obnovení ActionRefresh.1=Obnovuji adresář RenameAction.0=Přejmenovat RenameAction.1=Zadejte prosím nový název tohoto souboru: RenameAction.2=Zadejte prosím nový název tohoto adresáře: NewFolderAction.0=Nový adresář NewFolderAction.1=Zadejte prosím název nového adresáře: NewFolderAction.2=Adresář se stejným názvem již existuje. LyricsView.0=Texty LyricsView.1=Žádné dostupné texty, přístup k internetu byl zakázán. K opětovnému povolení použijte menu Nastavení. LyricsView.2=Zvolit režim úprav textu LyricsView.3=Ukončit režim úprav textu LyricsView.4=Uložit texty LyricsView.5=Odstranit texty ActionDelete.0=Soubory smazány ActionDelete.1=Adresáře smazány FindDuplicateTracksAction.0=Nenalezeny žádné duplicitní skladby FindDuplicateTracksAction.1=Nalezeny duplicitní skladby FindDuplicateTracksAction.2=Vyhledat duplicitní skladby FindDuplicateTracksAction.3=Nalezen seznam duplicitních skladeb FindDuplicateTracksAction.4=Vybrat všechny duplicitní skladby RefreshDialog.0=Připravuji obnovení zařízení... RefreshDialog.1=Obnovení zařízení RefreshDialog.2=Obnovení zařízení: RefreshDialog.3=Odstraňuji staré soubory RadioWizard.0=Prosím vyberte nebo vytořte webové rádio RadioWizard.1=Spravovat webová rádia RadioWizard.2=Nové RadioWizard.3=Odstranit RadioWizard.4=Výchozí RadioWizard.5=Webové rádio s tímto názvem již existuje RadioWizard.6=Název webového rádia RadioWizard.7=Průvodce webovým rádiem RadioWizard.8=URL RadioWizard.9=Název RadioWizard.10=Neplatná URL RadioWizard.11=Název a URL jsou povinné UpdateManager.0=Nová verze Jajuk ( UpdateManager.1=) je k dispozici. Můžete ji stáhnout z http://jajuk.info UpdateManager.2=Zatím není dostupná novější verze LastFmManager.0=Podpora Last.FM je vypnutá. Pokud chcete předložit Last.FM písně, které posloucháte, zapněte ji a nastavte Vaše Uživatelské jméno a heslo Last.FM v okně Předvolby na záložce Last.FM. SuggestionView.0=Nabídka SuggestionView.1=Oblíbené SuggestionView.2=Nejnovější SuggestionView.3=Další alba SuggestionView.4=Podobní umělci SuggestionView.5=Zřídka poslouchané SuggestionView.7=Nemám co zobrazit

    Informace Last.FM jsou zobrazeny pouze pokud:
    • Skladba je přehrávána
    • Autor přehrávané skladby je známý (správný tag)
    • Je zaškrtnuta volba "Povolit informační dotazy Last.FM" v okně Předvolby na záložce Last.FM
    AbstractThumbnail.0=Otevřít stránku LAST.FM AlbumsTableView.0=Seznam alb AlbumsTableView.1=Počet skladeb AlarmClock.0=Nastavit budík #Next value : 6 AlarmDialog.0=Čas (HH24:MM:SS) AlarmDialog.1=Hodiny AlarmDialog.2=Minuty AlarmDialog.3=Sekundy AlarmDialog.4=Úlohy budíku AlarmDialog.5=Vyberte úlohy budíku #Next value : 11 ShowPropertiesAction.0=Zobrazení vlastností položky QueueView.1=Vyčistit frontu QueueView.2=Automaticky přesunout na aktuálně přehrávanou skladbu JajukSlimWindow.0=Zobrazí / skryje Jajuk v liště JajukFullscreen.0=Zapnout / vypnut přehrávač v celoobrazovkovém režimu BanSelectionAction.0=Zakázat BanSelectionAction.1=Zakáže položku, takže už nemůže být nikdy vybrána UnBanSelectionAction.0=Odblokovat UnBanSelectionAction.1=Odblokuje zakázané položky, takže je lze opět vybrat OpenExplorerAction.0=Otevřít ve správci OpenExplorerAction.1=Otevře adresář v externím správci programů Preference.0=Nastavte osobní hodnocení oblíbenosti pro aktuální skladbu
    To bude započítáno do celkového hodnocení Preference.1=Odpad Preference.2=Špatné Preference.3=Průměrné Preference.4=Dobré Preference.5=Vynikající Preference.6=Klasické Preference.7=Předvolby... Preference.8=Nehodnotit ArtistView.0=Náhled na umělce Notificator.NONE=Žádný Notificator.TOAST=Toast Notificator.BALLOON=Bublina Notificator.track_change.webradio_title=Přehrávané webové rádio : Notificator.track_change.track_title=Přehrávaná stopa : SyncTreeTableAction.0=Synchronizovat náhled stromu a tabulky SyncTreeTableAction.1=Synchronizuje náhledy stromu a tabulky
    Pokud je použit pro zobrazení stromu, výběr položky v zobrazení tabulky rozbalí a přesune na položku ve stromu.
    Pokud je použit pro zobrazení tabulky, výběr položky v zobrazení stromu vyfiltruje patřičně tabulku. TipOfTheDay.0= Tip 0: aktuální skladbu můžete přehrát znovu od začátku [Shift+kliknutí] na tlačítko Zpět TipOfTheDay.1= Tip 1: aktuální album můžete přehrát znovu od první skladby [Ctrl+kliknutí] na tlačítko Předchozí TipOfTheDay.2= Tip 2: náhodnou skladbu můžete přidat do playlistu použitím tlačítka ?+ v editoru playlistu TipOfTheDay.3= Tip 3: obaly můžete získat online i pomocí proxy serveru za použití záložky Síť v okně Předvolby TipOfTheDay.4= Tip 4: Jajuk přichází s lištou (tlačítko na pravé straně lišty s menu) pro ovládání přehrávání, přičemž zabere jen minimum místa na ploše TipOfTheDay.5= Tip 5: skrýt nedostupné skladby můžete zatržením volby "Zobrazit pouze dostupné skladby" TipOfTheDay.6= Tip 6: většinu funkcí programu Jajuk můžete provádět pomocí klávesnice TipOfTheDay.7= Tip 7: můžete přetáhnout položky z okna Strom souborů do editoru a seznamu playlistů TipOfTheDay.8= Tip 8: k seznámení se skladbami můžete použít mód Úryvky TipOfTheDay.9= Tip 9: délku prolínání můžete nastavit v okně Předvolby na záložce Módy TipOfTheDay.10= Tip 10: Jajuk můžete použít jako pokročilý budík s využitím vlastností dostupných v nabídce Nástroje TipOfTheDay.11= Tip 11: většinu hlavních funkcí Jajuku můžete ovládat pomocí programu pouze v liště (Linux & Windows) TipOfTheDay.12= Tip 12: téma Jajuku je nastavitelné na záložce GUI v okně Předvolby TipOfTheDay.13= Tip 13: chování dvoj-kliknutí a přetahování můžete nastavit okně Předvolby na záložce Možnosti TipOfTheDay.14= Tip 14: "Plánované skladby" Jajuk jsou skladby, které budou přehrány po aktuálně vybrané skladbě TipOfTheDay.15= Tip 15: grafické rozhranní Jajuku je plně přizpůsobitelné a můžete jej upravovat přetažením oken TipOfTheDay.16= Tip 16: celkový počet souborů a skladeb můžete získat kliknutím na ikonku "Kolekce" v okně Strom souborů nebo Strom skladeb TipOfTheDay.17= Tip 17: tagy online můžete získat výběrem funkce "Získat tagy online" po kliknutí pravým tlačítkem myši na adresář v okně Strom souborů nebo Strom skladeb TipOfTheDay.18= Tip 18: panel historie Jajuku (navrchu okna) zobrazuje všechny dříve přehrávané skladby TipOfTheDay.19= Tip 19: můžete použít rychlé hledání použitím Vyhledávacího boxu (navrchu okna) TipOfTheDay.20= Tip 20: můžete nahlásit chyby nebo přání nových funkcí programu pomocí agenta kvality (Nápověda, Nahlásit chybu...) TipOfTheDay.21= Tip 21: Jajuk DJ může vytvořit inteligentní playlist přesně podle Vašich požadavků TipOfTheDay.22= Tip 22: texty skladeb můžete získat použitím okna "Texty" TipOfTheDay.23= Tip 23: okno Nabídka zobrazuje informace LAST.FM jako např. Podobní umělci TipOfTheDay.24= Tip 24: můžete nastavit obrázek na pozadí v okně Předvolby na záložce GUI TipOfTheDay.25= Tip 25: můžete zobrazit/skrýt skladby na odpojeném zařízení jedním kliknutím v nabídce Nastavení TipOfTheDay.26= Tip 26: nyní můžete zvolit adresář pro data Jajuku (např. externí disk) k uložení Vašich dat a předvoleb na jakémkoliv počítači (viz záložka Pokročilé v okně Předvolby) TipOfTheDay.27= Tip 27: můžete přidat jakékoliv okno v každém pohledu použitím nabídky "Pohledy" TipOfTheDay.28= Tip 28: stránku Wikipedia můžete spustit ve Vašem výchozím prohlížeči stiskem ikonky "Otevřít adresu ve výchozím prohlížeči"v okně Wikipedia Image:launch_16x16.png TipOfTheDay.29= Tip 29: Jajuk podporuje webová rádia Image:webradio_32x32.png TipOfTheDay.30= Tip 30: Jajuk může být také ovládán na dálku pomocí D-Bus, pokud je na platformě dostupný (tzn. na Windows nelze). To umožňuje používat k ovládání Jajuku multimediálních kláves na klávesnici. Další informace získáte v online příručce. ]]> jajuk-1.9.6.orig/src/main/java/org/jajuk/i18n/jajuk_fr.properties0000644000175000017500000017137211720500104024506 0ustar drazzibdrazzib onglet Historique (attention, toutes les notations existentes seront supprimées) Confirmation_exit=Voulez-vous vraiment quitter? Confirmation_delete=Attention! Vous êtes sur le point d'effacer physiquement le(s) fichier(s) suivants de votre disque, êtes vous sûr ? Confirmation_void_refresh=Attention! Vous allez rafraîchir un support vide. Sous Unix, vérifiez que le support est monté ou vous allez perdre toutes les informations Jajuk sur ce support. Confirmez-vous l’action ? Confirmation_remove_device=Voulez vous vraiment enlever ce support ? Confirmation_delete_cover=Voulez vous vraiment effacer définitivement cette pochette de votre disque ? Confirmation_clear_history=Voulez vous vraiment effacer l'historique ? Confirmation_reset_ratings=Voulez vous vraiment remettre tous les notes à zéro ? Confirmation_refactor_files=Voulez vous vraiment renommer les fichiers sélectionnés ? Confirmation_restore_all=La réinitialisation de toutes les perspectives nécessite un redémarrage de Jajuk, Voulez vous quitter maintenant ? Confirmation_defaults_radios=Cette opération supprimera toutes vos stations déjà créées, confirmez-vous ? Confirmation_delete_files=Voulez vous vraiment effacer ces fichiers définitivement ? Confirmation_delete_dirs=Voulez vous vraiment effacer ces répertoires définitivement ? Confirmation_delete_empty_dirs=Les répertoires suivants sont vides, voulez vous les effacer ? Confirmation_file_overwrite=Le fichier existe déjà, voulez vous l'écraser ? Confirmation_file_number=fichiers(s) seront effacés Confirmation_alarm_stop=Voulez vous vraiment arrêter cette alarme ? Confirmation_defaults=Notez que cette action réinitialisera toutes les options, et pas seulement celles de l'onglet courant. Confirmez-vous l'action ? Confirmation_rebuild_thumbs=Cette action reconstruira les vignettes de tous vos albums, ce qui peut prendre plusieurs minutes pour les grosses collections, confirmez-vous ? Confirmation_reset_preferences=Confirmez-vous la réinitialisation des preferences de tous vos morceaux ? Device_type.directory=Répertoire Device_type.file_cd=CD de fichiers musicaux Device_type.audio_cd=CD audio Device_type.extdd=Disque externe Device_type.player=Baladeur Device_type.network_drive=Lecteur réseau Perspective_Description_Simple=Simple Perspective_Description_Files=Fichiers Perspective_Description_Tracks=Morceaux Perspective_Description_Configuration=Config Perspective_Description_Statistics=Stats Perspective_Description_Help=Aide Perspective_Description_Display=Affichage Perspective_Description_Albums=Albums Perspective_Description_Info=Info Perspective_Description_Playlists=Playlists Item_Playlist_File=Liste de lecture Item_Playlist=Liste de lecture Item_Track=Morceau Item_Album=Album Item_Artist=Auteur Item_Genre=Style Item_Device=Support Item_File=Fichier Item_Directory=Répertoire Item_Year=Année Item_AlbumArtist=Album-Artist Property_id=Id Property_name=Nom Property_type=Type Property_url=Url Property_mount_point=Point de montage Property_auto_refresh=Rafraîchissement automatique Property_auto_mount=Montage automatique Property_album=Album Property_style=Style Property_author=Auteur Property_album_artist=Album-Artist Property_disc_number=No Disque Property_length=Durée Property_year=Année Property_rate=Note Property_files=Fichiers Property_hits=Lectures Property_filename=Fichier Property_date=Date Property_added=Date découverte Property_parent=Répertoire parent Property_device=Support Property_directory=Répertoire Property_track=Morceau Property_size=Taille (Mo) Property_quality=Qualité Property_hashcode=Hashcode Property_playlist_files=Liste de lecture Property_comment=Commentaires Property_order=No Property_path=Chemin absolu Property_tracks=Morceaux Property_file_date=Date Fichier Property_Format_Number=Entier Property_Format_String=Chaîne de caractères Property_Format_Boolean=Booléen Property_Format_Float=Flottant Property_Format_Date=Date Property_pf=Préférence Property_tpt=Temps total de lecture (secs) Property_ban=Banni Property_disc_id=DiscID Language_desc_en=Anglais Language_desc_fr=Français Language_desc_de=Allemand Language_desc_it=Italien Language_desc_sv=Suédois Language_desc_nl=Néerlandais Language_desc_zh=Chinois Language_desc_es=Espagnol Language_desc_ca=Catalan Language_desc_ko=Coréen Language_desc_el=Grecque Language_desc_ru=Russe Language_desc_gl=Galicien Language_desc_cs=Tchèque Language_desc_pt=Portugais #--- Error codes --- Error.000=Erreur inconnue Error.005=Erreur en lisant le fichier collection Error.007=Erreur de lecture, Mplayer n'a peut être pas démarré dans le temps imparti pour : Error.008=Erreur en arrêtant le fichier Error.009=Impossible de lire le fichier Error.010=Impossible de trouver un fichier associé avec cet élément sur un support monté Error.011=Erreur technique en montant le support ou support vide Error.012=Erreur technique en démontant le support, il est probablement utilisé par une autre application Error.013=Impossible de supprimer le support: soit il est monté, soit il est en cours de rafraîchissement ou de synchronisation Error.016=Impossible d'accéder au support spécifié, veuillez saisir un point de montage. Ex: '/cdrom' sous Unix,'e:' sous MS Windows Error.017=Erreur en lisant la liste de lecture Error.018=Aucun morceau n'est accessible Error.019=Un support portant ce nom existe déjà Error.020=Erreur d'entrée/sortie en copiant un fichier, vérifiez l'espace disque Error.021=Le champs 'url' est obligatoire Ex: 'd:\musique' sous MS Windows, '/home/foo/musique' sous Unix Error.022=Le champs 'nom' est obligatoire. Ex: 'Disque dur', 'CD ROCK' Error.024=Impossible d'écrire le fichier Error.025=Un des fichiers que vous désirez lire se trouve sur un support non monté Error.026=Erreur en enregistrant un lecteur de musique Error.027=Synchronisation annulée Error.028=Erreur en sauvegardant la liste de lecture Error.029=Il existe un support existant qui a le même chemin, qui est un sous répertoire ou qui est un répertoire parent Error.030=Dépassement du nombre d'erreurs de connexions, Jajuk stoppe les recherches de pochettes en ligne Error.101=Le support n'existe pas ou n'est pas accessible Error.102=Erreur Error.103=Erreur en lisant un tag Error.104=Erreur en écrivant un tag Error.105=La clé du Ressource Bundle ne peut être trouvée Error.106=Exception non traitée Error.107=Support déjà en cours de rafraîchissement ou de synchronisation Error.108=Erreur en lisant le fichier perspective Error.109=Une classe d'implémentation d'un lecteur ou d'un lecteur de méta-information est introuvable Error.110=Ce nom d'attribut est réservé par Jajuk, merci d'en choisir un autre Error.111=Support déjà monté Error.112=Impossible de monter le support Error.113=Impossible d'écrire la configuration utilisateur Error.114=Impossible de lire la configuration utilisateur Error.118=Erreur en traitant un événement Error.119=Pas de fichier d'historique ou erreur en l'ouvrant Error.120=Impossible d'accéder au support : soit il n'est pas monté, soit il est en cours de rafraîchissement ou de synchronisation Error.121=Le support est en cours d'utilisation et ne peut être démonté Error.122=Erreur dans la pile Error.123=Erreur en fixant le thème Error.124=Une autre session Jajuk a été trouvée, vous ne pouvez lancer qu'une seule session par machine en même temps Error.125=Support déjà démonté Error.126=L'avance rapide n'est pas supportée par ce format audio Error.127=Aucune nouveauté pour le l'intervalle de temps demandé, vous pouvez le changer dans la vue Paramétrage / onglet Options Error.128=Le morceau courant est le tout premier de la collection, pas de morceau précédent disponible Error.129=Erreur en chargeant l'image Error.131=Impossible d'effacer le fichier Error.133=Votre collection était corrompue pour une raison inconnue, Jajuk a pu restaurer la sauvegarde Error.134=Impossible de renommer le fichier Error.135=Le fichier n'existe pas Error.136=L'opération a échouée Error.137=Erreur de format Error.138=Certains fichiers référencés par ce morceau sont situés sur des supports non montés et n'ont donc pas été modifiés. Error.140=Mauvais format: ne doit pas contenir les caractères < > & ' " Error.141=Cette liste de lecture se trouve sur un support non monté ou en cours de rafraîchissement et n'est donc pas accessible Error.142=Cette liste de lecture contient des morceaux ignorés n'existant pas ou se trouvant en dehors des supports connus Error.143=Le chemin du support n'est pas accessible Error.144=Erreur en lisant le DJ Error.145=Impossible d'écrire le DJ Error.146=Le format du canevas de réorganisation de fichiers est erroné.
    Les éléments valides sont : %artist (nom de l'auteur); %title (nom du morceau); %album (nom de l'album);
    %n (no de piste); %genre (style); %year (année); %disc (No de disque)
    et le format doit contenir au moins un '/' Error.147=Certains fichiers n'ont pu être déplacés (Faire détail pour voir la liste) Error.148=Le champs Année n'est pas renseigné Error.149=Le champs Album n'est pas renseigné Error.150=Le champs Artiste n'est pas renseigné Error.151=Le champs Titre n'est pas renseigné Error.152=Le champs Numéro n'est pas renseigné Error.153=Le champs Style n'est pas renseigné Error.154=Impossible de renommer le fichier, vérifiez les caractères dans le nom du fichier ou dans les tags Error.155=Erreur en fixant les tags, vérifiez les permissions Error.156=Collection vide Error.157=Mauvais DJ, veuillez sélectionner ou créer un DJ en utilisant le bouton DJ de la vue Commande Error.158=Les contraintes de ce DJ ne peuvent être respectées ou aucun morceau disponible Error.159=L'ambiance associée ne peut être supprimée Error.160=Fichier non déplacé, source et destination identique Error.161=Impossible d'écrire dans le répertoire, vérifiez les permissions Error.163=Erreur en restaurant la disposition par défaut Error.164=Aucun morceau accessible pour l'ambiance: Error.165=Chemin erroné, le répertoire ne peut être trouvé ou n'est pas accessible en écriture Error.166=Album vide, impossible de récupérer de pochette Error.167=Impossible de créer le rapport Error.168=Aucun fichiers doublons trouvés Error.169=L'opération a échoué. Notez que cette opération nécessite un accès Internet pour récupérer la liste de webradios en ligne. Error.170=Erreur en lançant la webradio Error.171=Aucune source de synchronisation n'est encore définie pour ce support, fixez en double cliquant sur le support dans la vue Supports. Error.172=Le morceau en cours de lecture ainsi que ses répertoires parents ne peuvent être supprimés : Error.173=Erreur en supprimant le(s) répertoire(s) suivant(s) : Error.174=Erreur en accédant au site Freedb, vérifiez votre connexion réseau Error.175=Opération annulée Error.176=Erreur en générant la liste de lecture Error.177=Veuillez saisir une heure valide au format HH24:MM:SS Error.179=Impossible d'ouvrir d'explorer de fichiers, vous pouvez fixer un chemin vers l'outil dans la vue Préférences / Onglet Avancé Error.180=Erreur en copiant les fichiers # Warnings Warning.0=MPlayer n'a pas été trouvé. Certains formats audio (flac, wma, aac, mpg2 et certaines fonctions des ogg) seront inactivés. Si Mplayer est déjà installé, fixez son chemin dans la vue "Préférence" / onglet "Avancé" Warning.1=Mauvaise version de MPlayer, MPlayer1.0Pre8 et suivants est requis. Certains formats audio seront inactivés Warning.2=Quelqu'un semble déjà utiliser la collection. Le dernier utilisateur à quitter Jajuk écrasera les modifications de l'autre (options, statistiques d'écoute...). Warning.3=Mplayer ne peut être téléchargé. Si vous vous situez derrière un proxy HTTP, veuillez le configurer dans la vue Préférences / onglet Réseau et redémarrez Jajuk. Warning.4=Mplayer est requis pour utiliser les webradios Warning.5=Le répertoire cible existe déjà, des fichiers pourraient être écrasés, êtes vous sûr ? Warning.6=Aucun morceau accessible (Conseil: tentez de monter des supports ou changez l'ambience) Warning.7=Jajuk a détecté un besoin de rafraissement approfondi due à une mise à jour. Désirez vous procéder à ce rafraîchissment maintenant ? (notez que vous pouvez le faire plus tard à partir de la vue Supports) #--- Strings by class --- ParameterView.0=Durée de l'historique: ParameterView.2=Fixez ici le nombre de jours de conservation de l'historique. -1 : pas de limite, 0: pas d'historique ParameterView.3=Effacer l'historique ParameterView.4=Effacer l'historique ParameterView.8=Historique/Notations ParameterView.9=Joue : ParameterView.10=Rien ParameterView.11=Pas de musique au démarrage ParameterView.12=Dernier du début ParameterView.13=Joue au démarrage le dernier morceau de la session précédente ParameterView.14=Aléatoire ParameterView.15=Joue au démarrage en morceau au hasard parmi la collection toute entière ParameterView.16=Morceau/radio : ParameterView.17=Choisissez un morceau à jouer au démarrage ParameterView.18=Choisissez un morceau à jouer au démarrage ParameterView.19=Démarrage ParameterView.26=Confirmations ParameterView.27=Avant d'effacer physiquement un fichier ParameterView.28=Demander avant d'effacer physiquement un fichier ParameterView.29=Avant de quitter Jajuk ParameterView.30=Demander avant de quitter Jajuk ParameterView.33=Options ParameterView.35=Cacher les fichiers situés sur des supports non montés ParameterView.36=Redémarrer la collection en arrivant au bout ParameterView.37=Revenir au début quand on atteint la fin de la collection en mode 'continue' ParameterView.38=Langue : ParameterView.42=Options de multi-langue ParameterView.43=Thème : ParameterView.44==Sélectionnez un thème

    (nécessite un redémarrage de Jajuk pour un rafraîchissement complet de l'écran) ParameterView.45=Paramètres de thèmes ParameterView.46=Niveau de trace : ParameterView.47=Erreur Fatale ParameterView.48=Erreur ParameterView.49=Avertissement ParameterView.50=Info ParameterView.51=Debug ParameterView.52=Niveau de trace de Jajuk= 'Erreur Fatale': affiche seulement les erreurs critiques, 'Erreur': +erreurs, 'Info':+messages d'information, 'Avertissements':+avertissements, 'Debug':tous les messages ParameterView.59=Position de début (%) : ParameterView.60=Position de début (%) pour le mode intro de 0 (début du morceau) à 99 ( fin du morceau ) ParameterView.61=Durée de l'intro (sec) : ParameterView.62=Durée de l'intro en secondes ParameterView.85=Appliquer ParameterView.86=Défauts ParameterView.87=Préférences ParameterView.98=Modèles ParameterView.99=Forcer la relecture des tags ParameterView.100=Force Jajuk à relire les tags id3 lors du rafraîchissement

    Ce peut être utile si vous avez modifié entre temps les tags avec un autre outil ParameterView.101=Utiliser le répertoire comme album ParameterView.102=Utiliser le répertoire parent comme nom d'album si ce dernier ne peut être déterminé par les tags ParameterView.109=Préférences sauvegardées ParameterView.110=Préférences fixées aux valeurs par défaut ParameterView.111=Taille liste de lecture bestof : ParameterView.112=Taille de la liste de lecture bestof (de 1 à 100 morceaux) ParameterView.113=Utiliser les filtres regexp ParameterView.114=Utiliser les expressions régulières (au format regexp) dans les filtres des tables, exemple: .*toto.* ParameterView.115=Avancé ParameterView.116=Sauvegarde de la collection ParameterView.117=Cochez si vous voulez sauvegarder votre fichier collection vers des fichiers collection-.xml ParameterView.118=Taille de la sauvegarde (Mo) ParameterView.119=Taille totale cumulée de la sauvegarde (Mo) ParameterView.120=Encodage de la collection ParameterView.121=Encodage de la collection. L'UTF-16 est optimisé pour les langages asiatiques et non européennes et l'UTF-8 est optimisé pour les langues européennes ParameterView.129=Durée limite des nouveautés (jours): ParameterView.130=Durée limite des nouveautés en jours : tous les morceaux ajoutés avant cette durée sont considérés comme nouveauté ParameterView.131=Morceau bestof ParameterView.132=Jouer un de vos morceaux préférés au démarrage ParameterView.133=Nouveauté ParameterView.134=Jouer au démarrage une nouveauté de votre collection ParameterView.135=Dernier à la dernière position ParameterView.136=Jouer le dernier morceau à la dernière position dans la session Jajuk précédente ParameterView.139=Réseau ParameterView.142=Utilisateur du Proxy ParameterView.143=Utilisateur (login) du Proxy utilisé pour l'authentification ParameterView.144=Adresse du Proxy ParameterView.145=Adresse ou IP du Proxy ParameterView.146=Port du Proxy ParameterView.147=Port TCP-IP du Proxy (souvent 3128) ParameterView.148=Chercher des pochettes en ligne ParameterView.149=Chercher les pochettes en ligne, si besoin, configurez votre réseau dans l'onglet Réseau ParameterView.150=Taille des pochettes (Ko) ParameterView.151=Taille des pochettes (Ko) trouvées sur le web ParameterView.155=Précision de la recherche. Plus elle est elevée, moins vous obtiendrez de fausses pochettes ParameterView.156=Précision basse (cherche tous les mots) ParameterView.157=Précision moyenne (cherche tous les groupes de mots) ParameterView.158=Précision élevée (cherche tous les groupes de mots et tous sont obligatoires) ParameterView.159=Pochettes ParameterView.160=Timeout de la connexion (sec) ParameterView.161=Timeout de la connexion (secs) : l'opération échoue si la machine distante ne répond pas dans ce temps ParameterView.162=Timeout du transfert (sec) ParameterView.163=Timeout du transfert (sec) : l'opération échoue si les données ne sont pas complètement transférées dans ce temps ParameterView.164=Avant d'enlever un support ParameterView.165=Demande avant d'enlever un support ParameterView.166=Pochettes aléatoires ParameterView.167=Affiche les pochettes aléatoirement ParameterView.169=Pré charger les pochettes ParameterView.170=Pré charger les pochettes quand c'est possible ParameterView.171=Avant d'effacer physiquement une pochette ParameterView.172=Demande avant d'effacer physiquement une pochette ParameterView.177=Nombre de morceaux planifiés visibles ParameterView.178=Nombre de morceaux planifiés visibles ParameterView.179=La sélection pousse les morceaux ParameterView.180=Ne joue pas immédiatement les morceaux lorsqu'on les sélectionne ParameterView.181=Le glisser-déposer pousse les morceaux ParameterView.182=Le double clic et ne joue pas immédiatement les morceaux lorsqu'on les dépose ParameterView.186=Réinitialiser les notes ParameterView.187=Réinitialise toutes les notes à zéro ParameterView.188=Avant d'effacer l'historique ParameterView.189=Avant de réinitialiser les notes ParameterView.190=Durée du fondu enchaîné (sec) ParameterView.191=Durée du fondu enchaîné entre deux morceaux en secondes ParameterView.192=Organiseur de collection : ParameterView.193=Variables :%artist (auteur); %title (Nom du morceau); %album (Album); %n (Numéro du morceau); %genre (Style); %year (Année); %disc (No disque) ParameterView.194=Avant d'organiser un répertoire ParameterView.195=Vue animation : ParameterView.196=Activer les Hotkeys ParameterView.197=Activer une fonction permettant à certains raccourcis clavier comme F8 (muet) de fonctionner même lorsque Jajuk n'a pas le focus ParameterView.198=Certains changements ne seront pris en compte qu'au prochain démarrage de Jajuk ParameterView.199=Capturer mes écoutes ParameterView.200=Cette fonction permet d'envoyer les informations sur les morceaux que vous écoutez à Last.fm ParameterView.201=Utilisateur Last.FM ParameterView.202=Utilisateur Last.FM ParameterView.203=Mot de passe Last.FM ParameterView.204=Mot de passe Last.FM ParameterView.205=Arguments de MPlayer ParameterView.206=Arguments mplayer complémentaires comme '-ao esd' ou '-ao arts' ou '-novideo' (pour ne pas jouer les videos)' par exemple ParameterView.207=Emplacement de la collection ParameterView.208=Fixer le répertoire contenant la configuration de Jajuk (par défaut, répertoire utilisateur) ParameterView.209=Le chemin de configuration de Jajuk a été modifié pour l'utilisateur en cours (l'ancienne collection n'a pas été effacée car peut elle est peut être utilisée par d'autres utilisateurs). Jajuk va maintenant être redémarré. ParameterView.210=Si le fondu enchaîné ne fonctionne pas, essayez d'ajouter <-ao esd> sous Gnome ou <-ao arts> sous KDE dans la zone "Arguments du moteur de son" (onglet Avancé). ParameterView.211=Petites seulement ParameterView.212=Petites et moyennes ParameterView.213=Moyennes seulement ParameterView.214=Moyennes et larges ParameterView.215=Larges seulement ParameterView.216=Recherche par le nom de l'auteur ParameterView.217=Recherche par le nom de l'album ParameterView.218=Recherche par le nom du morceau ParameterView.219=Variables d'environnement ParameterView.220=Fixer ici des variables d'environnement pouvant être utilisées par le moteur de son (ARTS_SERVER sous KDE ou ESPEAKER sous Gnome par exemple). Format: var1=xx var2=yyy... #Respect English size ParameterView.221=Taille d'une page (0: tout sur une seule page) ParameterView.222=Fixer le nombre d'albums à afficher par page dans la vue catalogue d'albums. 0: tous les albums sont affiché sur une unique page. ParameterView.223=Taille des polices ParameterView.224=Fixer la taille des polices de caractère ParameterView.225=Interface graphique ParameterView.226=Modes ParameterView.228=Afficher les popups sur les albums ParameterView.229=Préférences de la vue Catalogue ParameterView.233=Le thème sera totalement appliqué au prochain démarrage de jajuk ParameterView.234=Vérifier les mises à jour de Jajuk ParameterView.235=Last.FM ParameterView.236=Pas de proxy ParameterView.237=Proxy HTTP ParameterView.238=Proxy SOCKS ParameterView.239=Mot de passe du proxy ParameterView.240=Activer les accès Last.FM en consultation ParameterView.241=Si activé, Jajuk cherche diverses informations et images sur le site de Last.FM et d'autres sites (voir la vue Suggestion) ParameterView.242=Chemin Mplayer ParameterView.243=Fixer ici le chemin complet de mplayer (espaces autorisés)
    Exemple: /Applications/MPlayer OSX.app/Contents/Resources/External_Binaries/mplayer_intel.app/Contents/MacOS/mplayer ParameterView.244=Date découverte = date fichier ParameterView.245=Si coché, jajuk utilisera la date des fichiers audio comme date de découverte des morceaux
    Nécessite un rafraichissement approfondi pour être pris en compte ParameterView.246=Taille boutons de perspectives (pixels) ParameterView.247=Le chemin de destination contient déjà une configuration jajuk. Cette configuration est maintenant utilisée pour l'utilisateur en cours (l'ancienne configuration a été conservée). Jajuk peut maintenant être redémarré. ParameterView.248=Titre de la fenêtre : ParameterView.249=Réinitialiser préférences ParameterView.250=Réinitialiser les préférences manuelles appliquées sur les morceaux ParameterView.251=L'historique a été réinitialisé avec succès ParameterView.252=Les notations ont été réinitialisées avec succès ParameterView.253=Les préferences ont été réinitialisées avec succès ParameterView.254=Utiliser les noms courts sous Windows ParameterView.255=[Windows 32 bits seulement] Force mplayer à utiliser les noms courts Windows pour les fichiers audio pour corriger des problèmes pour lire les fichiers contenant des caractères spéciaux dans leur nom. ParameterView.256=Nom des couvertures par défaut ParameterView.257=Jajuk prend comme couverture par defaut les images dont le nom est ici donné (sans extension). Il est possible de donner plusieurs noms séparés par des ';'. Exemple : "Folder,front". ParameterView.260=Sauvegarde des couvertures en mode Windows Explorer ParameterView.261=Sauvegarde les couvertures avec le nom folder.jpg/png/... de sorte que Windows Explorer l'utilise comme icone de repertoire. ParameterView.262=Utiliser la normaisation audio ParameterView.263=Maximise le volume sans distordre le son ParameterView.264=Désactive les accès Internet ParameterView.265=Désactive tous les accès Internet depuis Jajuk (LastFM, téléchargement de couvertures, de paroles...). ParameterView.266=Supprime de la file les morceaux joués ParameterView.267=Tous les morceaux déjà joués sont supprimés de la file. ParameterView.268=Configuration du proxy ParameterView.269=Chemin vers l'explorateur ParameterView.270=Chemin vers le binaire de l'explorateur de fichiers externe. ParameterView.271=Afficher le systray ParameterView.272=Si activé, Jajuk peut être controlé depuis la zone de notification (pas supporté sur tous les OS) ParameterView.273=Couvertures en miroir ParameterView.274=Si activé, la vue Couvertures affiche les images avec effet de miroir ParameterView.275=Notification de nouveau morceau : ParameterView.276=Type de notification lors d'un changement de morceau (un toast est une popup qui apparait briévement sur l'écran) ParameterView.277=Canevas pour la notification : ParameterView.278=Ce canevas est utilisé pour construire le texte affiché à chaque changement de morceau ParameterView.279=Canevas d'information : ParameterView.280=Ce canevas est utilisé pour construire le texte affiché dans la vue Information (bas de l'écran) à chaque changement de morceau ParameterView.281=Réduire vers le systray ParameterView.282=Si sélectionné, la fenêtre principale de Jajuk ne sera plus visible que dans le systray lors d'une minimization. Main.21=Confirmation Main.22=Vérifie/Télécharge MPlayer Player.0=En attente de la ligne audio (occupée) Device.25=] Rafraîchit en Device.26= sec - Device.27= nouveaux fichiers Device.31=Sync. [ Device.33=Synchronisation effectuée en Device.35= fichiers créés ( Device.36= Mo) Device.41=Sync. [ Device.42=] Copie [ Device.43= tags illisibles Device.44=Lit Device.45=Copie [ Device.46=Convertit [ Device.47=] vers [ FIFO.4=). Voulez vous le monter ? FIFO.10=Lecture: FIFO.13= kbps FIFO.14=Lit la webradio: HistoryItem.0=dd/MM/yy HH:mm DeviceWizard.0=Assistant de configuration de support DeviceWizard.1=Type de support* : DeviceWizard.2=Nom du support* : DeviceWizard.3=Localisation du support* : DeviceWizard.4=Point de montage Unix (optionnel): DeviceWizard.7=Faire un rafraîchissement immédiat DeviceWizard.8=Montage auto au démarrage DeviceWizard.10=Synchronisé avec : DeviceWizard.11=Synchronisation unidirectionnelle DeviceWizard.12=Tout nouveau fichier trouvé sur le support source est copié sur ce support. Rien n'est écrit sur le support source. DeviceWizard.13=Synchronisation bidirectionnelle DeviceWizard.14=Tout nouveau fichier trouvé sur un support est copié sur l'autre DeviceWizard.43=Veuillez choisir un répertoire DeviceWizard.44=Support créé DeviceWizard.45=Veuillez donner le nom du support. Ex: CD A, Portable... DeviceWizard.46=Veuillez donner la localisation du support. Ex: d:\musique sous Windows, /home/compte/musique sous Unix DeviceWizard.48=Cochez cette option si vous désirez faire un rafraîchissement immédiat du support (conseillé)

    Notez que cette opération peut être longue sur les supports volumineux DeviceWizard.49=Cochez cette option si vous désirez que ce support soit monté automatiquement au démarrage de Jajuk.

    Utile surtout pour les répertoires sur le disque dur courant, à éviter pour les CDs DeviceWizard.50=Donnez la fréquence de recherche de nouveaux fichiers en minutes (0: pas de scan, 0.5 mins est le minimum) DeviceWizard.51=Cochez cette option si vous désirez synchroniser ce support avec un autre DeviceWizard.52=Sélectionnez un support source DeviceWizard.53=Rafraîchir ce support toutes les DeviceWizard.54=min DeviceWizard.55=Erreur : l'interval de rafraîchissement doit être zero ou un nombre >= 0.5. JajukJMenuBar.0=Fichier JajukJMenuBar.1=Ouvrir fichier JajukJMenuBar.3=Quitter JajukJMenuBar.5=Attributs JajukJMenuBar.6=Créer un attribut personnalisé JajukJMenuBar.7=Supprimer un attribut personnalisé JajukJMenuBar.8=Vues JajukJMenuBar.9=Modes JajukJMenuBar.10=Boucle JajukJMenuBar.11=Aléatoire JajukJMenuBar.12=Continue JajukJMenuBar.13=Intro JajukJMenuBar.14=Aide JajukJMenuBar.15=Contenu de l'aide JajukJMenuBar.16=A propos JajukJMenuBar.17=Restaurer les vues par défaut (perspective en cours) JajukJMenuBar.18=Assistant supports JajukJMenuBar.19=Reporter un bug ou une évolution JajukJMenuBar.20=Astuce du jour JajukJMenuBar.21=Configuration JajukJMenuBar.22=Préférences JajukJMenuBar.23=Traces de debug JajukJMenuBar.24=N'afficher que les morceaux accessibles JajukJMenuBar.25=Afficher la vue: JajukJMenuBar.26=Restaurer les vues par défaut (toutes perspectives) JajukJMenuBar.27=Vérifier les mises à jour de Jajuk JajukJMenuBar.28=Outils JajukJMenuBar.29=Programmation JajukJMenuBar.30=Répéter tout JajukJMenuBar.31=Karaoké PlaylistFileItem.1=Nouveautés PlaylistFileItem.2=Nouvelle liste de lecture PlaylistFileItem.3=Signets PlaylistFileItem.4=Best of PlaylistFileItem.5=File de lecture JajukFileChooser.0=Sélection de fichiers SearchBox.0=Effectue une recherche parmi les noms de morceaux, d'auteur, de style, de répertoire. CommandJPanel.0=Voir l'historique CommandJPanel.1=[Ctrl-t] Mode boucle : joue un ou plusieurs morceaux en boucle CommandJPanel.2=[Ctrl-h] Mode aléatoire : joue les morceaux de la sélection au hasard CommandJPanel.3=Mode continue : continue à jouer quand la sélection est terminée CommandJPanel.4=Mode introduction : ne joue qu'une partie de chaque morceau. La position et la durée peuvent être paramétrées dans la vue Préférences de la perspective Configuration CommandJPanel.5=Joue un morceau au hasard parmi toute la collection CommandJPanel.6=Joue vos morceaux favoris CommandJPanel.8=[F9] Passe au morceau précédent dans la sélection courante
    Clic droit: relance le morceau courant
    Clic+[MAJ]: lance l'album précédent
    Clic+[CTRL]: relance l'album courant CommandJPanel.9=[F10] Passe au morceau suivant dans la sélection courante
    Un clic avec la touche MAJ enfoncée lance l'album suivant CommandJPanel.10=[Alt-gr F9] Retour rapide dans le morceau courant
    Un clic avec la touche MAJ enfoncée rejoue le morceau CommandJPanel.13=[Alt-gr F10] Avance rapide dans le morceau courant CommandJPanel.15=Cliquez ici pour changer de mode d'affichage du temps restant CommandJPanel.16=Lancer la sélection du DJ CommandJPanel.17=Gérer les DJ CommandJPanel.18=Lancer la sélection du DJ par défaut CommandJPanel.19=Gérer les ambiances CommandJPanel.20=Morceau après morceau CommandJPanel.21=Album mélangé après album CommandJPanel.22=Album après album CommandJPanel.23=Cliquez pour réinitialiser la zone de recherche CommandJPanel.24=Configurer les webradios CommandJPanel.25=Allumer la webradio CommandJPanel.26=Mode Répéter tout : boucle sur la file entière CommandJPanel.27=Mode Karaoké : supprime les voix (ne s'applique qu'au morceau suivant) InformationJPanel.5=Temps total restant à jouer [Nombre de morceaux restants] InformationJPanel.6=Qualité du fichier InformationJPanel.7=Position dans le morceau courant InformationJPanel.8=%title par %artist sur "%album" InformationJPanel.9= AbstractPlaylistEditorView.0=Morceau AbstractPlaylistEditorView.1=Chemin AbstractPlaylistEditorView.2=Jouer cette liste de lecture AbstractPlaylistEditorView.3=Sauver cette liste de lecture AbstractPlaylistEditorView.4=Ajouter un fichier à cette liste de lecture AbstractPlaylistEditorView.5=Enlever un fichier AbstractPlaylistEditorView.6=Monter AbstractPlaylistEditorView.7=Abaisser AbstractPlaylistEditorView.9=Effacer cette liste de lecture AbstractPlaylistEditorView.10=Ajoute un morceau aléatoire à cette liste de lecture AbstractPlaylistEditorView.15=Listes de lecture AbstractPlaylistEditorView.17=Vous êtes sur le point de mettre simultanément à jour les listes de lecture suivantes : AbstractPlaylistEditorView.18=Morceau dans la file AbstractPlaylistEditorView.19=Morceau répété AbstractPlaylistEditorView.20=Morceau planifié AbstractPlaylistEditorView.21=Elément de liste de lecture AbstractPlaylistEditorView.22=Liste de lecture sauvegardée AbstractPlaylistEditorView.23=Jouer AbstractPlaylistEditorView.24=Pousser AbstractPlaylistEditorView.27=Préparer une soirée AbstractPlaylistEditorView.28=répertoire créé dans AbstractPlaylistEditorView.29=Morceau en cours StatView.0=Autres StatView.1=Répartition par styles StatView.2=Pas de donnée disponible StatView.3=Autres StatView.4=Taille par support (Go) StatView.5=Pas de donnée disponible StatView.7=Taille de la collection par mois StatView.8=Mois StatView.9=Taille (Go) StatView.10=Pas de donnée disponible StatView.12=Nombre total de morceaux par mois StatView.13=Mois StatView.14=Nombre de morceaux StatView.15=Pas de donnée disponible StatView.16=Statistiques StatView.24=avant CDScanView.0=Nom du CD : CDScanView.1=Nom du CD. Ex: CD1, ROCK... CDScanView.2=Nom du CD. Ex: CD1, ROCK... CDScanView.3=Emplacement du CD : CDScanView.4=Emplacement du CD. Ex: '/cdrom' sous Unix, 'e:' sous MS Windows... CDScanView.5=Emplacement du CD. Ex: '/cdrom' sous Unix, 'e:' sous MS Windows... CDScanView.6=Scanner CDScanView.12=Scanneur de CD de données CDScanView.18=Scanne le CD et ajoute automatiquement tous les morceaux trouvés à la collection CDScanView.19=Sélectionne l'emplacement du CD TracksTreeView.0=Arbre des morceaux TracksTreeView.27=Collection TracksTreeView.31= morceaux TracksTreeView.33=Générer un récapitulatif TracksTreeView.34=Obtenir les tags en ligne TracksTreeView.35=Date de découverte TracksTreeView.36=Moins d'une semaine TracksTreeView.37=Moins d'un mois TracksTreeView.38=Mois de six mois TracksTreeView.39=Avant TracksTreeView.40=Moins d'un an TracksTreeView.41=Moins de deux ans TracksTreeView.42=Moins de cinq ans TracksTreeView.43=Moins de dix ans TracksTreeView.44=Moins de trois mois TracksTreeView.45=Année CoverView.2=Effacer physiquement cette pochette CoverView.3=Pochettes CoverView.4=Image précédente du disque ou du Web si la recherche en ligne est enclenchée CoverView.5=Image suivante du disque ou du Web si la recherche en ligne est enclenchée CoverView.6=

    Sauver la pochette avec son nom original

    Avec Control: Sauver sous...

    CoverView.8=Utiliser cette pochette comme défaut pour cet album CoverView.9=pochettes CoverView.10=Sauver la pochette comme CoverView.11=Pochette sauvée CoverView.12=Album CoverView.13=Morceau AnimationView.0=Animation FilesTreeView.0=Arbre fichiers FilesTreeView.3=Copier FilesTreeView.4=Couper FilesTreeView.5=Coller FilesTreeView.7=Effacer FilesTreeView.14=Désynchroniser FilesTreeView.15=Resynchroniser FilesTreeView.16=Créer une liste de lecture FilesTreeView.17=Copier FilesTreeView.18=Couper FilesTreeView.28=Monter FilesTreeView.29=Démonter FilesTreeView.30=Forcer le rafraîchissement FilesTreeView.31=Synchroniser FilesTreeView.32=Tester FilesTreeView.33=Créer des listes de lecture FilesTreeView.40=Copier FilesTreeView.41=Couper FilesTreeView.42=Coller FilesTreeView.47=Collection FilesTreeView.52= fichiers : FilesTreeView.53= Go FilesTreeView.54= Mo FilesTreeView.55=Configurer le support FilesTreeView.59=Désirez vous effectuer un rafraîchissement rapide ou approfondi (relit tous les tags) ? FilesTreeView.60=Rapide FilesTreeView.61=Approfondi FilesTreeView.62=Organiser les fichiers TracksTableView.0=Table des morceaux TracksTableView.7=Jouer TracksTableView.8=Pousser TracksTableView.9=Jouer au hasard TracksTableView.10=Jouer en boucle TracksTableView.11=Jouer l'album entier TracksTableView.12=Jouer l'auteur entier TracksTableView.14=Attributs TracksTableView.15=Poser un signet TracksTableView.16=Pousser comme suivant AbstractTableView.0=Filtre: AbstractTableView.1=Attribut à filtrer AbstractTableView.3=Valeur à utiliser pour filtrer AbstractTableView.4=Appliquer le filtre AbstractTableView.5=Supprimer le filtre AbstractTableView.6=Appliquer un filtre complexe AbstractTableView.7=contient : AbstractTableView.8=Tous AbstractTableView.10=(Pas disponible) AbstractTableView.11=Rendre le tableau éditable AboutView.7=A propos AboutView.8=Licence AboutView.9=Système AboutView.10=A Propos PhysicalPlaylistRepositoryView.0=Jouer PhysicalPlaylistRepositoryView.1=Éditer PhysicalPlaylistRepositoryView.2=Sauver sous PhysicalPlaylistRepositoryView.3=Supprimer PhysicalPlaylistRepositoryView.4=Attributs PhysicalPlaylistRepositoryView.6=Listes de lecture physiques PhysicalPlaylistRepositoryView.8=Spéciales PhysicalPlaylistRepositoryView.9=File courante PhysicalPlaylistRepositoryView.10=File courante: glissez/déposez-y des morceaux pour les jouer PhysicalPlaylistRepositoryView.11=Nouvelle PhysicalPlaylistRepositoryView.12=Nouvelle liste de lecture: glissez/déposez-y des morceaux pour ajouter des morceaux PhysicalPlaylistRepositoryView.13=Signets PhysicalPlaylistRepositoryView.14=Liste de lecture signets: glissez/déposez-y des morceaux pour en garder la trace PhysicalPlaylistRepositoryView.15=Bestof PhysicalPlaylistRepositoryView.16=Liste de lecture bestof: contient vos morceaux préférés PhysicalPlaylistRepositoryView.17=Nouveautés PhysicalPlaylistRepositoryView.18=Liste de lecture des nouveautés: contient les morceaux les plus récents de votre collection PhysicalPlaylistRepositoryView.19=Préparer fête FilesTableView.0=Table des fichiers FilesTableView.15=Jouer tout le répertoire DeviceView.0=Ajouter un support DeviceView.1=Supprimer un support (n'efface rien physiquement sur le disque) DeviceView.2=Propriétés du support sélectionné DeviceView.3=Monter le support sélectionné DeviceView.4=Démonter le support sélectionné DeviceView.5=Tester le support sélectionné DeviceView.6=Forcer le rafraîchissement du support sélectionné DeviceView.7=Synchroniser le support sélectionné DeviceView.8=Monter DeviceView.9=Démonter DeviceView.10=Tester DeviceView.11=Forcer le rafraîchissement DeviceView.12=Synchroniser DeviceView.13=Supprimer le support DeviceView.14=Configurer DeviceView.17=Nouveau DeviceView.18=Ajouter un support DeviceView.21=Le support est disponible DeviceView.22=Le support ne peut être accédé DeviceView.23=Supports JajukWindow.1=Son actif JajukWindow.2=Muet JajukWindow.3=Jajuk JajukWindow.4=Quitter JajukWindow.5=A propos JajukWindow.6=Jouer aléatoirement JajukWindow.7=Jouer le bestof JajukWindow.10=Pause JajukWindow.12=Lecture JajukWindow.13=précédent JajukWindow.14=Suivant JajukWindow.15=Jouer des nouveautés JajukWindow.16=Finir l'album JajukWindow.17=Jajuk: Advanced Jukebox JajukWindow.18=Prêt à jouer JajukWindow.19=[F8] Muet/normal
    Utilisez la molette pour changer le volume JajukWindow.21=Quitter JajukWindow.22=A propos de Jajuk JajukWindow.23=Jouer des morceaux aléatoirement dans la collection toute entière JajukWindow.24=Jouer le bestof dans la collection toute entière JajukWindow.26=[Ctrl-p] Jouer/Pauser JajukWindow.27=[Ctrl-s] Stopper JajukWindow.29=Jouer le morceau précédent. Clic gauche +[MAJ]= album précédent. JajukWindow.30=Jouer le morceau suivant. Clic gauche +[MAJ]= album suivant. JajukWindow.31=Jouer des nouveautés dans la collection toute entière JajukWindow.32=Finir de jouer l'album courant JajukWindow.33=[Ctrl-UP/DOWN] Volume JajukWindow.34=Position JajukWindow.35=Joue : JajukWindow.36=Ambiance courante: JajukWindow.37=Aucune ambiance JajukDonate.1=Donations JajukDonate.2=Jajuk a besoin de fonds pour son infrastructure. JajukDonate.3=Budget JajukDonate.4=Si vous désirez aider le projet, merci de faire une donation. ActiveTagsWizard.1=Tags activables ActiveTagsWizard.2=Tags activés ActiveTagsWizard.3=Il est ici possible de configurer les tags complémentaires à afficher dans Jajuk. Cette liste est construite directement analysant vos fichiers audio (entre autres les tags id3). Si vous activez un nouveau tag, Jajuk procédera à un rafraichissement approfondi pouvant prendre plusieurs minutes en fonction de la taille de votre collection. SimpleDeviceWizard.0=Création rapide de supports HelpView.2=Aide DownloadManager.0=Jajuk nécessite le mot de passe de votre proxy HTTP pour charger des pochettes sur le Web
    Si vous n'en voulez pas, changez vos options de la vue Paramétrage / onglet Réseau
    Si vous n'avez pas de proxy, décochez l'option Proxy DownloadManager.1=Mot de passe requis FirstTimeWizard.0=Démarrage rapide FirstTimeWizard.1=Bienvenue! Cet assistant vous permettra de créer rapidement votre collection. FirstTimeWizard.2=Sélectionnez le répertoire contenant votre musique FirstTimeWizard.4=Afficher l'aide tout de suite FirstTimeWizard.5=Veuillez choisir un répertoire FirstTimeWizard.6=Préférences avancées FirstTimeWizard.7=Fixer l'emplacement de la collection : FirstTimeWizard.8=Répertoire sélectionné : FirstTimeWizard.9=Aucun PropertiesWizard.0=Propriétés de l'élément PropertiesWizard.1=Attribut PropertiesWizard.2=Valeur PropertiesWizard.3=Editable? PropertiesWizard.4=Lien PropertiesWizard.6=Sélection PropertiesWizard.7=Type PropertiesWizard.8=Attribut mis à jour avec succès PropertiesWizard.9=Pas d'attribut éditable pour cette sélection PropertiesWizard.10=attribut(s) fixé(s) PropertiesWizard.11=Ecriture du tag dans: PropertiesWizard.12=Lien vers la fenêtre de propriétés de l'élément NewPropertyWizard.0=Créer un attribut personnel NewPropertyWizard.1=(*) Ajouter un attribut à l'élément NewPropertyWizard.2=(*) Nom de l'attribut NewPropertyWizard.3=(*) Type NewPropertyWizard.4=Format NewPropertyWizard.5=Valeur par défaut CustomPropertyWizard.0=(*) Elément CustomPropertyWizard.1=(*) Nom de l'attribut RemovePropertyWizard.0=Supprimer l'attribut personnel QualityFeedbackWizard.20=L'interface de saisie de votre demande va être maintenant ouverte dans une fenêtre de votre navigateur Web par défaut. Vos dernières actions (nettoyées des données personnelles) ont été copiées, veuillez les coller (CTRL-V ou bouton droit-> coller) dans le champs "Description". S'il s'agit d'un bug, ceci augmente considérablement les chances de résolutions. IncRateAction.0=Augmenter la note du morceau courant SplashScreen.0=Vérifications initiales SplashScreen.1=Chargement de la collection SplashScreen.2=Démarrage du moteur SplashScreen.3=Lancement de l'interface graphique CatalogView.0=Catalogue des albums #Note: CatalogView.2 label musn't be much larger than in English for correct display in 800x600 CatalogView.2=Voir les albums sans pochette CatalogView.3=Forcer la régénération des vignettes CatalogView.4=Taille des vignettes: CatalogView.5=Vignette créée pour: CatalogView.7=Sélectionner une pochette CatalogView.8=Aucune vignette trouvée CatalogView.9=Précèdent CatalogView.10=Suivant CatalogView.11=Page: CatalogView.12=Affiche la page précédente CatalogView.13=Affiche la page suivante CatalogView.14=Sélectionnez la page à afficher CatalogView.15=Taille des vignettes: CatalogView.16=albums CatalogView.17=/page CatalogView.18=Sélection d'une pochette CatalogView.19=Reconstruire les vignettes CatalogView.20=Voir le détail CatalogView.21=Afficher tous les albums CatalogView.22=Afficher les albums avec couverture WikipediaView.0=Wikipedia WikipediaView.1=Choix de la langue: WikipediaView.3=Aucun résultat trouvé WikipediaView.5=Recherche sur le nom de l'auteur WikipediaView.6=Recherche sur le nom de l'album WikipediaView.7=Recherche sur le nom du morceau WikipediaView.8=Chargement WikipediaView.9=La lecture de Wikipedia a échouée WikipediaView.10=La recherche sur un élément inconnu n'est pas supportée TipOfTheDayView.0=Astuces du jour TipOfTheDayView.1=Savez vous... ? TipOfTheDayView.2=Afficher au démarrage ? CDDBWizard.0=Accepter CDDBWizard.1=Fichier CDDBWizard.2=Morceau courant CDDBWizard.3=Album courant CDDBWizard.4=Morceau proposé CDDBWizard.5=Album proposé : CDDBWizard.6=Recherche effectuée. Trouvé CDDBWizard.7=résultats CDDBWizard.12=Pas de résultat CDDBWizard.14=Ce répertoire ne content aucun fichier CDDBWizard.16=Style: CDDBWizard.17=Résultats exacts trouvés CDDBWizard.18=Résultat(s) CDDBWizard.19=Obtenir les tags en ligne DigitalDJWizard.0=Veuillez choisir le type de DJ DigitalDJWizard.1=Programmation basée sur les transitions (ROCK -> POP...) DigitalDJWizard.2=Programmation basée sur les proportions (20% JAZZ, 30% ROCK...) DigitalDJWizard.3=Programmation basée sur les ambiances (Tranquille, Soirée...) DigitalDJWizard.4=Assistant DJ DigitalDJWizard.5=Configuration générale du DJ DigitalDJWizard.6=Nom du DJ(*) DigitalDJWizard.8=Nombre d'étoiles minimum: DigitalDJWizard.9=Durée de recouvrement (sec): DigitalDJWizard.10=Morceaux uniques DigitalDJWizard.11=Effacer DigitalDJWizard.12=Styles origine DigitalDJWizard.13=Styles Destination DigitalDJWizard.14=Sélection des styles (sélections multiples autorisées) DigitalDJWizard.15=Nombre de morceaux DigitalDJWizard.16=Désirez vous ? DigitalDJWizard.17=Créer un nouveau DJ ? DigitalDJWizard.18=Modifier un DJ ? DigitalDJWizard.19=Supprimer un DJ ? DigitalDJWizard.20=DJ basé sur les transitions #limited string size DigitalDJWizard.21=Effacer #limited string size DigitalDJWizard.22=Origine #limited string size DigitalDJWizard.23=Destination #limited string size DigitalDJWizard.24=Nb DigitalDJWizard.26=Veuillez créer au moins une transition #limited string size DigitalDJWizard.27=Sélection des styles #limited string size DigitalDJWizard.28=% DigitalDJWizard.29=DJ basé sur les proportions DigitalDJWizard.30=Veuillez créer au moins une proportion DigitalDJWizard.31=DJ basé sur les ambiances DigitalDJWizard.32=Création DigitalDJWizard.33=Créer une nouvelle ambiance DigitalDJWizard.34=Suppression DigitalDJWizard.35=Effacer l'ambiance sélectionnée DigitalDJWizard.36=Nom de l'ambiance DigitalDJWizard.37=Nom DigitalDJWizard.38=Veuillez créer au moins une ambiance DigitalDJWizard.39=Veuillez remplir le nom de l'ambiance et sélectionner les styles associés DigitalDJWizard.40=Veuillez sélectionner un DJ DigitalDJWizard.41=Veuillez donner un nom au DJ DigitalDJWizard.42=Un DJ portant ce nom existe déjà DigitalDJWizard.43=Modifier un DJ DigitalDJWizard.44=Veuillez sélectionner le DJ à configurer DigitalDJWizard.45=Choix de l'action DigitalDJWizard.46=Choix du type de DJ DigitalDJWizard.47=Veuillez sélectionner ou créer une ambiance DigitalDJWizard.48=Configuration générale DigitalDJWizard.49=Veuillez renseigner les attributs généraux du DJ DigitalDJWizard.50=Veuillez définir les proportions DigitalDJWizard.51=Suppression de DJ DigitalDJWizard.52=Veuillez définir les transitions DigitalDJWizard.53=Nombre d'étoiles minimum pour les morceaux de la sélection (1: tous les morceaux) DigitalDJWizard.54=Durée en seconde de recouvrement audio des morceaux de la selection DigitalDJWizard.55=La sélection du DJ ne contiendra que des morceaux uniques DigitalDJWizard.56=Assistant DJ DigitalDJWizard.57=Gérer les ambiances DigitalDJWizard.58=Sélection de l'ambiance: DigitalDJWizard.59=La somme de toutes les proportions doit être inférieure à 100 % DigitalDJWizard.60=Une ambiance portant ce nom existe déjà DigitalDJWizard.61=Suppression du DJ #limited string size DigitalDJWizard.62=Défauts DigitalDJWizard.63=Ajouter les ambiances par défaut DigitalDJWizard.64=Toutes DigitalDJWizard.65=Sélection du DJ DigitalDJWizard.66=Sélection de l'ambiance par défaut (une ambiance est un groupe de genres, voir le manuel) PreparePartyWizard.1=Préparer une soirée PreparePartyWizard.2=Sélection de l'origine des morceaux PreparePartyWizard.3=Veuillez définir les morceaux de la soirée PreparePartyWizard.4=Sélection des limites PreparePartyWizard.5=Veuillez définir les contraintes PreparePartyWizard.6=DJs PreparePartyWizard.7=Ambiences PreparePartyWizard.8=Playlistes PreparePartyWizard.9=Morceaux aléatoires PreparePartyWizard.10=Nb max morceaux PreparePartyWizard.11=Nombre maximal de morceaux à inclure PreparePartyWizard.12=Taille max. (Mo) PreparePartyWizard.13=Taille (Mo) maximale de la sélection PreparePartyWizard.14=Durée max (mins) PreparePartyWizard.15=Durée maximale en minutes de la soirée PreparePartyWizard.16=Restiction de types PreparePartyWizard.17=Sélection d'une extension de fichier audio. Utile pour filtrer les fichiers en fonction des codecs supportés sur le lecteur de destination. PreparePartyWizard.18=Sélection de la localisation PreparePartyWizard.19=Sélection de l'emplacement des fichiers (audio et playliste) de la soirée PreparePartyWizard.20=Veuillez séléctionner le repertoire de destination PreparePartyWizard.21=Répertoire sélectionné : PreparePartyWizard.22=Répertoire de destination : PreparePartyWizard.23=Les fichiers ont été copiés dans PreparePartyWizard.24=Playliste Best-of PreparePartyWizard.25=Playliste Nouveautés PreparePartyWizard.26=Normaliser les noms de fichiers PreparePartyWizard.27=Normalise les noms de fichiers pour remplacer les caractères spéciaux et assurer une portabilité maximale entre systèmes d'exploitation. PreparePartyWizard.31=Répertoire de destination : PreparePartyWizard.32=Fichiers en attente PreparePartyWizard.33=Fichiers avec signets PreparePartyWizard.34=Tenter de convertir les fichier vers d'autres formats audio PreparePartyWizard.35=Utilise l'outil externe 'pacpl - Perl Audio Converter' pour convertir les fichiers audio si nécessaire PreparePartyWizard.36= fichier(s) ne peuvent être convertis vers le format désiré. PreparePartyWizard.37=(nécessite PACPL, voir Perl Audio Converter) PreparePartyWizard.38=Configurer la conversion audio PreparePartyWizard.39=Veuillez définir la commande à utiliser pour lancer Perl Audio Converter.
    Sous Linux : en général "pacpl" or "perl <install-location>/pacpl.
    Sous MS Windows, en général: "perl <install-location>\pacpl PreparePartyWizard.40=Configurer... Ambiences.0=Rock/Pop Ambiences.1=Rap Ambiences.2=Hard Rock Ambiences.3=Techno Ambiences.4=Electro Ambiences.5=Classique Ambiences.6=Tranquille Ambiences.7=Fiesta Ambiences.8=Jazz Ambiences.9=Musique du monde Ambiences.10=Divers Ambiences.11=Nostalgie Ambiences.12=Indépendant Ambiences.13=Latino DebugLogAction.0=Traces de debug DebugLogAction.1=Rafraîchir CopyClipboardAction.0=Copier l'URL LaunchInBrowserAction.0=Lancer l'URL dans votre navigateur Web ReportAction.0=Le récapitulatif a été correctement généré ReportAction.1=Récapitulatif Jajuk ReportAction.2=Merci de penser à l'environnement et de ne pas imprimer sans nécéssité ReportAction.3=Liste des Albums ReportAction.4=Morceaux par Album ReportAction.5=Liste des Auteurs ReportAction.6=Albums par artistes ReportAction.7=Liste des Styles ReportAction.8=Albums par style ReportAction.9=Auteurs/ albums par style ReportAction.10=Liste des répertoires ReportAction.11=Fichiers par répertoire ReportAction.12=Nom du fichier ReportAction.13=Nom du morceau ReportAction.14=Liste des supports ReportAction.15=Répertoires par support ReportAction.16=Répertoires / fichiers ReportAction.17=Collection ReportAction.18=Auteurs/ albums/ morceaux par style ReportAction.19=Aller à: ActionMove.0=Coller ActionRefresh.0=Forcer le rafraichissement ActionRefresh.1=Rafraichir le répertoire RenameAction.0=Renommer RenameAction.1=Veuillez saisir un nouveau nom de fichier : RenameAction.2=Veuillez saisir un nouveau nom de répertoire : NewFolderAction.0=Nouveau répertoire NewFolderAction.1=Veuillez saisir le nouveau nom : NewFolderAction.2=Un répertoire de même nom existe déjà LyricsView.0=Paroles LyricsView.1=Pas de parole, accès Internet déactivé, utilisez le menu Configuration pour les activer. LyricsView.2=Passer en mode edition des paroles LyricsView.3=Sortir du mode édition des paroles LyricsView.4=Sauvegarder les paroles LyricsView.5=Supprimer les paroles ActionDelete.0=Fichiers supprimés ActionDelete.1=Répertoires supprimés FindDuplicateTracksAction.0=Aucun doublon détecté FindDuplicateTracksAction.1=Des doublons ont été trouvés FindDuplicateTracksAction.2=Rechercher les doublons FindDuplicateTracksAction.3=Liste des doublons FindDuplicateTracksAction.4=Sélectionner tous les doublons RefreshDialog.0=Préparation au rafraîchissement du support... RefreshDialog.1=Rafraîchi le support RefreshDialog.2=Rafraichissement du support: RefreshDialog.3=Nettoyage des anciens fichiers RadioWizard.0=Veuillez sélectionner ou créer une webradio RadioWizard.1=Gérer les webradios RadioWizard.2=Nouvelle RadioWizard.3=Suppression RadioWizard.4=Défauts RadioWizard.5=Une webradio poste déjà ce nom RadioWizard.6=Nom de la Webradio RadioWizard.7=Assistant Webradio RadioWizard.8=URL RadioWizard.9=Nom RadioWizard.10=Mauvaise URL RadioWizard.11=Le nom et l'URL sont obligatoires UpdateManager.0=Une nouvelle version de Jajuk ( UpdateManager.1=) a été détectée, vous pouvez la télécharger à partir de http://jajuk.info UpdateManager.2=Aucune nouvelle version détectée SuggestionView.0=Suggestions SuggestionView.1=Préférés SuggestionView.2=Récents SuggestionView.3=Autres albums SuggestionView.4=Artistes similaires SuggestionView.5=Rarement écoutés #Keep size small (100 pixels) for next item SuggestionView.7=Rien à afficher

    Les informations Last.FM sont affichés à condition:
    • Qu'un morceau soit en train d'être joué
    • Que l'auteur du morceau joué soit connu (tag renseigné)
    • Que l'option "Activer les accès Last.FM en consultation" soit cochée dans la vue Préférences / onglet Last.FM
    • L'option "Désactiver les accès Internet" n'est pas cochée dans la vue Préférence / onglet Réseau
    AbstractThumbnail.0=Ouvrir la page Last.FM AlbumsTableView.0=Table des albums AlbumsTableView.1=Nb morceaux AlarmClock.0=Fixer une alarme AlarmDialog.0=Heure (HH24:MM:SS) AlarmDialog.1=Heure AlarmDialog.2=Minute AlarmDialog.3=Seconde AlarmDialog.4=Action de l'alarme AlarmDialog.5=Sélection d'une action ShowPropertiesAction.0=Propriétés QueueView.1=Vider la file QueueView.2=Scroller automatiquent vers le morceau en cours JajukSlimWindow.0=Afficher/masquer la slimbar JajukFullscreen.0=Activer/désactiver le mode plein écran BanSelectionAction.0=Bannir BanSelectionAction.1=Bannir le morceau pour qu'il ne soit plus selectionné à l'avenir UnBanSelectionAction.0=Gracier UnBanSelectionAction.1=Gracier le morceau qui pourra être seléctionné à nouveau OpenExplorerAction.0=Ouvrir avec explorateur OpenExplorerAction.1=Ouvrir le répertoire avec un explorateur de fichier externe Preference.0=Fixer une préference pour le morceau couranr
    Cette dernière est prise en compte pour le calcul des notes finales Preference.1=Mauvais Preference.2=Faible Preference.3=Moyen Preference.4=Bon Preference.5=Excellent Preference.6=Classique Preference.7=Préferences... Preference.8=Aucune préference ArtistView.0=Vue Artiste Notificator.NONE=Aucune Notificator.TOAST=Toast Notificator.BALLOON=Ballon Notificator.track_change.webradio_title=Web radio : Notificator.track_change.track_title=Morceau : SyncTreeTableAction.0=Synchroniser les vues arbre et tableau SyncTreeTableAction.1=Synchronise les vues arbre et tableau
    Quand utilisé dans une vue arbre, la sélection d'un élément du tableau ouvre et scroll vers l'élément correspondant de l'arbre.
    Quand utilisé dans une vue tableau, la séléction d'un élément de l'arbre filtre le tableau en conséquence. #--- Tips of the day --- TipOfTheDay.0=Vous pouvez rejouer le morceau courant par un Clic Retour rapide + [MAJ] sur le bouton "Précédent" TipOfTheDay.1=Vous pouvez rejouer l'album courant par un Clic Précédant + [MAJ] TipOfTheDay.2=Vous pouvez ajouter des morceaux au hasard dans une liste de lecture en utilisant le bouton "?" dans l'éditeur de liste de lecture TipOfTheDay.3=Vous pouvez récupérer les pochettes en ligne même derrière un proxy en utilisant les options de l'onglet Réseau dans la vue Paramètres TipOfTheDay.4=Jajuk propose une barre réduite (bouton Réduire en haut à droite du menu) pour controler la lecture tout en prennant peu de place sur le bureau TipOfTheDay.5=Vous pouvez masquer les morceaux inaccessibles en utilisant l'option "N'afficher que les morceaux accessibles" TipOfTheDay.6=Vous pouvez piloter une grande partie des fonctions de jajuk au clavier TipOfTheDay.7=Vous pouvez glisser-déposer des éléments des arbres dans la file de lecture TipOfTheDay.8=Vous pouvez écouter des parties de morceaux en utilisant le mode Introduction TipOfTheDay.9=Vous pouvez configurer la durée du fondu enchaîné dans la vue Préférences TipOfTheDay.10=Vous pouvez utiliser Jajuk comme radio-reveil intelligent via la fonction Alarme (menu Outils) TipOfTheDay.11=Vous pouvez piloter les fonctions principales de Jajuk via le tray (Windows et Linux) TipOfTheDay.12=Le thème de Jajuk est configurable via la vue Préférences TipOfTheDay.13=Vous pouvez configurer la comportement du double clic et du glisser-déposer (pousser ou jouer) dans la vue Préférences TipOfTheDay.14=Les morceaux "planifiés" dans l'éditeur de liste de lecture sont les morceaux joués à la fin de la sélection courante TipOfTheDay.15=L'interface graphique de Jajuk est "dockable" et peut être redimensionnée ou réorganisée par glisser-déposer TipOfTheDay.16=Vous pouvez obtenir le nombre total de fichiers ou de morceaux en sélectionnant "Collection" dans les arbres TipOfTheDay.17=Vous pouvez modifier les tags de vos morceaux en ligne via la fonction "Obtenir les tags en ligne" d'un répertoire ou d'un album depuis les arbres TipOfTheDay.18=La barre d'historique fournit tous les morceaux joués précédemment TipOfTheDay.19=Vous pouvez trouver des morceaux rapidement en utilisant la boite de recherche en bas de l'écran TipOfTheDay.20=Vous pouvez communiquer facilement avec l'équipe Jajuk (envoi de bugs, demande de fonctionnalités..) grâce à la fonction Aide -> Reporter un bug ou une évolution TipOfTheDay.21=Vous pouvez créer des DJ intelligents pour faire votre programmation TipOfTheDay.22=Vous pouvez obtenir les paroles des morceaux via la vue "Paroles" TipOfTheDay.23=La vue Suggestions affiche les informations Last.FM de l'auteur en cours comme les auteurs similaires TipOfTheDay.24=Vous pouvez bannir un morceau que vous n'appréciez pas à partir de la barre de lecture ou du paneau de contrôle en bas de l'écran. TipOfTheDay.25=Vous pouvez montrer / masquer les morceaux non accessibles en un seul clic dans le menu "Configuration" TipOfTheDay.26=Vous pouvez choisir l'emplacement de la collection (sur un disque externe par exemple) pour rendre accessible votre collection à plusieurs ordinateurs (vue Préférences / onglet Avancé) TipOfTheDay.27=Vous pouvez maintenant ajouter n'importe quelle vue dans n'importe quelle perspective via le menu "Vues" TipOfTheDay.28=Vous pouvez lancer une page Wikipedia dans votre navigateur Web par défaut en utilisant la fonction "Lancer l'Url" Image:launch_16x16.png/ TipOfTheDay.29=Jajuk supporte les web radios Image:webradio_32x32.png/ TipOfTheDay.30=Jajuk peut être piloté à distance via D-Bus (Linux seulement). Il est alors possible d'utiliser les touches multimédia. Voir le manuel pour plus d'information. ]]> jajuk-1.9.6.orig/src/main/java/org/jajuk/Main.java0000644000175000017500000002124111720500104021532 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk; import ext.JVM; import java.util.Locale; import javax.swing.SwingUtilities; import javax.swing.UIManager; import javax.swing.UnsupportedLookAndFeelException; import org.jajuk.base.Collection; import org.jajuk.services.bookmark.History; import org.jajuk.services.core.ExitService; import org.jajuk.services.core.SessionService; import org.jajuk.services.dj.AmbienceManager; import org.jajuk.services.dj.DigitalDJManager; import org.jajuk.services.lastfm.LastFmManager; import org.jajuk.services.startup.StartupAsyncService; import org.jajuk.services.startup.StartupCollectionService; import org.jajuk.services.startup.StartupControlsService; import org.jajuk.services.startup.StartupEngineService; import org.jajuk.services.startup.StartupGUIService; import org.jajuk.ui.helpers.FontManager; import org.jajuk.util.Conf; import org.jajuk.util.Const; import org.jajuk.util.DownloadManager; import org.jajuk.util.LocaleManager; import org.jajuk.util.UpgradeManager; import org.jajuk.util.UtilGUI; import org.jajuk.util.UtilString; import org.jajuk.util.UtilSystem; import org.jajuk.util.log.Log; import org.jvnet.substance.skin.SubstanceBusinessLookAndFeel; /** * Jajuk launching class. */ public final class Main { /** * private constructor to avoid instantiating utility class. */ private Main() { } /** * Main entry. * * @param args CLI arguments */ public static void main(final String[] args) { // non ui init try { // check JVM version if (!JVM.current().isOrLater(JVM.JDK1_6)) { System.out.println("[BOOT] Java Runtime Environment 1.6 minimum required." + " You use a JVM " + JVM.current()); System.exit(2); // error code 2 : wrong JVM } // set flags from command line options SessionService.handleCommandline(args); // Set System properties setSystemProperties(); // set flags from system properties SessionService.handleSystemProperties(); // Set substance theme (for raw error windows displayed by initial // checkups only) // (must be done in the EDT) SwingUtilities.invokeLater(new Runnable() { @Override public void run() { try { UIManager.setLookAndFeel(new SubstanceBusinessLookAndFeel()); } catch (UnsupportedLookAndFeelException e) { // No Log here, logs are not yet initialized e.printStackTrace(); } } }); // perform initial checkups and create needed files StartupControlsService.initialCheckups(); // log startup depends on : initialCheckups Log.init(); Log.setVerbosity(Log.DEBUG); // Load user configuration. Depends on: initialCheckups Conf.load(); Log.debug("----------------------------------------------------------------------------"); Log.debug("Starting Jajuk " + Const.JAJUK_VERSION + " <" + Const.JAJUK_CODENAME + ">" + " " + Const.JAJUK_VERSION_DATE); // Full substance configuration now // (must be done in the EDT) SwingUtilities.invokeLater(new Runnable() { @Override public void run() { UtilGUI.setupSubstanceLookAndFeel(Conf.getString(Const.CONF_OPTIONS_LNF)); } }); // Set default fonts FontManager.getInstance().setDefaultFont(); // Detect current release UpgradeManager.detectRelease(); // Set actual log verbosity. Depends on: // Conf.load if (!SessionService.isTestMode()) { // test mode is always in debug mode Log.setVerbosity(Integer.parseInt(Conf.getString(Const.CONF_OPTIONS_LOG_LEVEL))); } // Set locale. setSystemLocal LocaleManager.setLocale(new Locale(Conf.getString(Const.CONF_OPTIONS_LANGUAGE))); // Display the splash screen through a invokeAndWait StartupGUIService.launchSplashScreen(); // Apply any proxy (requires load conf) DownloadManager.setDefaultProxySettings(); // Registers ItemManager managers StartupCollectionService.registerItemManagers(); // Upgrade configuration from previous releases UpgradeManager.upgradeStep1(); // Display user system configuration Log.debug("Workspace used: " + SessionService.getWorkspace()); Log.debug(UtilString.getAnonymizedSystemProperties().toString()); // Display user Jajuk configuration Log.debug(UtilString.getAnonymizedJajukProperties().toString()); // check for another session (needs setLocal) SessionService.checkOtherSession(); // Create a session file SessionService.createSessionFile(); // Register device types StartupCollectionService.registerDevicesTypes(); // registers supported audio supports and default properties. Display a // "Downloading mplayer" message by default in the splash screen in case // of it is downloaded StartupGUIService.fireStepOneOver(); StartupCollectionService.registerTypes(); // Display progress StartupGUIService.fireStepTwoOver(); // Load collection StartupCollectionService.loadCollection(); // Upgrade step2 (after collection load) UpgradeManager.upgradeStep2(); // Clean the collection up Collection.cleanupLogical(); // Display progress StartupGUIService.fireStepThreeOver(); // Load history History.load(); // Load ambiences AmbienceManager.getInstance().load(); // Start LastFM support LastFmManager.getInstance(); // Load djs DigitalDJManager.getInstance().loadAllDJs(); // Various asynchronous startup actions that needs collection load boolean bCollectionLoadRecover = StartupCollectionService.isCollectionLoadRecover(); StartupAsyncService.startupAsyncAfterCollectionLoad(bCollectionLoadRecover); // Auto mount devices, freeze for SMB drives // if network is not reachable // Do not start this if first session, it is causes concurrency with // first refresh thread if (!UpgradeManager.isFirstSession()) { StartupEngineService.autoMount(); } // Launch startup track if any (but don't start it if first session // because the first refresh is probably still running) if (!UpgradeManager.isFirstSession()) { StartupEngineService.launchInitialTrack(); } // Launch the right jajuk window StartupGUIService.launchUI(); // Late collection upgrade actions UpgradeManager.upgradeStep3(); } catch (final Exception e) { // last chance to catch any error for // logging // purpose e.printStackTrace(); Log.error(106, e); ExitService.exit(1); } catch (final Error error) { // last chance to catch any error for logging purpose error.printStackTrace(); Log.error(106, error); ExitService.exit(1); } finally { // make sure to close splash screen in all cases // (i.e. if UI is not started) StartupGUIService.startupOver(); } } /* * Initialize some useful System properties For some reasons (at least with Apple JVM), this * method must be in the Main class. Should be called ASAP in the startup process */ /** * Sets the system properties. * DOCUMENT_ME */ public static void setSystemProperties() { if (UtilSystem.isUnderOSX()) { String title = "Jajuk" + (SessionService.isTestMode() ? " (test)" : ""); System.setProperty("com.apple.mrj.application.apple.menu.about.name", title); // Make sure to disable Mac native menu, it can't display jajuk menu property System.setProperty("apple.laf.useScreenMenuBar", "false"); // Allow file selection of a directory System.setProperty("apple.awt.fileDialogForDirectories", "true"); // In full screen mode, only use a single screen instead of darkening others System.setProperty("apple.awt.fullscreencapturealldisplays", "false"); } } } jajuk-1.9.6.orig/src/main/java/org/qdwizard/0000755000175000017500000000000011720500104020524 5ustar drazzibdrazzibjajuk-1.9.6.orig/src/main/java/org/qdwizard/ActionsPanel.java0000644000175000017500000001355011720500104023753 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.qdwizard; import java.awt.Color; import java.awt.Dimension; import java.awt.Font; import java.awt.Graphics2D; import java.awt.GridLayout; import java.awt.RenderingHints; import java.awt.event.ActionListener; import javax.swing.BorderFactory; import javax.swing.Box; import javax.swing.BoxLayout; import javax.swing.JButton; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.SwingConstants; /** * Action panel *

    * contains a problem area where problems are displayed and a buttons area * (Previous, Next, Finish, Cancel). * * @author Bertrand Florat * @created 1 may 2006 */ class ActionsPanel extends JPanel { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** Problem text area. */ JLabel jlProblem; /** DOCUMENT_ME. */ JButton jbPrevious; /** DOCUMENT_ME. */ JButton jbNext; /** DOCUMENT_ME. */ JButton jbFinish; /** DOCUMENT_ME. */ JButton jbCancel; /** DOCUMENT_ME. */ private Color backgroundColor; /** DOCUMENT_ME. */ private Color backgroundColorProblem; /** Associated action listener. */ ActionListener al; /** * The Constructor. * * @param al associated action listener */ public ActionsPanel(ActionListener al) { backgroundColor = Color.WHITE; backgroundColorProblem = Color.WHITE; // Problem panel jlProblem = new JLabel(); jlProblem.setForeground(Color.RED); jlProblem.setFont(new Font("Dialog", Font.BOLD, 12)); //$NON-NLS-1$ jlProblem.setHorizontalAlignment(SwingConstants.CENTER); // Action buttons JPanel jpButtons = new JPanel(); jpButtons.setLayout(new BoxLayout(jpButtons, BoxLayout.X_AXIS)); Dimension dimButtons = new Dimension(150, 20); jbPrevious = new JButton("< " + Langpack.getMessage("Previous")); jbPrevious.setPreferredSize(dimButtons); jbPrevious.addActionListener(al); jbPrevious.setActionCommand("Prev"); //$NON-NLS-1$ jbNext = new JButton(Langpack.getMessage("Next") + " >"); jbNext.addActionListener(al); jbNext.setActionCommand("Next"); //$NON-NLS-1$ jbNext.setPreferredSize(dimButtons); jbFinish = new JButton(Langpack.getMessage("Finish")); jbFinish.addActionListener(al); jbFinish.setActionCommand("Finish"); //$NON-NLS-1$ jbFinish.setPreferredSize(dimButtons); jbCancel = new JButton(Langpack.getMessage("Cancel")); jbCancel.addActionListener(al); jbCancel.setActionCommand("Cancel"); //$NON-NLS-1$ jbCancel.setPreferredSize(dimButtons); jpButtons.add(Box.createHorizontalStrut(10)); jpButtons.add(Box.createHorizontalGlue()); jpButtons.add(jbPrevious); jpButtons.add(Box.createHorizontalStrut(5)); jpButtons.add(jbNext); jpButtons.add(Box.createHorizontalStrut(10)); jpButtons.add(jbFinish); jpButtons.add(Box.createHorizontalStrut(20)); jpButtons.add(jbCancel); jpButtons.add(Box.createHorizontalStrut(10)); jpButtons.setBorder(BorderFactory.createEmptyBorder(10, 0, 10, 0)); jpButtons.setOpaque(false); jlProblem.setOpaque(false); setOpaque(false); // Main panel setLayout(new GridLayout(2, 1)); add(jlProblem); add(jpButtons); } /** * Set buttons states. * * @param bPrevious DOCUMENT_ME * @param bNext DOCUMENT_ME * @param bFinish DOCUMENT_ME * @param bCancel DOCUMENT_ME */ void setState(boolean bPrevious, boolean bNext, boolean bFinish, boolean bCancel) { jbPrevious.setEnabled(bPrevious); jbFinish.setEnabled(bFinish); jbNext.setEnabled(bNext); jbCancel.setEnabled(bCancel); } /** * Sets the problem. * * @param problem the new problem */ void setProblem(String problem) { String sProblem = problem; jlProblem.setText(sProblem); } /** * Set the background color of the ActionPanel. * * @param color DOCUMENT_ME */ public void setBackgroundColor(Color color) { this.backgroundColor = color; } /** * Set the background color of the ActionPanel's Problem notification area. * * @param color DOCUMENT_ME */ public void setProblemBackgroundColor(Color color) { this.backgroundColorProblem = color; } /** * Set the background color of the ActionPanel's Problem notification area. * * @param color DOCUMENT_ME */ public void setProblemTextColor(Color color) { jlProblem.setForeground(color); } /* (non-Javadoc) * @see javax.swing.JComponent#paint(java.awt.Graphics) */ @Override public void paint(java.awt.Graphics g) { Graphics2D g2D = (Graphics2D) g; g2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); java.awt.Rectangle rect = getBounds(); g2D.setColor(backgroundColor); g2D.fillRect(0, 0, rect.width, rect.height); if ((jlProblem != null) && (jlProblem.getText() != null) && jlProblem.getText().length() > 0) { rect = jlProblem.getBounds(); g2D.setColor(backgroundColorProblem); g2D.fillRect(rect.x, rect.y, rect.width, rect.height); } super.paint(g); g2D.setColor(java.awt.Color.LIGHT_GRAY); g2D.drawLine(rect.x, 0, rect.width, 0); } } jajuk-1.9.6.orig/src/main/java/org/qdwizard/Screen.java0000644000175000017500000001334011720500104022607 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.qdwizard; import java.util.Map; import javax.swing.JPanel; import javax.swing.SwingUtilities; /** * A wizard screen *

      *
    • For each wizard page, create a public Screen class. You have to * implement initUI(), getDescription() and getName() abstract methods.
    • *
    • getName() method should return the step name and getDescription() the * step description (return null if no description needed).
    • *
    • initUI() method contains graphical code for your screen. This method is * automatically called from screen constructor so don't call it.
    • *
    * * @author Bertrand Florat * @created 1 may 2006 */ public abstract class Screen extends JPanel { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** DOCUMENT_ME. */ private final ScreenState state; /** DOCUMENT_ME. */ public Map data; /** DOCUMENT_ME. */ private Wizard wizard; /** * Construct a screen. */ public Screen() { data = Wizard.data; state = new ScreenState(true, true, true, false, null); initUI(); } /** * Give here the step name. * * @return screen name */ @Override abstract public String getName(); /** * Screen description (optional). * * @return screen description */ abstract public String getDescription(); /** * Can finish. * DOCUMENT_ME * * @return true if... */ boolean canFinish() { // Can finish only if none problem return state.getCanFinish() && (state.getProblem() == null); } /** * Set whether the finish button should be enabled. * * @param b DOCUMENT_ME */ public void setCanFinish(boolean b) { state.setCanFinish(b); notifyGUI(); } /** * Can go next. * DOCUMENT_ME * * @return true if... */ boolean canGoNext() { // if screen is last one, cannot go further return state.getCanGoNext() && !state.getCanFinish() && (state.getProblem() == null); } /** * Can cancel. * DOCUMENT_ME * * @return true if... */ public boolean canCancel() { return state.getCanCancel(); } /** * Can go previous. * DOCUMENT_ME * * @return true if... */ boolean canGoPrevious() { return state.getCanGoPrevious(); } /** * Set whether the next button should be enabled. * * @param b DOCUMENT_ME */ void setCanGoNext(boolean b) { state.setCanGoNext(b); notifyGUI(); } /** * Set whether the previous button should be enabled. * * @param b DOCUMENT_ME */ void setCanGoPrevious(boolean b) { state.setCanGoPrevious(b); notifyGUI(); } /** * Set whether the cancel (or System menu close) button should be enabled. * * @param b DOCUMENT_ME */ public void setCanCancel(boolean b) { state.setCanCancel(b); notifyGUI(); } /** * Set a problem (set to null if problem is fixed). * * @param sProblem Problem string or null if no more problem */ public void setProblem(String sProblem) { state.setProblem(sProblem); notifyGUI(); } /** * Get current problem. * * @return the current problem */ public String getProblem() { return state.getProblem(); } /** * UI creation. */ abstract public void initUI(); /** * Called by wizard before the screen is displayed. This happens only in * forward mode, which means onEnter won't be called when you return to a * screen via the previous button. */ public void onEnter() { // required by interface, but nothing to do here... } /** * Called by wizard before the screen is left. This happens only in forward * mode, which means onLeave won't be called when you leave the screen via the * previous button. *

    * * @return return true if the Wizard should display the next screen * return false if the Wizard should stay on the current screen */ public boolean onNext() { return true; } /** * Called by wizard when the wizard is being canceled. Use this function to * clean up (like stop any threads that this Screen might have created) */ public void onCancelled() { // required by interface, but nothing to do here... } /** * Called by wizard when the wizard is closing because the Finish button was * pressed. Use this function to clean up (like stop any threads that this * Screen might have created) */ public void onFinished() { // required by interface, but nothing to do here... } /** * access to wizard instance. * * @return the wizard */ public Wizard getWizard() { return wizard; } /** * Sets the wizard. * * @param wizard the new wizard */ protected void setWizard(Wizard wizard) { this.wizard = wizard; } /** * Notify gui. * DOCUMENT_ME */ private void notifyGUI() { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { Screen.this.wizard.updateGUI(); } }); } } jajuk-1.9.6.orig/src/main/java/org/qdwizard/package.html0000644000175000017500000000017111720500104023004 0ustar drazzibdrazzib DOCUMENT_ME jajuk-1.9.6.orig/src/main/java/org/qdwizard/Langpack.java0000644000175000017500000000676611720500104023126 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.qdwizard; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; /** * This class includes all langpacks strings. Note that we don't use * ResourceBundle here to ease translation tasks (properties doesn't support * non-latin1 characters) and because QDwizard comes with very few strings */ public class Langpack { /** DOCUMENT_ME. */ private static List defaults = Arrays.asList("Finish", "Cancel", "Previous", "Next"); // Strings content : "Finish", "Cancel", "Previous", "Next" /** DOCUMENT_ME. */ static private Map> strings = new HashMap>(4); /** static set of strings, can contain non-ISO8859 chars * */ static { strings.put(new Locale("ca"), Arrays.asList("Finalitzar", "Cancelar", "Anterior", "Següent")); strings.put(new Locale("cs"), Arrays.asList("Dokončit", "Storno", "Předchozí", "Další")); strings.put(new Locale("de"), Arrays.asList("Fertig", "Abbrechen", "Zurück", "Weiter")); strings.put(new Locale("en"), defaults); strings.put(new Locale("es"), Arrays.asList("Finalizar", "Cancelar", "Anterior", "Siguiente")); strings.put(new Locale("el"), Arrays.asList("Τέλος", "Ακύρωση", "Προηγούμενο", "Επόμενο")); strings.put(new Locale("fr"), Arrays.asList("Terminé", "Annuler", "Précédent", "Suivant")); strings.put(new Locale("gl"), Arrays.asList("Rematar", "Cancelar", "Anterior", "Seguinte")); strings.put(new Locale("nl"), Arrays.asList("Afgerond", "Annuleren", "Vooropgaand", "Aanstaande")); strings.put(new Locale("ru"), Arrays.asList("Готово", "Отмена", "Назад", "Дальше")); strings.put(new Locale("pt"), Arrays.asList("Terminar", "Cancelar", "Anterior", "Seguinte")); } /** Used locale for the wizard buttons, use English as a default *. */ private static Locale locale = new Locale("en"); /** * private constructor for utility class with only static methods. */ private Langpack() { super(); } /** * Set the QDwizard locale. * * @param locale DOCUMENT_ME */ public static void setLocale(Locale locale) { Langpack.locale = locale; } /** * Return label for given key or null if not matching key is found. * * @param key the key as a string using the default locale * * @return label for given key or null if not matching key is found */ public static String getMessage(String key) { List labels = strings.get(locale); // If the local is unknown, use default one if (labels == null) { labels = defaults; } int index = defaults.indexOf(key); return labels.get(index); } } jajuk-1.9.6.orig/src/main/java/org/qdwizard/Header.java0000644000175000017500000000666111720500104022570 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.qdwizard; import java.awt.Dimension; import java.awt.Font; import java.awt.Graphics2D; import java.awt.GridLayout; import java.awt.Image; import java.awt.RenderingHints; import javax.swing.ImageIcon; import javax.swing.JPanel; /** * Screen Header *

    * Contains a wizard title, a subtitle used to display the name of the current * screen and an optional background image *

    . * * @author Bertrand Florat * @created 1 may 2006 */ class Header extends JPanel { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1L; /** DOCUMENT_ME. */ JPanel jta; /** DOCUMENT_ME. */ Image backgroundImage; /** DOCUMENT_ME. */ ImageIcon icon; /** DOCUMENT_ME. */ String sTitleText; /** DOCUMENT_ME. */ String sSubtitleText; /** * The Constructor. */ public Header() { setLayout(new GridLayout()); jta = new JPanel(); jta.setOpaque(true); jta.setPreferredSize(new Dimension(0, 70)); add(jta); } /** * Set the header title text. * * @param sText DOCUMENT_ME */ public void setTitleText(String sText) { sTitleText = sText; } /** * Set the header subtitle text. * * @param sText DOCUMENT_ME */ public void setSubtitleText(String sText) { sSubtitleText = sText; } /** * Set the header Image. * * @param img DOCUMENT_ME */ public void setImage(Image img) { backgroundImage = img; } /** * Set the header right-side icon. * * @param icon DOCUMENT_ME */ public void setIcon(ImageIcon icon) { this.icon = icon; } /* (non-Javadoc) * @see javax.swing.JComponent#paint(java.awt.Graphics) */ @Override public void paint(java.awt.Graphics g) { super.paint(g); Graphics2D g2D = (Graphics2D) g; java.awt.Rectangle rect = getBounds(); g2D.setColor(java.awt.Color.WHITE); g2D.fillRect(rect.x, rect.y, rect.width, rect.height); if (backgroundImage != null) { g2D.drawImage(backgroundImage, 0, 0, rect.width, rect.height, this); } if (icon != null) { int h = icon.getIconHeight(); int w = icon.getIconWidth(); g2D.drawImage(icon.getImage(), rect.width - w - 10, (rect.height - h) / 2, w, h, this); } g2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g2D.setColor(java.awt.Color.BLACK); g2D.setFont(new Font("Dialog", Font.BOLD, 14)); g2D.drawString(sTitleText, 20, 25); g2D.setFont(new Font("Dialog", Font.PLAIN, 13)); g2D.drawString(sSubtitleText, 20, 50); g2D.setColor(java.awt.Color.BLACK); g2D.drawLine(rect.x, rect.height - 1, rect.width, rect.height - 1); } }jajuk-1.9.6.orig/src/main/java/org/qdwizard/ClearPoint.java0000644000175000017500000000203411720500104023426 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.qdwizard; /** * Screens needing to clear wizard cache (values filled up in different screens) * should implement this interface. * * @author Bertrand Florat */ public interface ClearPoint { } jajuk-1.9.6.orig/src/main/java/org/qdwizard/Wizard.java0000644000175000017500000004600211720500104022631 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.qdwizard; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Cursor; import java.awt.Frame; import java.awt.Image; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.ComponentEvent; import java.awt.event.ComponentListener; import java.awt.event.WindowEvent; import java.awt.event.WindowListener; import java.util.Arrays; import java.util.HashMap; import java.util.Locale; import java.util.Map; import javax.swing.BorderFactory; import javax.swing.ImageIcon; import javax.swing.JDialog; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.ScrollPaneConstants; import javax.swing.WindowConstants; import org.jajuk.ui.widgets.JajukJDialog; import org.jajuk.util.log.Log; /** * A Wizard dialog displaying one to many screens *
      *
    • Create a class that extends Wizard. You have to implement * getPreviousScreen(), getNextScreen() and finish() abstract methods
    • *
    • Displaying the wizard:
    • * *
       * MyWizard wizard = new MyWizard(String sName,Class initial,
       * ImageIcon icon,Frame parentWindow,
       * Locale locale,int iHSize,int iVSize);
       * wizard.show();
       * 
      * *
    • finish() method implements actions to be done at the end of the wizard
    • *
    • getPreviousScreen() and getNextScreen() have to return previous or next * screen class. Example:
    • * *
       * public Class getNextScreen(Class screen) {
       * if (ActionSelectionPanel.class.equals(getCurrentScreen())) {
       * String sAction = (String) data.get(KEY_ACTION);
       * if (ActionSelectionPanel.ACTION_CREATION.equals(sAction)) {
       * return TypeSelectionPanel.class;
       * } else if (ActionSelectionPanel.ACTION_DELETE.equals(sAction)) {
       * return RemovePanel.class;
       * }
       * }
       * }
       * 
      * *
    * * @author Bertrand Florat * @created 1 may 2006 */ public abstract class Wizard implements ActionListener, WindowListener { /** Wizard name. */ private String sName; /** Current screen. */ private Screen current; /** Wizard left side icon. */ private ImageIcon icon; /** Wizard data. */ protected final static Map data = new HashMap(10); /** Wizard header. */ private Header header; /** Wizard action Panel. */ private ActionsPanel actions; /** Wizard dialog. */ private JDialog dialog; /** Parent window. */ private Frame parentWindow; /** Screens instance repository. */ private Map, Screen> hmClassScreens = new HashMap, Screen>( 10); /** Default Wizard size. */ protected static final int DEFAULT_H_SIZE = 700; /** The Constant DEFAULT_V_SIZE. DOCUMENT_ME */ protected static final int DEFAULT_V_SIZE = 500; /** The Constant DEFAULT_H_LAYOUT_PADDING. DOCUMENT_ME */ protected static final int DEFAULT_H_LAYOUT_PADDING = 5; /** The Constant DEFAULT_V_LAYOUT_PADDING. DOCUMENT_ME */ protected static final int DEFAULT_V_LAYOUT_PADDING = 5; /** Was the Wizard Canceled?. */ private boolean bCancelled; /** Layout Padding. */ private int layoutHPadding = DEFAULT_H_LAYOUT_PADDING; /** DOCUMENT_ME. */ private int layoutVPadding = DEFAULT_V_LAYOUT_PADDING; /** * Wizard constructor. * * @param sName Wizard name displayed in dialog title * @param initial Initial screen class * @param icon Wizard icon (null if no icon) * @param backgroundImage background image * @param parentWindow wizard parent window * @param locale Wizard locale * @param iHSize Horizontal size * @param iVSize Vertical size * @param iLayoutHPadding Horizontal layout padding * @param iLayoutVPadding Vertical layout padding */ @SuppressWarnings("unchecked") public Wizard(String sName, Class initial, ImageIcon icon, Image backgroundImage, Frame parentWindow, Locale locale, int iHSize, int iVSize, int iLayoutHPadding, int iLayoutVPadding) { bCancelled = false; this.sName = sName; this.parentWindow = parentWindow; if (locale != null) { Langpack.setLocale(locale); } else { Langpack.setLocale(Locale.getDefault()); } this.icon = icon; this.layoutHPadding = iLayoutHPadding; this.layoutVPadding = iLayoutVPadding; createUI(); header.setImage(backgroundImage); setScreen(initial); current.onEnter(); dialog.setSize(iHSize, iVSize); } /** * Wizard constructor. * * @param sName Wizard name displayed in dialog title * @param initial Initial screen class * @param icon Wizard icon (null if no icon) * @param parentWindow wizard parent window * @param locale Wizard locale * @param iHSize Horizontal size * @param iVSize Vertical size */ @SuppressWarnings("unchecked") public Wizard(String sName, Class initial, ImageIcon icon, Frame parentWindow, Locale locale, int iHSize, int iVSize) { bCancelled = false; this.sName = sName; this.parentWindow = parentWindow; if (locale != null) { Langpack.setLocale(locale); } else { Langpack.setLocale(Locale.getDefault()); } this.icon = icon; createUI(); setScreen(initial); current.onEnter(); dialog.setSize(iHSize, iVSize); } /** * Wizard constructor. * * @param sName Wizard name displayed in dialog title * @param initial Initial screen class * @param icon Wizard icon (null if no icon) * @param backgroundImage Wizard header background (null if no image) * @param parentWindow wizard parent window * @param locale Wizard locale */ public Wizard(String sName, Class initial, ImageIcon icon, Image backgroundImage, Frame parentWindow, Locale locale) { this(sName, initial, icon, backgroundImage, parentWindow, locale, DEFAULT_H_SIZE, DEFAULT_V_SIZE, DEFAULT_H_LAYOUT_PADDING, DEFAULT_V_LAYOUT_PADDING); } /** * Wizard constructor. * * @param sName Wizard name displayed in dialog title * @param initial Initial screen class * @param icon Wizard icon (null if no icon) * @param parentWindow wizard parent window * @param locale Wizard locale */ public Wizard(String sName, Class initial, ImageIcon icon, Frame parentWindow, Locale locale) { this(sName, initial, icon, null, parentWindow, locale, DEFAULT_H_SIZE, DEFAULT_V_SIZE, DEFAULT_H_LAYOUT_PADDING, DEFAULT_V_LAYOUT_PADDING); } /** * Wizard constructor (uses default locale). * * @param sName Wizard name displayed in dialog title * @param initial Initial screen class * @param icon Wizard icon (null if no icon) * @param backgroundImage Wizard header background (null if no image) * @param parentWindow wizard parent window */ public Wizard(String sName, Class initial, ImageIcon icon, Image backgroundImage, Frame parentWindow) { this(sName, initial, icon, backgroundImage, parentWindow, Locale.getDefault()); } /** * Wizard constructor (uses default locale). * * @param sName Wizard name displayed in dialog title * @param initial Initial screen class * @param icon Wizard icon (null if no icon) * @param parentWindow wizard parent window */ public Wizard(String sName, Class initial, ImageIcon icon, Frame parentWindow) { this(sName, initial, icon, null, parentWindow, Locale.getDefault()); } /** * Show. * DOCUMENT_ME */ public void show() { dialog.setVisible(true); } /** * access to the JDialog of the wizard, in case we need it (for instance to * set a glass pane when waiting). * * @return the wizard dialog */ public JDialog getDialog() { return dialog; } /** * UI manager. */ private void createUI() { dialog = new JajukJDialog(parentWindow, true);// modal // Set default size dialog.setSize(DEFAULT_H_SIZE, DEFAULT_V_SIZE); dialog.setTitle(sName); header = new Header(); actions = new ActionsPanel(this); dialog.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE); dialog.addWindowListener(this); display(); dialog.setLocationRelativeTo(parentWindow); } /* * (non-Javadoc) * * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent) */ @Override public void actionPerformed(ActionEvent ae) { dialog.setCursor(new Cursor(Cursor.WAIT_CURSOR)); try { // Previous required. Note that the previous button is enabled only // if the user can go previous if (ae.getActionCommand().equals("Prev")) { //$NON-NLS-1$ setScreen(getPreviousScreen(current.getClass())); } else if (ae.getActionCommand().equals("Next")) { //$NON-NLS-1$ current.onNext(); setScreen(getNextScreen(current.getClass())); current.onEnter(); } else if (ae.getActionCommand().equals("Cancel")) { //$NON-NLS-1$ current.onCancelled(); data.clear(); bCancelled = true; onCancel(); dialog.dispose(); } else if (ae.getActionCommand().equals("Finish")) { //$NON-NLS-1$ current.onFinished(); finish(); dialog.dispose(); } } finally { dialog.setCursor(new Cursor(Cursor.DEFAULT_CURSOR)); } } /** * Set the screen to display a a class. * * @param screenClass DOCUMENT_ME */ private void setScreen(Class screenClass) { Screen screen = null; try { // If the class is an clear point, we clean up all previous screens if (Arrays.asList(screenClass.getInterfaces()).contains(ClearPoint.class)) { clearScreens(); screen = screenClass.newInstance(); } // otherwise, try to get a screen from buffer or create it if needed else { if (!hmClassScreens.containsKey(screenClass)) { screen = screenClass.newInstance(); hmClassScreens.put(screenClass, screen); } screen = hmClassScreens.get(screenClass); } } catch (InstantiationException e) { Log.error(e); throw new RuntimeException("setScreen " + screenClass + " caused " + e.toString(), e); } catch (IllegalAccessException e) { Log.error(e); throw new RuntimeException("setScreen " + screenClass + " caused " + e.toString(), e); } current = screen; current.setWizard(this); current.setCanGoPrevious((getPreviousScreen(screenClass) != null)); current.setCanGoNext((getNextScreen(screenClass) != null)); String sDesc = screen.getDescription(); if (sDesc != null) { header.setTitleText(screen.getName()); header.setSubtitleText(sDesc); } else { header.setTitleText(screen.getName()); header.setSubtitleText(""); } display(); } /** * Called at each screen refresh. */ private void display() { ((JPanel) dialog.getContentPane()).removeAll(); dialog.setLayout(new BorderLayout(layoutHPadding, layoutVPadding)); if (icon != null) { final JLabel jlIcon = new JLabel(icon); dialog.add(jlIcon, BorderLayout.WEST); // Add a listener to resize left side image if wizard window is // resized jlIcon.addComponentListener(new ComponentListener() { @Override public void componentShown(ComponentEvent e) { // nothing to do here } /* (non-Javadoc) * @see java.awt.event.ComponentListener#componentResized(java.awt.event.ComponentEvent) */ @Override public void componentResized(ComponentEvent e) { Wizard.this.icon = getResizedImage(icon, jlIcon.getWidth(), jlIcon.getHeight()); jlIcon.setIcon(Wizard.this.icon); jlIcon.setVisible(true); // Display icon new size, useful to create an image with // right default size System.out.println("Icon new size : " + jlIcon.getIcon().getIconWidth() + "x" + jlIcon.getIcon().getIconHeight()); } @Override public void componentMoved(ComponentEvent e) { // nothing to do here } @Override public void componentHidden(ComponentEvent e) { // nothing to do here } }); } dialog.add(actions, BorderLayout.SOUTH); JScrollPane jsp = new JScrollPane(header); jsp.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); jsp.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER); jsp.setBorder(BorderFactory.createEmptyBorder()); dialog.add(jsp, BorderLayout.NORTH); if (current != null) { dialog.add(current, BorderLayout.CENTER); } dialog.getRootPane().setDefaultButton(actions.jbNext); ((JPanel) dialog.getContentPane()).revalidate(); dialog.getContentPane().repaint(); } /** * Set the header image. * * @param img DOCUMENT_ME */ public void setHeaderImage(Image img) { header.setImage(img); } /** * Set the header icon. * * @param icon DOCUMENT_ME */ public void setHeaderIcon(ImageIcon icon) { header.setIcon(icon); } /** * Set the background color of the ActionPanel. * * @param color DOCUMENT_ME */ public void setActionsBackgroundColor(Color color) { actions.setBackgroundColor(color); } /** * Set the background color of the ActionPanel's Problem notification area. * * @param color DOCUMENT_ME */ public void setProblemBackgroundColor(Color color) { actions.setProblemBackgroundColor(color); } /** * Gets the previous screen. * * @param screen DOCUMENT_ME * * @return previous screen class */ abstract public Class getPreviousScreen(Class screen); /** * Clear screens history. */ public final void clearScreens() { hmClassScreens.clear(); } /** * Gets the next screen. * * @param screen DOCUMENT_ME * * @return next screen class */ abstract public Class getNextScreen(Class screen); /** * Get current screen. * * @return current screen class */ public Class getCurrentScreen() { return this.current.getClass(); } /** * Refresh buttons and problems. Called asynchronously by the screens or by * the wizard itself. */ public void updateGUI() { boolean bPrevious = current.canGoPrevious(); boolean bNext = current.canGoNext(); boolean bFinish = current.canFinish(); boolean bCancel = current.canCancel(); actions.setState(bPrevious, bNext, bFinish, bCancel); actions.setProblem(current.getProblem()); } /** * Finish action. Called when user clicks on "finish" */ abstract public void finish(); /** * Called when user clicks on "cancel". Override it if you want to do * something in cancel such as display a confirmation dialog. *

    * * @return return true if the Wizard should continue to close * return false if the Wizard should abort the cancellation */ public boolean onCancel() { return true; } /** * Icon resizing. * * @param img DOCUMENT_ME * @param iNewWidth DOCUMENT_ME * @param iNewHeight DOCUMENT_ME * * @return resized icon */ private static ImageIcon getResizedImage(ImageIcon img, int iNewWidth, int iNewHeight) { if (img == null) { return null; } ImageIcon iiNew = new ImageIcon(); Image image = img.getImage(); Image scaleImg = image.getScaledInstance(iNewWidth, iNewHeight, Image.SCALE_AREA_AVERAGING); iiNew.setImage(scaleImg); return iiNew; } /* (non-Javadoc) * @see java.awt.event.WindowListener#windowClosing(java.awt.event.WindowEvent) */ @Override public void windowClosing(WindowEvent windowEvent) { // if cancel is disabled, then don't call the onCancel function and // don't dispose if (current.canCancel() && onCancel()) { bCancelled = true; dialog.dispose(); } } /** * Called when the wizard dialog opens. Override it if you want notification * of this event. * * @param windowEvent DOCUMENT_ME */ /* * (non-Javadoc) * * @see java.awt.event.WindowListener#windowOpened(java.awt.event.WindowEvent) */ @Override public void windowOpened(WindowEvent windowEvent) { // nothing to do here } /** * Called when the wizard dialog is closed. Override it if you want * notification of this event. *

    * caution: You must always call super.windowClosed(windowEvent) * within the override function to ensure that the Wizard closes completely. * * @param windowEvent DOCUMENT_ME */ /* * (non-Javadoc) * * @see java.awt.event.WindowListener#windowClosed(java.awt.event.WindowEvent) */ @Override public void windowClosed(WindowEvent windowEvent) { // nothing to do here } /** * Called when the wizard dialog is iconified. Override it if you want * notification of this event. * * @param windowEvent DOCUMENT_ME */ /* * (non-Javadoc) * * @see java.awt.event.WindowListener#windowIconified(java.awt.event.WindowEvent) */ @Override public void windowIconified(WindowEvent windowEvent) { // nothing to do here } /** * Called when the wizard dialog is deiconified. Override it if you want * notification of this event. * * @param windowEvent DOCUMENT_ME */ /* * (non-Javadoc) * * @see java.awt.event.WindowListener#windowDeiconified(java.awt.event.WindowEvent) */ @Override public void windowDeiconified(WindowEvent windowEvent) { // nothing to do here } /** * Called when the wizard dialog is activated. Override it if you want * notification of this event. * * @param windowEvent DOCUMENT_ME */ /* * (non-Javadoc) * * @see java.awt.event.WindowListener#windowActivated(java.awt.event.WindowEvent) */ @Override public void windowActivated(WindowEvent windowEvent) { // nothing to do here } /** * Called when the wizard dialog is deactivated. Override it if you want * notification of this event. * * @param windowEvent DOCUMENT_ME */ /* * (non-Javadoc) * * @see java.awt.event.WindowListener#windowDeactivated(java.awt.event.WindowEvent) */ @Override public void windowDeactivated(WindowEvent windowEvent) { // nothing to do here } /** * Was cancelled. * DOCUMENT_ME * * @return true if... */ public boolean wasCancelled() { return bCancelled; } } jajuk-1.9.6.orig/src/main/java/org/qdwizard/ScreenState.java0000644000175000017500000000726611720500104023622 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.qdwizard; /** * A screen state: *

      *
    • can cancel ?
    • *
    • can finish ?
    • *
    • can go next ?
    • *
    • can go previous ?
    • *
    . */ public class ScreenState { /** DOCUMENT_ME. */ private boolean bCanFinish; /** Can Go Next. */ private boolean bCanGoNext; /** Can Go Previous. */ private boolean bCanGoPrevious; /** Can Cancel. */ private boolean bCanCancel; /** Problem. */ private String sProblem; /** * Construct a ScreenState. */ public ScreenState() { this(false, false, false, false, null); } /** * Construct a ScreenState. * * @param bCanGoNext next button is enabled * @param bCanGoPrevious previous button is enabled * @param bCanCancel cancel button is enabled * @param bCanFinish cancel button is enabled * @param sProblem problem text */ public ScreenState(boolean bCanGoNext, boolean bCanGoPrevious, boolean bCanCancel, boolean bCanFinish, String sProblem) { this.bCanGoNext = bCanGoNext; this.bCanGoPrevious = bCanGoPrevious; this.bCanCancel = bCanCancel; this.bCanFinish = bCanFinish; this.sProblem = sProblem; } /** * Gets the can finish. * * @return Finish button enabled */ public boolean getCanFinish() { return bCanFinish; } /** * Set whether the finish button should be enabled. * * @param bCanFinish DOCUMENT_ME */ public void setCanFinish(boolean bCanFinish) { this.bCanFinish = bCanFinish; } /** * Gets the can go next. * * @return Next button enabled */ public boolean getCanGoNext() { return bCanGoNext; } /** * Set whether the next button should be enabled. * * @param bCanGoNext DOCUMENT_ME */ public void setCanGoNext(boolean bCanGoNext) { this.bCanGoNext = bCanGoNext; } /** * Gets the can go previous. * * @return Previous button enabled */ public boolean getCanGoPrevious() { return bCanGoPrevious; } /** * Set whether the previous button should be enabled. * * @param bCanGoPrevious DOCUMENT_ME */ public void setCanGoPrevious(boolean bCanGoPrevious) { this.bCanGoPrevious = bCanGoPrevious; } /** * Gets the can cancel. * * @return Cancel button enabled */ public boolean getCanCancel() { return bCanCancel; } /** * Set whether the cancel (or System menu close) button should be enabled. * * @param bCanCancel DOCUMENT_ME */ public void setCanCancel(boolean bCanCancel) { this.bCanCancel = bCanCancel; } /** * Gets the problem. * * @return Problem button enabled */ public String getProblem() { return sProblem; } /** * Set a problem (set to null if problem is fixed). * * @param sProblem Problem string or null if no more problem */ public void setProblem(String sProblem) { this.sProblem = sProblem; setCanGoNext(sProblem == null); } } jajuk-1.9.6.orig/src/packaging/0000755000175000017500000000000011720500104016167 5ustar drazzibdrazzibjajuk-1.9.6.orig/src/packaging/OSX/0000755000175000017500000000000011720500104016640 5ustar drazzibdrazzibjajuk-1.9.6.orig/src/packaging/OSX/dmg_background.xcf0000644000175000017500000121657711720500104022333 0ustar drazzibdrazzibgimp xcf file,BBG gimp-commentCreated with GIMPgimp-image-grid(style solid) (fgcolor (color-rgba 0.000000 0.000000 0.000000 1.000000)) (bgcolor (color-rgba 1.000000 1.000000 1.000000 1.000000)) (xspacing 10.000000) (yspacing 10.000000) (spacing-unit inches) (xoffset 0.000000) (yoffset 0.000000) (offset-unit inches) I,Array     `,HII,,<L\l|\ >O_o0 DDDDDDE H"HJHZHjHzHHHHHHH    U<:=:=:=:=:=:U<ts<rs<s=s=s=s<<<<<<<`<f<f<f<f(3<:<::;9;::;8;::36;::<::955;::vY::94;::|h::9;3;::|z;::;2;::|A::+0;::|J::6/;::|U::9.;::|c::.;::||mt::9,;::||Na?::U*;::||NOZH::7);::||OOPVR::7(;::||OPPQS_::<';::|}PPQQRSuq::;&;::|}PQQRSSTi=::&;::|}PQRRSTTUaD::&;::|}QQRSSTUUV]O::%;::|}QRRSTTUVVWZ[:%;::|~QRSSTUUVWWXY~m%;::|~RRSTUUVWWXXYZs;99<:|yRSTTUVVWXXYZZ[i:(:|yRSTUUVWWXYYZ[[\e:(:}ySTTUVVWXXYZ[[\\]a::<<::=??@EySTUUVWWXYYZ[\\]]^_:Y$ySTUVVWXXYZ[[\]]^__:Y$yTTUVWWXYZZ[\\]^^_`:Y#yTUUVWXXYZ[[\]]^__`(<tsrt:s:rsst8s6sussu5sssq4sʜssr3s˫usst2syss0sssy/sŋssq.sʘsst-s˴̨tssr,s˴͵wsstU*s˴οssm)s˴NJssv(s˵Εsst(s˵ssrs&s˶ҵvsst%s̶}ss&s̶Ɉss%s̷ѓs%s̷%s͸qws͵s(s͵s(sͶssuussuww悻ζs%ζs$ηs$ηg;9977G'4N}63N~~L3N~~] 1N~~j1N~~t!.N~~{1.N~~F1z~~E,N~~F t~X ,N~~Fif+N~~F[q*N~~FK{,'N~~F9}?&N~~F(yS&N~~F od&N~~G ap%N~~G Sy&%N~G  B9%N~G   /|N@   !t(N>   g(N?    [   V?      %~&~?      %~%~?      %~%~?      ( ;B7:[97 65-4N3u2 0 / $. B- g,*)(7'[&%&&&&+--" ;3<:9:;:9::;9;::9B::;+6L::@5W::94h::4`{}::3`ar@::;U0ablJ::@/ r<st;sq:sr9uss9{sst6ʅssp5Ӑssq4ؠsst3tsst2xsstU0̂ssj/ ==:9N9_ 7l7x!4J34 8H2(yZ 2nj1 = <;-:N9s865$4B3 e2 0 /    =:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=7:=@=s=s=s=s=s=s=s=s=s=s=s=s=s=s=s=s=s=s=s=s=s=s=s=s=s=s=s=s=s=s=s=s=s=s=s=s=s=s=s=s=s=s=s=s=s=s=s=s=s=s=s=rs<vs=j=<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<==f<f<f<f<f<f<f<f<f<f<f<f<f<f<f<f<f<f<f<f<f<f<f<f<f<f<f<f<f<f<f<f<f<f<f<f<f<f<f<f<f<f<f<f<f<f<f<f<f<f<f<`<= :YX XYZZ[[\XTUVVWXYYZ[\\]^__``:YN NOPQQRSTTUVWXXYZ[[\]]^_``a:ZRQQPOONNOPQRRSTUUVWXYYZ[\\]^__`aa:ZUUTSRQONNOPQRSSTUVVWXYZZ[\]]^_``ab:ZV VURQON NOPPQRSTTUVWWXYZ[[\]^^_`aab:ZWWURON NOPQQRSTUUVWXXYZ[\\]^__`abb:ZXXVRONNOPQRRSTUVVWXYYZ[\]]^_`aabc:ZYYXTONNOPQRRSTUVVWXYZ[[\]^^_`abbc:ZZZYUONNOPQRSSTUVWWXYZ[\\]^__`abcc:[[[ZYTNNOPPQRSTTUVWXXYZ[\]]^_``abcd:[]]\[ZXPNOPPQRSTTUVWXYYZ[\]]^_`aabcd:[]]\ZSOPQQRSTUUVWXYYZ[\]^^_`abbcd:\__^]VPQQRSTUUVWXYZZ[\]^__`abccd:\__`_^]^XQQRSTUVVWXYZ[[\]^__`abccd:\aa`_`ZRRSTUVVWXYZ[[\]^_``abcdd:\aab a`_`aYRSTUVVWXYZ[[\]^_``abcdd:\ccbabccWSTUVVWXYZ[\\]^_``abcde:\ddcbabccdbUTUVVWXYZ[\\]^_``abcde:]eefedcbcddee`TUVVWXYZ[\\]^_``abcde:]ffedefgZUVVWXYZ[[\]^_``abcdd:]gg hgfefgfVVWXYZ[[\]^__`abcdd:]hhgfghhiaVVWXYZ[[\]^__`abccd:^iij jihghihijjXVWXYYZ[\]^^_`abbcd:^jjihijkldVWXYYZ[\]^^_`abbcd:^kkl lkjijklZWXXYZ[\]]^_`aabcd:_mmlkjklmngWXXYZ[\\]^_``abcc:_mn n mlklmno\WXYZ[[\]^__`abbc:_oonmlmnnopgWXYZZ[\]^^_`aabc:aop p onmnopq\XYYZ[\]]^_``abc:aqqponopqpqqiXXYZ[\\]^__`abb:aqr r qpopqrs\XYZ[[\]^^_``ab:assrqpqrqrrsrkXYYZ[\]]^__`ab:attsrqrsrsststt_XYZ[\\]^^_``a:buuvutsrqrsrssttuoYYZZ[\]]^__`a:bvvutsrsstueYYZ[\\]^^_``:bwwxwvutstuvu[YZ[[\]]^__`:cxxwvutuvwmYYZ[\\]^^__:cyy zyxwvuvvwvwwxdYZZ[\\]^^_:dzz {zyxwvwxwxxyxw^YZ[[\]]^^:d||{zyxwvwwxwxxyt[ZZ[\\]]^:d}}|{zyxyxyyxyyxyypZZ[[\\]]:d~~}|{zyxyzyzzyyoZZ[[\\]:d~}|{zyzyzzyzz{znZZ[[\\:e~}|{z{z{{zz{zz{{zr[Z[[\:e~}|{zz{{|{{|u_Z[[:f~}|{|{|{{|{|{||{{|yeZ[:f~}|}||{||{||{|{o]:g }}|}||{|{y:g}}|}||{||:g ~~}|}||}|{{:?NN MT~~~}~}}||{:(:~~}}~}}||:(:~}~}}|9<$<:~}~}%;::~}%;::]%;::N:%;::D::%;::=::&;::~::9%;::l::9&;::\::7';::O::3(;::§D::Usʠ!⢣sĚsƜsǞޛsǞ sǟ sȠߛsȠߛsȡߛsɢߛsɢۡsʣݡsʤ ߠsʤߥsʥ ߥs˥ޥs˦ ২s˦ ަşߧsͨ ݦsͨ ިsͩܧsͩ ߩsΪߪsΫߪsΫ߫sϬ ଭsϭ᭯sϭ୮sЮ ߭sЮ 㰱sѯயsѰ 泴sѰ 峴sұ䲳sұ sҲ峴sӳᰱsӳ 𬫭sӴⲳsԵsԵsն그sշ絶sշ䳴sոsָs ƶs ƶs ƶsw$焎ƶs(sƶs(sǷrs'sǷ%sȷ%sȸԒ%sȸ΄s%sɸ|ss%sɹvss&s˹٭ssr%s̺םssq&s̺Ґsstv'sͺ̓ss(sͻ{ssU%~~|"      %~~n!     'r      't      'u       'v       (w       (x     (x      )z     )z      ){      *{     *|      *}       +~!!"!      +##"!        +$$%$#"!       +&&'&%$#"#""#      +(('&%$      +)) *)('&%&%"     +++*)('(''('&     ,,,- -,+*)()())((     ,..-,+*     ,//0 0/.-,+,++,+     -110/.-,-,,-!     -23 3210/./..-.-    .443210/00/0//"     156 6543210100    17787654323221%    289 98765434332    2::;:987654544332(    2<<;:987676654    2==>=<;:987877665-    2??>=<;:98998776766    2@@A@?>=<;:9875    3BBA@?>=<;<;;::98988)    3CC DCBA@?>=<;::9    4DD EDCBA@?>=<<;:7    4FFEDCBA@?>=<;:2   5GG HGFEDCBA@?>=<;<;-   5IIHGFEDCBA@@??>=<;+   5JJ KJIHGFEDCBBAA@@?>==<*   6LLKJIHGFEDCBBAA@?@?>>===4  7OOPONMLKJIHGFFEEDDCBCBAA@??>>=: 7PPQ QPONMLKJIIHHGFFEEDDCBBA@?@?>==+8 oFFEDDCCBBA@@?>==98qGGFFDEDCBBA@@?>=>8rHGHGFEEDCCBA@@?>>  rIHHGFGEDDCBA@@?F(wsJJIIHGGEDCBA@P(wtLKJIIHGGFEDDCBY(wuMLKJIJIHGGFEDCf%wvNMLKJJIHGGFEt%twONMLKKJJIHGK+%qxPONMMLKJJIO%oyQPONMMLKJZ{%pyRQPONNMLbi&pSRQPONMoS%qTSRQPO{?&rUTSRT+)rVUTZ*rWVd @:<$<&&&&&%L%-&' (abbcgT::7.bcdec::<-bccddeex::9,bcddeefgz=::;+cdeefgghsF::9)cddefgghhioO::9=(cdeffghhiijl^::9'defgghiijjkkq::'deffghhijjkkll;::7%defgghijjkkllmm{B::8 #efghhijkkllmmnnvL::9"effghijjkllmmnnooqX::'!efgghijkklmmnnooj::9. efghhijkllmnnoppo~::3efghiijklmmnooppqppoo~@::4efghijjklmnnopqqponwH::7 efghijjklmnnopqrrqqponmqR::8efghijjklmnnopqrrqponmmc::9%efghijjklmnnopqqrqqponmmlkv::,efghiijklmmnoppqqponmllkj|=::0efghiijkllmnoopponnmllkjitE::4efghhijkklmnnooppoonmmlkkjihmM::7efgghijjklmmnnoonmllkjjihgh[::5efghiijkklmmnnmlkkjihhgfr::7defghhijjkllmmnmlkjjihggb::9'defgghiijkkllmlkjjiihiV::7deefghhijjkklkjiihmJ::5 defgghhijjkklkjihsA::2cdeefgghiijjkjih{;::/cddeffgghhiijjihu::)cdeeffgghhiijihb::9"bccdeeffgghhihjW::8bcddeeffgghnJ::7 abccddeeffgghggrB::7 abccddeefgz;::5!`abbccddefu::1"`aabbccdeb::.#_`aabbcdhV::9+$_``aabcdjJ::9"%^_``abcoB::3&^_`abv;::)]^^__``a~t::;)]^_`b::9*\]]^^_bV::7+\]^dJ::3,[\\]]jB::U-[\p;::0g[[yr::;0{u`::91U::72M::33D::9U4<::7~::8k::98:79:3::;U;:~Սssv.󸹺ܜsst-ޯssrs,𹺻wss,ssq)։ssm(򻼽ݗssrq'񻼽ssq&]ussq%|ssq(#轾Յssq<"𽾿ܒssrN!潾ssr\ tssrd㽿yssi⾿Ђssm᾿׌ssp4྿ܜssqHޭssrUݽvss_~sshцssm&񽾿הssj񽾿ڨssm񼾿ٛsspK񼽾Վssm.񻽾΁ssj񻼽{ssc񻼽ݹuss\ݬssrR򹻻ۛssqD֎sso7򸹺ςssn"{ssl ݺussg!ssrb"ڛssr]#Տssr\$𴵶΂ssU%{ss3&ussr(񳴴٪ss*𱲲ךssq*Ҏssv+ˁss,󮯰{sstU-ussr/էssr0Әssq1΍ssv2Ѓss3|ssU4vssr6ۭsst7ssq8sv9s:srU;r~au0R~--@B,/}V,#te*hs*Z}''H;&6O&)x` $!mo$`z!!P3 =H .|[ #pievU-A@1}T%tchrY|&:> M~, Zx jm"tb  /}P ;AN~- [x  km #tb   .}P";@"M~-# [v & im' "sa ( ,|P(  9?)  K},*  Yv - hl.  q` /  *{O/ 8~=0=2S|,1A{t45v6e6O7<8;<=~ .7&Y&~& %$-$O#s "!  3Ss( @!Y"u#%%&1''&H%9 $3## !` 8"!qQ  5 !$ "##i$I$-$$ $$ i% J% - % 2 34i6K7-89 :;i~    &;::¨=::,;::¨::<,;::m::9-;::^::7.;::°O::3/;::E::U0;::Ö<::3;::ă::;3;::n::94;::A::75;::36;::U7:::;;7@ U&sͻvssr+sڭsst,sٝssq-sՐssv.sЃss/s|ssU0sݼvssr2sݯssr3sssq4sxssrv5s6rssrU7sr9tssr;v U&rXlm+sxW,s@-t-0u1u2uq2uZ3nA4 7899 &i+ M, -- . / 0i2N3-45 67i9eN; U.=< R                                }K>%, Background     I,I,Jg>0eL.mf8n7Rt^_ l=iXzmFtn"#EaxJ[-                                                                                𨧨   𩪪     񬫫    򧨨                                                                                           鰱  𵶶︷                                                                             񶵶 񿾿 󼻼򿾿󷸷   ¸ ¹¹¹¹¹¹úºú úúú                                                                            Ⱦȿǿȿȿȿ                                                                                                                                                                                                                                                                                                                                                                                                                                      ﱰ󳲳 򲱲󴳴    򯰰                                                                                      񺻲                                                                                         ĺĻ ûļżŻżļƽŽƽƽ Ž󾽾ǾƾƾƾǾƾǿǿǾǿǿȿȿȿȿǿ                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         鶵 񴳴궵󶵶򴳴 򱲲򷶷ﵴ 򴳴                                                                                       󼻼  ¸ ¹ º ºº¹º¹úºú úú úúĻûĻĻĻ  Ż                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    ļŻļļŽżŽ ƼƼƽŽŽƽŽŽŽƽƽƾǽ ƾƾǾǾ ȿȿ ȿǿ ǿȿ                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             ¸¹¹ ùºú ú úúûúúĺĻĻ                                                                                                                                                                                                                                                                                                                                                                                                                                            }K>%,Selection Mask S,s[gs,#'+/37;?CG   )19SW %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%  8888888888888888888888888888888888888888888888 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%8888888888888888888888888888888888888888888888888888888888888888 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%8888888888888888888888888888888888888888888888888888888888888888   %%%%%%   888888  }K>%jajuk-1.9.6.orig/src/packaging/OSX/dmg_background.jpg0000644000175000017500000011470711720500104022322 0ustar drazzibdrazzibJFIFHHCreated with GIMPCC,"  Y!1AQaq "2RW%'5BGr&EF#(67TUbfguw K !1AQaq"2#Bb&35RTrc6SUdt ?@G#=_Tu!LXIN  [+Ws*QNAJ(#54 gEe^q u'Nu0nnAR*OвR* 8suɅGA^m,Yj~pq6"#by~te+ݴN7Cdf)Pr]I!RS)QVPrJŀQE(B%O/,{ yPD P,Jr)Old(Uu\POT8qP!@Whb@Fk -ADvgR\p/"@SR){"`v_.@x (OPaem98iDsO"Mae|s& e訽B!AZc _ *UݲQgXAcmFg'7~6(qAWYHAg CbXРX@g\qD0sIEhyhuuFP\LG _my(" E[Rʵ|)uD/ t5+ܼD:dܕs*X v#@CԌ–Edq8*@P%ŭ MXZ u:(LŒ$%߰uQ3WX˙.kxР9|ѐ(&e( + (* y\=4F柳Fth+P(kzr vIp@I#1[DP1*- B*KQ=sv*T2"2ͪbT8V[W 0c}z8};(Q(QŁԬPSUB.qk@SQsCoPBNAH9EJ 22Ј@R"fQr D)-HA][^(iFmT +jR9@n@([ʼDO.M9 u4>|{wx pj 2"(Y&Z9:vXByp.TMh!"Fj %2-_t֗(lP(߫HYCќB rA,^.%qXA(G58 ]* |.nBH0҄(Z)Co|Eّ"E^߭c~w!勶Pu Yi (@bu,}WN *8U ^;.iD0G% mdt4>t׺v7Nv"KLHr;:Q]#bͨrZy%|HDv3$, C+2wT֚.1r (,[ x %cTT YS( w0e@nBKJ iS=o0k<-y0+cVuJ {X"rR׶<*B\3G,?,$AB[!@( ީsecXIFD5Z\E]@/s(Fʫ (@zF(\+NەȢٯ (ƵeGTBa]2CᒐL0+WV9U1>hsvH@Z 5S0-tTT ?9rj>+O.O ׬[OZ5OzE 0]ʰt 8 ݞPHΖQZA ONt4D*#lT(E<I@Uo!;f "WlCtwoJ.-3Vj(sxYB "eÝjl 9:NV~1iFԝN:Ș*F (\偢0bmΜ(;F1KLB'hh*Û]^'z8wxV_JT%LkzG B1wVeeP0GXY@Q42J5CꝢseBp?>ʊ ';[D -T.d8bL [ܒX.Ĕ4,%( Q`$ ߘ! .Q2ʨhJ*@*<$R*&B- $N)\aMhZJ=ڨQ  BJ|ybZ+&d!@pfRdOlF6P] k*-sBMrcPwb4\rsqZѴ:] 4H: 4Ŕy,HstSvf\IOxB(>Pi%58!e\æ'ݬ\a bK rDַ̨hWqƅܿf!%GE_lg!e&F? jQ\4M4sB OPs_^~nhhPo}hr(weGI RT lV4|\2OpFvzAUiʬk4q5 VPQڮp\V*$OS(i@D=E?o]V=QRܡ)(44t Gd垕0rչ@  /_\]>ېCTBB:< Ў@kAt\MPrhQM(\ ; *bE@K'~j88ZEZX֦9ʊV )֪`U5P9ёZ"B*>eBKDEMP[fP)֏"VمQ4w;, OkZQTX HnwovJ 'u`(MND 2(zBܽP7!<ְ r@RsEDnu9Z W UUR!`/P{ ËjoE}MBJ5[iS gw5YC`Ҍh,e*i jB?/3!ZJXaw dHv{bhƖGUVThkTl֫=PWF8V)f+e1/[`5<)š@_AѫE-eJEK-0U]O;,I`L4hQ3XP0(AB4-4TF1 QDu@@*Z!冄P}-EEJU\c (STyd@BA|ZPw( \Sҥ*X`Qq[RРUP{\אՈY(iA)YPFAdAXYG#|fO<%k  Zr@xa ,HFHa+2W,7o`(ʮR*L +ᅝ#\PnLK& )tnRĭkc"(x a (R>4"S<,1aM;XI+@} x 0&G"lyr-3Q6GɿG kB MB {(rbp(?ԪU*PUJ%[΀07d(y <[jpTJdū[ ,aT=/d8I jk>J ~ v@1KVjJn 2tlQVPTf]0FUd!Q>_y~:{4dr+P<)Q2dB5L~QsQO2Q +m[͜! l\epnNVj L޵ρZ/'830;+Zg8BH>Ud*QM^5s "ЃmA_PS<#}_)lBJ:QJ%TڧDXƵ4mDFB%B'ڜsg :d\RErO@|%]AJ!b@uQ;Pj%nPd̋"cdEK.L,R, m25U6pp sK^pp)h[jyWhe_Fl1 UH B@_/^J:Q 0b#-y( +eeg"̕T j!Y]%(BtZ NcPO]:5f\\.Ґ+ 1|d[NtO2& TbHEe*-i(VTU6R'q|b+WrgDP" '#eVw0 @]qWC(65BS̪&(T2(MtR-]y\j9_j/.PnGg:C7txޕzb((p5t@z,``<8'vH'\W[A@ wC:عWߓ4ފQXE/7J;fS|&[hUC \*.*8*) I 1A|:k+~[mP*A@+|%hJUKJ>" V-(RgFr]SըBbƷw 5΀,h@5, r8.jpR,;{ZbPRPNl1F\ \yܡVFb^SuwKPAUҐȇh3 Y8iBAٞr  w(\x2s,{HQMy`8rؒζXY9U3u# (e^RL\\Ҡ*26eC2P& {+Т@9};,Pw@]Њ b SW >PR@z!RšQBTP Q BJ.+dTjvDߢI&VT԰Q\w@DP˝Hq (`jA( hJSCε nFN q\a%uy+Ayި֨U {r+X ڳ T5:( S`壺AHE2L(LFdO(R?lV5eK y(jS0u/ %7 V@#5{w(AZP2]=O$Ek^tNA $.4Њ9{e5k"VAVבX`b/ ӓ (`߮BZ7>RWu!zEjy,J)^$LTs "Θ=9 4,-6@>k\]"24(SvՈSӥJ1sqˮ"C 9x1vJ+@3P]GEQK ԧ}p|+is#tpib)W`lkYGP/P@/,+[rg({RkJE;\)!Cas\mXl=c@@-2"@:+^.E U5GD)@: zBw)TPhׅjY_y-)U ^,+>;^(gr,A24EGLݕ3*Vҫ;YB2+QU`+ ҄uPن(KE@Vqu*H_,>@,8 R3ϿXoDst$jr$^6/h`:U؃jD 6?E( erfP'XPAȄ#z1 W4 hC,U,eAh |*QЮ>:4՗ 8!iYpBPd€ hܻ1@P {0L3JfEPU GP4W2TBJ6ML;Fd24H OF{B1΍ ,,AupՊPԕW,tW)0mF@Rl{U:0F44"-[Z*rD\QU (0 rp8+hU2/`!|.\VA{Sr}tN ~ѱȦNr9!#cAF&x*!vEVKP^2P_0S ,gq a8~扮U=45$#IАn SItuNo{]n$ ve쌈 UFvae 4~8hpE*[әEU4llZJ]3^bPIDt /Ţh(J>XQ{䰠%H.P:%qA~U9`-S3[a-=!5ѠQ g (jV{(a V晻`3U\\5UJWDVk+P{+\"@Y \GjHZB؄+S W=8 hIU[dmRcA (MPGhA(;H.} .PPDt:o( 򑓃]Hl6JCq ~1W獰XkHYFŶ(uy֢,2mQڕ1RzlQ7(?c/Z;=OVzk>6zռwsn=cq^/n{mo{mijeiS [gmdlvIvS˴mv[I=i!2O4<&0 PC9q%YL 9I4dJHc,/&PB ҨP @Hrg m{ AjВsߝ*VFx' CJ V'Q}6}A6P~#@JPBJ0~(U+BQMs^V2 [>gJH.bfQ")Cks ,@2T桳S ?*33/P--(gK=yV057XIG(VvB^P Pd@ZΑrіagBP$: R(Һ.rzr 9,gBC(R-<!&k`" ڭ(  R4^Sb-UMiTj`2(*)N2 U|ޯ K0O`hY/v>Bj'S']v1rISP:QVpF,PX%StJ4"_dVG!UVE|8;9R6P nAɮ\"c`"^+)K@HUqDTSiW2kBih&wl (7/qr#| J}(F Wx@bil] *hGrEz:l<N m/n1DrP*t܇z@."X1TlUeTdG,:7mݳAW0R(t^ Q ,O`39Z7Kw]PAV{B/TW]`J]*3 Z8LR{#ap(R?-GO'J`Kba%JVj-U 0 # $b@ѝg3Pׯ1K^ʱru U!G]FE&QkAdFuskjPRQ3ehKK꼺Co~J($TP̅B r{~Z':d Fh5kQqBR#%jV?QE")yJ@, Tc-#￈G d*j2Qj JM_͡) ˮZYBmBumn|(55.>|I@Rp%TkӸfǙrO( Z;emy%[ÖuiCR+{z bkp)UÚsGV;j.PB1=p<|OOghTkڨ YS6}[Tn]T43:=NY>P3ΰҎO5 mK%B{W#C5マ(A7¸`*N 1IkP)ȖHeQz<,҅ATX@T2Hc ı zރ j#(1㧯_fz= 4 &@K2,?_;w.^+'] Pnym췝6swD[m N7M-} XV^gϩ^xgKN&W`g )Z~%ǖyx?g\N.^#1BYɍ(c4Q1?Ѓe23>~oC^6\Oq lķ-"MlfC4;q&u6[]y췍g/?,O}q58~߾ ax=>׷|lgpe.cx?K%hl<#}pn%A}*K;S~zwx vI㞜=]i8?܆O a>Èp~;n| 8—, N7/b % UGAQeA q.JesUߤhdD6GCG+tVY@Pܼąz]nQ%A 'zZEIN\.ZmdאU= ^CYy*v5ッ(Keq\::@).- qQ| PEY,~~:*P#uQ4O< غZ+UP5*naB rbW#ۗPkwW5\@=ot4J#TުXa!&71|sQe`jb! ]EF|hTEG#%υp!aˠschC.#Le텑sT60cC"Vمd !u |X] -LB* aE>RYKh=])uW/ s| ( Ҁ ;QEں< n,%N3TEq`N,1%"P@ƤױB:W߭,_aZDFƁ6a\/ (5Eb@8}B9seC.sBJ"W}~`6TuNe1Xw}c6m;OMO0Oڙ%fYG 9U`Gp9cxֹvwͳl;k>}oɽvm;Om ~W^1 _p?DL͈&3 9q'1'~&i$B !݄߼$⛎NuaeƉ/<{~y_OXX8lxsn;}lio?s%9s9sM^ՏԸƬ>|'ccab<ɉ 2@.[&LL I)4JY !zI8D6yM&H!KD!^-C~I1Rڬ~>???ӄk͸ ? GQ>sԽ{eo xnc[mZ$li7^a,m ) KcOfd1O!e\H  c/iNt Nf%S)j2T {O/CzӊOAg2x6lwN#m6'aJ7mqk<ۼM6efJ'ǣ?Xp?Sx_xO`Np<cL8>;11@—.'DRL8S xn/bϋ' .O0P)+Yx-ׄ{/B_6S>&p)vzrMx]mv]ϱ6cz3~[rݾiYYvGLU#K}ogg=]\+oWuFJ&z7y;=kzGgv?>(rwuP =GG}7o{ OM)l)嗆 Ino;[]w'$>HoS_H>;qDq]߄Yo|6B8o;Iz~6^)l?x^یp}޷3sU8~+$pY|?(_(|C̲8BqK1χd\IGqPZۙ?ɲ_ɄPЅ,{@Ar*۩PNYsX`7v0Ge X8G%Һ-Z5Ћ ǩHiGȡB<$c,r|+zZ O07D: N.QS5?0k@d +S;Z 0d)L5"5d hjJa-|{ (%2>bֵ@AM|M'[TՆ]JTIe]Z v@U3T]QɊB08#$e]054Y($ !nʌXC X{G~6*_ү ,מEwI=S (hMB*mPOpV#0.ʌ(eU!qAܡ%!(jjW05A[mM%a;:6r´Y+\ef4cv`be nm+ d**sŠ .TPnԺ ݾTKbesKhZQV-~쐒^k:(U#šWPqp@!ZgРS"<,(aݣG+ٺTli1 D|ؐS*ZPSF/UA쐲Օ zTo]Ɗ[W(*rO:!f+wHDQb֪i (Q[@Rg 4D5rВ]Bv@dF|rz<,Ԅ %Lئ6[(uO`)zW1ƀ6M5oBoRnލ,@ `jKZաeda 0`*y u(jrbf׫Qo>!9 5UQr艢hA;(''A (ъTOeqrJ3}eO:oE+ʗ-ޱ`"iU2vxICib| x#xi (@5~ޞGUkEj/מ9GH?qj6b` U(\6=h o.?۶ x"/Dzÿ;+C,0ҟ7oM՞4 )/Rn!7yJD~-u171?>S\$3xK_~ज़&@W/*I*G[J/dzkv#d\$h.ģofقf/JS81'03n @l!;d4BHyXYtHH\ާ{G7)WhNO>kGCi@7e( 2mQSƨG 8h+8q}3ssp.' fd~f^=Mnjl?7]v=Mi.g+n%蟨8OI&Y[oM&M2xd6Camd}sZo~';p樂YMvlf-u';p;)wN[M=16\6~7J?_ 0t1ȔK}CI8X~# yqqq1p曊_La2ߩI8ϗt`?ÎY4ғ/` r*\XE`9j-Yz[xG=8w77M }m-vm6Sy&YgM,)2M),R\2TllL}M!yeY)Yf`&a0YH! OaJJDA(T"O*M#d?}{X`Q*M@?!%Z+P.0!Pw_x<`-z"\zW:h<-X Qz٨ \sby2Qk]e(%@::H7B|(D(kEFҪQ1@ ,XP$sJ8,ODÕC"Xs0҄yZIn4 A5U8JQhYB4WtQ^,L9Zޫ-ZQ J*T:W҅"}inQrW-5ҬW5Β[Aa!@`r boHP({;s蛬hU4^Pj0fȔKPMpMPUe*ESU)\Zf܃YC_bB/ EI4hyBd;Ut 4ൕZsPNkRYl=wVoˀ/Q Kc.-(L38DU*;+W¤*{!D1ي&m\ޜ5jx( O<5'%O[*)0:6\_]Tz;7"Qe}RJ{ǖl@+4>Z)L]% :l1`2G#cUƛ]zhs~@["Vb1sh(&%s -RCJ VPk q9݉~s/ze(GыQaGB&e8(|t%@Q,DG.e.QTT6QV8u,FTYoΑrUBd ɜ@4Ws @BKdTl(!6NtmRϘHXxkZJqpU@vy@AWa\ (⢠QI!BB5s(gfPB)KrLO`/48κ\m,y]e:!ʈD)|̝@6!|;cp҉Omޏ^ZJUeQp(BbJТ)б?oErvnJ:-PJB$-R+$@ܡDh^#B$Q5dQ 3t:H|?sfſy1V҃c/RU~n֓pMx`ywo؇%o1`(tQڴ ceAPPc1ek=öB윕쿬mI"JU^ֱ{@9WgL_/{-pbJE@׵I UsLIRsC洏~}<Ϸ_z۔=M6[9z;ׅo;oYcgGz7Zzω}#ہ7!=E=Y۶7}sI$zrwm<1ml^GcAk7o_N?l8}{*d}Ye!mq/ C4O~l~<v}j߃[(T~wüSfRli0%i_ Ė_/xA"iȔM4a Y^\#S06JSMI-( B{Pe2PQJ`<[aU%)Hi<&,&vb}[)7e0Z* -Ȏ b+['''wd pE`%+/G5ߏǴ$J 67,0/a@6"oMyF K\{J<h9e=% r{lVQJ)zY>z=EY+D S #5DH,:r[P Vy7ru+ 24WuL/dV*҄זipДrj&TBʂݙz#Jދ0렽@|D,bfkSGԻ~TT8,yK%-4d ʒ(pPK,XP?@㠲cb4>xL,9PUF"YW,-CJ;yjqrHel.Q|*M@GD(3U4|R@6Fb<CD7QA;|r/W~C!bN,kBq>#-Q̴?t1k&& q^1E3 tXQaAt(=GQߥ"j^̖iD$KbGcc"u*Dij>ː\W@er) (kc(8 (#D̀R??v@QhzB5*ڧ3U0r5j0! UAF+#\FsHIB)6^W*VѺ:*y -TaPVUW_0TމCD@DsUi,Va,W6TT0 G0. gP2Y>ٙmV9NCth ؐj?9BW^%VTjB7VgaXAjV:InlML\MK>'#|,I$M|c6f26A Cw"uBJ_v_̿_Ѻ8"9~?o|'{iɳNiv{7 ڨQ$AIOq~`peYL0U"bA3U#8 ⰰ&&$Y(,}s鍮j}Al)Oc$dP(}ҁ.Lo'';>>k>f YK82 0,eEB!o#om]Kd6mYv|5y=f3발JdǢ~SG&3bJf\`͇*S Le>9JOu!@}DRdg}}eH>p}~ ۦdo 8w[N)+_>no6YE8oE4~!RKIn o;ӜKe&}y7oQ`IMw \x ^xɏ.Z0Zuӵ# ( F\/FX6ڀʙQ`FtztQ:Ѕ-2G,pj(( DO.[G(WD,h.];P h@ĠɎH,Jf"e hU0~ `jrz+0a%.:*'8CWKա("PMKN V~7W"iE2PP6ֵz pQ`]ҢL^Z=80PVUtB)؊V]*?lzEw(s*Մ bO|Q#%-d$,нVGF1m.PoD,XY.`PhTPKWT3:  V/}b|Oqr9b)"ev]yQ*+ʗ;a/ ,[}Z_KG)HAD̠Ъ*r{b,*bG ilqB+ḵ qxE ~@| (p>V/R@]} tG[=gg0c@Z (SbF[/*I-8"V!VvQu!e]2M5J!wT?*Q0vP]({D@VCT,Ɏ=3^BE *PC1zJ"R(M4ZuaH*H2+ZRU]u{Nܒ.P=JTtWE D@:[%dQRk) *~cEBUu޹{T,3vBJYZCQev(#ޅ@9 3$@Gu2؈3}*SDx.׭¯"PY#*J)#:ػr)Ξ㷲zF 4XP+40kUyLA 9D]@8CHզl0!IRQ+ 4-Zg , ȤyhOoGvd1shP*/qfJt%mвk:阢S]QFގ ݮh 0a%dK֎p5SU %G[pUU ]}a %S6h||W4ngmoNz'w~,g |/yw|[s7uɻw]&o yEGe'`d3H~7 !%'s4Pʁ,F<#mvenۼy/1=_>oMg,Mli|ߦž7}ԯGwm_O8Az9Mxao\?w.x%p/w}bAߠ|_s;8Yl$p^-IlH&߶>x/uO=en??ܾq->M9޷͒m7ONm`eSKn;w}'x^oK ~;Ď&?pJ8Đc_Ӏ<O/`7pgQ$ر~q\ dB?_Q?>YQe4ed%i\n_oOU}B߿ٸ>=zk|:IAG}&q;OxwOۧ M_ӆ,P%@@d B-(\%}JP;Mo>S&_7qPM|AlLBW( Rd’IZ=p`J6&4qeĜ@H /:إME !2k =X@?/)Utl6P@"(_Hv)t`ʷe \2n(5(~+ G|w$$:Ffz5T+?#س_Uz~9DP"RpT0WeYj.o3V e~;JEJ21"+ ,?HՈ_AA,Ze_V9{|c_gRInqOvLu%P`&UDX)O*1k 0 ,`X8En@Q]sTw IAidW&P%A|aB1+慫P] @Lmb.PV4J fL$P`bE^ fB ށ@@6nh7~Y`bgu nآ;,ݻ*ni (͂e$G=6*PJV`y.T(K֕ƨLѬPz H@ &<@ڽ{DU~f)׫ QlJВJ+ݞ ~.Pp^f7.A\B`9) (pn`O_e6$Δ̠E z94uTP;TgaS,?SK (r&.tdE 4$sͿT,% ]tF>(rvŊ|\%ETCCZ1.ad>tNA_mj36Ϫ[h(^`,4NJlP(kW(WjhEΔmE"8|\7 e) ThO[ &s*s: S BJOpE ߧ^(,Kb*jHt{V KPL䢊_PX֧F`TBƋV g,0)J*kzDJ~at [/Pr"69B4)Ge@sJ|;tt!@T2斫%sE 5Zg iBށZ2XuSBBZCzb*U5 vZ/'F6P &x P:~t9?;= P/gK"AYP/K;OUz} ܽys=Kk6|Ksn{#lŷ򧓉al][93gu{ywm~Rfٞ/.#}nl8Oo]mm6ޭa3jS;! CaT\d>W(wmҸaedTW ap^/Ta@|+Ae*t4龶[\E5'kB&J`-2(}iݡ{|}n k!%Vk EJ t\9J-dJ*1O29 Yq ndv5((+]#Zhd1 XQ$PʡCTRpXj9\aEl?B5kɖY׵DPwRP. Vq%V$ۚWt&d^^( w=4zլ8I합 (5gS,WC)DVU#7 VC&' i3j4b魩* }߼(7UTU*ĀYE+S~֧s (eHBZUv˚_iXe7 ]>Op( u=BKl9c4 t>E ˙0{ z!`P\馾;)qڷ (o| @U.24zfh]J1{Q\9ATfJ4\GO(|TFRi+Jmk* 7iAn2`7к%k)uEW5,CH _BJб;cX9띜*!(ꒇ (6| -ZPJen=oTlǺ uUBorDH ս(Qg!%r?krG6P'6[‰QDlI&Q{,y>աt | VBz  Z;wC19tĨѳʣK*U#ܻ/!%!>3SZEE hˆq*m Ѐ5 a)G S )G0%  ;j@0|*, =<|ae rFVca;NaUizeUJIIBUUKd&hQ?4F BJ*rم'݇csPg6H@ #FQ :$\ PB\[H`tJo{v#EGyC0 Qs(@ȵ^EAr -h"r(ƥu2޺EJ gc\Q1x&PQAF (ν yAB sYjAD1Z"@FUΝ~u28D97+ܘYh{Z"'(=p\j1 ,4-B|El (O3N\V&-ؽ=@DaЇMTX[X9\.\󸶅$h?`ʖvls4J1 Ulut݆e9YS=.aeFQI7 * Sh@5V4aڙ[Ai$SR0ƈB|UԀά(o ;Š{Y5eƔ5A L(rS:=HVU }O~^4eʾ(4uc C-pIb4A`aeFW.h7!% @u;E\ h+/0 z]GR 2,xJg:l  hR`Ih<~!ej %^(R>q?+ pP.$vhGXU;=C91'>goɯ (|G0 FJh/쑠wO(άBE*+D֋CW*P2Ya%jCr ZWɴ x(K34=XnryÀ߫SZaGU簿UQP271[Y.Ts,O=x;%/RY"7Z,)K\,>m;[X9]T3IC Z VlL`'B ӣ,F]u唭;>Y?}S#/.B|,aeسXET٩-.4BsC6x"T޷ġv֘>Ycs5Ɲ%R YUYV9 ŀLܠ*I!|F WFR"P.W׾J/ W0 d#M)(UlZeWLPX!k(# rWmB,?.Pvc}r"6(JIILmG{rilzٖ[pyQdVPRj4ܶCJ5rl M7ʢǀJU*+C#G4xPQP`(/E)CmnRkPP,Ú|n{P#sJ-PD`0vTC ֶa(5ȄF+T8z g<WQ_DYͅS$M=:ЎPݟ4nhSۑ,U*r{zDvQuJfe6ON+:O*rɞB*Q7$(ԢE _[3 *aPZfVhgy1f;(%YPnBXq\P@s~L4(ƅV,[{ze GGbS"oҁlgq𘛚#u PFXY@;CʴcTvɝ>}-b":>tXea1p]x@Si+ۖ>!@,ƇUKJsέJ-`ĖFQ}*`C-d*sKe(?:J(ԢuB KQTUsb@#tl i/ˑkfɯ_7 !@L[S1.ZQA{jqPKĄ=b B~KH(f5h EZ~v_/e}Q> aZ 5S'@"@qs_ aE(UWɒ(TF(?<\VjB+0-r(RЀ|Ȭȁ@Y]A{N؊k-F<巵eTUEyJ_ϮmԡO:&w7po ]_D*rf6!OB5MBGβ,x u݇L5TG\J t,m7~>;2BJ_KQ@- duYe1N欑254e E>ҁ^[SVcL<Ԟd951[P2%6\R :Bh*Qe(6nTCֵh`#u`TQPb ?2!Pe2!'[)\f*RʪAa@Vjёr2 ra% XseUZ0^.Q{-:r"L.PCi*[E_JW汃w=TxU4]/~] \s* (^N2::BlMhR2vMrm!mqe隘iE%BaʗR-Eu֤`0Դ$_T :Tf `~A(b.Dl((i;wIرDh W@AhT$40nWs>j(և,)Z.%pRL.j )EVݻƆ8'5`BDf!"@Y8IC}Ъ`0]J ҿ֝puUЇ ʰʧ]b@'RMC҄APP.:*8HYh6RFDOyF+(˱KC 0Lž|9CX,P5JBRsQHR0\ekDԥ!a  ZQG|ȂU 1mecAZPn( .elҰ]єhi9GKl"Ņ*%ò\Fl*$UDx*`k^bYR!4 _׻*U'(T (p8-Jr,F C{;E6d;Pf j<<n=MJk` _aXP;*WX_@4DGz:4X@:("h`" 4 M4057Gw&N ڑ*#qٕPOQ@]*^Q[/) (p^ڏ>qZeNI$.Q{SW Xآp|KZ-3dhF%Ƚ7Q%p,1(ʅ"R\4AVBP#^t)(GZRN["E@>s,9A:qAEAv[0y瓟ֈM%N2F`Z;BQZ Trn,1)ZPZ]yB-%VtLx"vѠcFRb\Pۨ=W2B"Ս, ߣIBnkoJqCKOUq޵.(1K`A (S'xuQa0(infЄV oaEMFvfl̶ ESҰu+\+R ,d`pE*8K,U:y~۔x讚s`d, VhP0OU9PP/Z:*@CrUV@V18ҋ֙YPbLUPր&0.߿yGF!IP^ٰΘQ ˿rBJ #9BS>kM0wACԪB{*cf` :tRGhB&q@/]ThP S֫eP::Sfec+wpki(ox`lh\U @RTw𲏽KK/?XB(WO:xp-UtD^B)(, %(G,OAqrʽS%dJ FzY2:U]*ot )sWLR^PYl-ytՏ,P[NaƊOG;8Zz~Z .95S&e=."!v\P9Cc@RR7Y=UDdlTx UA`PXڧ, ٔׯ/AՋ]t! ܐ?j ^֌] . a@ t!?a |7*PYfbNmoxP([Z)%0 slGc,@6QTA/MKdڵ-(=(ZPtvBz29B!@*j<

    DP]o Ez.o/DDOh=rV0m(R(u8u\dqx0mV2P~p[f>uc7 Z-& լHey9RJV-B(_4{%D uiB-XIA;_h^׎ QeDƹbBB( :bjC0 EM1ŠrW0CmT fS"(<YS~ulP̪FZ*YY.LąF $񛢛f*=NT]iq.郅* *hQڇu{Sz1`,.0> (S 3G\.Pw&& cju58(: aD49v;QJʺŋXt*z1RP(lD *^U*bC B*ENNdH,ɨDSJnPPj?zK-X@lc vaPZa|%twȼ|+8a*o\ f@h9ȯNЀr+,c9Fcu{GRPdzd H/{;'[Y hR;Ibpxi\>$0Bjz0рlF$q4+ (`soT tP3@|aE>9cNg%bJUJ8,@e!KXNܨ9JX/A((d7BTB\YAPU{Jf!GzB d4P{3Z +_Vuvp"@Ϫ7!܁ *hMp*P!"#bSO:5 jY Y;PGuaV]ԜmU@=@eʟkfG>ebPU)k&uhqc[/{.AMMn*Phd4z]QoC (Nw7u葒jVƈ.yA (5mVv;WVGPQjEj0gܭZ2P 5+oDZe6S3&ٳEK*W % jS4N~#XY*l ВQdnkXC us 0䅙("@f&piʔP*KdZ` @ߴTA FT1cE؋, -[?!K%fae:dӲ@ 0ܾ@**DA@sD%h98ZrEwjEM0`0h[$+B R`*$rlaۗXcVQ]H*] Ss,B3Rq *ϊ:aHC"CJ. QP*ŖYsɑA&-}DN,yVo jFFJkuԶʅh0P%1ʈ!%AOmquH_1Bx`&)P>jǫk)v/?&3Ҋ:/K+DJ F&,/ *WDܩi  Kms\VUCR5j->u(mUA*Tj7#Gw v¶^4?.Ŝdg@%jŒ١ PT'.J\/FOP*?%zܡK¨ⴊ ~}zJ(_$aP1yP KSʐ%Ҫ9T7tѲ@hc@aEx!DZԢIr7w HYAep QJD+zt =J?s2P:u@⬡p9_d΄d$lJ**PtclTVD-cʯ*+(5oD!ム@FVݮ: xqy*ru%^`)c@R֬ s4Lq2]6DETʹB2QP8`Cac 2tm(}}TQ+A,lHa. ^~ad9d|H֨NV)9W +sR͌L+T΅0%rWJ ~`=WR!au80zŋx)U9XJsɆL$-6uFF[lPBk1/q (Ո @̤(SkEua%ߺT S\3`\"Q| KH tJQBkEv8r9m= x@0ӛ(y0|B)9J'xPLAS(j{*bU |!dp P7!eQ](, ݹŀ njMX1\@£6 t>T{Mbj'J|p~ CtwHE9p4')H)EQ|pnlΜeD{?*Ph9GE @4`檣$1AD]_@{9NYuhUX@,CSl CrF8izoj, = !5%a>a++9<̖MH:ʈ0ُK=nFd }]BTd{L/0h/9`964vBȭ!>0˗,d8@a*T@wxI9wX *ʠd:WxD(Ij?i@T@PybБ49jQ U*(в ]е$%^#f?{-<YB[`(<5E.C %2d,)PA l"Q, 4hI%Ps)zgh5Ohik *h-,i@ 4/*`g@ρx`fp*3t:ЩM hyh5۝.PP.r.TDcZ%(^;fJR>:jX_һZ]^JR(!.Y-ahy>%%}(JdޟcPMv,gU𢀔[UЫPc(7 ?) n%>ՊfKPHoP[ڀc(Rg 7_~)7蟎@8yױ{+11 АlH4eoJ., [;#x:cX O$Hrf]~",k I*+т 0 z'̡Iy0 \ٜEFBUs ()::>EY@AD|ar,baeĂ5t?J)]@!]pW`OA)07D@+ةBa΂C1 _GQoQ<_EǮhSPPZ(#!*XEv,\&sT&QzQo$y溁 (p>R AtS.]Ul @fP5]snvEP-8yh@_8nlX `Rh@QDRwH7 SyuD׿ًmBBPܩĊi[€y$8\˻t=憽W4@ u Jajuk VERSION_REPLACED_BY_ANT 1.6 http://jajuk.info Main pack

    jajuk-1.9.6.orig/src/packaging/IzPack/shortcutSpec.xml0000644000175000017500000000335311720500104022564 0ustar drazzibdrazzib jajuk-1.9.6.orig/src/packaging/IzPack/installDirectory.unix.txt0000644000175000017500000000002011720500104024416 0ustar drazzibdrazzib/usr/share/jajukjajuk-1.9.6.orig/src/packaging/jnlp/0000755000175000017500000000000011720500104017132 5ustar drazzibdrazzibjajuk-1.9.6.orig/src/packaging/jnlp/tags.jnlp0000644000175000017500000000067611720500104020766 0ustar drazzibdrazzib Tag librairies JAudiotagger Team jajuk-1.9.6.orig/src/packaging/jnlp/swingx.jnlp0000644000175000017500000000117311720500104021340 0ustar drazzibdrazzib Swingx Sun jajuk-1.9.6.orig/src/packaging/jnlp/log4j.jnlp0000644000175000017500000000074411720500104021043 0ustar drazzibdrazzib Log4j Apache Fondation jajuk-1.9.6.orig/src/packaging/jnlp/substance.jnlp0000644000175000017500000000065711720500104022016 0ustar drazzibdrazzib Substance Look And Feel Kirillcool jajuk-1.9.6.orig/src/packaging/jnlp/launch.jnlp0000644000175000017500000000450111720500104021271 0ustar drazzibdrazzib Jajuk-Webstart Jajuk team Jajuk advanced jukebox Jajuk advanced jukebox TEST_FLAG_REPLACED_BY_ANT jajuk-1.9.6.orig/src/packaging/jnlp/jnlp-servlet.jar0000644000175000017500000017044311720500104022266 0ustar drazzibdrazzibPK 8 META-INF/PKPK 8META-INF/MANIFEST.MFMLK-. K-*ϳR03r.JM,IMu &$*h)f&W+x%irrPKdLLPK 8jnlp/PK 8 jnlp/sample/PK 8jnlp/sample/servlet/PK 8jnlp/sample/servlet/resources/PK 80jnlp/sample/servlet/resources/strings.propertiesVn8}| yIYuC:XŒ%Y?2I/%%5\6h9sp8 qz򡪍TZΈ\pp F\FWr,+E%̃(ܣE!)]SKJTPIV࣬AW75lt!W27Fֵ(x~_aR?bvkUHrF +@#Kwz1e.\AX2*pyFw/BfW4?hb4ˮy:}D5.ZYh?6PHEo9P1٪X`Tuhwj3 T󂼐FZi $+\h~.j+r!tT[GuTUO 勬Xm WsRxf3 ZA@/f,a>KY&-a Bn8”,YxP^|lMaēkxlҥSsA=Xxq&̋aŋ(  W(p#x0GxqA\.6 |,9(Y&i0o9pz ,-XM0kS pڻ-LU6t|`g@P\EIYJe s`lO$e8fM["O" AnPқ q/rs[(TgQR",p`Gफ़CS'&)%`¼C;f1v{Fދ,dıŁ0!iʋ)(^&N-n׽%V,->)װ4ӯ#j%#=p7txX< p"2\c ҏ(֢o6,<\+Q8خrxkjEx!v=;yWYmԢ;WN"¨&/7,e#8=5#JQ^+r (^ cnvxN(1_>%xA?.  mn?+W5liׅ>:Dqr/oj=XRcFRTV82b$ϳ,lJw qR*Ast"LؘJC@hr;B0̫ [&s@X[^Ӗ?u D3LGh /$ uPG{aԱݭ8xE  CUhW"vW=|/q+=Z7 }0]k]~ŇA?[kTךNJ|/PKC PK 8-jnlp/sample/servlet/JnlpDownloadServlet.classX x\UO2ɼL^2Mڦ MlMJWHJkڤMI&m!-^2o)tM(" jUA\HLRVEAP\Dyo,t\}s}w}@%]@G`$n['_u|Mܑ .|ˎ;e8j]Ln pTxSp lǽρY8"~8  ;-r#B{2TpJB}?"'<*+ PG ~,:>!I~x?\3fˀdW/(xQ /]~(ߋ1PG$5+xCvU-LQq?KyW|3"bJcJW:Pd Pd p~| Mb}(NvbNmA=;uaۧj=Ze*GU44mjrmm;{]SKÖ&Ӣi#w2NfƓ5Imm@'ak]Һ}zeHtԃ6$,HJi$ZXW z=8#L1׬ 2hLk%;7; Mv=]k_PTl7αفogpv݆]jsU|2=M& ,ˁ{JTzSvTyŅXWTA3E,8LG疐 58B!r͞l*R|NsTKTOSFuaG^@ NT*AOۨ*Q90S:Wx@E0DŁyEF&*U4*g^gqcxuCWi nPq#qgkUX[a;2r9JVv:G*Vi+`x}*:ԠneK5R*ZqJuPku` x%eS}6R-|">{8$ 2_c*S6\3TvTj$>TB[U&\E*p7]hk0`:"_ pIӦ5a]ƴ] ʺX(_vd:OlgU(S|jn wwƶ,|* [KZ=̗ⱷ-A1wAV-ut%tVhaϋ4 }r䶒.q!,=fbLtgs)!5}W7)]gOv477ʱVuw~3!뼐R8}@lNM&j]ds=ϼbe8cGZN+$ W,47Ȗz1Gvfpvafb;]sP%;}Ib:vٱpNф`ҷf}TEp=.-dXu9FSJ!{Hs7gBRqq6ƿ%򟁨+wa)d; nLY{v nuTSvҲr'tr>qLٙ<R'i򲷨6j6bhq&$ aV,E0Yډ`G06y-Fp-bYzei.DPǁŒq84,-UNTR[De3I\\)cl`T5%2]^9T8*6TMǹH>vqflkX BEZ_UUAmp[jVFnƨ,V+fYsћјi)4 l:cI˸k7s{9\dro礹a8Y܌qp;M4wR9xUj!E} Gt-q"^^"hj,wn`aL*wn9rP:l0NR|[Xs/Q|2q Y=v V&*m{3= {) !JG)Xݬh nD41yP~PKv@ PK 8 jnlp/sample/servlet/Logger.classW_= VaPB6n-?ZQ-1` , [H`Ҥq6Ϋm6IicX&kze,9~`fs;{^Ёk4#SoY9J㔈?G% E n̦a푮E`{gUwYx҇"8[-MMH$wY@\%9&2S{C-GMU'rnZ]Mf#SZ1mΒv؅y:cװ/ľ*8af2GM۶GXo5aO ꞷR뭟1.s+c#Vq6Џse8l ^q8oxp1c",x rBS7e Y uE"30i3":>|k&r9njyt/LX9r6xԔ儋iZmfM<&h௲6p'5lVvV.gN[=K68H;=Mزhp*uXe~~B|E"Y+X6p (}kԱbC'RLGΜ$^P]Y6>MXT߀9߈~Q~,TJj׻s9%Դ=wNe2V>93[׹V/[ӖRbyˬԤ/m#WNsQ:wr .WC(z$m5`'rH)RD2-9vUbypM|Gl@=.>m-/|nD{ RW0/ߥ ΂. ,S0[q@@^?v"HGjU#+Qn"R2eD.C _pkb2|ưyT<7W|*o%x{&7Rۃ\ͣyVj>mt5ڢzPTxX c)0ݍLM3bZ(2ȄL0I2d-`g0W0x=hq+ rF%jj=%ѶM70*qa򬢼.ڦe=jIzEMBPE cFAFK@CNT.d'| RY4 - j*2S48{%9V[3+SĂBTq|ȣҪ#pZyv[X.Vԧ8]͵xxB\u5RZ s%0,<˿_)s0ӋoCM_k zW8mDKSw]RH?.WBHKLdJ8{y} 7KT2ͫxuE3si.ͨSȥ:ˆ|[Q%\.R}Tz@ħ|%a?ǏyurNN|GyUu vDH}i*nB. >߈.8#tr³!-YFܵ,!,˸EN yٝڜqu/["]x?C-AmFéVJ2YEStGCVy˼yv%v+W<`ɎȐRPKQכ}PK 87jnlp/sample/servlet/JnlpFileHandler$JnlpFileEntry.classQ[K`~>.93;gEFtYtcE6&4QAAtGEI^_t(!@+*c]Cgد==?qwds_?wfsw°xo_sL&0O-ag Zq5C옄V-~FۦLfȬX,MvRD3t;ҚlUhĽ2isgl2 G w:3qZd2,6DWo{ s`@ϋG#$4,YDAH1Q cH"AFN qC4Y_qSU)k >sq "@d BdSɮPz"% IR GShJNRPE2U*VijJ2C*Je(SiJsU*WhJaJ'TR<䕡Jj-$Nt":IpOvj:&[ xtAkhm(1”5M뷮mX[m}=ո-= ݾx4^Dj#X<o >~y]˛[֮S4ԭ1#=d7nf%I1Lֶ5&hFY K+}nF:YnD[!u& aG;WEvC@~#_\yX+%0A^*t:[$X L0gVHO<[CJ5iV&}"2shhh} 2''{aVbX{, k*&$ٜƌ`guYW1M0Ӳ`54T6ܽxG@O ը)^hFBXt19KIVΦ6P# Y-\W .>fjF|SSԠ7}qV5:Gsi+eeidhNK ֖fBuQuk؇cībU~V q4ŽPPm5 Q\(B}] &ʕu~N@e=Fe8]eY#Bˣ 'F]S!VnP4.R^FPWŗFvRW ]ѵtgH۷_gW2z0zeE4nPF&n[s|7GXW$ڛ<]n  iqLmb%eŅm ݮV'}*nt H wJ6זݶ,.e]]2nh$d_ 4܇5-^pןy^<=o^O$B{4+d`ז(^ $U*@>t;pbv$&F#=*ĜS_V^//(0R圯3~fh@|D\LjuZ_oB_hkq=):Fs =Q }duیN:҆^B*x 3*'xN=pYKTQtg)̔6nhdИMsndyYLV9Ʈw7iX4xĄJ0^h>JEj&I׹MGR@eJ R 0 F.c1KJ!Ɉ^L8HF|)**&y\s-trIigcZ'#L3&d-N ; 3*tM)2c,TdAfNBU>)dvvh<܂&L󀻢!TJ*Qq62[Vk)ix4ɬ &ca7qg]Ŗ/\ēs&OdYeIh,iUJð "O3NgALذ-,G!V`:jQ:.|o,=Е&TS`繴 LqM0mA$J0b{{/G\6WjՕQWu0t5b;ɕ錃SsV}3-yBq8k-~ms1oS) ,OէF@:!=hSs'I}D;F18IqDa/ r58G$YQ;u<@+}C8FI-fD'ꮃ#MmFC m؉.A;DQ܍8؎0ƛ؅w4\HfbKS5Sp%khqu6vnԞaԴ|TNuwb(>0ѧgJg>r[kr k!,Oc8,i<%| 6a6:匹jJc^b=: ^FT/u4)g$HwI aKM6g ^96} g }V wf*ipQ{xJhNe-7miǹe_t*# 3(Eق gy hA^8 A8WO~<Gx C8Cx/] c| GuE: /Lg⛴ ߦFB-8L5 {on|›?G#zoѳ ҷ3z?mz¯,skgYXj[K-޷4wMNG>r!>\O,O{g˃|jy |G`|fG,j!Z@yYY=4%# YȩM */5*vG?jNpv}A9M<;{[ yi'd;bJ =+~nYhiPh:J0J8ōTbdž5zWvvn\˷?#$wVSV\Eծ`r=m+rؖǩɧn"c&iLnWx] lg3vx\Bv% t!NKbvs3mnq_sS]CX8r77oqaTabVs+p9ڊ<6`+gQΦN&SԃK(m6Jc/ gAԇ9S,3.Nqfҥ=,CWP)]Met-ͧ먆3&ji30s5c.}bs llx{x0wð[.i}^rGicX,߇<}D UV8mV'Yt/}a/r0a>Y}UpPKw$:.#PK 83jnlp/sample/servlet/JarDiffHandler$JarDiffKey.classTKOQuKP@X`B"є)g +l\aąѭ?R5ΜsswϹ?>T1$"!)1 ܔ_$ܖpG]ypO}c kk8Y.{5 JUvr 状k-G 4A<`,g%WӥY]W o;[TۙHFLC+#Ks0Fkyb^('xg9_,޶cʌri3T1gyY-8% tc@h!]:&nƷwD9Xe΋WlWY޴c O4Џ>p@\~ !\13:/5 [aC-5MdBB|\;TTr0UQmn#Лa\5?A1SG#͑#fzOvf#qxHUUh5#`3 1ޒ6STLj׼J;a+BRyd H!1}+(:x|pqXks[:"yL@ . SL6f*0/M䣫\cH:i֥ i*s(! PK$ 2PK 85jnlp/sample/servlet/JarDiffHandler$JarDiffEntry.classPJP=7icFqѦMUT.rޖۛrFW I,vff̜3/{. a`6 3@IJ7A3|P: t1ԛ˥#C TZN=iD/FnZUv˿zc}%@Iszp㡈]j5O4 _Ňn[ZKQ"eL+(G~`7a~`e RdQ`lO"`~k풭?gʮÛ3E ˂Rʓ3GUSF PK2PK 8(jnlp/sample/servlet/JarDiffHandler.classY x\qg_+5~z6 ؒeK,#"ڽ^+K6%Фi!5HlD! ҄nK!)yqRBfJ+ym+t=̙9s>Zک!ч毥COd>awio5? 魯OCWi 3BdR<"di؆ T|Q?KHaTI 1 4_ ~R|ESxZϨ8#;}]?jXE u';pd%*YoJ-i^Qmwd/sV7<+xU!w|O,zM_ 744<-4_x[_xGoTV_*xO!`1ݽ)f&93 `2i$ Zfuk]Mw4|̈́†x,ic`t lhlnjܶigv& Ff"빚PĖ٥4M6`F[޶`?9G=ycd?j&aֶ{z%-3ژƐIX`I'1iYJ EGYw׺H,b֗]bʔfaW`WTfz s(+H!!hwlƢ`ø~H^@Jr|84la &wd$#+zSϺ|/&!#,L6̻:Z3 xmS$jX#4{ ̇(mP7Y٤hFp42&b E3 H,33zn Q#Q#:vq>F&8/JtQvБ̗H'ncwPPR;T-D7rبNSurAfe?ş8IťIA!N 9uR1rQvbpPHש835|&5Xw`"4wIدԩi %̚ni\(8vKfNQڞD4~oݼEW5qա}<| Ȏ–$3ZHo%,"Bl]c}HBjdsf*w6Q[a6˱mfZtJ:n8YylNgQ%=2AÈN?&OH̯PNۨ]킉92'G!ad$bzI"RZd`PMQ(raFf;j"优H-Q:4|gx?};k FҼ*’ w V6zv$)'(/QO23pz.9%Ө ]iH$8Kdd3<,oq_bpayۂ} 9䩃ә+Ҵg&a7la$ 9gv0j6VQ] ')R5y=4ϵlAL4FXi_4qGKWc-(ܭY9es@K޻tbpyƮZGCX6-B W)a֕O 3'"7;o mD2w:̲ŮpWDvY5l'a|"?ܙ%!;ܬ(Tgc5oaC<^~-&=~䒚C)O[\9p|63$ͤ"`;{Ays`\$ kyM,h?4vicpv%rmEG)ﺀ]{7|6TDU gऑ*~u1uVP, ܗxwAq>'a9SFis/@Ia0fǛ˛¬ʪjcO937N2WZϕe{gf} I,C=}Qǰw'O88{Џ{0 ܍Gp?>OcM9_9)YV߳۰ڳ$wi :G<9RX1җ>'[U^l`u@ gyUxy՞jtx{q^'sj^q5u8xݵW%&w`&X'0_b<Ő*Vk q A;`7E'>^B/;~M6,nǫ ]~` 7V9u 8).C]g(Ś^TՀӝBNaf\>pګzuǰS5^5kSlް;O#7Mi"cku J)dfd^0~[w/Fhz.G~Z\y_Lp9u?c3#FfNi-r7QmO ^n^G?3GƑc'B]Q1:xW-NY?V.6_^NO.<@n||3V(0ig8[24k),rll+SDDj$_nz|(T9 }p|)cs"w܍+%Mu1?a䬷:3ZfW4"biMBܰL(ƍ9E9wzd(w"ZOKXr(aɓU#=D#G|8wo [iz/gǸV޴syֺU jqoI/t 1** TK(i=P=65hhFtfwh1jmtFi=gx>i?۔{drT bmTO5Q7㿗n}I:δ1Ӟ}$y!ӦРM!<>h+wVEM6}Ͻs&r.kzǬ[_mW)IL~PKcǢqPK 8)jnlp/sample/servlet/DownloadRequest.classW xT_2y01Ha8R-j hCI$83asZkbƺDZhBV[7Ixyr=s9͑> }ɏُ($w;nv |B;{p{~R>?_"|Z"(xȇGẋ~Cq'T|F>*T *V1q~@AYx^ˋ½gbqr؇ #* U|IŗUU_T|]7T|SŷٷU|Gwxߓ=% Mz8'mt<5WAq$ddv3xžM_H}S "lhmkli6.T0I Z[ۏ8^7շ/ji]vHܲyx˨ mѥ\ ګgn4ҙx*`b4֗NܝiPMemi z:Fh"`0JX5 c7~"JXOE3\/4d)m_6ק)q 5MIß&;\jȢOqDR֞CV^:!: Ǹՠq0h3`*c1 JTVȖ}* ):9x)([oĬg9Z-\h5%!mVUc7a$fio]n啍ޜÑFHvdVES5VSm55ՊLƢxfa2.=VV/2@.~\tyͻx.u|a%H 19oIXOVJyQn%WRn%WQ`UP/P$DpJJCU"V W@`?ȗPy?j! 탧f$V-P`" O8D<)BT" yTxnSWWx1j* p.]6AZc:.`+k NX=dVbčldUaLPjZOH6cFtwѰ#$E21l.\Lu0!\LyLz&P`ҪV,e4V @iS&jdJ?tb*ae } RN%.JrWb҉r)zH*"Dr7߶+g%"#J}(tz&HUYP!RŲiJ4ˠo2la3\Ơ_꽂>*|An7K`ǮٔF؟A= C(Pa63Mu!|3uڽȄ9=, %0cgQ?r=깄慶)֜ fc9+}Q>yAV(Yjsv9j p~!;yx7+-[y;q2nccok7]w3p=La3TzF|#>1dɎ%Oy3›b{Fʏ'f$tk*8M&^ju/w5-r>CTs ^jZ4=H=4}x43gXBk\MNXucMvHSgiKiķZCmpز; %| 5RsB\[NX I"&9a LaD:',X%-K4Z(ֳ%zt93?.3o8mX@U,X6P;*{)HX06oeGP$l;b2HNjl5CTuIHq1跅!)H& [u+QDPM]/{[%n Z#$PXXuibA%ok27}Y6UHS mym{8(TOo2`zN"^?0{[K"~dv\_ذʿneuUWCY) )᮲f- wU W 4%UB}*Uә&뒒k׷6655Lix;p, [9Cڜj:XC0 (l2WE? (!r)j, |CDX֬n`O!%t;*ꙡ'أl%b#9j8@ .cVv*}!-HLM|gZH }=jEiN`8]/`!,F7fc+~m >1;񾲭+ufRQYSuE$B*evb\L#թL.H2Lenv1KUb:z V0VOE,) D߬Q>ҳЦf&ϵAV\q:tvgQ'j+͢1Ȗڰ*+?+-X-fI dV-2٬ߖ 2%P)\P)ƾN5*wJ)^0F,Ġ T ]f,5 x]:V mX.`  )L7LI} )uzt {%yR,Љ. EZgc*QsFjj/Wįx{TztRT~IwR0"Ep]%i^\*/0/)BirյZJpSSjmJcl) wl >-*Q4R?01 NN5#sPa%;c.>Po;}Ř,*XYL KHhڻՀ6j+Yd!5=򻎬GBT $នK!UT>+˶jJw>c 錎@W-1$_HCdVb3X,9C"25U&d3WBFǟ}Exj4WH6oV\bo\ž`$SQek|*nSdAe8wa*nr#, OeWWސW2 };{fs֧-\ך} >?i_r^8f ~-1ӶH:#$iS5V_i6_ 9gS:A`y 짿t0c"Sa7lM9v`'.*{)vS|a/Ã8}8xpi[x" '8"T) O '&pZhG\ aC]8#9a^ yi?̄Gs(]+Sێ ^dsR+9YaL?OlB|䵤Vd;FbQB*0#HF@2)@gEL%L,F_Bz -ԇ$΍Nf0rfOP6nl -$}`RLw һ(E"q,=2IgRYf ڲfO7r)=; ci&oa!~D0fI:>5YdfK $ŒԕI'fD/p0^,ʲX2>#ca"qקGQSE>FsӁ-Djw$g|Wt?p4Yȷ` EΣk%xR'^K"K9&^߹]7e]ot@\׳i"xMD,=nҗɯ)nXbp[8n IN Ist )]4]5f1#k(spPKId PK 8>jnlp/sample/servlet/DownloadResponse$NotModifiedResponse.classQNP=<FYXݙh(FD BroVretQƹE1Qt13=9s: $ R(de+&GB!Qv' M!yɆ\W }Q0|L|$E(NJ9}zu#L? ߁m#E5`ʹ\1Pmfb5*@z ll3M3DZNu{26%z[Lw@a3E&(SPQtPڠlQvU􊜅~'P=KUɔ=mYߋE36 iC USR~ PK{PK 8<jnlp/sample/servlet/DownloadResponse$NoContentResponse.classQ[KAu [/E/f$A;:fԟ)Jу3p.|:_olȠX:J6 lrgsBV2M BIѝ"u>#-{#tKh:#gl-©/".Eo̙ZIl(c6=5 ҋo]{+ 93["g`.'#vƁ/5Vd$:fawPY&7e{n_/!T[!*%>߈O/ kb=z=AXaKySI(`6J|E*_<2 2[&װp(i PKkI$PK 8>jnlp/sample/servlet/DownloadResponse$HeadRequestResponse.classT[OQζ ݢ l)w@(Y#,ٞ ?J4/LlL}qfK!x3g3߽FRh !Y FX&e=:b<|rũU)Sڰ,ӵԚZH8*e G/K}ELb'&]A9A]amo(o!Jd }-j*:w=Zi*H]CiWPKSPK 8?jnlp/sample/servlet/DownloadResponse$FileDownloadResponse.classV[pSU]7In -E IT-`6Ї z$71-~( ㌣{ߴiiӏ>{s:{_@{D[={q<_G>a4ÃkѦ@< `݋aqIS<=J(H)w"#$:GQ-ԌDFYw`TdM=mD $5J!].g!=)!wn,Zh_wHܚShEn\jPd$YĨ au3 ԕM%CUyS~@eXIִa FMxLd, 7IrfC=E{ -E{ˆf&mBSdGŠ [V&ACoP4wO6Q8?؛ec]gnjdZD400UP"C"*YڊmX*rUь*0b;IX1̄?UI;DLgR(4dIW$bNˆ3[e-I=C\?+*vn iQ,A$//S䞎;n憆W7E%KK8M{k}nZZ*CR%g>L USxU1I;IIQP˷3HYڬF Cd[LA.f86.(OX.hXi.{92ZZ9޴6%D(i? t5aPG ۓ&atβ2M\UẻiufqyXVDEmr\dyvk&/uB636 7E Qk(W+]5% J23=heی-pImpE?xR04 G~IAis(NWM{\R\r\*oC5 N칺U a~HU~|Bvz˦1, l1m?я޹*; ~?Ie*C6B!dP0o1 BBJ4+4}.+Mr_߿xavzװ>5lrar2:wp9=i2?*_ _b"F+A1|a|OC#?x-J7àŻZ$q;2_abi+^o3PF2<g eq >{Hn[dKN/PKuvO PK 8Hjnlp/sample/servlet/DownloadResponse$ByteArrayFileDownloadResponse.classS]oQ= mRmEA]`L Ƅ`I-rw?BbTu@m(<읹3sޙu g2XC*nk⎆JOQjiq?^TQVQaH}.Y:H!-Ű Y0`BMEPK$&!PK 8Gjnlp/sample/servlet/DownloadResponse$ResourceFileDownloadResponse.classTmoP~. eceɦcNnDM0DMM1;6m(?h%2 !YHO=9'eUXeWpU y +*\aUY`kCorVbn1u-M}wMyE5Sg]0v-ܯ¯q3s*c;i O-2BW7՘ow2L vC@;v˭',ydm4P)*3ky ipS`CYP0weҖy,hyV3w-pK{2?Un2<{ '8jz; 36s'"ǨK%a;\жwvy+1!=:"|8QtJu4+N2Y,EK5eHFIc<0U(D6Bod͐L Lj#2I //|E8@$OĨ v}sL~JM2y%.L]uBԩ8BM$$!3zfMqҒq3PK??fPK 8Cjnlp/sample/servlet/DownloadResponse$DiskFileDownloadResponse.classTNA-v] mUP D 1,tfw>MM$|( cg9†1Ha"$*SCZG jԑ V}1i 5<&;t\A>m  %G:Sœ,XB V5!ܹHS. "y22'D&A_t J@<~3]/dS!s ȥCK9jv 6Nڻ}g_TbZehX0X2Ѝ/ \U4x3<'5WTCR*r7,a@o5[Xr\|P]ƦϹv0%P=fyqw"K IZ̽-BidUȀrz]* 'LTzȳeV_&1o1F(cK?K3c2S}lTE[&oYv  Fnn2xOd#RAzZL9h!އq,1˿}@ZM 3$3U\H]%SA;yQps,%1GPY<PK] PK 8,jnlp/sample/servlet/DownloadResponse$1.classM 0[pEqi J'-1)Mx5CQw|Ã{~2-ۛ3l^+lmc k+Sr5C 8akFma4JeMKMNϢ躦W Jy}ECW\W%V8K3H$bebj])izN~LOK^8zcrVW*ZIZɉ9usLE--zm 0y-עهhT}zKkJ윦\QԜ/q4hlV|&J +$j2t3-}p65ٛ4 EoY}ʑh؜t;xz7no8TL&9zͬf$.ڔNsJjǶ^s&Fut/ՂvRicbM3* $QB]%" KĨLjw, y꽵=o/ckHYtO?Fu7|s)% pڇo8 $|ۇ$|LJw Oׄg|G? nJKYқ;;wT0ע8gb<@(FE:a/؊`7#tD_N_& GgMz#HAJ0P KDz~: #tCQH \ ' Ym9w 1NЛGN7JxK$1qI"(I)#S'QLܕ.$)Yd|LO RIqJ`PK{Ky PK 8!jnlp/sample/servlet/XMLNode.classV[SSWvn'Ѐ  Q뭊XUbCֶTmF;;SSf:Ce>O: cN/[k˷3 >Ç}=~4Wf}"Ew5{~ ! lHİ `DĨu!Gz`#2x1ET1/^\|‹1aR̮vDu@8yV+ǚeZrm2Ǻ<$Z98f ȉ6b@ArRC[8MSgctaʳXK4pJyUV'BF +@)M2+Db:zn+aF2Dئc)" KFG+4:k$>8fhG7pXإ&?###ᆰq8\lхu4u|$.55|E2^2%\>V(-P-Qݑh:t ,w^/ E&ugB%52kcK] 6Js_DP$89~#i;N{,bQvQjņ2p='xEgnh}dfMeMXoixaNe4MmlǨfixsjd uiC9c=NtH1{J5G.yC{·<PO>PAm(u<ʃSazOꑚ-*OIy`(v=Cy0֓SNS_{ |җ&;\UT+Z-JWk .gKuLR>fvSvv۵v3ڛlJcEx9+zLQ>@IJkl(ɷ!T`nn'g+Qf̡Ȝ0X/sK3cT әƪcAAg@]dLUiؔQ:`s Lje3XXZO4*:ݺNn/PAn1nb?Zp[iqWŧ?>6f)ԫ%FqOiul=r>_{ sޛ/8BfؿlgQoΠ]|no3%_b^oPKZw: PK 8&jnlp/sample/servlet/XMLAttribute.classS[OAr [[hAnR0 @ //d lnѿ0b41?xf`S6Þs;9ߙƬv$#B&`DuTdTf,0 O1`!aEЙ5ʹe;5\w }Ӫr; ܮmXxw/s Ys*R5tcZC:5\&.ek8'Xe 3x4 3p'aJbHś=v$w%9F@mٛQ\5zΎ 8- B, Z1F.&هići4EL4Cw1h _8P:G6FëCHJ@  ױd=lqG'ˢ}_~!yu&ȓ]O?A봺ЂEy2^oQ-YnԠcP]1=Q\hx! WLjNkP;}V5Ю?xwִnsgs̝7.^ڰPJ#6*f-+_*a܏#쁷Gb_~ d'G!1 K.7>iILUO23čv6P&ܚpX%j|`ZEZݎ'\yvyFG8g}eE[kU559^i>Ղ=??_.뀙g7BƠ_}P6FW= ?PK2 sPK 8$jnlp/sample/servlet/XMLParsing.classWW-BZ +m IXqlT86 ni M+$,46i4׶NZ&{U4}/}c.`dp63o.K?I 4PoQ4@BoǠ əaa!Q?ĘN 1 HƸL3>d5L'e~Vvr2`ʠO#W@>>||W<-9}@>+%5>6by#76Ʉ`wqHYZ!q&5SX33cm2fΒ d=!JQ2\$ٌŏ $e?aVjb>#Q33r??ֽ:QqL/]NJ~"sֵa&`q̪ް&o6:Mɜճ Gp7ru4)ׁE$/+z5^+).x8jY=Q!P;ʦt -+8㗸WB~~r~$t ({ FNE1@9:e6ڜLǎrGf޺>8 Pэ r:>D**䙎q?c!%Iis:%]EdzFwc6l(XYX$Ri[b7*eS4W.kwj|=502cR",,L]׶ N |*ٽbm[lE7R/w;\ީ*T[ݨ\WOA#>.CEv+sJYҕp.K&& 1D+5KNf.w.ƒ6kGy<1 BSIm]#ʴ{qg]PNT^g t, m{=յ\/ VC}vΚe'< eR*L*DTYק; _G))4/*4=MhE=WmmO-_#i3S\y<+*׽x]l.}d_qG/St=t6:^\9͋i`ڷ5@,^?\BuoFhgK;簫{H8mHJbL ew#{7G G9Z~xyxx@oK# ϋ ͡9:.θ:?whUt=KƇ46\==wbAu[~6mt O9u })a?qbwG%١p [pGP%UUP ,s؊8x+ĖjOF;JS㧉NqJN/G)vS t}8RwW#;A1J'lcLu&OjAm!IioDe*P\^j4LO]x.3Ӈ̟"Ma1`8X;]GZvM#|~[]wyK@>R*hC{'j sW|PKկ3oVPK 85jnlp/sample/servlet/ResourceCatalog$PathEntries.classSn@=c;1u}PPZyx&4(iaٓH|HDH,> q}8`s333O*lܙAjXӰnc}rkēTq_6Ef/P h9\#~әf5:E.T;Tk0_H *#w8 nG*Xaӱ`yie葳X:48"]LQVI a0'cX5F+ҕhMܦu"vp R,2t'](`%\?ׯRd 7_.Ō|G|Ko\)C›4Ը>hs%;\/{؄PKZByPK 8+jnlp/sample/servlet/ResourceCatalog$1.classVSe}te[-H^)*j1PJ[/K7IZ_W}O%`ю:q:x$`BH7~~9g[D h9%c؏bDF̏Cc e<'yyFƸ_IgeLxQ´p 9/Y5' {0b%1yY+U.!7yn;Fƚef#Κ$ܴPx"i 3혩;r`Jr̊{"Sև! +Y%=ٻg8z">XcY[sw C?GY͉^=yN:U޵hwx ,ܿpd"|aͷHp7~`z9NTWː#@ ej6%Kh"nZ扈e[㾈mj-nQ;BN45lk@ -o_EيDj>MkUt]­p&RZ` ;A︌#$mӂ%캌CCD- HgA{]+UW lؗhg_aa ٷ0̾SGc?`3+ecٟLbR+W2嚶P'T>!O; PKC}2. PK 8)jnlp/sample/servlet/ResourceCatalog.classY `TNq'77B 1I JeIx1 dp2f&WZ"GB0junnݭmuv;0<>}5L& 2Rq'N+xQ38b.2|CV_QWЫ18-y^wl|S 2Bk|KxCeV|W'$/ 7eW}ok@tP#Ïd[+d] ?U32#A~.E$_ȖdKJ~-_d_X&o7݁Om)~'H%~*VG4r? 'ßdx_,|\"yg`dUG#BJʔAU(K%U1*,GY4TrrD- Jh|MaT]-*M2Y VEB)Tb?]PBnBZ_:(ABzdi4oSz͵5M˽5uUՄܚݾ/Z^ϘP4 6:  ;ʣ^#z&ڪGklS1+FjZ?dQMzR @|/V P ptZV4瓌 zdoG!ch3oaJZ{BϿ^թGcRZŰ$)_j;bV'!%bmAǭ D퐖[//Fi{ G /̐jW"ew!# -E9­d)BDBYES=K$\$7 )( - DXX/C}Wk;|<6]%LicCDaͺWRcː)aO2~?s8f=9gFJ",|F8|ʬ@B:m';/Ft< L5܏4܋4A`E) d4qD0hWԲnp2ᾣ~ "(tFw]M&'5M{C1ޫF^9} ݯB!zXG4*F_Hk9'jZVAzEB,s5C胴Yſ9ӑ 1ɱ~azBouJ8s$@T)sʂGNu#苵#WfoY(;%GPZ%80eu6 5-z}Ȍv;`P* fI=) ='SK,=o,QZ ^.+Юwm ,v 6t_5,# vlCI  פAץY‘K!~@tm]DNbna~iNg 5&uoHћyNaMohdKKAS7 PK{27f@iFX}]x\Ix6t9}TK4i/{`v \oYm>ɭ6[x޻:}0 ~[qb5m UN`*nus%[p$m2SjlpՔb۔kirJ"|W3ҺJ7CgK9Ɉ H3,sᙓ;:9sfnVrcF]b\$zN-x5n3H {PmHU,$KyK,loI!Sxi1P$aٮbK:AYKHx߱܅qO.#[[Z4'%\~pUPAcM,L vY t25қnfyɑYuP7"2>&$/h$R6_aךmn.ua>͒DSZg8֨ȒkkÞ`v~itCsRi ɣL煮RK4eDI*tWbIV¬W_jI0s(C+B4܁;X=xqo;X{a{y,#|ǩPx\!F濅[17GE7JPj챺spTڜpzpin#m1TqdcCv#CcX;8r{1ޣr)quYN= c#e^%(]VqaәL~ŮL겺^LSR/=vS!:zS cZe39}<l3kf'aS<=!a-a)Mج26))ůxJE e@k7N2cf ߳Sq݃8XCmrX68+a/xs9|>dsz9'M# #ɸݹ)Pfjm>W[Őg_j~[n1)_D)lIGv\KڙcT<#,ew*  goHx FǫN]6J{ nZ@:I]e ,( +f Ir`X`A!B㱇p9q_&xUǻ9h~G3i ͠<*$QʘSx:al\|uR8A,`P )lxu[`lVxYݜlV6?ҙR\Pz8ƨD =֊8XSqϵRpTڝv -.qq~ab)"ʅ`1u0MBZ']*߫وd=8:hT)tȃzZm~ -{i)2A5^[۴ LLB߿QΝE\YAnKQz]2r=|wrۀ ,6b Ԉ|h6g*i;KHjjjeAEyq7 vp݅nu,P/i/>}#FVOv2.6 f^ȳ ~O3a-RTAEI|)=s9V3z9l7c'Їꍣ8teo93:ܝr CCq&VwFΊkEscF5V;8vZ>t5r=--sǠq2AgH;%yr48"C'0b"uŎC'e3|Ӄ}i^az Ge{f¾2[&rhn+-psr)}n~Oи_~EOfPKX'?$PK 8jnlp/sample/util/PK 8$jnlp/sample/util/VersionString.classTISA:{ " .,&;aѠT@ IɄ zOx…Vi2U'32A4={DC#nt`C؋jtN\eu{|i} 7x8hȍa{FܸC-,38èe;j}6>Vwȶ"c>jYsP59BHF$f1x($@ETvzMKZVYyK'RמKC@piԟ~ n#\JwU0y hWưpMU0CtPg{<-= SWZf2Jɴlu˧fDhEM&Kzmzҙf 7q3MrRNӱ%8^ԯhHoVлS䦘:EJ4Q;}`>}B8g' aXtҏȒ'FC+qԘÙwrs8^{a_{?"C9Q $:iE:BdFcy +ʸh]Y󿼝Ev'o1H䭪 %(0nQ#'5)P) J.QK >u[-}p!PeK˅=} K5X'/S| 1͆PK]Yw/'PK 8 jnlp/sample/util/VersionID.classWkpTwݽwn6!\ؔG۰7TPHCٚMr,@վj>ڤm3QTavjgNꌶν] {s F|;*CB>''8$~|^w~$øߏ~  ]~ QBQ9[HRȈ- %$-dT=B2BBr8&'8.Ǘx0(<$a!'u_o.?:v4~,ޘ2'g}{0q=V,ޖ9;s`8RPޛȶGFԀooێM4sdc&ҩحT۞H%r;#]ץ@kIеmݑ飵x8"ݟEu HN\ϲH{d*۝}G#pTpS1dɼ+(-U)X.IUՒ}gUQ^;9jgn<_YRT:3O&NHJVegk&K&RWJK`:$${]mQeMB N3W2ql!j <ǘkW5ѽCVhQ,OI.LbQ|+hKJՆhxj8mh1.v!{V!4pxs X#ȵGsgЦ`X,쌁11Y77<^˷x(:3Y$drI@Zpm6 ˗SCagˢԀ}sHl/[{u$+Y`N db~xf֨e48Se=vJ s,qƏIJh>k%)嗢D6g0qq?=JG]+qW\AN m0LJ(rjeH@¨FZy EGG[|[ȗQ-GP~G'3pExB4 VYxa_@َh15\BRO0mX;R2/b vr10׬Ta(R-ULi6rsY%ŗP3Uj6y^DSe,sZ<䴼 XjGS^e+A2jK -#nfԤf$LO>HAcb˘L*&&Ђhe88za)᜺stIΒp^`.+~1 Ɵq?ѧc@DU--AD!yY ơkSsѻI9= 3*Ȗ3MkUω1<OeP3iML#\CN3hivTwcb"..cz/`ݘ wYƹEa4`Jxh0{Q3ou6}e7psMK٩[SVfq.:3 ӌgRBDFG7Lv,Xe|*phKg,8+ߪ KXA*nO3';6SM$;k$n^Y'񆴐w.xJ[ ('5]~][bm; '@DxO, "pḧ́'QԨjͼ 3jDg* ymi]Z+?(qu[<>wZ{P!1 ;oFwWQYn{.!GMvR Lb%0mU4pK)S#1˺6H3-`UX"Lх`7: c=a‘8h<پӈf4vx0g] OiţA3F.K%v27Xg!e 6bd@4-9h ž䁐aow2p-khl 1Gk0#`bH3J*?ь)I-sdfԈm =lad>ՎfI V;gM~RfeAX|tSNeƐ E1+2) n"}@V^m_[q#(N]gc :_#k"VIt hLMOi^(t|wqZLHM{O"Z>+Rܥ*M:^KѪ⨊~/G:^Q?ƀWuG-1&\(dtq PgDY<7B'T H`5aZ޶xXg!1( 2جc'taqт:F뱁?%lұJN3vR:OUq:qA^Ui|6oe4j_M]1?EAGq}홋:%?0&ϸLشnN3M(.% rt0Uלv\\yٵTS )a5F `b-FҐM6߷yb9^,E[zbq58 8cmԈDL]ꪼ|IonQ4 Bc\*=FL5Fkm6S~_V;ۂvuEǯmfI:\C͙t?.YowjӲ\dGͼoR%sz\y|pl ]m_s9"07NOer ;9[+S4V{jϫ9$mͼZ7S@IjQ86W9 V>a 0,̤0no%{WVij2 ¤(X-Oj,w+w 4%_ZuoC^h^FBoNGDÑaLI`Y0򼼤ø70mPTx}% L/DaT>u㎒#SK$\Ֆ,C4K̫G]pw:T%PW&*]Oש=Ou𪧋]P9䧧JgsE^_e|)xE| 탋z(J1HOb=6ڏt&=NztP/г8H0yz2M88 a:tFHˍErY`NmĦTu\\U Y4*Ha(9N)y*MU$95r $PΜ(eNE0wP.jCPp:2ϓ s|E.سc>2921Oybf1uN.S[4Cq99F{ IΤ^U{2Fy=<6ekvkͱ5N\L~YwlQI`D-}'_8C ]wM@,KU}I*"-܊\,-dH\2]UYU*yL%K* {O wC ?.h?k/ /Gj@_5|F|~"&I%ن!Y~jHc;SJ62m#tTViJ jOpg<"L_YqMK [ @Ȫ Ca?7d :ik 4B`L_˳SJ5.QAw;YTzr\0A t k~x:| w# _IDfgpgayA ,z;+ƃx0C Oo~_E]>BuAߠ؈i^g7rkk|\%Kр o/~Dx^xy\]qbqj$LKDxu§Ujq'tP %1tHci%JIPݛ(G)0 RFPʹ Ty3@?4w2:W<JX!M7.ISAXspbu|ʨ:r(;j29$S*Kicĺ#n5 >ZCaP@bneD%e_~}Yf:-H4 pfs􉝏P:9qh5{|3s%aȣK)Gzqpa(&=.N'QͬLw b f|nE!K/bz[,c 8!32[7lt7̞Ax!]Sf X/>%DI3R{޾-޾xDԂ5 +f4R@m'hX'VGa598( 5H/T> O]B5B= `eċZŘhIcLfjWi{\qc#|ޓ>kQ~ߟ/70#q1?c,7 ^n6:34Y˭4n&ij a"K<.B8^n"GzIXxT6XQzJI06VĪH,ðB[΋,Xd$"a"muX_;!L Ċ$У"َ(9:F.b4GQ8r929l(ܤ_5B'1¬8CXa;%P TL!RYb;5&hFk\!󘜪S8}|4XdgѲ"49L=$<o3hOLݑ͊ycj.6KMjPH oa ۋfBŬ*puv/J.-/rYGF b̗ e̋Sc`aBazIΫI}Y,c,s.qXNci!sqGQEXb5yB9T#8b3qODCE-? ?<ɐ@MW G b#J Њjx hD'x4 =漜vs*Aqa 17?n' wRy8H.R\{h+NO{tgp<зq^1z _8OxJ fTR VԈaiqV9ɇ祽xA_E.=oHg^^77-xU ^>ߓ'<o3<?#y).?;>'{oA/ߌ? ߆?)߅_#x0Cw2ޣw'g|-*Ĵa*|wUO˛\Q\W(/Qr!p0Jr!JfZ\:mEH(jVbPq(/ѡģVl)vXpme_j>rih :(8Bͅ찞bH "O,qdb( ,&*(դZ7Dl!;i2~-4w4*A3%/Uxfis4/LsG`=1{sZ(WɭMtEJ:#|ޭ:(6-? Qh\z]9iZ!SlrLe$*J|pPr̦E(%X@Kܸ*L+Bգ+_0QԳ 95M:]zd1sxaVk' Gyy>_~j!o|v[kr\Jloq[ g# BXXEfFx(JsjXU\ ;srpQeʨKgU|>j'[9fdSHKIK <d[+J}k >L sr;{;AL0D"1ScJeLCO癀NЦEH3A])džyˏ ({\ŲN[>3e=mS-ʎr%4vG;ݖv>{od8x+# i8PoX+ڊ qvDRR]t+݆qB$UBJ+0I|%R=VJ:u)Kp cR K\,ڸ8\Ki;.J;ԁ| uI>RdT$i-`B H&}vi?*HI7' WnM ^ p>˼xCi&t \t×1s'i8%όXƤWc"y Gϟ/aP|J.almŚ7PKAyPK 8*jnlp/sample/jardiff/JarDiffConstants.class]NP i\kWF qGPhp.|xĈnf曜93ϯ 3#c0A^-S*2oXXIy ϋE^G"KBl{ LQ]?w]˳ \;j*,J.LfKQzc^Մ4v]&Y*7ak*W5ȲJ޼#L\l:ނo56A+h!iBG}+H8UԁXo=TTo:oPKCfPK 8(jnlp/sample/jardiff/JarDiffPatcher.classW |[uYҕn11njHfKȌ(ސ97bDGptpydrb2T ]G͉dI(ay:tvB4/cŽya=ͽF;əo%Z& 㜡z'&d[QDnIp&G ;^s-"t_jo'ZxÑlVa*+[xBN  ò 'L.oh$B|~5|QHCB4*2ʩBJȫ bkRF˨5ԳgkgMkz;5Yp7~_ýO÷h |a2hTGjt-ϝ8o}A3-agvR?y$H=<vWѢn#iD3u &)|. 24u}됶x8*}Dnh?,#<Ѽ7–H% rOsT⳪bʄ͵cB3a Sr`s%cJ&V񌿽N@0[ V H80#,f3Dz9]GqC(Whbk\3)&-Jyg^&4Ͽ=#o>.1.ꂼҙ\*G3v+''[>΃HX儔m˿k oUy9K>%l JӰ5 朁cP *3PuGBgLC 30=[WuOt4J (#"ݕByT/=z4*DZT_$x%yTφ=Soꋦs]{Na[J[+]ye1ݣeRҫ`D+XFs[^֟’O`}}_REpkE^ݝF ZV,_VL!'KZ>/v{ t%6ȪZw)Ϣar.\ \)A uT 4V__B} 1 & 6+2ؕ)`WpukI"~4]F+;[Ts奩$A>=M:Gd*62.ą`uc8Ω/J %/p= ոp#؁؏akhWn݃a3“0A1D*6O~$s4~.i%- +pm}ԍi-x݉GI:qƣ,>Egq^5.wX[MbjvLaj6;Y#+wfIa+UTk:MkxopR)mNr}w~/pB2Ϙx1e%pu01l@C rߘ)4vqS)"ܐJa 1fOizj+'"L_E%#R`)1;o\'m4|ȁfI"PqCq;xoմ8|'aZ\>W͏bs;G^W΢d2ڬ Vd15-)\ֹf~Np5tvp­!Ra# T q*@UXK^#jn}~nhLt)>Jqô{B{jxp,5t%ޠuxߋI&VԘide C ^Nnj|i<1Y{_ MO!BN@oeϞR-X-F?u`nUԃ;prMm…/F([i/OYdw]ٷ͝ܡ?tPK)Ãb PK 8/jnlp/sample/jardiff/Patcher$PatchDelegate.class}@g{[ iИPibb\ΓpY>[d |LA-\.@[Lww#&ZXy5 %SUK]RwnVZZ˖0Kۣ%{~%vxN# ?PKO/PK 8!jnlp/sample/jardiff/Patcher.classON0-!Jr=*UJJMئ\NJƁ8dg@c0R+K[.Mdhքn9_z[ֵiZܞxiָ̓Rb[WjtEEQlg[~,ǪqAXڂo*gp "L]󻚋Hψ+RJ J)aP:b_0mOnPK@Yjnlp/sample/servlet/DownloadResponse$NotModifiedResponse.classPK 8{;'[jnlp/sample/servlet/DownloadResponse$NotFoundResponse.classPK 8kI$< ]jnlp/sample/servlet/DownloadResponse$NoContentResponse.classPK 8cb>^jnlp/sample/servlet/DownloadResponse$HeadRequestResponse.classPK 8S<ajnlp/sample/servlet/DownloadResponse$JnlpErrorResponse.classPK 8uvO ?0ejnlp/sample/servlet/DownloadResponse$FileDownloadResponse.classPK 8$&!Hjjnlp/sample/servlet/DownloadResponse$ByteArrayFileDownloadResponse.classPK 8??fGmjnlp/sample/servlet/DownloadResponse$ResourceFileDownloadResponse.classPK 8] C^pjnlp/sample/servlet/DownloadResponse$DiskFileDownloadResponse.classPK 8I,Ssjnlp/sample/servlet/DownloadResponse$1.classPK 8{Ky *Ntjnlp/sample/servlet/DownloadResponse.classPK 8Zw: !yjnlp/sample/servlet/XMLNode.classPK 8Xb&kjnlp/sample/servlet/XMLAttribute.classPK 8Ji&kjnlp/sample/servlet/XMLParsing$1.classPK 82 s3gjnlp/sample/servlet/XMLParsing$ElementVisitor.classPK 8կ3oV$ƅjnlp/sample/servlet/XMLParsing.classPK 8ZBy5njnlp/sample/servlet/ResourceCatalog$PathEntries.classPK 8A  +jnlp/sample/servlet/ResourceCatalog$1.classPK 8C}2. +ɔjnlp/sample/servlet/ResourceCatalog$2.classPK 8X'?$)jnlp/sample/servlet/ResourceCatalog.classPK 8jnlp/sample/util/PK 8]Yw/'$5jnlp/sample/util/VersionString.classPK 843 jnlp/sample/util/VersionID.classPK 8jnlp/sample/jardiff/PK 8iq**jnlp/sample/jardiff/JarDiff$JarFile2.classPK 8Ay! jnlp/sample/jardiff/JarDiff.classPK 8Cf*jnlp/sample/jardiff/JarDiffConstants.classPK 8)Ãb (jnlp/sample/jardiff/JarDiffPatcher.classPK 8O//jnlp/sample/jardiff/Patcher$PatchDelegate.classPK 8 BasicPlayer Javazoom jajuk-1.9.6.orig/src/packaging/jnlp/vldocking.jnlp0000644000175000017500000000063711720500104022005 0ustar drazzibdrazzib Tiny Hans Bickel jajuk-1.9.6.orig/src/packaging/jnlp/jfreechart.jnlp0000644000175000017500000000106011720500104022131 0ustar drazzibdrazzib JFreechart and JCommon Object Refinery Limited jajuk-1.9.6.orig/src/packaging/jnlp/web.xml0000644000175000017500000000106311720500104020431 0ustar drazzibdrazzib Jajuk JnlpDownloadServlet jnlp.sample.servlet.JnlpDownloadServlet logLevel DEBUG logPath /tmp/jnlpdownloadservlet.log JnlpDownloadServlet /app/* jajuk-1.9.6.orig/src/packaging/jnlp/jlayer.jnlp0000644000175000017500000000156611720500104021315 0ustar drazzibdrazzib Jlayer Javazoom jajuk-1.9.6.orig/src/packaging/jnlp/jintellitype.jnlp0000644000175000017500000000065511720500104022541 0ustar drazzibdrazzib Jintellitype melloware.com jajuk-1.9.6.orig/src/packaging/jnlp/xml.jnlp0000644000175000017500000000064111720500104020620 0ustar drazzibdrazzib XML utilities Thoughtworks jajuk-1.9.6.orig/src/packaging/jnlp/windows/0000755000175000017500000000000011720500104020624 5ustar drazzibdrazzibjajuk-1.9.6.orig/src/packaging/jnlp/windows/jintellitype-native.jar0000644000175000017500000003472211720500104025332 0ustar drazzibdrazzibPKֵ6?}META-INF/MANIFEST.MFMLK-. K-*ϳR03r.JM,IMu (h)f&W+x%irr%Z)xy敤dTr{8dR733N7L050 PKe.7META-INF/JAJUKTEA.SFmN@@= 0KMVM; +B[Ikp7…\C/̥ <}Y;dXNm%)&ضЛ8`IaHǬc0R̷;*0 f^a=]:{-_b(}p*H$X`DD{Nuo~z'oFqxJXF4ܲihR(8,/7v|^\PKlpǂPKe.7META-INF/JAJUKTEA.DSA3hbƩiAk&Ll|LR E@E@EML03121 3PC X?s( 0[!_ggaf H,,YJa|n_@gBRs y ̍ ,LLy L\:q3562n- 5G͓ټwa8,g߰-P-5A)wmoįG2vzvhFYOi ۳g,]2 jCW^V,gQL!Qb~^x]'%fɹ=32LOU>iΦE[?D|9f;guَSeg-{Sz`dx߮+ x*~ӨIJ6bU!5޼tbz_I'U1XYqߊ +?z:mRwZ\Cuj Z̍ w[&Ue AM0;?[3Sn'^=vVn+;#2ώH_|co,tmC]Ê7Ih7WE-_#=s>ܴck܏M],L)^)>ybJe6`0ZNJN6&;齧4zw`} 45hVCədg$"Ҭ}o\,* x̉I$[Oz6|ybu|%IPKWPK6 META-INF/PKPK6JIntellitype.dll} \Tוa1Q$'vbfSEJQ oS1aIK\ݵtu[ I lؔTh@Dc= W//ws9sϽoy8NF]iܗ_5&N;9{i[4ߺgJSQg²r޴tJLL[ʋLpYkl+p{߹UNA )AN뱆TDjFJ.2PQ8? qBƙ}"F륊~f|k_\bLвNk=?/dy@[Zy8Ycizis6TVB p3xģ.#+a2#tnd}tD]+f5,}qaVq_R?یm[X5 @0iMnH# ,[,k띭/݋I1BYS >Oc86:0יuPLa~d X}bJ@k'jlHb V@M!lzW# _Mtuhϸl{gp%(Yhr"8 68|V/TWV fi0j}@Uz ;h7^GL&I1VEՃclGmѢ #);2BO+ V1̀]U͗ s=۬; )Nr(4pꋇ~7U ׉. xk" V"z ? ])/hx ~yoWi[Ye&y:m;>|?t~*ZU C፤˴❈0lSH|lZ# x0S0 Gôp,TTE/˜UÀ&w IaKeW|~2j^ܓ8s9k(.7|`a鰠d3n+p":p7ykcpP40ǑZ;@/ascoa,i% Jrpz2&rcyC 0Ng/ -v=l祓* A`Al215|(=n2<T0#9O ^{zO$>9ax\*z%!nQn݂8~H [&0*Qx(E ъ"4~Jp' ;R"@'{C+. 9#'z4k"2 L hN"#Ր#\V|Ȉ ¨l gR𑢿Ab,M_k`ՒIuw/g 2Ou?dN:O7P|怿Qf Ø<5'u2pP9C7t*xGn 8,^AB$"PXCB%'MM!OjF.isaߓ0C-a AR8e(dhGGl[KԐ7cy/ߌuaڰ|iX",?}^ ˟ /g0ڰ1,υ寇3 {? ϮU'i 5R|\wo{ħN?9=lSBǗX"9%a)tsmhr]A|~=_ W ]ec+R`(>>Xu! ^ ]'0>PO`<dL7ZA {MI٠fww3HWhB2K,>r,#3ju"OP_[^Z ǂzn,z=9F^KgscRۢ$'޵Jf x}кl}m'g}I_ZeF ìyek!8Ё$̭%B/d^.\ OzQzL. ҞګReeDGhߝ.2 ;zT]Y؃NZh#:#=>27}XPS#F3 Uͫ2]tu4(b{_& o@ A k~ { ?s~PԄ1UWNϫ*AIL!cn7:]Ʌ RxKhT9, 22m3}F˸ kQghSZKS"8l?w `QB[9\},֓=bG%tN4ZdsMF̍bY>1,z;+8HQTc7G~He[ٳ/`D3ņ@6萶p9P-G 3no.SjW:BA$;{*Jص\A5 uj^[8TXov6au[|4*=Dg06ݓ[K~۽AP,5ư OZY׸vb'̡P`kX)n㹇v~sW ÿ7Q_ @A ~372-'-N; Hq#C|%~|NX%*\ ^V$~x{+gEPp']#`[6u]8:>?O >xd|.|ć t*0&i9#%)5`їCYAL/\R/ܤ~*?R }xm~߫MCчCᅿ?Mg/$+ >k0|*} Gh3XL6o6Fl$F(> m;V]Bx&["- YIn4p,stʮ(XAcc]B !fF'xvC>8ؠ35*O0!G')7;O1t:_C5Y-]H<b!@j+u7|>1_bB ? ]u5Uu9ca9O8~x (81BԲ M T2"0`= 5pwpL'ٰiĞks ]&bw|p`683t$ VoQ5&ϰ&'q1C'Jg7 YK3,VVku{hk$MˆH7Kp>}h7($jcF%%+*wAS`@FQ!5"0nWre0> r  B+8AM9QڶiPg1r+>e&6gwGcsX_L40s(}2i]-m2 Goj;bNq5zW;( â]F0_e_g .LesuŠYXu M!\~p k_ !8u+B\Iu<,چҵ-PN0{>-FZwu#@Ac?C"i~_w퐇W1(! :@uj"  Rtի4ns:ÓC}^k74RCU6χKס K>w!. 9G?bC*~5fP=?&(Le~10_<&bбQL:950Q(iQ :nj4w XrrVխo"D8<^.wш|6P 8:HC(뷄u > =&'vJ%l̨)gr;9OsVOuC9J;`:mƐSL0CkB}n֊KU7Dcv:F0ؽBmo) ;'tTב+ }!3-@$qbȉgAw0Rτj%I(=Ή7jA:d`ֱf([s\e{tKپ~|Oä́B`M3Vdi h3;v>8A2h(ߕwXmĮ@ ?b@9YQk@.I3b9 U_7h2dR6U߲avuts-8zkZVRiI~z?'TL.гP5cfg=\dx+P5K̼MFSj`\SsunC"@':ιE,{a2yX }Oh>CF3c4mيk8#nt}5.5ง65-Tv3?wXt; ~,, Z+t!"d6e`wbJhJӪ0.>T{m\~4^$ ɳ2u'Ьzhd?"ֳ/EgX<߅]`B1|i~(r>Y5 t cY^s[p:#4ϏW|ӃC7rPua6Mm; 0z}]{:y=waQ~Ͼ/~/n2q[¨q:ʉi_jYJ?RG\|~4GGAɤSA^H`$ƅwY69ZnaOHl~D|eG}n׶ M[E)ĥcǠ% 2Jo9^dcB1Tt ]t`a>'O]K3%]Gc|it3 nlop} ciN8[̳4ۮa1fZՂ?doA7G#6|]c^OPLXC%$x^2i Ie, " ܮY<Ӿq9(ި-z2jۧJ8䑐x+JSge@t٘kƃdijM뽇!av!=\׾(h>]ְKI!/ga Hg Fw"KEa?vdE|`XD|;R7/1f o/nA{T}ݻK֑g3R_` 4 QG_dy<~ C7擆n~}yX*2 GA0? XmP5λN,-2OH*)T .]hP> "c"hy:@ Kk/0)86 d Ƌ!rC;tZhazQ@8ŷ )weه\%KS;Rb][I򌉟cŵ1DS`v|ft &( 8 |~ゖͯ17_KA,;hskZA{?}?ާ-AߌzzGj!%94 V"?# <?fOG/3?)Oiz!D>?&PMw30#>_9yZ1{=B+??W`G{zݩ6xߒ&F{~?'g &:9"L2Dj&#=zuNF}oϟ=Uf)xU|8Cy_~_bw<^izX{Y4N>x]:VMqߑ߀K8XfstCq%MÝL GdX W.2W}ߎOtX VZ5/`so?vwq4>YVtJc{IJm{ǩEyP{ѿDg,D;> mP5 ; "%W4IǏ~?P?&WyU{TQq c}^ֳɋ  xwllj54zj!\q-|EЗ~ x,&jԘVT<-|DI=1-[i?fO6_$mb"]gL==/GވF̢kt<@o El}@؀qXZ>Fb/ + @}I\7 ZyJA=ɺ&R_31 3 te8\+ޥMAgcZ<]P>Pۼ7ZwB:E@k&EB/zڭ6v)n"MOWzd*1AUBvbqw5#@8?Gbp Kjƅ>!HBzWз`]i5*E*-dfv3TitէKtsU…|$V-.tr[҃=Plk;Bٍ1JOc2 |xtJ9^+=w'V\7&yM_mx{tesK?DHr>Ep[N˟O+YQÂU* t2 RaB6vccDžtB@f]MЍ?0&@o&ȶIzROZig#x bVmTP>9J h)B6aRfiZAw~e|8<'NȚx>??^{y/aVh᧲پx +fa߇j΃/r7^Qc:>2k )#sUi().1s9X:?Bχ2Eh46kh?˃ّm ⏩}\4w[_Ek*YqPlmº~eD:WMɪ} ;-X }KG Ț|qУH7 U"F 0b8=Ka7,,,o 7 a|UX~oX(,>,_;·}ߚ+zQE9~Ag9+2;SR];7?nVT2QjN$>!{UL姙_Kar\Xf3,͜_ȗoY^h)YY ʙ3M,_ R*Ap?d{Fs1y8Yógȳ2`cUUᆒVu:bd77Wo8R6>y,::0 E}s lHCnHB: 9H!i/|H&H %@ʂBf<@ i/g!&Hː9 ) H!퀴HMz @7oc7>|7+0sby[ +6;`e+7 /7bua ܙ@3WPDyY1b>|E 7;y΢޴UI%!Q vuU@L 1qV㡦 (ϓieJi;:-"M Bh .7dCQzQn32 =psq aWBBhurɴ%8~.ۖT^$nͅ@ !Yz56\3*v_0nARxŰ //!-9--Y޲\LβnZXnMͶmغl[㟎$^7|yy8y۞Ix1ᵄ+ 9?O4-inR~҉OMnI~#yNJBJz)OIٓ򇔼Ի'矜?m-xqA˂,?΍22kIl8-OY/ZZ,ݖj~?x!9#靤ɃCHy8!eBSRצV֥>F`Mn] R<@\pt-@̢-)ԻRݝ~8 -/s / cOݖ ]H ZWZi=iw?X??v&Xuˎ[W->70fbk]6&>2W6vɼW杛w{9၄ [v& y5݄'GՄɉ%Z7$>ؑx.|-O*N~IړwI%]K|k&?NL28\|55%x̧Sj{ꇩ7Ȑ;?g3i~|2ǖS ghngdyknqq;^\mm'm>qgŧgoӠΛk[ZY53s U̫{OLXTCN8qBdbLbY 6&=}.Ť.%''O-MO^!ٙT_N zX PLޢhARcYw[{AG@Ǭb_mmߌ={.7b;;{9v8z, q [-Ӗe˶V٪l;l5Z[m׶dl7aنmׁ[xC1>*>:>fŧggį___Wk#ڈomė؈oPKc2vPKֵ6?}META-INF/MANIFEST.MFPKe.7lpǂMETA-INF/JAJUKTEA.SFPKe.7WMETA-INF/JAJUKTEA.DSAPK6 META-INF/PK6c2v@JIntellitype.dllPK@|8jajuk-1.9.6.orig/src/packaging/jnlp/layout.jnlp0000644000175000017500000000065011720500104021335 0ustar drazzibdrazzib Layouts Various jajuk-1.9.6.orig/src/packaging/jnlp/dbus.jnlp0000644000175000017500000000113311720500104020752 0ustar drazzibdrazzib D-Bus for Java Matthew Johnson - dbus@matthew.ath.cx jajuk-1.9.6.orig/src/packaging/jnlp/jajuk-icon_64x64.gif0000644000175000017500000001067011720500104022532 0ustar drazzibdrazzibGIF89a@@ikkrGTDJSGnaNXY_103^p\S62Ckxch<=BsVX]e]RTYOPVmHA>LaxXM (ZT]SiipDEJPQVLLRQN\>:KNLYAJ;65=S`\Za\ZegJKQIFUmXcU)&2TUZjabg2*C]h78=GFPuN\//2;y쀃fel1?vp_2ItKDQbԹf0X ɘYeP)c,'Z$)ŸU!UŌ6k[ 7vS._Dg#L]l3fThƥcǼMʼnqՇ u礋$2cc? ̰ xRz 2FRPF P "N-ɔ/*hdpUK!? v`,}!F)faFQW?ژя ؆GǠ:SIBe4`!Naytt?/dIK5Թ SViheh>R$qIqD)%H&BK\pV~`idE5!,\ 9G"E)V0@̀nhdn&TcB!1N1!.e"E4E|#<M6 CD6m*wA=Ph yMN` sG@T ̀tVPR"h'N$1F''ٔAD% Ԑ8Щ~\ 0\aO=.rQk|1c|!%PT+Ml; eX\7$1Ke>G%peıA/XJt8,HjP5SE1[hvYv|a`gbt1*tЂ3(a*K1L)4^07:=c"W6M 7#.0&tL#,)+d MpO!oyO1 #,CTh5F  P,v`0   z~A4QA} r(>@-"JQ B80*P Aa`Xє) a b@! ]hͰ ~$1/|!b;~Ah( @/!p@p K (_x" Ibp้, &pq LD 8,@ T hD~e؇4`ubJ* B`#l@6UP}ūE }@X> @Z8*ȑ(Rj`/ h$ T Y40`PDaH 5D4ր $ v,1f5ZA8d Z` *-CdB P%@a'c HZ`&ܐ<`;p-$= 1,o؄pnb@*\R@x b $$݈H> 3qEu,!KHVz`R)o7;,pA [" $  "C17t\X0?A j*G;(C2Q:V7P* pI _ K= pX+d5Ȁ 0t[  s w1wH0 p}8'pͶ 'p$ -Pto@ 22@O u00AK ;Pb= :tw 0 s p!ows P iȀ  O@u4p3 A  P1}@ '}u:"18}$`P`q4@)Mj` ,l .m`P v(P H wPE g2}g0tPߠ6s :   @ h" 1 p-p X p00U 0   W`sHt`%P & ɀn 簠    >;9l О`D D. @Ef Pd+ZdlP4ٞ߀0Т,jg%6l0x P;0 P`,С> h%,@〡 (He ` x( . \ s*h;` >֧ߠ@#w7l g % @E&DI< YXUPg%FLa ـD P c:0 $ DZdPhZ쓧Yv+n ␩ g ФPbJ,M>@*=*Z, ICH0 i Z P@Z 밬@* j]RPj ֺ>)09ұI,`3j%@Ð ˕:*7ӣ )İ2KEiZ=DО+OۦE +Yv YZ%àa> Z6s E`Zj%P; DV` FZwjVҖ);jajuk-1.9.6.orig/src/packaging/jnlp/cobra.jnlp0000644000175000017500000000075611720500104021115 0ustar drazzibdrazzib Cobra WebBrowser Cobra Team jajuk-1.9.6.orig/src/packaging/jnlp/entagged_freedb.jnlp0000644000175000017500000000066011720500104023106 0ustar drazzibdrazzib EntaggedFreedb Entagged team jajuk-1.9.6.orig/src/packaging/jnlp/guava.jnlp0000644000175000017500000000062411720500104021124 0ustar drazzibdrazzib Guava Google jajuk-1.9.6.orig/src/packaging/jnlp/apache_commons.jnlp0000644000175000017500000000161711720500104023000 0ustar drazzibdrazzib Apache Commons libs Apache Fondation jajuk-1.9.6.orig/src/packaging/jnlp/animation.jnlp0000644000175000017500000000064111720500104021777 0ustar drazzibdrazzib Animation JGoodies jajuk-1.9.6.orig/src/packaging/jnlp/bindings.jnlp0000644000175000017500000000064411720500104021620 0ustar drazzibdrazzib Bindings Bindings jajuk-1.9.6.orig/src/packaging/RPMS/0000755000175000017500000000000011720500104016750 5ustar drazzibdrazzibjajuk-1.9.6.orig/src/packaging/RPMS/.rpmmacros0000644000175000017500000000071111720500104020753 0ustar drazzibdrazzib%packager Bertrand Florat %author Jajuk team %_topdir /tmp/jajuk-dist/RPMBUILD %_tmppath %{_topdir}/tmp %_builddir %{_tmppath} %_rpmtopdir %{_topdir}/%{name} %_sourcedir %{_rpmtopdir} %_specdir %{_topdir}/SPECS %_rpmdir %{_topdir}/RPMS %_srcrpmdir %{_topdir}/SRPMS %_rpmfilename noarch/%%{NAME}-%%{VERSION}-%%{RELEASE}.noarch.rpm jajuk-1.9.6.orig/src/packaging/RPMS/jajuk.spec0000644000175000017500000000205711720500104020734 0ustar drazzibdrazzibSummary: Jajuk Advanced Jukebox Name: jajuk Version: VERSION_REPLACED_BY_ANT Release: 1 Group: Applications/Audio URL: http://jajuk.sourceforge.net License: GPL Source: http://jajuk.sourceforge.net Packager: Bertrand Florat BuildRoot: %{_topdir}/%{name} %description Jajuk is a Java music organizer for all platforms. The main goal of this project is to provide a fully-featured application to advanced users with large or scattered music collections. Jajuk is a Free Software published under GPL license. Jajuk main principles are : * Maximum portability: 100% pure Java when possible. * Maximum features: Jajuk is made firstly for advanced users looking for powerful functionalities. * Maximum usability: Jajuk is designed to be simple, fast and provide multiple ways to perform the same operation. %files %defattr(-,root,root) /usr/bin/* /usr/share/jajuk/bin/* /usr/share/applications/* /usr/share/doc/jajuk/* /usr/share/pixmaps/* %defattr(555,root,root) /usr/share/jajuk/lib/* /usr/share/jajuk/lib64/* %post %postun jajuk-1.9.6.orig/src/packaging/RPMS/jajuk.desktop0000644000175000017500000000024011720500104021443 0ustar drazzibdrazzib[Desktop Entry] Name=Jajuk Comment=Jajuk Advanced Jukebox Exec=jajuk Icon=jajuk-icon_16x16 Terminal=false Type=Application Encoding=UTF-8 Categories=AudioVideo jajuk-1.9.6.orig/src/packaging/native_launcher/0000755000175000017500000000000011720500104021336 5ustar drazzibdrazzibjajuk-1.9.6.orig/src/packaging/native_launcher/installer.launch4j0000644000175000017500000000120211720500104024760 0ustar drazzibdrazzib false gui /tmp/jajuk-dist/java/jajuk-java-installer-VERSION_REPLACED_BY_ANT.jar /tmp/jajuk-dist/windows/jajuk-VERSION_REPLACED_BY_ANT-setup.exe normal http://java.com/download http://trac.jajuk.info/ false false /tmp/jajuk-dist/jajuk/dist-files/images/jajuk-icon.ico 1.6.0 preferJre jajuk-1.9.6.orig/src/packaging/native_launcher/izpack.ico0000644000175000017500000001635611720500104023326 0ustar drazzibdrazzibh6 00F( @ubЕnzzE<Oih`U)"ڟO軰(aQp̾zfϪC9Ӑn^P"լ8zRKd7u죎ˆW·f̢a]vΟڷƲř汢ɾؙ0ƚVo'[MZNŒ9|m誗i+Љҧ^Uğ˙0ŽΦҮ몖ξ&jIhanp23Eueq T|g0{ylmKOsi}j;z&R^LVJ B-v<t>?rbHAodX(YP)/f_\,86$CQ4`MZw7G.w W= kUF~cS@D%!95+x#]"1*N [:'( @m]zA6]œ{ٷw{WHY8ҁs{ҬywQžٜ_MӥsȐninzb'љLJ@wmh[݋~ԼeY梇^Pװl̴ƭ糧㗇CAfU}sgP޹PF}ԉy֣|mj욅ꝎܜsdcU͢w/܅qZUxe֢O˷~ޓHӳ픁ҾȫnWݍvɧھYMR]Qkˁp#2>aV5paΨiV՜硏eZRrՃu֭MFcYY8/llmghJ/9U.d\H|=<55R{****-6rY5[,,,,vu˭ѫeeeeee)>*[5tS2*[yFI$$IIDZ Z!ySKs +vL $oskG+1#hh?@(0` lYZ82[sPD׮1Vzv~m՜w_Oإƺz꩜Gptnpм؋曂ǿ|Jӥ.`ֆo{H;eXYtbh;3⚐zљVJrmfӲ~t履>Oy`dƬzhÛɅuΨݯǷБѶ׍v街zMޠiҟ[V硎?fSmc^SˠπiwhٽcҀrۉ|dZWIT`zҺ};޹Xvxf}zp暊_Rq\vg{oj嬛m_׮׶魥WLA͂qȽՐಧOqgڊs͹Ѭꘃճ0xAHZ{le>3ULHEO@ @Uӕ@H1B[ǐB1HI$ǵvvYH ;;[ǵvv X:B;ǵvv^ 5wrHןvvvvKovS|M|vUcvvUǗiǢMMM Yvzriivv MMMMnXP^ii5pMMMM Xv]];l|MMMM w;]][3l| MM /[;;$ߑa5 M ;Ԭߑ[ Mo;voYv™[Jꗗ M o;vSSM omv|SS.v쬮bbbbS;lllSS.vv™bbb|llllllkvvߙ!6bllllllllkvcbb䳗[/NuuHvv[!堠bSS@ <<~&mﵵ[[[yc6##lSSSkFjj)O9ٱcy栠NF?F `````>ECذزcllll&۔D,gggg,RIؽlllllݴxT 88fllll鉉_TEؽlll3e=鉉ݴ*ؽlliK(Qe=}Rli(eQ\ݴ}}}Rؽ:e\=R9:ݪe=\=鉉ذVV77Ъ\=նROV7=\=ƨƨƨƨ+$W%V7\\')sGG_VV77=``````````'L_-{{77Ͷ2E-{qЯh*J"{{qggggggggggAEyq'ZHEBhZZgdddtE4Zgg4dإ0d@U@cc????? px?jajuk-1.9.6.orig/src/packaging/native_launcher/jajuk.launch4j0000644000175000017500000000154211720500104024076 0ustar drazzibdrazzib true bin/jajuk.jar gui /tmp/jajuk-dist/windows/jajuk.exe bin TEST_FLAG_REPLACED_BY_ANT normal http://java.com/download http://trac.jajuk.info/ false false /tmp/jajuk-dist/jajuk/dist-files/images/jajuk-icon.ico 1.6.0 preferJre 20 512 -client -XX:MinHeapFreeRatio=5 -XX:MaxHeapFreeRatio=10 jajuk-1.9.6.orig/src/packaging/pad/0000755000175000017500000000000011720500104016733 5ustar drazzibdrazzibjajuk-1.9.6.orig/src/packaging/pad/jajuk-icon_32x32.gif0000644000175000017500000000331611720500104022320 0ustar drazzibdrazzibGIF89a )#,!%*&," $% )""*$"/'"+%#'$$,+"1'%)%&.*%.(&*(&3%)+)(+((0+),,*-(,.,+.+,*-*8-+//)=.,0*.0--53*D/-;0.22040195/C1307/I-5153652@15775966>96D97;;5I6;399A;;C=;?>;I:?6A;O>?G>>Q?@>A>MB@CC@O;E6?CEABJGAKECQDDMFDHDFC=J5EFNKEOFGOIGJIFTCK7HIQKIMKHWFKMIJSEMIAQ0BP:JKTJNPLMUOMPHPLBT8FS>NOWQOSLQSIU:MSJQQZOSUTRVIY8SS\NVRNXHWUYNZO[U_WXaP^HS]M[XgO`>YZcU]Y[[d][_S`UOi9``ib`d]bdZhRccl]gWhfj`jZWp@^nK[s=lixmkohnd[x;evSayClriopysquwuygHqzuty|yz|z~eBcHtaiE|hBnBrZrPmFtHqrVuQrHwPh~YzPzFORXSMInLa\PXyaN\WQeQkMUcc]PWSZSa\j]VdP^YYs`aTo\jce^W^Zab\V~WX`[\d]_mtZ\!Created with GIMP! ,  HP *J dNzTG欹Ҥ #JզF 4xHqVM2Ē$IKX`5WMVs)s&CA$$-Zz*;h6y G /x@l*[Zʔ1W86҆ #< +VPU$B-]pw YJ* )#; }RJ!bį\0y;ZQR#OEX|XF])j";e[1 lՎǩ ).avʍ>zQ3&\;Jzh$ C@#sȁ9,ч> QM P=Dsc έI4C M5ӎ8528VM;|CM2+¸Îӎ>>u#C98#1ɐr@PRϭ7p32K5J#2#M''|0<0A_M>0 `@c™"tAP$'pL@4 Dt LAX`A@y @A4xЁHc0 >AT \ށW0A?%.l oj9? @iy,x+@ۧP;jajuk-1.9.6.orig/src/packaging/pad/jajuk_pad.xml0000644000175000017500000001513211720500104021407 0ustar drazzibdrazzib 3.10 Online PAD Generator 1.33 - http://www.padbuilder.com Portable Application Description, or PAD for short, is a data set that is used by shareware authors to disseminate information to anyone interested in their software products. To find out more go to http://www.asp-shareware.org/pad Jajuk team Internet Internet Internet Internet 00000 Internet http://jajuk.info Jajuk Team Jajuk Team jajuk-developers@lists.sourceforge.net Jajuk Team Jajuk Team jajuk-developers@lists.sourceforge.net jajuk-developers@lists.sourceforge.net jajuk-developers@lists.sourceforge.net jajuk-developers@lists.sourceforge.net 0000000000 0000000000 0000000000 0000000000 Jajuk 1.9.6 02 20 2012 Freeware New Release No Install Support Java,Linux,Linux Gnome,Linux GPL,Linux Open Source,Mac OS X,Unix,Win2000,Win7 x32,Win7 x64,Win98,WinOther,WinVista,WinVista x64,WinXP English,French,German,Greek,Korean,Russian,Spanish Audio Audio & Multimedia::Audio File Players jukebox P3 600Mhz, 512 MB RAM 22470983 21944 21.43 N Days java,jukebox,mp3,ogg,music,collection,player Jajuk is a powerful music organizer Jajuk is a powerful music organizer for all platforms Jajuk is a powerful music organizer for all platforms. The main goal of this project is to provide a fully-featured application to advanced users with large or scattered music collections. Jajuk is a powerful music organizer for all platforms. The main goal of this project is to provide a fully-featured application to advanced users with large or scattered music collections. Jajuk main principles are maximum features, maximum portability and maximum usability Jajuk is a powerful music organizer for all platforms. The main goal of this project is to provide a fully-featured application to advanced users with large or scattered music collections. Jajuk is a Free Software published under GPL license. Jajuk main principles are maximum features, maximum portability and maximum usability. http://jajuk.info http://jajuk.info/upload/f/fe/Mainpage_screenshot.png http://gitorious.org/jajuk/jajuk/blobs/raw/master/jajuk/src/packaging/pad/jajuk-icon_32x32.gif http://repository.jajuk.info/jajuk_pad.xml http://sourceforge.net/projects/jajuk/files/jajuk/1.9.6/jajuk-1.9.6-setup.exe This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,USA This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,USA jajuk-1.9.6.orig/src/test/0000755000175000017500000000000011720500104015222 5ustar drazzibdrazzibjajuk-1.9.6.orig/src/test/java/0000755000175000017500000000000011720500104016143 5ustar drazzibdrazzibjajuk-1.9.6.orig/src/test/java/ext/0000755000175000017500000000000011720500104016743 5ustar drazzibdrazzibjajuk-1.9.6.orig/src/test/java/ext/scrollablepopupmenu/0000755000175000017500000000000011720500104023036 5ustar drazzibdrazzibjajuk-1.9.6.orig/src/test/java/ext/scrollablepopupmenu/TestXCheckedButton.java0000644000175000017500000001362411720500104027421 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package ext.scrollablepopupmenu; import java.awt.Component; import java.awt.Graphics; import java.awt.event.ActionEvent; import java.beans.PropertyChangeListener; import javax.swing.Action; import javax.swing.ButtonGroup; import javax.swing.DefaultButtonModel; import javax.swing.Icon; import javax.swing.ImageIcon; import org.apache.commons.lang.ArrayUtils; import org.jajuk.JajukTestCase; /** * DOCUMENT_ME. */ public class TestXCheckedButton extends JajukTestCase { /** * Test method for. * * {@link ext.scrollablepopupmenu.XCheckedButton#XCheckedButton()}. */ public final void testXCheckedButton() { new XCheckedButton(); } /** * Test method for. * * {@link ext.scrollablepopupmenu.XCheckedButton#XCheckedButton(javax.swing.Action)} * . */ public final void testXCheckedButtonAction() { new XCheckedButton(new Action() { @Override public void addPropertyChangeListener(PropertyChangeListener listener) { } @Override public Object getValue(String key) { return null; } @Override public boolean isEnabled() { return false; } @Override public void putValue(String key, Object value) { } @Override public void removePropertyChangeListener(PropertyChangeListener listener) { } @Override public void setEnabled(boolean b) { } @Override public void actionPerformed(ActionEvent e) { } }); } /** * Test method for. * * {@link ext.scrollablepopupmenu.XCheckedButton#XCheckedButton(javax.swing.Icon)} * . */ public final void testXCheckedButtonIcon() { new XCheckedButton(new DummyIcon()); } /** * Test method for. * * {@link ext.scrollablepopupmenu.XCheckedButton#XCheckedButton(java.lang.String, javax.swing.Icon)} * . */ public final void testXCheckedButtonStringIcon() { new XCheckedButton("testtext", new DummyIcon()); } /** * Test method for. * * {@link ext.scrollablepopupmenu.XCheckedButton#XCheckedButton(java.lang.String)} * . */ public final void testXCheckedButtonString() { new XCheckedButton("testtext"); } /** * Test method for. * * {@link ext.scrollablepopupmenu.XCheckedButton#displayIcon(boolean)}. */ public final void testDisplayIcon() { XCheckedButton button = new XCheckedButton("testtext", new DummyIcon()); button.displayIcon(false); button.displayIcon(true); } /** * Test method for. * * {@link ext.scrollablepopupmenu.XCheckedButton#isDisplayCheck()}. */ public final void testIsAndSetDisplayCheck() { XCheckedButton button = new XCheckedButton("testtext", new DummyIcon()); assertTrue(button.isDisplayCheck()); button.setDisplayCheck(false); assertFalse(button.isDisplayCheck()); } /** * Test method for. * * {@link ext.scrollablepopupmenu.XCheckedButton#setDisplayCheck(boolean)}. */ public final void testSetDisplayCheck() { // tested above } /** * Test method for. * * {@link ext.scrollablepopupmenu.XCheckedButton#setCheckedIcon(javax.swing.ImageIcon)} * . */ public final void testSetCheckedIcon() { XCheckedButton button = new XCheckedButton("testtext", new DummyIcon()); button.setCheckedIcon(new ImageIcon()); } /** * Test method for. * * {@link ext.scrollablepopupmenu.XCheckedButton#setIconAlwaysVisible(boolean)} * . */ public final void testSetIconAlwaysVisible() { XCheckedButton button = new XCheckedButton("testtext", new DummyIcon()); button.setIconAlwaysVisible(true); button.setIconAlwaysVisible(false); } /** * DOCUMENT_ME. */ public class DummyIcon implements Icon { /* (non-Javadoc) * @see javax.swing.Icon#getIconHeight() */ @Override public int getIconHeight() { return 0; } /* (non-Javadoc) * @see javax.swing.Icon#getIconWidth() */ @Override public int getIconWidth() { return 0; } /* (non-Javadoc) * @see javax.swing.Icon#paintIcon(java.awt.Component, java.awt.Graphics, int, int) */ @Override public void paintIcon(Component c, Graphics g, int x, int y) { } } /** * Test mouse adapter. * DOCUMENT_ME */ public void testMouseAdapter() { XCheckedButton button = new XCheckedButton("testtext", new DummyIcon()); // we should have at least one a mouse listener on the button assertTrue(ArrayUtils.toString(button.getMouseListeners()), button.getMouseListeners().length > 0); // none of them looks at the actual event right now... button.getMouseListeners()[1].mousePressed(null); button.getMouseListeners()[1].mouseEntered(null); button.getMouseListeners()[1].mouseExited(null); } /** * Test model. * DOCUMENT_ME */ public void testModel() { XCheckedButton button = new XCheckedButton("testtext", new DummyIcon()); assertNotNull(button.getModel()); button.setSelected(true); button.setSelected(false); ((DefaultButtonModel) button.getModel()).setGroup(new ButtonGroup()); button.setSelected(true); button.setSelected(false); } } jajuk-1.9.6.orig/src/test/java/ext/scrollablepopupmenu/TestXJPopupMenu.java0000644000175000017500000000710711720500104026740 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package ext.scrollablepopupmenu; import java.awt.HeadlessException; import javax.swing.AbstractButton; import org.jajuk.JajukTestCase; /** * DOCUMENT_ME. */ public class TestXJPopupMenu extends JajukTestCase { /** * Test method for {@link ext.scrollablepopupmenu.XJPopupMenu#removeAll()}. */ public void testRemoveAll() { try { XJPopupMenu menu = new XJPopupMenu(null); menu.removeAll(); } catch (HeadlessException e) { // happens if run without GUI support } } /** * Test method for {@link ext.scrollablepopupmenu.XJPopupMenu#addSeparator()}. */ public void testAddSeparator() { try { XJPopupMenu menu = new XJPopupMenu(null); menu.addSeparator(); } catch (HeadlessException e) { // happens if run without GUI support } } /** * Test method for. * * {@link ext.scrollablepopupmenu.XJPopupMenu#XJPopupMenu(javax.swing.JFrame)} * . */ public void testXJPopupMenu() { try { XJPopupMenu menu = new XJPopupMenu(null); assertNotNull(menu); } catch (HeadlessException e) { // happens if run without GUI support } } /** * Test method for. * * {@link ext.scrollablepopupmenu.XJPopupMenu#show(java.awt.Component, int, int)} * . */ public void testShowComponentIntInt() { try { XJPopupMenu menu = new XJPopupMenu(null); menu.show(null, 0, 0); } catch (HeadlessException e) { // happens if run without GUI support } } /** * Test method for {@link ext.scrollablepopupmenu.XJPopupMenu#hidemenu()}. */ public void testHidemenu() { try { XJPopupMenu menu = new XJPopupMenu(null); menu.hidemenu(); } catch (HeadlessException e) { // happens if run without GUI support } } /** * Test method for. * * {@link ext.scrollablepopupmenu.XJPopupMenu#add(javax.swing.AbstractButton)} * . */ public void testAddAbstractButton() { try { XJPopupMenu menu = new XJPopupMenu(null); AbstractButton button = null; menu.add(button); } catch (HeadlessException e) { // happens if run without GUI support } } /** * Test method for. * * {@link ext.scrollablepopupmenu.XJPopupMenu#actionPerformed(java.awt.event.ActionEvent)} * . */ public void testActionPerformed() { try { XJPopupMenu menu = new XJPopupMenu(null); menu.actionPerformed(null); } catch (HeadlessException e) { // happens if run without GUI support } } /** * Test method for {@link ext.scrollablepopupmenu.XJPopupMenu#getComponents()} * . */ public void testGetComponents() { try { XJPopupMenu menu = new XJPopupMenu(null); menu.getComponents(); } catch (HeadlessException e) { // happens if run without GUI support } } } jajuk-1.9.6.orig/src/test/java/ext/TestJSplash.java0000644000175000017500000001117111720500104022013 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package ext; import java.awt.HeadlessException; import java.net.URL; import org.jajuk.JajukTestCase; /** * DOCUMENT_ME. */ public class TestJSplash extends JajukTestCase { /** * Test method for. * * @throws Exception the exception * {@link ext.JSplash#JSplash(java.net.URL, boolean, boolean, boolean, java.lang.String, java.lang.String, java.awt.Font)} * . */ public void testJSplash() throws Exception { try { new JSplash(new URL("http://www.example.com"), true, true, true, "copyright", "version", null); } catch (HeadlessException e) { // expected when tests are executed without UI support } } /** * Test j splash2. * DOCUMENT_ME * * @throws Exception the exception */ public void testJSplash2() throws Exception { try { new JSplash(new URL("http://www.example.com"), true, false, false, "copyright", "version", null); } catch (HeadlessException e) { // expected when tests are executed without UI support } } /** * Test j splash null url. * DOCUMENT_ME * * @throws Exception the exception */ public void testJSplashNullURL() throws Exception { try { new JSplash(null, true, false, false, "copyright", "version", null); fail("Should throw exception with null-URL"); } catch (IllegalArgumentException e) { assertTrue(e.getMessage(), e.getMessage().contains("Invalid URL specified for Splashscreen")); } catch (HeadlessException e) { // expected when tests are executed without UI support } } /** * Test method for {@link ext.JSplash#splashOn()}. * * @throws Exception the exception */ public void testSplashOn() throws Exception { try { JSplash splash = new JSplash(new URL("http://www.example.com"), true, true, true, "copyright", "version", null); splash.splashOn(); splash.splashOff(); } catch (HeadlessException e) { // expected when tests are executed without UI support } } /** * Test method for {@link ext.JSplash#splashOff()}. * * @throws Exception the exception */ public void testSplashOff() throws Exception { try { JSplash splash = new JSplash(new URL("http://www.example.com"), true, true, true, "copyright", "version", null); splash.splashOff(); } catch (HeadlessException e) { // expected when tests are executed without UI support } } /** * Test method for {@link ext.JSplash#setProgress(int)}. * * @throws Exception the exception */ public void testSetProgressInt() throws Exception { try { JSplash splash = new JSplash(new URL("http://www.example.com"), true, true, true, "copyright", "version", null); splash.setProgress(30); splash.splashOff(); } catch (HeadlessException e) { // expected when tests are executed without UI support } } /** * Test method for {@link ext.JSplash#setProgress(int, java.lang.String)}. * * @throws Exception the exception */ public void testSetProgressIntString() throws Exception { try { JSplash splash = new JSplash(new URL("http://www.example.com"), true, true, true, "copyright", "version", null); splash.setProgress(30, "testmessage"); splash.splashOff(); } catch (HeadlessException e) { // expected when tests are executed without UI support } } /** * Test set progress int string2. * DOCUMENT_ME * * @throws Exception the exception */ public void testSetProgressIntString2() throws Exception { try { JSplash splash = new JSplash(new URL("http://www.example.com"), true, true, false, "copyright", "version", null); splash.setProgress(30, "testmessage"); splash.splashOff(); } catch (HeadlessException e) { // expected when tests are executed without UI support } } } jajuk-1.9.6.orig/src/test/java/ext/TestJScrollingText.java0000644000175000017500000004147011720500104023367 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package ext; import java.awt.Color; import java.awt.Composite; import java.awt.Font; import java.awt.FontMetrics; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.GraphicsConfiguration; import java.awt.Image; import java.awt.Paint; import java.awt.Rectangle; import java.awt.RenderingHints; import java.awt.RenderingHints.Key; import java.awt.Shape; import java.awt.Stroke; import java.awt.font.FontRenderContext; import java.awt.font.GlyphVector; import java.awt.geom.AffineTransform; import java.awt.image.BufferedImage; import java.awt.image.BufferedImageOp; import java.awt.image.ImageObserver; import java.awt.image.RenderedImage; import java.awt.image.renderable.RenderableImage; import java.text.AttributedCharacterIterator; import java.util.Map; import org.jajuk.JajukTestCase; /** * DOCUMENT_ME. */ public class TestJScrollingText extends JajukTestCase { /** * Test method for {@link ext.JScrollingText#JScrollingText(String)}. */ public void testJScrollingTextString() { new JScrollingText("teststring"); } /** * Test method for {@link ext.JScrollingText#JScrollingText(String, int)}. */ public void testJScrollingTextStringInt() { new JScrollingText("teststring", 1000); } /** * Test method for {@link ext.JScrollingText#JScrollingText(String, int, int)} * . */ public void testJScrollingTextStringIntInt() { new JScrollingText("teststring", 500, 1000); } /** * Test method for. * * {@link ext.JScrollingText#JScrollingText(String, int, int, int)}. */ public void testJScrollingTextStringIntIntInt() { new JScrollingText("teststring", 700, 100, 10); } /** * Test method for {@link ext.JScrollingText#paintComponent(Graphics)}. */ public void testPaintComponent() { JScrollingText t = new JScrollingText("teststring"); assertNotNull(t); t.paintComponent(new MyGraphics2D()); } /** * Test paint component opaque. * DOCUMENT_ME */ public void testPaintComponentOpaque() { JScrollingText t = new JScrollingText("teststring"); t.setOpaque(true); t.paintComponent(new MyGraphics2D()); } /** * Test paint component speed. * DOCUMENT_ME */ public void testPaintComponentSpeed() { JScrollingText t = new JScrollingText("teststring", 1000); t.paintComponent(new MyGraphics2D()); } /** * Test paint component speed zero. * DOCUMENT_ME */ public void testPaintComponentSpeedZero() { JScrollingText t = new JScrollingText("teststring", 0); t.paintComponent(new MyGraphics2D()); } /** * Test method for {@link ext.JScrollingText#start()}. * * @throws Exception the exception */ public void testStart() throws Exception { JScrollingText t = new JScrollingText("teststring"); assertNotNull(t); t.start(); // have to sleep some time here to make the Timer run at least once Thread.sleep(1100); } /** * DOCUMENT_ME. */ private final class MyGraphics2D extends Graphics2D { /* (non-Javadoc) * @see java.awt.Graphics#setXORMode(java.awt.Color) */ @Override public void setXORMode(Color c1) { } /* (non-Javadoc) * @see java.awt.Graphics#setPaintMode() */ @Override public void setPaintMode() { } /* (non-Javadoc) * @see java.awt.Graphics#setFont(java.awt.Font) */ @Override public void setFont(Font font) { } /* (non-Javadoc) * @see java.awt.Graphics#setColor(java.awt.Color) */ @Override public void setColor(Color c) { } /* (non-Javadoc) * @see java.awt.Graphics#setClip(int, int, int, int) */ @Override public void setClip(int x, int y, int width, int height) { } /* (non-Javadoc) * @see java.awt.Graphics#setClip(java.awt.Shape) */ @Override public void setClip(Shape clip) { } /* (non-Javadoc) * @see java.awt.Graphics#getFontMetrics(java.awt.Font) */ @Override public FontMetrics getFontMetrics(Font f) { return new FontMetrics(f) { private static final long serialVersionUID = 9139781111511738969L; @Override public int stringWidth(String str) { return str.length(); } @Override public int getHeight() { return 10; } @Override public int getAscent() { return 10; } }; } /* (non-Javadoc) * @see java.awt.Graphics#getFont() */ @Override public Font getFont() { return null; } /* (non-Javadoc) * @see java.awt.Graphics#getColor() */ @Override public Color getColor() { return null; } /* (non-Javadoc) * @see java.awt.Graphics#getClipBounds() */ @Override public Rectangle getClipBounds() { return null; } /* (non-Javadoc) * @see java.awt.Graphics#getClip() */ @Override public Shape getClip() { return null; } /* (non-Javadoc) * @see java.awt.Graphics#fillRoundRect(int, int, int, int, int, int) */ @Override public void fillRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight) { } /* (non-Javadoc) * @see java.awt.Graphics#fillRect(int, int, int, int) */ @Override public void fillRect(int x, int y, int width, int height) { } /* (non-Javadoc) * @see java.awt.Graphics#fillPolygon(int[], int[], int) */ @Override public void fillPolygon(int[] xPoints, int[] yPoints, int nPoints) { } /* (non-Javadoc) * @see java.awt.Graphics#fillOval(int, int, int, int) */ @Override public void fillOval(int x, int y, int width, int height) { } /* (non-Javadoc) * @see java.awt.Graphics#fillArc(int, int, int, int, int, int) */ @Override public void fillArc(int x, int y, int width, int height, int startAngle, int arcAngle) { } /* (non-Javadoc) * @see java.awt.Graphics#drawRoundRect(int, int, int, int, int, int) */ @Override public void drawRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight) { } /* (non-Javadoc) * @see java.awt.Graphics#drawPolyline(int[], int[], int) */ @Override public void drawPolyline(int[] xPoints, int[] yPoints, int nPoints) { } /* (non-Javadoc) * @see java.awt.Graphics#drawPolygon(int[], int[], int) */ @Override public void drawPolygon(int[] xPoints, int[] yPoints, int nPoints) { } /* (non-Javadoc) * @see java.awt.Graphics#drawOval(int, int, int, int) */ @Override public void drawOval(int x, int y, int width, int height) { } /* (non-Javadoc) * @see java.awt.Graphics#drawLine(int, int, int, int) */ @Override public void drawLine(int x1, int y1, int x2, int y2) { } /* (non-Javadoc) * @see java.awt.Graphics#drawImage(java.awt.Image, int, int, int, int, int, int, int, int, java.awt.Color, java.awt.image.ImageObserver) */ @Override public boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2, Color bgcolor, ImageObserver observer) { return false; } /* (non-Javadoc) * @see java.awt.Graphics#drawImage(java.awt.Image, int, int, int, int, int, int, int, int, java.awt.image.ImageObserver) */ @Override public boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2, ImageObserver observer) { return false; } /* (non-Javadoc) * @see java.awt.Graphics#drawImage(java.awt.Image, int, int, int, int, java.awt.Color, java.awt.image.ImageObserver) */ @Override public boolean drawImage(Image img, int x, int y, int width, int height, Color bgcolor, ImageObserver observer) { return false; } /* (non-Javadoc) * @see java.awt.Graphics#drawImage(java.awt.Image, int, int, int, int, java.awt.image.ImageObserver) */ @Override public boolean drawImage(Image img, int x, int y, int width, int height, ImageObserver observer) { return false; } /* (non-Javadoc) * @see java.awt.Graphics#drawImage(java.awt.Image, int, int, java.awt.Color, java.awt.image.ImageObserver) */ @Override public boolean drawImage(Image img, int x, int y, Color bgcolor, ImageObserver observer) { return false; } /* (non-Javadoc) * @see java.awt.Graphics#drawImage(java.awt.Image, int, int, java.awt.image.ImageObserver) */ @Override public boolean drawImage(Image img, int x, int y, ImageObserver observer) { return false; } /* (non-Javadoc) * @see java.awt.Graphics#drawArc(int, int, int, int, int, int) */ @Override public void drawArc(int x, int y, int width, int height, int startAngle, int arcAngle) { } /* (non-Javadoc) * @see java.awt.Graphics#dispose() */ @Override public void dispose() { } /* (non-Javadoc) * @see java.awt.Graphics#create() */ @Override public Graphics create() { return null; } /* (non-Javadoc) * @see java.awt.Graphics#copyArea(int, int, int, int, int, int) */ @Override public void copyArea(int x, int y, int width, int height, int dx, int dy) { } /* (non-Javadoc) * @see java.awt.Graphics#clipRect(int, int, int, int) */ @Override public void clipRect(int x, int y, int width, int height) { } /* (non-Javadoc) * @see java.awt.Graphics#clearRect(int, int, int, int) */ @Override public void clearRect(int x, int y, int width, int height) { } /* (non-Javadoc) * @see java.awt.Graphics2D#translate(double, double) */ @Override public void translate(double tx, double ty) { } /* (non-Javadoc) * @see java.awt.Graphics2D#translate(int, int) */ @Override public void translate(int x, int y) { } /* (non-Javadoc) * @see java.awt.Graphics2D#transform(java.awt.geom.AffineTransform) */ @Override public void transform(AffineTransform Tx) { } /* (non-Javadoc) * @see java.awt.Graphics2D#shear(double, double) */ @Override public void shear(double shx, double shy) { } /* (non-Javadoc) * @see java.awt.Graphics2D#setTransform(java.awt.geom.AffineTransform) */ @Override public void setTransform(AffineTransform Tx) { } /* (non-Javadoc) * @see java.awt.Graphics2D#setStroke(java.awt.Stroke) */ @Override public void setStroke(Stroke s) { } /* (non-Javadoc) * @see java.awt.Graphics2D#setRenderingHints(java.util.Map) */ @Override public void setRenderingHints(Map hints) { } /* (non-Javadoc) * @see java.awt.Graphics2D#setRenderingHint(java.awt.RenderingHints.Key, java.lang.Object) */ @Override public void setRenderingHint(Key hintKey, Object hintValue) { } /* (non-Javadoc) * @see java.awt.Graphics2D#setPaint(java.awt.Paint) */ @Override public void setPaint(Paint paint) { } /* (non-Javadoc) * @see java.awt.Graphics2D#setComposite(java.awt.Composite) */ @Override public void setComposite(Composite comp) { } /* (non-Javadoc) * @see java.awt.Graphics2D#setBackground(java.awt.Color) */ @Override public void setBackground(Color color) { } /* (non-Javadoc) * @see java.awt.Graphics2D#scale(double, double) */ @Override public void scale(double sx, double sy) { } /* (non-Javadoc) * @see java.awt.Graphics2D#rotate(double, double, double) */ @Override public void rotate(double theta, double x, double y) { } /* (non-Javadoc) * @see java.awt.Graphics2D#rotate(double) */ @Override public void rotate(double theta) { } /* (non-Javadoc) * @see java.awt.Graphics2D#hit(java.awt.Rectangle, java.awt.Shape, boolean) */ @Override public boolean hit(Rectangle rect, Shape s, boolean onStroke) { return false; } /* (non-Javadoc) * @see java.awt.Graphics2D#getTransform() */ @Override public AffineTransform getTransform() { return null; } /* (non-Javadoc) * @see java.awt.Graphics2D#getStroke() */ @Override public Stroke getStroke() { return null; } /* (non-Javadoc) * @see java.awt.Graphics2D#getRenderingHints() */ @Override public RenderingHints getRenderingHints() { return null; } /* (non-Javadoc) * @see java.awt.Graphics2D#getRenderingHint(java.awt.RenderingHints.Key) */ @Override public Object getRenderingHint(Key hintKey) { return null; } /* (non-Javadoc) * @see java.awt.Graphics2D#getPaint() */ @Override public Paint getPaint() { return null; } /* (non-Javadoc) * @see java.awt.Graphics2D#getFontRenderContext() */ @Override public FontRenderContext getFontRenderContext() { return null; } /* (non-Javadoc) * @see java.awt.Graphics2D#getDeviceConfiguration() */ @Override public GraphicsConfiguration getDeviceConfiguration() { return null; } /* (non-Javadoc) * @see java.awt.Graphics2D#getComposite() */ @Override public Composite getComposite() { return null; } /* (non-Javadoc) * @see java.awt.Graphics2D#getBackground() */ @Override public Color getBackground() { return null; } /* (non-Javadoc) * @see java.awt.Graphics2D#fill(java.awt.Shape) */ @Override public void fill(Shape s) { } /* (non-Javadoc) * @see java.awt.Graphics2D#drawString(java.text.AttributedCharacterIterator, float, float) */ @Override public void drawString(AttributedCharacterIterator iterator, float x, float y) { } /* (non-Javadoc) * @see java.awt.Graphics2D#drawString(java.text.AttributedCharacterIterator, int, int) */ @Override public void drawString(AttributedCharacterIterator iterator, int x, int y) { } /* (non-Javadoc) * @see java.awt.Graphics2D#drawString(java.lang.String, float, float) */ @Override public void drawString(String str, float x, float y) { } /* (non-Javadoc) * @see java.awt.Graphics2D#drawString(java.lang.String, int, int) */ @Override public void drawString(String str, int x, int y) { } /* (non-Javadoc) * @see java.awt.Graphics2D#drawRenderedImage(java.awt.image.RenderedImage, java.awt.geom.AffineTransform) */ @Override public void drawRenderedImage(RenderedImage img, AffineTransform xform) { } /* (non-Javadoc) * @see java.awt.Graphics2D#drawRenderableImage(java.awt.image.renderable.RenderableImage, java.awt.geom.AffineTransform) */ @Override public void drawRenderableImage(RenderableImage img, AffineTransform xform) { } /* (non-Javadoc) * @see java.awt.Graphics2D#drawImage(java.awt.image.BufferedImage, java.awt.image.BufferedImageOp, int, int) */ @Override public void drawImage(BufferedImage img, BufferedImageOp op, int x, int y) { } /* (non-Javadoc) * @see java.awt.Graphics2D#drawImage(java.awt.Image, java.awt.geom.AffineTransform, java.awt.image.ImageObserver) */ @Override public boolean drawImage(Image img, AffineTransform xform, ImageObserver obs) { return false; } /* (non-Javadoc) * @see java.awt.Graphics2D#drawGlyphVector(java.awt.font.GlyphVector, float, float) */ @Override public void drawGlyphVector(GlyphVector g, float x, float y) { } /* (non-Javadoc) * @see java.awt.Graphics2D#draw(java.awt.Shape) */ @Override public void draw(Shape s) { } /* (non-Javadoc) * @see java.awt.Graphics2D#clip(java.awt.Shape) */ @Override public void clip(Shape s) { } /* (non-Javadoc) * @see java.awt.Graphics2D#addRenderingHints(java.util.Map) */ @Override public void addRenderingHints(Map hints) { } } } jajuk-1.9.6.orig/src/test/java/ext/TestAutoCompleteDocument.java0000644000175000017500000001336011720500104024551 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package ext; import java.util.Arrays; import javax.swing.JComboBox; import javax.swing.JTextField; import javax.swing.text.Document; import javax.swing.text.JTextComponent; import org.jajuk.JajukTestCase; import org.jdesktop.swingx.autocomplete.AbstractAutoCompleteAdaptor; import org.jdesktop.swingx.autocomplete.ComboBoxAdaptor; import org.jdesktop.swingx.autocomplete.ObjectToStringConverter; import org.jdesktop.swingx.autocomplete.TextComponentAdaptor; /** * DOCUMENT_ME. */ public class TestAutoCompleteDocument extends JajukTestCase { /** * Test method for {@link ext.AutoCompleteDocument#remove(int, int)}. * * @throws Exception the exception */ public void testRemove() throws Exception { String[] items = new String[] { "exact", "exacter", "exactest" }; JTextComponent textComponent = new JTextField(); TextComponentAdaptor adaptor = new TextComponentAdaptor(textComponent, Arrays.asList(items)); Document document = new AutoCompleteDocument(adaptor, true); document.insertString(0, "test", null); // TODO: this does not work for some reason.... // document.remove(0, 2); } /** * Test method for. * * {@link ext.AutoCompleteDocument#AutoCompleteDocument(org.jdesktop.swingx.autocomplete.AbstractAutoCompleteAdaptor, boolean, org.jdesktop.swingx.autocomplete.ObjectToStringConverter)} * . */ public void testAutoCompleteDocumentAbstractAutoCompleteAdaptorBooleanObjectToStringConverter() { new AutoCompleteDocument(new ComboBoxAdaptor(new JComboBox()), false, null); } /** * Test auto complete document abstract auto complete adaptor boolean object to string converter selected. * DOCUMENT_ME */ public void testAutoCompleteDocumentAbstractAutoCompleteAdaptorBooleanObjectToStringConverterSelected() { AbstractAutoCompleteAdaptor adaptor = new ComboBoxAdaptor(new JComboBox(new Object[] { "string1", "string2", "string3" })); adaptor.setSelectedItem("string2"); adaptor.setSelectedItemAsString("string3"); assertNotNull(adaptor.getSelectedItem()); assertNotNull(adaptor.getSelectedItemAsString()); new AutoCompleteDocument(adaptor, false, new ObjectToStringConverter() { @Override public String getPreferredStringForItem(Object obj) { return null; } }); } /** * Test method for. * * {@link ext.AutoCompleteDocument#AutoCompleteDocument(org.jdesktop.swingx.autocomplete.AbstractAutoCompleteAdaptor, boolean)} * . */ public void testAutoCompleteDocumentAbstractAutoCompleteAdaptorBoolean() { new AutoCompleteDocument(new ComboBoxAdaptor(new JComboBox()), false); } /** * Test method for {@link ext.AutoCompleteDocument#isStrictMatching()}. */ public void testIsStrictMatching() { AutoCompleteDocument document = new AutoCompleteDocument(new ComboBoxAdaptor(new JComboBox()), false); assertFalse(document.isStrictMatching()); document = new AutoCompleteDocument(new ComboBoxAdaptor(new JComboBox()), true); assertTrue(document.isStrictMatching()); } /** * Test method for. * * @throws Exception the exception * {@link ext.AutoCompleteDocument#insertString(int, java.lang.String, javax.swing.text.AttributeSet)} * . */ public void testInsertStringIntStringAttributeSetStrictMatching() throws Exception { String[] items = new String[] { "exact", "exacter", "exactest" }; JTextComponent textComponent = new JTextField(); TextComponentAdaptor adaptor = new TextComponentAdaptor(textComponent, Arrays.asList(items)); Document document = new AutoCompleteDocument(adaptor, true); document.insertString(0, "test", null); } /** * Test insert string int string attribute set. * DOCUMENT_ME * * @throws Exception the exception */ public void testInsertStringIntStringAttributeSet() throws Exception { String[] items = new String[] { "exact", "exacter", "exactest" }; JTextComponent textComponent = new JTextField("012345"); TextComponentAdaptor adaptor = new TextComponentAdaptor(textComponent, Arrays.asList(items)); Document document = new AutoCompleteDocument(adaptor, false); document.insertString(0, "test", null); } /** * Test prefer exact match over currently selected. * DOCUMENT_ME * * @throws Exception the exception */ public void testPreferExactMatchOverCurrentlySelected() throws Exception { String[] items = new String[] { "exact", "exacter", "exactest" }; JTextComponent textComponent = new JTextField(); TextComponentAdaptor adaptor = new TextComponentAdaptor(textComponent, Arrays.asList(items)); Document document = new AutoCompleteDocument(adaptor, true); textComponent.setDocument(document); textComponent.setText("exacter"); assertTrue(adaptor.getSelectedItem().equals("exacter")); document.remove(4, 3); assertTrue(adaptor.getSelectedItem().equals("exacter")); document.insertString(4, "t", null); assertTrue(adaptor.getSelectedItem().equals("exact")); } } jajuk-1.9.6.orig/src/test/java/ext/TestAutoCompleteDecorator.java0000644000175000017500000001306111720500104024713 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package ext; import java.awt.Component; import javax.swing.JComboBox; import javax.swing.JList; import javax.swing.text.JTextComponent; import junit.framework.TestCase; /** * DOCUMENT_ME. */ public class TestAutoCompleteDecorator extends TestCase { /** * Test method for {@link ext.AutoCompleteDecorator#decorate(javax.swing.text.JTextComponent, java.util.List, boolean)}. */ public void testDecorateJTextComponentListOfObjectBoolean() { // TODO: make working // AutoCompleteDecorator.decorate(null, null, false); } /** * Test method for {@link ext.AutoCompleteDecorator#decorate(javax.swing.text.JTextComponent, java.util.List, boolean, org.jdesktop.swingx.autocomplete.ObjectToStringConverter)}. */ public void testDecorateJTextComponentListOfObjectBooleanObjectToStringConverter() { // TODO: make working // AutoCompleteDecorator.decorate(null, null, false, null); } /** * Test method for {@link ext.AutoCompleteDecorator#decorate(javax.swing.JList, javax.swing.text.JTextComponent)}. */ public void testDecorateJListJTextComponent() { AutoCompleteDecorator.decorate(new JList(), new JTextComponent() { private static final long serialVersionUID = 1L; /* (non-Javadoc) * @see javax.swing.text.JTextComponent#getText() */ @Override public String getText() { return "testtext"; } }); } /** * Test method for {@link ext.AutoCompleteDecorator#decorate(javax.swing.JList, javax.swing.text.JTextComponent, org.jdesktop.swingx.autocomplete.ObjectToStringConverter)}. */ public void testDecorateJListJTextComponentObjectToStringConverter() { // TODO: make working //AutoCompleteDecorator.decorate(new JList(), new JTextComponent() { // private static final long serialVersionUID = 1L;}, null); } /** * Test method for {@link ext.AutoCompleteDecorator#decorate(javax.swing.JComboBox)}. */ public void testDecorateJComboBox() { // TODO: make working // AutoCompleteDecorator.decorate(null); } /** * Test method for {@link ext.AutoCompleteDecorator#decorate(javax.swing.JComboBox, org.jdesktop.swingx.autocomplete.ObjectToStringConverter)}. */ public void testDecorateJComboBoxObjectToStringConverter() { // TODO: make working // AutoCompleteDecorator.decorate((JComboBox)null, null); } /** * Test method for {@link ext.AutoCompleteDecorator#decorate(javax.swing.text.JTextComponent, ext.AutoCompleteDocument, org.jdesktop.swingx.autocomplete.AbstractAutoCompleteAdaptor)}. */ public void testDecorateJTextComponentAutoCompleteDocumentAbstractAutoCompleteAdaptor() { // TODO: make working // AutoCompleteDecorator.decorate((JTextComponent)null, null, null); } ///////////////////////7 // Tests from singx itself /** DOCUMENT_ME. */ private JComboBox combo; /* (non-Javadoc) * @see junit.framework.TestCase#setUp() */ @Override protected void setUp() { combo = new JComboBox(new String[] { "Alpha", "Bravo", "Charlie", "Delta" }); } /** * SwingX Issue #299. */ public void testDecorationFocusListeners() { Component editor = combo.getEditor().getEditorComponent(); //current count plus 2 from UI delegate and 1 from AutoComplete int expectedFocusListenerCount = editor.getFocusListeners().length + 3; AutoCompleteDecorator.decorate(combo); assertEquals(expectedFocusListenerCount, editor.getFocusListeners().length); //redecorating should not increase listener count AutoCompleteDecorator.decorate(combo); // TODO: make working // assertEquals(expectedFocusListenerCount, editor.getFocusListeners().length); } /** * SwingX Issue #299. */ public void testDecorationKeyListeners() { Component editor = combo.getEditor().getEditorComponent(); //current count 1 from AutoComplete int expectedKeyListenerCount = editor.getKeyListeners().length + 1; AutoCompleteDecorator.decorate(combo); assertEquals(expectedKeyListenerCount, editor.getKeyListeners().length); //redecorating should not increase listener count AutoCompleteDecorator.decorate(combo); // TODO: make working // assertEquals(expectedKeyListenerCount, editor.getKeyListeners().length); } /** * SwingX Issue #299. */ public void testDecorationPropertyListeners() { //current count 1 from AutoComplete int expectedPropListenerCount = combo.getPropertyChangeListeners("editor").length + 1; AutoCompleteDecorator.decorate(combo); assertEquals(expectedPropListenerCount, combo.getPropertyChangeListeners("editor").length); //redecorating should not increase listener count AutoCompleteDecorator.decorate(combo); // TODO: make working // assertEquals(expectedPropListenerCount, combo.getPropertyChangeListeners("editor").length); } } jajuk-1.9.6.orig/src/test/java/ext/TestJSplashLabel.java0000644000175000017500000004002511720500104022753 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package ext; import java.awt.Color; import java.awt.Composite; import java.awt.Font; import java.awt.FontMetrics; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.GraphicsConfiguration; import java.awt.Image; import java.awt.Paint; import java.awt.Rectangle; import java.awt.RenderingHints; import java.awt.RenderingHints.Key; import java.awt.Shape; import java.awt.Stroke; import java.awt.font.FontRenderContext; import java.awt.font.GlyphVector; import java.awt.geom.AffineTransform; import java.awt.image.BufferedImage; import java.awt.image.BufferedImageOp; import java.awt.image.ImageObserver; import java.awt.image.RenderedImage; import java.awt.image.renderable.RenderableImage; import java.net.URL; import java.text.AttributedCharacterIterator; import java.util.Map; import org.jajuk.JajukTestCase; import org.jajuk.util.Const; /** * DOCUMENT_ME. */ public class TestJSplashLabel extends JajukTestCase { /** * Test method for. * * @throws Exception the exception * {@link ext.JSplashLabel#JSplashLabel(java.net.URL, java.lang.String, java.lang.String, java.awt.Font)} * . */ public void testJSplashLabel() throws Exception { new JSplashLabel(new URL("http://www.example.com/"), "copyright", "teststring", null); } /** * Test j splash label url. * DOCUMENT_ME * * @throws Exception the exception */ public void testJSplashLabelURL() throws Exception { new JSplashLabel(Const.IMAGES_SPLASHSCREEN, "copyright", "teststring", null); } /** * Test j splash label font. * DOCUMENT_ME * * @throws Exception the exception */ public void testJSplashLabelFont() throws Exception { new JSplashLabel(Const.IMAGES_SPLASHSCREEN, "copyright", "teststring", new Font("Roman", Font.ITALIC, 10)); } /** * Test method for {@link ext.JSplashLabel#paint(java.awt.Graphics)}. * * @throws Exception the exception */ public void testPaintGraphics() throws Exception { JSplashLabel label = new JSplashLabel(Const.IMAGES_SPLASHSCREEN, "copyright", "teststring", null); label.paint(new MyGraphics2D()); } /** * DOCUMENT_ME. */ private final class MyGraphics2D extends Graphics2D { /* (non-Javadoc) * @see java.awt.Graphics#setXORMode(java.awt.Color) */ @Override public void setXORMode(Color c1) { } /* (non-Javadoc) * @see java.awt.Graphics#setPaintMode() */ @Override public void setPaintMode() { } /* (non-Javadoc) * @see java.awt.Graphics#setFont(java.awt.Font) */ @Override public void setFont(Font font) { } /* (non-Javadoc) * @see java.awt.Graphics#setColor(java.awt.Color) */ @Override public void setColor(Color c) { } /* (non-Javadoc) * @see java.awt.Graphics#setClip(int, int, int, int) */ @Override public void setClip(int x, int y, int width, int height) { } /* (non-Javadoc) * @see java.awt.Graphics#setClip(java.awt.Shape) */ @Override public void setClip(Shape clip) { } /* (non-Javadoc) * @see java.awt.Graphics#getFontMetrics(java.awt.Font) */ @Override public FontMetrics getFontMetrics(Font f) { return new FontMetrics(f) { private static final long serialVersionUID = 9139781111511738969L; @Override public int stringWidth(String str) { return str.length(); } @Override public int getHeight() { return 10; } @Override public int getAscent() { return 10; } }; } /* (non-Javadoc) * @see java.awt.Graphics#getFont() */ @Override public Font getFont() { return null; } /* (non-Javadoc) * @see java.awt.Graphics#getColor() */ @Override public Color getColor() { return null; } /* (non-Javadoc) * @see java.awt.Graphics#getClipBounds() */ @Override public Rectangle getClipBounds() { return null; } /* (non-Javadoc) * @see java.awt.Graphics#getClip() */ @Override public Shape getClip() { return null; } /* (non-Javadoc) * @see java.awt.Graphics#fillRoundRect(int, int, int, int, int, int) */ @Override public void fillRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight) { } /* (non-Javadoc) * @see java.awt.Graphics#fillRect(int, int, int, int) */ @Override public void fillRect(int x, int y, int width, int height) { } /* (non-Javadoc) * @see java.awt.Graphics#fillPolygon(int[], int[], int) */ @Override public void fillPolygon(int[] xPoints, int[] yPoints, int nPoints) { } /* (non-Javadoc) * @see java.awt.Graphics#fillOval(int, int, int, int) */ @Override public void fillOval(int x, int y, int width, int height) { } /* (non-Javadoc) * @see java.awt.Graphics#fillArc(int, int, int, int, int, int) */ @Override public void fillArc(int x, int y, int width, int height, int startAngle, int arcAngle) { } /* (non-Javadoc) * @see java.awt.Graphics#drawRoundRect(int, int, int, int, int, int) */ @Override public void drawRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight) { } /* (non-Javadoc) * @see java.awt.Graphics#drawPolyline(int[], int[], int) */ @Override public void drawPolyline(int[] xPoints, int[] yPoints, int nPoints) { } /* (non-Javadoc) * @see java.awt.Graphics#drawPolygon(int[], int[], int) */ @Override public void drawPolygon(int[] xPoints, int[] yPoints, int nPoints) { } /* (non-Javadoc) * @see java.awt.Graphics#drawOval(int, int, int, int) */ @Override public void drawOval(int x, int y, int width, int height) { } /* (non-Javadoc) * @see java.awt.Graphics#drawLine(int, int, int, int) */ @Override public void drawLine(int x1, int y1, int x2, int y2) { } /* (non-Javadoc) * @see java.awt.Graphics#drawImage(java.awt.Image, int, int, int, int, int, int, int, int, java.awt.Color, java.awt.image.ImageObserver) */ @Override public boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2, Color bgcolor, ImageObserver observer) { return false; } /* (non-Javadoc) * @see java.awt.Graphics#drawImage(java.awt.Image, int, int, int, int, int, int, int, int, java.awt.image.ImageObserver) */ @Override public boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2, ImageObserver observer) { return false; } /* (non-Javadoc) * @see java.awt.Graphics#drawImage(java.awt.Image, int, int, int, int, java.awt.Color, java.awt.image.ImageObserver) */ @Override public boolean drawImage(Image img, int x, int y, int width, int height, Color bgcolor, ImageObserver observer) { return false; } /* (non-Javadoc) * @see java.awt.Graphics#drawImage(java.awt.Image, int, int, int, int, java.awt.image.ImageObserver) */ @Override public boolean drawImage(Image img, int x, int y, int width, int height, ImageObserver observer) { return false; } /* (non-Javadoc) * @see java.awt.Graphics#drawImage(java.awt.Image, int, int, java.awt.Color, java.awt.image.ImageObserver) */ @Override public boolean drawImage(Image img, int x, int y, Color bgcolor, ImageObserver observer) { return false; } /* (non-Javadoc) * @see java.awt.Graphics#drawImage(java.awt.Image, int, int, java.awt.image.ImageObserver) */ @Override public boolean drawImage(Image img, int x, int y, ImageObserver observer) { return false; } /* (non-Javadoc) * @see java.awt.Graphics#drawArc(int, int, int, int, int, int) */ @Override public void drawArc(int x, int y, int width, int height, int startAngle, int arcAngle) { } /* (non-Javadoc) * @see java.awt.Graphics#dispose() */ @Override public void dispose() { } /* (non-Javadoc) * @see java.awt.Graphics#create() */ @Override public Graphics create() { return null; } /* (non-Javadoc) * @see java.awt.Graphics#copyArea(int, int, int, int, int, int) */ @Override public void copyArea(int x, int y, int width, int height, int dx, int dy) { } /* (non-Javadoc) * @see java.awt.Graphics#clipRect(int, int, int, int) */ @Override public void clipRect(int x, int y, int width, int height) { } /* (non-Javadoc) * @see java.awt.Graphics#clearRect(int, int, int, int) */ @Override public void clearRect(int x, int y, int width, int height) { } /* (non-Javadoc) * @see java.awt.Graphics2D#translate(double, double) */ @Override public void translate(double tx, double ty) { } /* (non-Javadoc) * @see java.awt.Graphics2D#translate(int, int) */ @Override public void translate(int x, int y) { } /* (non-Javadoc) * @see java.awt.Graphics2D#transform(java.awt.geom.AffineTransform) */ @Override public void transform(AffineTransform Tx) { } /* (non-Javadoc) * @see java.awt.Graphics2D#shear(double, double) */ @Override public void shear(double shx, double shy) { } /* (non-Javadoc) * @see java.awt.Graphics2D#setTransform(java.awt.geom.AffineTransform) */ @Override public void setTransform(AffineTransform Tx) { } /* (non-Javadoc) * @see java.awt.Graphics2D#setStroke(java.awt.Stroke) */ @Override public void setStroke(Stroke s) { } /* (non-Javadoc) * @see java.awt.Graphics2D#setRenderingHints(java.util.Map) */ @Override public void setRenderingHints(Map hints) { } /* (non-Javadoc) * @see java.awt.Graphics2D#setRenderingHint(java.awt.RenderingHints.Key, java.lang.Object) */ @Override public void setRenderingHint(Key hintKey, Object hintValue) { } /* (non-Javadoc) * @see java.awt.Graphics2D#setPaint(java.awt.Paint) */ @Override public void setPaint(Paint paint) { } /* (non-Javadoc) * @see java.awt.Graphics2D#setComposite(java.awt.Composite) */ @Override public void setComposite(Composite comp) { } /* (non-Javadoc) * @see java.awt.Graphics2D#setBackground(java.awt.Color) */ @Override public void setBackground(Color color) { } /* (non-Javadoc) * @see java.awt.Graphics2D#scale(double, double) */ @Override public void scale(double sx, double sy) { } /* (non-Javadoc) * @see java.awt.Graphics2D#rotate(double, double, double) */ @Override public void rotate(double theta, double x, double y) { } /* (non-Javadoc) * @see java.awt.Graphics2D#rotate(double) */ @Override public void rotate(double theta) { } /* (non-Javadoc) * @see java.awt.Graphics2D#hit(java.awt.Rectangle, java.awt.Shape, boolean) */ @Override public boolean hit(Rectangle rect, Shape s, boolean onStroke) { return false; } /* (non-Javadoc) * @see java.awt.Graphics2D#getTransform() */ @Override public AffineTransform getTransform() { return null; } /* (non-Javadoc) * @see java.awt.Graphics2D#getStroke() */ @Override public Stroke getStroke() { return null; } /* (non-Javadoc) * @see java.awt.Graphics2D#getRenderingHints() */ @Override public RenderingHints getRenderingHints() { return null; } /* (non-Javadoc) * @see java.awt.Graphics2D#getRenderingHint(java.awt.RenderingHints.Key) */ @Override public Object getRenderingHint(Key hintKey) { return null; } /* (non-Javadoc) * @see java.awt.Graphics2D#getPaint() */ @Override public Paint getPaint() { return null; } /* (non-Javadoc) * @see java.awt.Graphics2D#getFontRenderContext() */ @Override public FontRenderContext getFontRenderContext() { return null; } /* (non-Javadoc) * @see java.awt.Graphics2D#getDeviceConfiguration() */ @Override public GraphicsConfiguration getDeviceConfiguration() { return null; } /* (non-Javadoc) * @see java.awt.Graphics2D#getComposite() */ @Override public Composite getComposite() { return null; } /* (non-Javadoc) * @see java.awt.Graphics2D#getBackground() */ @Override public Color getBackground() { return null; } /* (non-Javadoc) * @see java.awt.Graphics2D#fill(java.awt.Shape) */ @Override public void fill(Shape s) { } /* (non-Javadoc) * @see java.awt.Graphics2D#drawString(java.text.AttributedCharacterIterator, float, float) */ @Override public void drawString(AttributedCharacterIterator iterator, float x, float y) { } /* (non-Javadoc) * @see java.awt.Graphics2D#drawString(java.text.AttributedCharacterIterator, int, int) */ @Override public void drawString(AttributedCharacterIterator iterator, int x, int y) { } /* (non-Javadoc) * @see java.awt.Graphics2D#drawString(java.lang.String, float, float) */ @Override public void drawString(String str, float x, float y) { } /* (non-Javadoc) * @see java.awt.Graphics2D#drawString(java.lang.String, int, int) */ @Override public void drawString(String str, int x, int y) { } /* (non-Javadoc) * @see java.awt.Graphics2D#drawRenderedImage(java.awt.image.RenderedImage, java.awt.geom.AffineTransform) */ @Override public void drawRenderedImage(RenderedImage img, AffineTransform xform) { } /* (non-Javadoc) * @see java.awt.Graphics2D#drawRenderableImage(java.awt.image.renderable.RenderableImage, java.awt.geom.AffineTransform) */ @Override public void drawRenderableImage(RenderableImage img, AffineTransform xform) { } /* (non-Javadoc) * @see java.awt.Graphics2D#drawImage(java.awt.image.BufferedImage, java.awt.image.BufferedImageOp, int, int) */ @Override public void drawImage(BufferedImage img, BufferedImageOp op, int x, int y) { } /* (non-Javadoc) * @see java.awt.Graphics2D#drawImage(java.awt.Image, java.awt.geom.AffineTransform, java.awt.image.ImageObserver) */ @Override public boolean drawImage(Image img, AffineTransform xform, ImageObserver obs) { return false; } /* (non-Javadoc) * @see java.awt.Graphics2D#drawGlyphVector(java.awt.font.GlyphVector, float, float) */ @Override public void drawGlyphVector(GlyphVector g, float x, float y) { } /* (non-Javadoc) * @see java.awt.Graphics2D#draw(java.awt.Shape) */ @Override public void draw(Shape s) { } /* (non-Javadoc) * @see java.awt.Graphics2D#clip(java.awt.Shape) */ @Override public void clip(Shape s) { } /* (non-Javadoc) * @see java.awt.Graphics2D#addRenderingHints(java.util.Map) */ @Override public void addRenderingHints(Map hints) { } } } jajuk-1.9.6.orig/src/test/java/ext/services/0000755000175000017500000000000011720500104020566 5ustar drazzibdrazzibjajuk-1.9.6.orig/src/test/java/ext/services/network/0000755000175000017500000000000011720500104022257 5ustar drazzibdrazzibjajuk-1.9.6.orig/src/test/java/ext/services/network/TestProxy.java0000644000175000017500000001041111720500104025100 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package ext.services.network; import java.io.IOException; import java.net.Proxy.Type; import java.net.ServerSocket; import java.net.Socket; import java.net.URL; import java.net.UnknownHostException; import org.jajuk.JajukTestCase; import org.jajuk.util.log.Log; /** * DOCUMENT_ME. */ public class TestProxy extends JajukTestCase { /** The Constant PROXY_PORT. DOCUMENT_ME */ private static final int PROXY_PORT = 0; // auto-choose /** DOCUMENT_ME. */ ServerSocket socket; /** DOCUMENT_ME. */ boolean bStop = false; /* * (non-Javadoc) * * @see junit.framework.TestCase#setUp() */ @Override protected void setUp() throws Exception { socket = new ServerSocket(PROXY_PORT); Thread thread = new Thread("ProxySocketAcceptThread") { @Override public void run() { try { while (!bStop) { Socket sock = socket.accept(); Log.debug("Accepted connection, sending back garbage and close socket..."); sock.getOutputStream().write(1); sock.close(); } } catch (IOException e) { Log.error(e); } } }; thread.setDaemon(true); // to finish tests even if this is still running thread.start(); super.setUp(); } /* * (non-Javadoc) * * @see junit.framework.TestCase#tearDown() */ @Override protected void tearDown() throws Exception { bStop = true; socket.close(); super.tearDown(); } /** * Test method for. * * @throws UnknownHostException the unknown host exception * @throws Exception the exception * {@link ext.services.network.Proxy#Proxy(java.net.Proxy.Type, java.lang.String, int, java.lang.String, java.lang.String)} * . */ public void testProxyTypeStringIntStringString() throws UnknownHostException, Exception { new Proxy(Type.SOCKS, "localhost", socket.getLocalPort(), "user", "pwd"); } /** * Test method for. * * @throws Exception the exception * {@link ext.services.network.Proxy#getConnection(java.net.URL)}. */ public void testGetConnection() throws Exception { Proxy proxy = new Proxy(Type.SOCKS, "localhost", socket.getLocalPort(), "user", "pwd"); proxy.getConnection(new URL("http://www.google.com/")); } /** * Test method for {@link ext.services.network.Proxy#getPassword()}. * * @throws Exception the exception */ public void testGetPassword() throws Exception { Proxy proxy = new Proxy(Type.SOCKS, "localhost", socket.getLocalPort(), "user", "pwd"); assertEquals("pwd", proxy.getPassword()); } /** * Test method for {@link ext.services.network.Proxy#getUrl()}. * * @throws Exception the exception */ public void testGetUrl() throws Exception { Proxy proxy = new Proxy(Type.SOCKS, "localhost", socket.getLocalPort(), "user", "pwd"); assertEquals("localhost", proxy.getUrl()); } /** * Test method for {@link ext.services.network.Proxy#getPort()}. * * @throws Exception the exception */ public void testGetPort() throws Exception { Proxy proxy = new Proxy(Type.SOCKS, "localhost", socket.getLocalPort(), "user", "pwd"); assertEquals(socket.getLocalPort(), proxy.getPort()); } /** * Test method for {@link ext.services.network.Proxy#getUser()}. * * @throws Exception the exception */ public void testGetUser() throws Exception { Proxy proxy = new Proxy(Type.SOCKS, "localhost", socket.getLocalPort(), "user", "pwd"); assertEquals("user", proxy.getUser()); } } jajuk-1.9.6.orig/src/test/java/ext/services/network/TestNetworkUtils.java0000644000175000017500000002244111720500104026437 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package ext.services.network; import java.io.IOException; import java.net.HttpURLConnection; import java.net.Proxy.Type; import java.net.ServerSocket; import java.net.Socket; import org.apache.commons.lang.StringUtils; import org.jajuk.JUnitHelpers; import org.jajuk.JajukTestCase; import org.jajuk.util.Conf; import org.jajuk.util.Const; import org.jajuk.util.log.Log; /** * DOCUMENT_ME. */ public class TestNetworkUtils extends JajukTestCase { /** The Constant PROXY_PORT. DOCUMENT_ME */ private static final int PROXY_PORT = 0; // auto-choose /** The Constant URL. DOCUMENT_ME */ private static final String URL = "http://www.google.com/"; /** The Constant FTP_URL. DOCUMENT_ME */ private static final String FTP_URL = "ftp://www.google.com/"; /* * (non-Javadoc) * * @see junit.framework.TestCase#setUp() */ @Override protected void setUp() throws Exception { Conf.setProperty(Const.CONF_NETWORK_NONE_INTERNET_ACCESS, "false"); super.setUp(); } /** * Test method for. * * @throws Exception the exception * {@link ext.services.network.NetworkUtils#getConnection(java.lang.String, ext.services.network.Proxy)} * . */ public void testGetConnectionStringProxy() throws Exception { // null when no connection is allowed Conf.setProperty(Const.CONF_NETWORK_NONE_INTERNET_ACCESS, "true"); assertNull(NetworkUtils.getConnection(URL, null)); // useful content when inet access is allowed Conf.setProperty(Const.CONF_NETWORK_NONE_INTERNET_ACCESS, "false"); HttpURLConnection connection = NetworkUtils.getConnection(URL, null); assertNotNull(connection); connection.disconnect(); } /** * Test get connection string proxy invalid url. * DOCUMENT_ME * * @throws Exception the exception */ public void testGetConnectionStringProxyInvalidURL() throws Exception { // useful content when inet access is allowed Conf.setProperty(Const.CONF_NETWORK_NONE_INTERNET_ACCESS, "false"); try { NetworkUtils.getConnection(FTP_URL, null); fail("Should fail here"); } catch (IllegalArgumentException e) { // make sure the url is part of the error message assertTrue(e.getMessage(), e.getMessage().contains(FTP_URL)); } } /** * Test method for. * * @throws Exception the exception * {@link ext.services.network.NetworkUtils#getConnection(java.net.URL, ext.services.network.Proxy)} * . */ public void testGetConnectionURLProxy() throws Exception { // null when no connection is allowed Conf.setProperty(Const.CONF_NETWORK_NONE_INTERNET_ACCESS, "true"); assertNull(NetworkUtils.getConnection(new java.net.URL(URL), null)); // useful content when inet access is allowed Conf.setProperty(Const.CONF_NETWORK_NONE_INTERNET_ACCESS, "false"); HttpURLConnection connection = NetworkUtils.getConnection(new java.net.URL(URL), null); assertNotNull(connection); connection.disconnect(); } /** DOCUMENT_ME. */ boolean bStop = false; /** * Test get connection url proxy with proxy. * DOCUMENT_ME * * @throws Exception the exception */ public void testGetConnectionURLProxyWithProxy() throws Exception { final ServerSocket socket = new ServerSocket(PROXY_PORT); Thread thread = new Thread("ProxySocketAcceptThread") { @Override public void run() { try { while (!bStop) { Socket sock = socket.accept(); Log.debug("Accepted connection, sending back garbage and close socket..."); sock.getOutputStream().write(1); sock.close(); } } catch (IOException e) { Log.error(e); } } }; thread.setDaemon(true); // to finish tests even if this is still running thread.start(); Log.debug("Using local port: " + socket.getLocalPort()); try { // useful content when inet access is allowed Conf.setProperty(Const.CONF_NETWORK_NONE_INTERNET_ACCESS, "false"); HttpURLConnection connection = NetworkUtils.getConnection(new java.net.URL(URL), new Proxy( Type.SOCKS, "localhost", socket.getLocalPort(), "user", "password")); assertNotNull(connection); connection.disconnect(); } finally { bStop = true; socket.close(); thread.join(); } } /** * Test method for. * * @throws Exception the exception * {@link ext.services.network.NetworkUtils#readURL(java.net.URLConnection, java.lang.String)} * . */ public void testReadURLURLConnectionString() throws Exception { HttpURLConnection connection = NetworkUtils.getConnection(URL, null); assertNotNull(connection); String str = NetworkUtils.readURL(connection, "UTF-8"); assertNotNull(str); assertTrue(StringUtils.isNotBlank(str)); connection.disconnect(); } /** * Test read urlurl connection string disabled. * DOCUMENT_ME * * @throws Exception the exception */ public void testReadURLURLConnectionStringDisabled() throws Exception { HttpURLConnection connection = NetworkUtils.getConnection(URL, null); assertNotNull(connection); Conf.setProperty(Const.CONF_NETWORK_NONE_INTERNET_ACCESS, "true"); assertNull(NetworkUtils.readURL(connection, "UTF-8")); connection.disconnect(); } /** * Test method for. * * @throws Exception the exception * {@link ext.services.network.NetworkUtils#readURL(java.net.URLConnection)}. */ public void testReadURLURLConnection() throws Exception { HttpURLConnection connection = NetworkUtils.getConnection(URL, null); assertNotNull(connection); String str = NetworkUtils.readURL(connection); assertNotNull(str); assertTrue(StringUtils.isNotBlank(str)); connection.disconnect(); } /** * Test method for. * * @throws Exception the exception * {@link ext.services.network.NetworkUtils#readPostURL(java.net.HttpURLConnection, java.lang.String)} * . */ public void testReadPostURL() throws Exception { HttpURLConnection connection = NetworkUtils.getConnection(URL, null); assertNotNull(connection); connection.setDoOutput(true); // TODO: currently I do not have an URL that works via POST, therefore we // get an invalid return code try { NetworkUtils.readPostURL(connection, "post"); fail("Currently fails here"); } catch (IllegalArgumentException e) { assertTrue(e.getMessage(), e.getMessage().contains("Invalid HTTP return code")); } connection.disconnect(); } /** * Test read post url disabled. * DOCUMENT_ME * * @throws Exception the exception */ public void testReadPostURLDisabled() throws Exception { HttpURLConnection connection = NetworkUtils.getConnection(URL, null); assertNotNull(connection); connection.setDoOutput(true); Conf.setProperty(Const.CONF_NETWORK_NONE_INTERNET_ACCESS, "true"); assertNull(NetworkUtils.readPostURL(connection, "post")); connection.disconnect(); } /** * Test method for. * * @throws Exception the exception * {@link ext.services.network.NetworkUtils#getImage(java.net.URLConnection)}. */ public void testGetImage() throws Exception { HttpURLConnection connection = NetworkUtils.getConnection(URL, null); assertNotNull(connection); connection.setDoOutput(true); assertNull(NetworkUtils.getImage(connection)); } /** * Test get image disabled. * DOCUMENT_ME * * @throws Exception the exception */ public void testGetImageDisabled() throws Exception { HttpURLConnection connection = NetworkUtils.getConnection(URL, null); assertNotNull(connection); connection.setDoOutput(true); Conf.setProperty(Const.CONF_NETWORK_NONE_INTERNET_ACCESS, "true"); assertNull(NetworkUtils.getImage(connection)); } /** * Test method for. * * {@link ext.services.network.NetworkUtils#encodeString(java.lang.String)}. */ public void testEncodeString() { assertEquals("teststring", NetworkUtils.encodeString("teststring")); assertEquals( "teststring%26%21%40%23*%21%40%23%28%40%23%25%24%23%40%24%29%5E*%2F%3F%3E%3C%3F%3E%2F%2C.%22%3A%22%3B%27%27%3B%27%7B%7D%7C%5C%5D%5B%5C%22", NetworkUtils.encodeString("teststring&!@#*!@#(@#%$#@$)^*/?>/,.\":\";'';'{}|\\][\\\"")); } // helper method to emma-coverage of the unused constructor /** * Test private constructor. * DOCUMENT_ME * * @throws Exception the exception */ public void testPrivateConstructor() throws Exception { // For EMMA // code-coverage tests JUnitHelpers.executePrivateConstructor(NetworkUtils.class); } } jajuk-1.9.6.orig/src/test/java/ext/services/lastfm/0000755000175000017500000000000011720500104022054 5ustar drazzibdrazzibjajuk-1.9.6.orig/src/test/java/ext/services/lastfm/TestLastFmAlbumsRunnable.java0000644000175000017500000002651611720500104027612 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package ext.services.lastfm; import java.awt.Image; import java.io.File; import java.util.List; import javax.swing.SwingUtilities; import org.jajuk.JUnitHelpers; import org.jajuk.JajukTestCase; import org.jajuk.base.Track; import org.jajuk.util.Const; /** * DOCUMENT_ME. */ public class TestLastFmAlbumsRunnable extends JajukTestCase { /** * Test method for. * * {@link ext.services.lastfm.LastFmAlbumsRunnable#LastFmAlbumsRunnable(ext.services.lastfm.ContextListener, ext.services.lastfm.LastFmService, ext.services.lastfm.AudioObject, long)} * . */ public void testLastFmAlbumsRunnable() { new LastFmAlbumsRunnable(null, LastFmService.getInstance(), null, 1); } /** * Test method for. * * {@link ext.services.lastfm.LastFmAlbumsRunnable#interrupt()}. */ public void testInterrupt() { LastFmAlbumsRunnable runnable = new LastFmAlbumsRunnable(null, LastFmService.getInstance(), null, 1); runnable.interrupt(); } /** * Test method for {@link ext.services.lastfm.LastFmAlbumsRunnable#run()}. * * @throws Exception the exception */ public void testRun() throws Exception { // first run it normally new LastFmAlbumsRunnable(new MyContextListener(), LastFmService.getInstance(), new MyAudioObject(), 1).run(); // then run it in the background LastFmAlbumsRunnable runnable = new LastFmAlbumsRunnable(new MyContextListener(), LastFmService .getInstance(), new MyAudioObject(), 1); SwingUtilities.invokeLater(runnable); // and tell it to interrupt at some point runnable.interrupt(); // now wait for it to finish JUnitHelpers.clearSwingUtilitiesQueue(); } /** * Test method for. * * {@link ext.services.lastfm.LastFmAlbumsRunnable#setRetrieveArtistInfo(boolean)} * . */ public void testSetRetrieveArtistInfo() { LastFmAlbumsRunnable runnable = new LastFmAlbumsRunnable(null, LastFmService.getInstance(), null, 1); runnable.setRetrieveArtistInfo(true); } /** * Test method for. * * @throws Exception the exception * {@link ext.services.lastfm.LastFmAlbumsRunnable#getImageForAudioFile(org.jajuk.base.Track, int, int)} * . */ public void testGetImageForAudioFileNone() throws Exception { LastFmAlbumsRunnable.getImageForAudioFile(JUnitHelpers.getTrack(2), 100, 100); } /** * Test get image for audio file not exists. * DOCUMENT_ME */ public void testGetImageForAudioFileNotExists() { Track track = JUnitHelpers.getTrack(3); track.getAlbum().setProperty(Const.XML_ALBUM_DISCOVERED_COVER, System.getProperty("java.io.tmpdir") + "nonexist"); // don't read covers // for LastFmAlbumsRunnable.getImageForAudioFile(track, 100, 100); } /** * Test get image for audio file exists. * DOCUMENT_ME * * @throws Exception the exception */ public void testGetImageForAudioFileExists() throws Exception { Track track = JUnitHelpers.getTrack(3); File file = File.createTempFile("test", ".img"); track.getAlbum().setProperty(Const.XML_ALBUM_DISCOVERED_COVER, file.getAbsolutePath()); assertNotNull(LastFmAlbumsRunnable.getImageForAudioFile(track, 200, 100)); // TODO: cleanup does not work on Windows because the file seems to still be // used somewhere file.delete(); } /** * Test get image for audio file exists max size. * DOCUMENT_ME * * @throws Exception the exception */ public void testGetImageForAudioFileExistsMaxSize() throws Exception { Track track = JUnitHelpers.getTrack(3); File file = File.createTempFile("test", ".img"); track.getAlbum().setProperty(Const.XML_ALBUM_DISCOVERED_COVER, file.getAbsolutePath()); // don't // read // covers // for assertNotNull(LastFmAlbumsRunnable.getImageForAudioFile(track, 100, 200)); // TODO: cleanup does not work on Windows because the file seems to still be // used somewhere file.delete(); } /** * Test get image for audio file exists no resize. * DOCUMENT_ME * * @throws Exception the exception */ public void testGetImageForAudioFileExistsNoResize() throws Exception { Track track = JUnitHelpers.getTrack(3); File file = File.createTempFile("test", ".img"); track.getAlbum().setProperty(Const.XML_ALBUM_DISCOVERED_COVER, file.getAbsolutePath()); // don't // read // covers // for assertNotNull(LastFmAlbumsRunnable.getImageForAudioFile(track, -1, -1)); // TODO: cleanup does not work on Windows because the file seems to still be // used somewhere file.delete(); } /** * DOCUMENT_ME. */ private final class MyContextListener implements ContextListener { /* (non-Javadoc) * @see ext.services.lastfm.ContextListener#setLastArtistRetrieved(java.lang.String, long) */ @Override public void setLastArtistRetrieved(String artist, long id) { } /* (non-Javadoc) * @see ext.services.lastfm.ContextListener#setLastAlbumRetrieved(java.lang.String, long) */ @Override public void setLastAlbumRetrieved(String album, long id) { } /* (non-Javadoc) * @see ext.services.lastfm.ContextListener#setImage(java.awt.Image, ext.services.lastfm.AudioObject, long) */ @Override public void setImage(Image img, AudioObject ao, long id) { } /* (non-Javadoc) * @see ext.services.lastfm.ContextListener#setAlbums(java.util.List, long) */ @Override public void setAlbums(List album, long id) { } /* (non-Javadoc) * @see ext.services.lastfm.ContextListener#setAlbum(ext.services.lastfm.AlbumInfo, long) */ @Override public void setAlbum(AlbumInfo album, long id) { } /* (non-Javadoc) * @see ext.services.lastfm.ContextListener#notifyWikiInfoRetrieved(java.lang.String, java.lang.String, long) */ @Override public void notifyWikiInfoRetrieved(String wikiText, String wikiURL, long id) { } /* (non-Javadoc) * @see ext.services.lastfm.ContextListener#notifyStartRetrievingCovers(long) */ @Override public void notifyStartRetrievingCovers(long id) { } /* (non-Javadoc) * @see ext.services.lastfm.ContextListener#notifyStartRetrievingArtistImages(long) */ @Override public void notifyStartRetrievingArtistImages(long id) { } /* (non-Javadoc) * @see ext.services.lastfm.ContextListener#notifyFinishGetSimilarArtist(ext.services.lastfm.ArtistInfo, java.awt.Image, long) */ @Override public void notifyFinishGetSimilarArtist(ArtistInfo a, Image img, long id) { } /* (non-Javadoc) * @see ext.services.lastfm.ContextListener#notifyCoverRetrieved(ext.services.lastfm.AlbumInfo, java.awt.Image, long) */ @Override public void notifyCoverRetrieved(AlbumInfo album, Image cover, long id) { } /* (non-Javadoc) * @see ext.services.lastfm.ContextListener#notifyArtistImage(java.awt.Image, long) */ @Override public void notifyArtistImage(Image img, long id) { } /* (non-Javadoc) * @see ext.services.lastfm.ContextListener#notifyAlbumRetrieved(ext.services.lastfm.AudioObject, long) */ @Override public void notifyAlbumRetrieved(AudioObject file, long id) { } /* (non-Javadoc) * @see ext.services.lastfm.ContextListener#getAlbums() */ @Override public List getAlbums() { return null; } } /** * DOCUMENT_ME. */ private class MyAudioObject implements AudioObject { /* * (non-Javadoc) * * @see ext.services.lastfm.AudioObject#getAlbum() */ @Override public String getAlbum() { return "By The Way"; } /* * (non-Javadoc) * * @see ext.services.lastfm.AudioObject#getAlbumArtist() */ @Override public String getAlbumArtist() { return "Red Hot Chilli Peppers"; } /* * (non-Javadoc) * * @see ext.services.lastfm.AudioObject#getArtist() */ @Override public String getArtist() { return "Red Hot Chilli Peppers"; } /* * (non-Javadoc) * * @see ext.services.lastfm.AudioObject#getBitrate() */ @Override public long getBitrate() { return 0; } /* * (non-Javadoc) * * @see ext.services.lastfm.AudioObject#getComposer() */ @Override public String getComposer() { return null; } /* * (non-Javadoc) * * @see ext.services.lastfm.AudioObject#getDiscNumber() */ @Override public Integer getDiscNumber() { return null; } /* * (non-Javadoc) * * @see ext.services.lastfm.AudioObject#getDuration() */ @Override public long getDuration() { return 0; } /* * (non-Javadoc) * * @see ext.services.lastfm.AudioObject#getFrequency() */ @Override public int getFrequency() { return 0; } /* * (non-Javadoc) * * @see ext.services.lastfm.AudioObject#getGenre() */ @Override public String getGenre() { return null; } /* * (non-Javadoc) * * @see ext.services.lastfm.AudioObject#getLyrics() */ @Override public String getLyrics() { return null; } /* * (non-Javadoc) * * @see ext.services.lastfm.AudioObject#getStars() */ @Override public int getStars() { return 0; } /* * (non-Javadoc) * * @see ext.services.lastfm.AudioObject#getTitle() */ @Override public String getTitle() { return null; } /* * (non-Javadoc) * * @see ext.services.lastfm.AudioObject#getTitleOrFileName() */ @Override public String getTitleOrFileName() { return null; } /* * (non-Javadoc) * * @see ext.services.lastfm.AudioObject#getTrackNumber() */ @Override public Integer getTrackNumber() { return null; } /* * (non-Javadoc) * * @see ext.services.lastfm.AudioObject#getUrl() */ @Override public String getUrl() { return null; } /* * (non-Javadoc) * * @see ext.services.lastfm.AudioObject#getYear() */ @Override public String getYear() { return null; } /* * (non-Javadoc) * * @see ext.services.lastfm.AudioObject#isSeekable() */ @Override public boolean isSeekable() { return false; } /* * (non-Javadoc) * * @see ext.services.lastfm.AudioObject#setStars(int) */ @Override public void setStars(int stars) { } } } jajuk-1.9.6.orig/src/test/java/ext/services/lastfm/TestLastFmCache.java0000644000175000017500000002647511720500104025707 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package ext.services.lastfm; import java.awt.Image; import java.awt.image.BufferedImage; import java.util.ArrayList; import java.util.List; import org.jajuk.JUnitHelpers; import org.jajuk.JajukTestCase; /** * DOCUMENT_ME. */ public class TestLastFmCache extends JajukTestCase { /* * (non-Javadoc) * * @see junit.framework.TestCase#setUp() */ @Override protected void setUp() throws Exception { JUnitHelpers.createSessionDirectory(); // make sure the cache is cleaned up front to not find items from previous // runs LastFmCache cache = new LastFmCache(); cache.clearCache(); super.setUp(); } /** * Test method for {@link ext.services.lastfm.LastFmCache#clearCache()}. */ public void testClearCache() { LastFmCache cache = new LastFmCache(); cache.clearCache(); } /** * Test method for. * * {@link ext.services.lastfm.LastFmCache#retrieveAlbumCover(ext.services.lastfm.AlbumInfo)} * . */ public void testRetrieveAlbumCover() { LastFmCache cache = new LastFmCache(); LastFmAlbum album = new LastFmAlbum(); album.setBigCoverURL("testurl"); assertNull(cache.retrieveAlbumCover(album)); } /** * Test method for. * * {@link ext.services.lastfm.LastFmCache#retrieveAlbumInfo(java.lang.String, java.lang.String)} * . */ public void testRetrieveAlbumInfo() { LastFmCache cache = new LastFmCache(); assertNull(cache.retrieveAlbumInfo("Red Hot Chili Peppers", "By the way")); } /** * Test method for. * * {@link ext.services.lastfm.LastFmCache#retrieveArtistInfo(java.lang.String)} * . */ public void testRetrieveArtistInfo() { LastFmCache cache = new LastFmCache(); assertNull(cache.retrieveArtistInfo("Red Hot Chili Peppers")); } /** * Test method for. * * {@link ext.services.lastfm.LastFmCache#retrieveArtistImage(ext.services.lastfm.SimilarArtistsInfo)} * . */ public void testRetrieveArtistImage() { LastFmCache cache = new LastFmCache(); LastFmSimilarArtists artists = new LastFmSimilarArtists(); artists.setArtistName("Red Hot Chili Peppers"); assertNull(cache.retrieveArtistImage(artists)); } /** * Test method for. * * {@link ext.services.lastfm.LastFmCache#retrieveAlbumList(java.lang.String)} * . */ public void testRetrieveAlbumList() { LastFmCache cache = new LastFmCache(); assertNull(cache.retrieveAlbumList("Red Hot Chili Peppers")); } /** * Test method for. * * {@link ext.services.lastfm.LastFmCache#retrieveArtistSimilar(java.lang.String)} * . */ public void testRetrieveArtistSimilar() { LastFmCache cache = new LastFmCache(); assertNull(cache.retrieveArtistSimilar("Red Hot Chili Peppers")); } /** * Test method for. * * {@link ext.services.lastfm.LastFmCache#retrieveArtistThumbImage(ext.services.lastfm.ArtistInfo)} * . */ public void testRetrieveArtistThumbImage() { LastFmCache cache = new LastFmCache(); LastFmArtist artist = new LastFmArtist(); artist.setName("Red Hot Chili Peppers"); assertNull(cache.retrieveArtistThumbImage(artist)); } /** * Test method for. * * {@link ext.services.lastfm.LastFmCache#retrieveArtistWiki(java.lang.String)} * . */ public void testRetrieveArtistWiki() { LastFmCache cache = new LastFmCache(); assertNull(cache.retrieveArtistWiki("Red Hot Chili Peppers")); } /** * Test method for. * * {@link ext.services.lastfm.LastFmCache#storeAlbumCover(ext.services.lastfm.AlbumInfo, java.awt.Image)} * . */ public void testStoreAlbumCover() { LastFmCache cache = new LastFmCache(); LastFmAlbum album = new LastFmAlbum(); album.setBigCoverURL("testurl"); Image cover = new BufferedImage(10, 10, BufferedImage.TYPE_INT_RGB); cache.storeAlbumCover(album, cover); assertNotNull(cache.retrieveAlbumCover(album)); assertEquals(10, cache.retrieveAlbumCover(album).getHeight(null)); } /** * Test method for. * * {@link ext.services.lastfm.LastFmCache#storeAlbumInfo(java.lang.String, java.lang.String, ext.services.lastfm.AlbumInfo)} * . */ public void testStoreAlbumInfo() { LastFmCache cache = new LastFmCache(); LastFmAlbum album = new LastFmAlbum(); album.setBigCoverURL("testurl"); cache.storeAlbumInfo("Red Hot Chili Peppers", "By the way", album); assertNotNull(cache.retrieveAlbumInfo("Red Hot Chili Peppers", "By the way")); } /** * Test method for. * * {@link ext.services.lastfm.LastFmCache#storeArtistInfo(java.lang.String, ext.services.lastfm.ArtistInfo)} * . */ public void testStoreArtistInfo() { LastFmCache cache = new LastFmCache(); LastFmArtist artist = new LastFmArtist(); artist.setName("Red Hot Chili Peppers"); cache.storeArtistInfo("Red Hot Chili Peppers", artist); assertNotNull(cache.retrieveArtistInfo("Red Hot Chili Peppers")); assertEquals("Red Hot Chili Peppers", cache.retrieveArtistInfo("Red Hot Chili Peppers") .getName()); } /** * Test method for. * * {@link ext.services.lastfm.LastFmCache#storeArtistImage(ext.services.lastfm.SimilarArtistsInfo, java.awt.Image)} * . */ public void testStoreArtistImage() { LastFmCache cache = new LastFmCache(); LastFmSimilarArtists artists = new LastFmSimilarArtists(); artists.setArtistName("Red Hot Chili Peppers"); Image cover = new BufferedImage(10, 10, BufferedImage.TYPE_INT_RGB); cache.storeArtistImage(artists, cover); assertNotNull(cache.retrieveArtistImage(artists)); assertEquals(10, cache.retrieveArtistImage(artists).getHeight(null)); } /** * Test method for. * * {@link ext.services.lastfm.LastFmCache#storeAlbumList(java.lang.String, ext.services.lastfm.AlbumListInfo)} * . */ public void testStoreAlbumList() { LastFmCache cache = new LastFmCache(); LastFmAlbumList list = new LastFmAlbumList(); LastFmAlbum album1 = new LastFmAlbum(); album1.setTitle("Test1"); LastFmAlbum album2 = new LastFmAlbum(); album2.setTitle("Test2"); List alist = new ArrayList(); alist.add(album1); alist.add(album2); list.setAlbums(alist); cache.storeAlbumList("Red Hot Chili Peppers", list); assertNotNull(cache.retrieveAlbumList("Red Hot Chili Peppers")); assertNotNull(cache.retrieveAlbumList("Red Hot Chili Peppers").getAlbums()); assertEquals(cache.retrieveAlbumList("Red Hot Chili Peppers").getAlbums().toString(), 2, cache .retrieveAlbumList("Red Hot Chili Peppers").getAlbums().size()); /* * assertTrue(cache.retrieveAlbumList("Red Hot Chili Peppers").getAlbums().toString * (), * cache.retrieveAlbumList("Red Hot Chili Peppers").getAlbums().contains( * album1)); * assertTrue(cache.retrieveAlbumList("Red Hot Chili Peppers").getAlbums * ().toString(), * cache.retrieveAlbumList("Red Hot Chili Peppers").getAlbums( * ).contains(album2)); */ } /** * Test method for. * * {@link ext.services.lastfm.LastFmCache#storeArtistSimilar(java.lang.String, ext.services.lastfm.SimilarArtistsInfo)} * . */ public void testStoreArtistSimilar() { LastFmCache cache = new LastFmCache(); LastFmSimilarArtists artists = new LastFmSimilarArtists(); artists.setArtistName("Hed Rot Phili Ceppers"); cache.storeArtistSimilar("Red Hot Chili Peppers", artists); assertNotNull(cache.retrieveArtistSimilar("Red Hot Chili Peppers")); assertEquals("Hed Rot Phili Ceppers", cache.retrieveArtistSimilar("Red Hot Chili Peppers") .getArtistName()); } /** * Test method for. * * {@link ext.services.lastfm.LastFmCache#storeArtistThumbImage(ext.services.lastfm.ArtistInfo, java.awt.Image)} * . */ public void testStoreArtistThumbImage() { LastFmCache cache = new LastFmCache(); LastFmArtist artist = new LastFmArtist(); artist.setName("Red Hot Chili Peppers"); Image cover = new BufferedImage(10, 10, BufferedImage.TYPE_INT_RGB); cache.storeArtistThumbImage(artist, cover); assertNotNull(cache.retrieveArtistThumbImage(artist)); assertEquals(10, cache.retrieveArtistThumbImage(artist).getHeight(null)); } /** * Test method for. * * {@link ext.services.lastfm.LastFmCache#storeArtistWiki(java.lang.String, java.lang.String)} * . */ public void testStoreArtistWiki() { LastFmCache cache = new LastFmCache(); cache.storeArtistWiki("Red Hot Chili Peppers", "TestWikiText"); assertNotNull(cache.retrieveArtistWiki("Red Hot Chili Peppers")); assertEquals("TestWikiText", cache.retrieveArtistWiki("Red Hot Chili Peppers")); } /** * Test method for. * * {@link ext.services.lastfm.LastFmCache#addSubmissionData(ext.services.lastfm.FullSubmissionData)} * . */ public void testAddSubmissionData() { LastFmCache cache = new LastFmCache(); FullSubmissionData data = new FullSubmissionData("Red Hot Chili Peppers", "title", "By The Way", 10, 1, "Source", 10); cache.addSubmissionData(data); } /** * Test method for {@link ext.services.lastfm.LastFmCache#getSubmissionData()} * . */ public void testGetSubmissionData() { // TODO: currently this fails because library xpp3 is not found for XML Pull // Parsing, not sure why that is not part of // Jajuk distribution. Are these methods used at all?? /* * LastFmCache cache = new LastFmCache(); * * FullSubmissionData data = new FullSubmissionData("Red Hot Chili Peppers", * "title", "By The Way", 10, 1, "Source", 10); * * cache.addSubmissionData(data); * * assertEquals(1, cache.getSubmissionData().size()); * assertEquals(data.getArtist(), * cache.getSubmissionData().get(0).getArtist()); */ } /** * Test method for. * * {@link ext.services.lastfm.LastFmCache#removeSubmissionData()}. */ public void testRemoveSubmissionData() { // TODO: currently this fails because library xpp3 is not found for XML Pull // Parsing, not sure why that is not part of // Jajuk distribution. Are these methods used at all?? /* * LastFmCache cache = new LastFmCache(); * * FullSubmissionData data = new FullSubmissionData("Red Hot Chili Peppers", * "title", "By The Way", 10, 1, "Source", 10); * * cache.addSubmissionData(data); * * assertEquals(1, cache.getSubmissionData().size()); * assertEquals(data.getArtist(), * cache.getSubmissionData().get(0).getArtist()); * * cache.removeSubmissionData(); * * assertEquals(0, cache.getSubmissionData().size()); */ } } jajuk-1.9.6.orig/src/test/java/ext/services/lastfm/TestLastFmAlbumList.java0000644000175000017500000000604711720500104026571 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package ext.services.lastfm; import java.util.ArrayList; import java.util.List; import net.roarsoftware.lastfm.Album; import org.jajuk.JajukTestCase; import org.jajuk.util.UtilString; /** * DOCUMENT_ME. */ public class TestLastFmAlbumList extends JajukTestCase { /** The Constant API_KEY. DOCUMENT_ME */ private static final String API_KEY = "711591ss6q695ps349o6681pr1oq1467"; /** * Test method for. * * {@link ext.services.lastfm.LastFmAlbumList#getAlbumList(java.util.Collection, java.lang.String)} * . */ public void testGetAlbumList() { List list = getAlbumList(); AlbumListInfo info = LastFmAlbumList.getAlbumList(list, "Red Hot Chilli Peppers"); assertNotNull(info); assertEquals(2, info.getAlbums().size()); } /** * Gets the album list. * * @return the album list */ private List getAlbumList() { Album a1 = Album.getInfo("Red Hot Chilli Peppers", "By The Way", UtilString.rot13(API_KEY)); Album a2 = Album.getInfo("Red Hot Chilli Peppers", "Stadium Arcadium", UtilString .rot13(API_KEY)); List list = new ArrayList(); list.add(a1); list.add(a2); return list; } /** * Test method for {@link ext.services.lastfm.LastFmAlbumList#getAlbums()}. */ public void testGetAlbums() { LastFmAlbumList list = new LastFmAlbumList(); List info = new ArrayList(); LastFmAlbum album = new LastFmAlbum(); album.setTitle("testtitle"); info.add(album); list.setAlbums(info); assertNotNull(list.getAlbums()); list.setAlbums(null); assertNull(list.getAlbums()); } /** * Test method for {@link ext.services.lastfm.LastFmAlbumList#getArtist()}. */ public void testGetArtist() { LastFmAlbumList list = new LastFmAlbumList(); assertNull(list.getArtist()); list.setArtist("testartist"); assertEquals("testartist", list.getArtist()); } /** * Test method for. * * {@link ext.services.lastfm.LastFmAlbumList#setAlbums(java.util.List)}. */ public void testSetAlbums() { // tested above } /** * Test method for. * * {@link ext.services.lastfm.LastFmAlbumList#setArtist(java.lang.String)}. */ public void testSetArtist() { // tested above } } jajuk-1.9.6.orig/src/test/java/ext/services/lastfm/TestFullSubmissionData.java0000644000175000017500000001156411720500104027336 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package ext.services.lastfm; import org.jajuk.JajukTestCase; /** * DOCUMENT_ME. */ public class TestFullSubmissionData extends JajukTestCase { /** * Test method for. * * {@link ext.services.lastfm.FullSubmissionData#FullSubmissionData(java.lang.String, java.lang.String, java.lang.String, int, int, java.lang.String, int)} * . */ public void testFullSubmissionData() { new FullSubmissionData("artist", "title", "album", 120, 3, "source", 4); } /** * Test method for {@link ext.services.lastfm.FullSubmissionData#getArtist()}. */ public void testGetAndSetArtist() { FullSubmissionData sub = new FullSubmissionData("artist", "title", "album", 120, 3, "source", 4); assertEquals("artist", sub.getArtist()); sub.setArtist("artist2"); assertEquals("artist2", sub.getArtist()); } /** * Test method for. * * {@link ext.services.lastfm.FullSubmissionData#setArtist(java.lang.String)}. */ public void testSetArtist() { // tested above } /** * Test method for {@link ext.services.lastfm.FullSubmissionData#getTitle()}. */ public void testGetTitle() { FullSubmissionData sub = new FullSubmissionData("artist", "title", "album", 120, 3, "source", 4); assertEquals("title", sub.getTitle()); sub.setTitle("title2"); assertEquals("title2", sub.getTitle()); } /** * Test method for. * * {@link ext.services.lastfm.FullSubmissionData#setTitle(java.lang.String)}. */ public void testSetTitle() { // tested above } /** * Test method for {@link ext.services.lastfm.FullSubmissionData#getAlbum()}. */ public void testGetAlbum() { FullSubmissionData sub = new FullSubmissionData("artist", "title", "album", 120, 3, "source", 4); assertEquals("album", sub.getAlbum()); sub.setAlbum("album2"); assertEquals("album2", sub.getAlbum()); } /** * Test method for. * * {@link ext.services.lastfm.FullSubmissionData#setAlbum(java.lang.String)}. */ public void testSetAlbum() { // tested above } /** * Test method for. * * {@link ext.services.lastfm.FullSubmissionData#getDuration()}. */ public void testGetDuration() { FullSubmissionData sub = new FullSubmissionData("artist", "title", "album", 120, 3, "source", 4); assertEquals(120, sub.getDuration()); sub.setDuration(99); assertEquals(99, sub.getDuration()); } /** * Test method for. * * {@link ext.services.lastfm.FullSubmissionData#setDuration(int)}. */ public void testSetDuration() { // tested above } /** * Test method for. * * {@link ext.services.lastfm.FullSubmissionData#getTrackNumber()}. */ public void testGetTrackNumber() { FullSubmissionData sub = new FullSubmissionData("artist", "title", "album", 120, 3, "source", 4); assertEquals(3, sub.getTrackNumber()); sub.setTrackNumber(5); assertEquals(5, sub.getTrackNumber()); } /** * Test method for. * * {@link ext.services.lastfm.FullSubmissionData#setTrackNumber(int)}. */ public void testSetTrackNumber() { // tested above } /** * Test method for {@link ext.services.lastfm.FullSubmissionData#getSource()}. */ public void testGetSource() { FullSubmissionData sub = new FullSubmissionData("artist", "title", "album", 120, 3, "source", 4); assertEquals("source", sub.getSource()); sub.setSource("source2"); assertEquals("source2", sub.getSource()); } /** * Test method for. * * {@link ext.services.lastfm.FullSubmissionData#setSource(java.lang.String)}. */ public void testSetSource() { // tested above } /** * Test method for. * * {@link ext.services.lastfm.FullSubmissionData#getStartTime()}. */ public void testGetStartTime() { FullSubmissionData sub = new FullSubmissionData("artist", "title", "album", 120, 3, "source", 4); assertEquals(4, sub.getStartTime()); sub.setStartTime(7); assertEquals(7, sub.getStartTime()); } /** * Test method for. * * {@link ext.services.lastfm.FullSubmissionData#setStartTime(int)}. */ public void testSetStartTime() { // tested above } } jajuk-1.9.6.orig/src/test/java/ext/services/lastfm/TestLastFmAlbum.java0000644000175000017500000002130411720500104025726 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package ext.services.lastfm; import java.net.UnknownHostException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Locale; import net.roarsoftware.lastfm.Album; import net.roarsoftware.lastfm.CallException; import net.roarsoftware.lastfm.Playlist; import org.jajuk.JUnitHelpers; import org.jajuk.JajukTestCase; import org.jajuk.util.IconLoader; import org.jajuk.util.UtilString; /** * DOCUMENT_ME. */ public class TestLastFmAlbum extends JajukTestCase { /** The Constant API_KEY. DOCUMENT_ME */ private static final String API_KEY = "711591ss6q695ps349o6681pr1oq1467"; /** * Test method for. * * {@link ext.services.lastfm.LastFmAlbum#getAlbum(net.roarsoftware.lastfm.Album, net.roarsoftware.lastfm.Playlist)} * . */ public void testGetAlbum() { Album a = Album.getInfo("Red Hot Chilli Peppers", "By The Way", UtilString.rot13(API_KEY)); assertNotNull(a); LastFmAlbum.getAlbum(a, null); } /** * Test get album playlist. * DOCUMENT_ME */ public void testGetAlbumPlaylist() { Album a = Album.getInfo("Red Hot Chilli Peppers", "By The Way", UtilString.rot13(API_KEY)); assertNotNull(a); try { // may fail if internet is not available Playlist p = Playlist.fetchAlbumPlaylist(a.getId(), UtilString.rot13(API_KEY)); assertNotNull(p); } catch (CallException e) { // ignore for now if it contains an UnknownHostException inside assertTrue(e.getMessage(), e.getCause() instanceof UnknownHostException); } /** * TODO: find out how to get a Session here... * * Session session = null; Playlist.addTrack(p.getId(), "Red Hot Chilli Peppers", "By The Way", null); LastFmAlbum.getAlbum(a, p); */ } /** * Test method for {@link ext.services.lastfm.LastFmAlbum#getArtist()}. */ public void testGetArtist() { LastFmAlbum album = new LastFmAlbum(); assertNull(album.getArtist()); album.setArtist("artist"); assertEquals("artist", album.getArtist()); } /** * Test method for {@link ext.services.lastfm.LastFmAlbum#getArtistUrl()}. */ public void testGetArtistUrl() { LastFmAlbum album = new LastFmAlbum(); assertNull(album.getArtistUrl()); album.setUrl("testurl"); assertEquals("testurl", album.getArtistUrl()); // cuts off after last path... album.setUrl("http://test.url/url1/url2/url3/test123.html"); assertEquals("http://test.url/url1/url2/url3", album.getArtistUrl()); } /** * Test method for {@link ext.services.lastfm.LastFmAlbum#getBigCoverURL()}. */ public void testGetBigCoverURL() { LastFmAlbum album = new LastFmAlbum(); assertNull(album.getBigCoverURL()); album.setBigCoverURL("bigurl"); assertEquals("bigurl", album.getBigCoverURL()); } /** * Test method for {@link ext.services.lastfm.LastFmAlbum#getCover()}. */ public void testGetCover() { LastFmAlbum album = new LastFmAlbum(); assertNull(album.getCover()); assertNotNull(IconLoader.getNoCoverIcon(50)); album.setCover(IconLoader.getNoCoverIcon(50)); assertNotNull(album.getCover()); } /** * Test method for {@link ext.services.lastfm.LastFmAlbum#getCoverURL()}. */ public void testGetCoverURL() { LastFmAlbum album = new LastFmAlbum(); assertNull(album.getCoverURL()); album.setCoverURL("coverurl"); assertEquals("coverurl", album.getCoverURL()); } /** * Test method for {@link ext.services.lastfm.LastFmAlbum#getReleaseDate()}. * * @throws Exception the exception */ public void testGetReleaseDate() throws Exception { LastFmAlbum album = new LastFmAlbum(); assertNull(album.getReleaseDate()); album.setReleaseDateString("1 January 2009, 00:00"); assertEquals(new SimpleDateFormat("d MMM yyyy, HH:mm", Locale.ENGLISH) .parse("1 January 2009, 00:00"), album.getReleaseDate()); } /** * Test get release date invalid. * DOCUMENT_ME */ public void testGetReleaseDateInvalid() { LastFmAlbum album = new LastFmAlbum(); assertNull(album.getReleaseDate()); album.setReleaseDateString("Invalid date..."); assertNull(album.getReleaseDate()); } /** * Test method for. * * {@link ext.services.lastfm.LastFmAlbum#getReleaseDateString()}. */ public void testGetReleaseDateString() { LastFmAlbum album = new LastFmAlbum(); assertNull(album.getReleaseDateString()); album.setReleaseDateString("1 January 2009, 00:00"); assertTrue(album.getReleaseDate().toString().contains("2009")); } /** * Test method for {@link ext.services.lastfm.LastFmAlbum#getSmallCoverURL()}. */ public void testGetSmallCoverURL() { LastFmAlbum album = new LastFmAlbum(); assertNull(album.getSmallCoverURL()); album.setSmallCoverURL("smallurl"); assertEquals("smallurl", album.getSmallCoverURL()); } /** * Test method for {@link ext.services.lastfm.LastFmAlbum#getTitle()}. */ public void testGetTitle() { LastFmAlbum album = new LastFmAlbum(); assertNull(album.getTitle()); album.setTitle("title"); assertEquals("title", album.getTitle()); } /** * Test method for {@link ext.services.lastfm.LastFmAlbum#getTracks()}. */ public void testGetTracks() { LastFmAlbum album = new LastFmAlbum(); assertNull(album.getTracks()); ArrayList tracks = new ArrayList(); album.setTracks(tracks); assertNotNull(album.getTracks()); album.setTracks(null); assertNull(album.getTracks()); } /** * Test method for {@link ext.services.lastfm.LastFmAlbum#getUrl()}. */ public void testGetUrl() { LastFmAlbum album = new LastFmAlbum(); assertNull(album.getUrl()); album.setUrl("url"); assertEquals("url", album.getUrl()); } /** * Test method for {@link ext.services.lastfm.LastFmAlbum#getYear()}. */ public void testGetYear() { LastFmAlbum album = new LastFmAlbum(); assertEquals("", album.getYear()); album.setReleaseDateString("1 January 2009, 00:00"); assertEquals("2009", album.getYear()); } /** * Test method for. * * {@link ext.services.lastfm.LastFmAlbum#setArtist(java.lang.String)}. */ public void testSetArtist() { // tested above } /** * Test method for. * * {@link ext.services.lastfm.LastFmAlbum#setBigCoverURL(java.lang.String)}. */ public void testSetBigCoverURL() { // tested above } /** * Test method for. * * {@link ext.services.lastfm.LastFmAlbum#setCover(javax.swing.ImageIcon)}. */ public void testSetCover() { // tested above } /** * Test method for. * * {@link ext.services.lastfm.LastFmAlbum#setCoverURL(java.lang.String)}. */ public void testSetCoverURL() { // tested above } /** * Test method for. * * {@link ext.services.lastfm.LastFmAlbum#setReleaseDateString(java.lang.String)} * . */ public void testSetReleaseDateString() { // tested above } /** * Test method for. * * {@link ext.services.lastfm.LastFmAlbum#setSmallCoverURL(java.lang.String)}. */ public void testSetSmallCoverURL() { // tested above } /** * Test method for. * * {@link ext.services.lastfm.LastFmAlbum#setTitle(java.lang.String)}. */ public void testSetTitle() { // tested above } /** * Test method for. * * {@link ext.services.lastfm.LastFmAlbum#setTracks(java.util.List)}. */ public void testSetTracks() { // tested above } /** * Test method for. * * {@link ext.services.lastfm.LastFmAlbum#setUrl(java.lang.String)}. */ public void testSetUrl() { // tested above } /** * Test method for {@link ext.services.lastfm.LastFmAlbum#toString()}. */ public void testToString() { LastFmAlbum album = new LastFmAlbum(); JUnitHelpers.ToStringTest(album); album.setArtist("artist"); album.setBigCoverURL("url"); JUnitHelpers.ToStringTest(album); album.setTitle("title"); JUnitHelpers.ToStringTest(album); } } jajuk-1.9.6.orig/src/test/java/ext/services/xml/0000755000175000017500000000000011720500104021366 5ustar drazzibdrazzibjajuk-1.9.6.orig/src/test/java/ext/services/xml/TestXMLUtils.java0000644000175000017500000002270311720500104024556 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package ext.services.xml; import java.io.File; import java.io.IOException; import org.apache.commons.io.FileUtils; import org.apache.commons.lang.StringUtils; import org.jajuk.JUnitHelpers; import org.jajuk.JajukTestCase; import org.jajuk.util.log.Log; import org.w3c.dom.Document; import org.w3c.dom.Element; /** * DOCUMENT_ME. */ public class TestXMLUtils extends JajukTestCase { // helper method to emma-coverage of the unused constructor /** * Test serializable utilities private constructor. * DOCUMENT_ME * * @throws Exception the exception */ public void testSerializableUtilitiesPrivateConstructor() throws Exception { // For EMMA code-coverage tests JUnitHelpers.executePrivateConstructor(XMLUtils.class); } /** * Test method for. * * {@link ext.XMLUtils#getChildElement(org.w3c.dom.Element, java.lang.String)} * . */ public void testGetChildElement() { Document doc = XMLUtils.getDocument(""); assertNotNull(doc); assertNotNull(XMLUtils.getChildElement(doc.getDocumentElement(), "test")); } /** * Test get child element null. * DOCUMENT_ME */ public void testGetChildElementNull() { assertNull(XMLUtils.getChildElement(null, "test")); } /** * Test get child element not existing. * DOCUMENT_ME */ public void testGetChildElementNotExisting() { Document doc = XMLUtils.getDocument(""); assertNotNull(doc); assertNull(XMLUtils.getChildElement(doc.getDocumentElement(), "notexist")); } /** * Test method for. * * {@link ext.XMLUtils#getAttributeValue(org.w3c.dom.Element, java.lang.String)} * . */ public void testGetAttributeValue() { Document doc = XMLUtils.getDocument(""); assertNotNull(doc); Element test = XMLUtils.getChildElement(doc.getDocumentElement(), "test"); assertNotNull(test); assertNotNull(XMLUtils.getAttributeValue(test, "value")); assertEquals("", XMLUtils.getAttributeValue(test, "notexist")); assertEquals("", XMLUtils.getAttributeValue(doc.getDocumentElement(), "value")); } /** * Test get attribute value null. * DOCUMENT_ME */ public void testGetAttributeValueNull() { assertNull(XMLUtils.getAttributeValue(null, "value")); } /** * Test method for. * * {@link ext.XMLUtils#getChildElementContent(org.w3c.dom.Element, java.lang.String)} * . */ public void testGetChildElementContent() { Document doc = XMLUtils.getDocument("testcontent"); assertNotNull(doc); assertEquals("testcontent", XMLUtils.getChildElementContent(doc.getDocumentElement(), "test")); } /** * Test get child element content null. * DOCUMENT_ME */ public void testGetChildElementContentNull() { assertEquals("", XMLUtils.getChildElementContent(null, "test")); } /** * Test method for {@link ext.XMLUtils#getDocument(java.lang.String)}. */ public void testGetDocument() { Document doc = XMLUtils.getDocument(""); assertNotNull(doc); assertEquals("xml", doc.getDocumentElement().getTagName()); } /** * Test get document parse error. * DOCUMENT_ME */ public void testGetDocumentParseError() { Document doc = XMLUtils.getDocument("adsasd"); assertNull(doc); doc = XMLUtils.getDocument(StringUtils.repeat("1", 1000)); // more than 500 // characters for // log.debug assertNull(doc); } /** * Test method for. * * @throws Exception the exception * {@link ext.services.xml.XMLUtils#writeBeanToFile(java.lang.Object, java.lang.String)} * . */ public final void testWriteBeanToFile() throws Exception { PersonBean bean = new PersonBean(); bean.setName("testvalue"); File file = File.createTempFile("test", ".bean"); assertTrue(file.delete()); // delte file to create it from scratch assertFalse(file.exists()); XMLUtils.writeBeanToFile(bean, file.getAbsolutePath()); { // check file assertTrue(file.exists()); String contents = FileUtils.readFileToString(file); Log.debug("Contents: " + contents); assertTrue(contents, file.length() > 0); } /* * TODO: somehow this test does not work, we should find out and fix this * test... * * Object obj = XMLUtils.readBeanFromFile(file.getAbsolutePath()); * assertTrue(obj instanceof PersonBean); * * assertEquals("testvalue", ((PersonBean)obj).getName()); */ } /** * Test write bean to file invalid file. * DOCUMENT_ME */ public final void testWriteBeanToFileInvalidFile() { PersonBean bean = new PersonBean(); bean.setName("testvalue"); try { XMLUtils.writeBeanToFile(bean, "&@#$@(*^)!#!@#@#)}{?M<>?PersonBean. */ public class PersonBean implements java.io.Serializable { /** Generated serialVersionUID. */ private static final long serialVersionUID = 1124123276327532379L; /** DOCUMENT_ME. */ private String name; /** DOCUMENT_ME. */ private boolean deceased; /** No-arg constructor (takes no arguments). */ public PersonBean() { } /** * Property name (note capitalization) readable/writable. * * @return the name */ public String getName() { return this.name; } /** * Setter for property name. * * @param name the new name */ public void setName(final String name) { this.name = name; } /** * Getter for property "deceased" Different syntax for a boolean field (is * vs. get) * * @return true, if is deceased */ public boolean isDeceased() { return this.deceased; } /** * Setter for property deceased. * * @param deceased the new deceased */ public void setDeceased(final boolean deceased) { this.deceased = deceased; } } /** * Test method for. * * {@link ext.services.xml.XMLUtils#readBeanFromFile(java.lang.String)}. */ public final void testReadBeanFromFile() { // tested above } /** * Test method for. * * {@link ext.services.xml.XMLUtils#readObjectFromFile(java.lang.String)}. */ public final void testReadObjectFromFile() { // tested above } /** * Test method for. * * @throws Exception the exception * {@link ext.services.xml.XMLUtils#readObjectFromString(java.lang.String)}. */ public final void testReadObjectFromString() throws Exception { String str = new String("teststring"); File file = File.createTempFile("test", ".bean"); assertTrue(file.delete()); // delte file to create it from scratch assertFalse(file.exists()); XMLUtils.writeObjectToFile(str, file.getAbsolutePath()); assertTrue(file.exists()); String xml = FileUtils.readFileToString(file); assertTrue(StringUtils.isNotBlank(xml)); assertNotNull(XMLUtils.getDocument(xml)); /* * TODO: currently this reports an error about xpp3 pull parser missing, not * sure how this works inside Jajuk... * * Object obj = XMLUtils.readObjectFromString(xml); assertTrue(obj * instanceof String); * * assertEquals("teststring", obj); */ } /** * Test method for. * * @throws Exception the exception * {@link ext.services.xml.XMLUtils#writeObjectToFile(java.lang.Object, java.lang.String)} * . */ public final void testWriteObjectToFile() throws Exception { String str = new String("teststring"); File file = File.createTempFile("test", ".bean"); assertTrue(file.delete()); // delte file to create it from scratch assertFalse(file.exists()); XMLUtils.writeObjectToFile(str, file.getAbsolutePath()); assertTrue(file.exists()); /* * TODO: currently this reports an error about xpp3 pull parser missing, not * sure how this works inside Jajuk... * * Object obj = XMLUtils.readObjectFromFile(file.getAbsolutePath()); * assertTrue(obj instanceof String); * * assertEquals("teststring", obj); */ } /** * Test write object to file invalid file. * DOCUMENT_ME */ public final void testWriteObjectToFileInvalidFile() { String str = new String("teststring"); try { XMLUtils.writeObjectToFile(str, "&@#$@(*^)!#!@#@#)}{?M<>?")); // empty values should be silently ignored assertNull(XMLBuilder.getXMLDocument(null)); assertNull(XMLBuilder.getXMLDocument("")); // some invalid XML should cause an exception internally but report null assertNull(XMLBuilder.getXMLDocument("invliad document without end tag...")); } // helper method to emma-coverage of the unused constructor /** * Test private constructor. * DOCUMENT_ME * * @throws Exception the exception */ public void testPrivateConstructor() throws Exception { JUnitHelpers.executePrivateConstructor(XMLBuilder.class); } } jajuk-1.9.6.orig/src/test/java/org/0000755000175000017500000000000011720500104016732 5ustar drazzibdrazzibjajuk-1.9.6.orig/src/test/java/org/jajuk/0000755000175000017500000000000011720500104020036 5ustar drazzibdrazzibjajuk-1.9.6.orig/src/test/java/org/jajuk/JajukTestCase.java0000644000175000017500000000260011720500104023377 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2009 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision: 3132 $ */ package org.jajuk; import junit.framework.TestCase; import org.jajuk.base.Collection; import org.jajuk.services.startup.StartupCollectionService; /** * */ public abstract class JajukTestCase extends TestCase { /* * (non-Javadoc) * * @see junit.framework.TestCase#setUp() */ @Override protected void setUp() throws Exception { // let's clean up before we begin any test JUnitHelpers.waitForAllWorkToFinishAndCleanup(); // Clean the collection StartupCollectionService.registerItemManagers(); Collection.clearCollection(); super.setUp(); } } jajuk-1.9.6.orig/src/test/java/org/jajuk/LogChecker.java0000644000175000017500000000566511720500104022723 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk; import java.io.File; import java.io.FileNotFoundException; import junit.framework.TestCase; import org.jajuk.util.UtilSystem; import org.jajuk.util.error.JajukException; import org.jajuk.util.log.Log; /** * This Test is used to check conveniently jajuk log content to find special * warnings or errors that may imply a problem Note that this test only work * when redirecting stdin et stderr to a file named /tmp/jajuk_out.log */ public class LogChecker extends TestCase { /** The Constant FILE_PATH. DOCUMENT_ME */ private static final String FILE_PATH = System.getProperty("java.io.tmpdir") + File.separator + "jajuk_out.log"; /** DOCUMENT_ME. */ private String logs; /* (non-Javadoc) * @see junit.framework.TestCase#setUp() */ @Override public void setUp() throws Exception { try { logs = UtilSystem.readFile(FILE_PATH).toString(); } catch (JajukException e) { // if an exception occurs, ensure it is a "FileNotFound" assertNotNull("Should have an underlying cause when catching JajukException", e.getCause()); assertTrue("We only accept FileNotFoundException as valid exception in this test", e .getCause() instanceof FileNotFoundException); // set string to empty to not fail any of the tests in this case logs = ""; // also log a warning to indicate that this test did not do anything Log.warn("File " + FILE_PATH + " not found, cannot run checks on log file."); } } /** * Check for "Overflow" string. */ public void testOverflow() { assertFalse(logs.matches(".*Event overflow for.*")); } /** * Check for playtime rate issue. */ public void testPreferences() { assertFalse(logs.matches(".*Playtime rate > 1 for.*")); } /** * Check for play time outs. */ public void testPlayOOT() { assertFalse(logs.matches("OOT Mplayer process.*")); } /** * Check for EDT violations (this test is required but far not enough as most * of the time, we don't log this kind of errors). */ public void testOutEDT() { assertFalse(logs.matches("creation must be done on Event Dispatch Thread ")); } } jajuk-1.9.6.orig/src/test/java/org/jajuk/ThreadTestHelper.java0000644000175000017500000001266311720500104024120 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk; import java.util.LinkedList; import java.util.List; import junit.framework.Assert; import org.jajuk.util.log.Log; /** * Helper class to test with many threads. * * Sample usage is as follows: * * public void testMultipleThreads() throws Exception { ThreadTestHelper helper * = new ThreadTestHelper(NUMBER_OF_THREADS, NUMBER_OF_TESTS); * * helper.executeTest(new ThreadTestHelper.TestRunnable() { public void * doEnd(int threadnum) throws Exception { // do stuff at the end ... } * * public void run(int threadnum, int iter) { // do the actual threaded work ... * } }); } */ public class ThreadTestHelper { /** DOCUMENT_ME. */ private final int threadCount; /** DOCUMENT_ME. */ private final int testsPerThread; /** DOCUMENT_ME. */ private boolean failed = false; /** DOCUMENT_ME. */ private int executions[] = null; /** * Initialize the class with the number of tests that should be executed. * * @param threadCount The number of threads to start running in parallel. * @param testsPerThread The number of single test-executions that are done in each thread */ public ThreadTestHelper(int threadCount, int testsPerThread) { this.threadCount = threadCount; this.testsPerThread = testsPerThread; // Initialize array to allow to summarize afterwards executions = new int[threadCount]; } /** * Execute test. * DOCUMENT_ME * * @param run DOCUMENT_ME * @throws Exception the exception */ public void executeTest(TestRunnable run) throws Exception { Log.debug("Starting thread test"); List threads = new LinkedList(); // start all threads for (int i = 0; i < threadCount; i++) { Thread t = startThread(i, run); threads.add(t); } // wait for all threads for (int i = 0; i < threadCount; i++) { threads.get(i).join(); } // make sure the resulting number of executions is correct for (int i = 0; i < threadCount; i++) { // check if enough items were performed Assert.assertEquals("Thread " + i + " did not execute all iterations", testsPerThread, executions[i]); } // check that we did not fail in any thread, i.e. no exception occurred... Assert.assertFalse(failed); } /** * This method is executed to start one thread. The thread will execute the * provided runnable a number of times. * * @param threadnum * The number of this thread * @param run * The Runnable object that is used to perform the actual test * operation * * @return The thread that was started. * */ private Thread startThread(final int threadnum, final TestRunnable run) { Log.debug("Starting thread number: " + threadnum); Thread t1 = null; t1 = new Thread(new Runnable() { @Override public void run() { try { for (int iter = 0; iter < testsPerThread; iter++) { // Log.debug("Executing iteration " + iter + " in thread" + // Thread.currentThread().getName()); // call the actual testcode run.run(threadnum, iter); executions[threadnum]++; } // do end-work here, we don't do this in a finally as we log Exception // then anyway run.doEnd(threadnum); } catch (Throwable e) { Log.error(e); failed = true; } } }, "Thread " + threadnum); t1.start(); return t1; } /** * DOCUMENT_ME. */ public interface TestRunnable { /** * When an object implementing interface Runnable is used to * create a thread, starting the thread causes the object's run * method to be called in that separately executing thread. *

    * The general contract of the method run is that it may take * any action whatsoever. * * @param threadnum The number of the thread executing this run() * @param iter The count of how many times this thread executed the method * @throws Exception the exception * @see java.lang.Thread#run() */ public abstract void run(int threadnum, int iter) throws Exception; /** * Perform any action that should be done at the end. * * This method should throw an Exception if any check fails at this point. * * @param threadnum DOCUMENT_ME * @throws Exception the exception */ void doEnd(int threadnum) throws Exception; } /** * Test dummy. * DOCUMENT_ME */ public void testDummy() { // small empty test to not fail if this class is executed as test case by // Hudson/Sonar } } jajuk-1.9.6.orig/src/test/java/org/jajuk/JUnitHelpers.java0000644000175000017500000006347511720500104023274 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2009 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision: 3132 $ */ package org.jajuk; import java.io.File; import java.io.IOException; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import javax.swing.SwingUtilities; import junit.framework.Assert; import org.jajuk.base.Album; import org.jajuk.base.AlbumManager; import org.jajuk.base.Artist; import org.jajuk.base.ArtistManager; import org.jajuk.base.Device; import org.jajuk.base.DeviceManager; import org.jajuk.base.Directory; import org.jajuk.base.DirectoryManager; import org.jajuk.base.FileManager; import org.jajuk.base.Genre; import org.jajuk.base.GenreManager; import org.jajuk.base.Track; import org.jajuk.base.TrackManager; import org.jajuk.base.Type; import org.jajuk.base.TypeManager; import org.jajuk.base.Year; import org.jajuk.base.YearManager; import org.jajuk.events.JajukEvents; import org.jajuk.events.ObservationManager; import org.jajuk.services.bookmark.History; import org.jajuk.services.core.SessionService; import org.jajuk.services.players.IPlayerImpl; import org.jajuk.services.players.QueueModel; import org.jajuk.services.webradio.WebRadio; import org.jajuk.util.Const; import org.jajuk.util.log.Log; /** * Small helper class with functionality that is used in multiple unit tests */ public class JUnitHelpers { /** * Set a temporary session directory and make sure it exists and is writeable. * * @throws IOException * If the temporary directory can not be created or is not writeable */ public static void createSessionDirectory() throws IOException { // get a temporary file name File tempdir = File.createTempFile("test", ""); if (!tempdir.delete()) { throw new IOException("Could not create the temporary session directory at " + tempdir.getAbsolutePath() + ", could not remove the temporary file."); } // set the directory as base directory for the workspace SessionService.setWorkspace(tempdir.getAbsolutePath()); // read the session directory that we are using now for caching File sessiondir = SessionService.getConfFileByPath(Const.FILE_CACHE); // create the directory structure sessiondir.mkdirs(); // do some checks if (!sessiondir.exists()) { throw new IOException("Could not create the temporary session directory at " + sessiondir.getAbsolutePath()); } if (!sessiondir.isDirectory()) { throw new IOException("Could not create the temporary session directory at " + sessiondir.getAbsolutePath() + ", not a directory!"); } if (!sessiondir.canWrite()) { throw new IOException("Could not create the temporary session directory at " + sessiondir.getAbsolutePath() + ", not writeable!"); } // make sure the directory is removed at the end of the tests again sessiondir.getParentFile().deleteOnExit(); } /** * Helper method for removing emma-reports for classes with only static * methods *

    * see * http://sourceforge.net/tracker/index.php?func=detail&aid=1173251&group_id * =108932&atid=651900 * * add this to the test case for any class that has only static methods where * EMMA reports the default constructor as not covered * * Template: // helper method to emma-coverage of the unused constructor public void testPrivateConstructor() throws Exception { JUnitHelpers.executePrivateConstructor(.class); } * * * @param targetClass */ public static T executePrivateConstructor(final Class targetClass) throws Exception { final Constructor c = targetClass.getDeclaredConstructor(new Class[] {}); c.setAccessible(true); return c.newInstance((Object[]) null); } public static void EqualsTest(final Object obj, final Object equal, final Object notequal) { // none of the three should be null Assert.assertNotNull("Object in EqualsTest should not be null!", obj); Assert.assertNotNull("Equals-object in EqualsTest should not be null!", equal); Assert.assertNotNull("Non-equal-object in EqualsTest should not be null!", notequal); // make sure different objects are passed in Assert.assertFalse("Object and equals-object in EqualsTest should not be identical", obj == equal); Assert.assertFalse("Object and non-equals-object in EqualsTest should not be identical", obj == notequal); // make sure correct objects are passed Assert.assertTrue("Classes of objects in EqualsTest should be equal!", obj.getClass().equals( equal.getClass())); Assert.assertTrue("Classes of objects in EqualsTest should be equal!", obj.getClass().equals( notequal.getClass())); // make sure correct parameters are passed // equal should be equal to obj, not-equal should not be equal to obj! Assert.assertTrue("Object and equal-object should be equal in EqualsTest!", obj.equals(equal)); Assert.assertFalse("Object and non-equal-object should not be equal in EqualsTest!", obj .equals(notequal)); // first test some general things that should be true with equals // reflexive: equals to itself Assert .assertTrue("Reflexive: object should be equal to itself in EqualsTest!", obj.equals(obj)); Assert.assertTrue("Reflexive: equal-object should be equal to itself in EqualsTest!", equal .equals(equal)); Assert.assertTrue("Reflexive: non-equal-object should be equal to itself in EqualsTest!", notequal.equals(notequal)); // not equals to null Assert.assertFalse("Object should not be equal to null in EqualsTest!", obj.equals(null)); Assert.assertFalse("Equal-object should not be equal to null in EqualsTest!", equal .equals(null)); Assert.assertFalse("Non-equal-object should not be equal to null in EqualsTest!", notequal .equals(null)); // not equals to a different type of object Assert.assertFalse("Object should not be equal to an arbitrary string in EqualsTest!", obj .equals("TestString")); // then test some things with another object that should be equal // symmetric, if one is (not) equal to another then the reverse must be true Assert.assertTrue("Symmetric: Object should be equal to equal-object in EqualsTest", obj .equals(equal)); Assert.assertTrue("Symmetric: Equals-object should be equal to object in EqualsTest!", equal .equals(obj)); Assert.assertFalse("Symmetric: Object should NOT be equal to non-equal-object in EqualsTest", obj.equals(notequal)); Assert.assertFalse("Symmetric: Non-equals-object should NOT be equal to object in EqualsTest!", notequal.equals(obj)); // transitive: if a.equals(b) and b.equals(c) then a.equals(c) // not tested right now // hashCode: equal objects should have equal hash code Assert.assertTrue("Transitive: Equal objects should have equal hash-code in EqualsTest!", obj .hashCode() == equal.hashCode()); Assert.assertTrue("Transitive: Equal objects should have equal hash-code in EqualsTest!", obj .hashCode() == obj.hashCode()); Assert.assertTrue("Transitive: Equal objects should have equal hash-code in EqualsTest!", equal .hashCode() == equal.hashCode()); Assert.assertTrue("Transitive: Equal objects should have equal hash-code in EqualsTest!", notequal.hashCode() == notequal.hashCode()); } @SuppressWarnings("unchecked") public static void CompareToTest(final Comparable obj, final Comparable equal, final Comparable notequal) { // none of the three should be null Assert.assertNotNull("Object in CompareToTest should not be null!", obj); Assert.assertNotNull("Equals-object in CompareToTest should not be null!", equal); Assert.assertNotNull("Non-equal-object in CompareToTest should not be null!", notequal); // make sure different objects are passed in Assert.assertFalse("Object and equals-object in CompareToTest should not be identical", obj == equal); Assert.assertFalse("Object and non-equals-object in CompareToTest should not be identical", obj == notequal); // make sure correct parameters are passed // equal should be equal to obj, not-equal should not be equal to obj! Assert.assertEquals("Object and equal-object should compare in CompareToTest!", 0, obj .compareTo((T) equal)); Assert.assertFalse("Object and non-equal-object should not compare in CompareToTest!", 0 == obj .compareTo((T) notequal)); // first test some general things that should be true with equals // reflexive: equals to itself Assert.assertEquals("Reflexive: object should be equal to itself in CompareToTest!", 0, obj .compareTo((T) obj)); Assert.assertEquals("Reflexive: equal-object should be equal to itself in CompareToTest!", 0, equal.compareTo((T) equal)); Assert.assertEquals("Reflexive: non-equal-object should be equal to itself in CompareToTest!", 0, notequal.compareTo((T) notequal)); // not equals to null Assert.assertFalse("Object should not be equal to null in CompareToTest!", 0 == obj .compareTo(null)); Assert.assertFalse("Equal-object should not be equal to null in CompareToTest!", 0 == equal .compareTo(null)); Assert.assertFalse("Non-equal-object should not be equal to null in CompareToTest!", 0 == notequal.compareTo(null)); // not equals to a different type of object /* * Assert.assertFalse("Object should not be equal to an arbitrary string in CompareToTest!" , 0 * == obj.compareTo("TestString")); */ // then test some things with another object that should be equal // symmetric, if one is (not) equal to another then the reverse must be true Assert.assertEquals("Symmetric: Object should be equal to equal-object in CompareToTest", 0, obj.compareTo((T) equal)); Assert.assertEquals("Symmetric: Equals-object should be equal to object in CompareToTest!", 0, equal.compareTo((T) obj)); Assert.assertFalse( "Symmetric: Object should NOT be equal to non-equal-object in CompareToTest", 0 == obj .compareTo((T) notequal)); Assert.assertFalse( "Symmetric: Non-equals-object should NOT be equal to object in CompareToTest!", 0 == notequal.compareTo((T) obj)); // transitive: if a.equals(b) and b.equals(c) then a.equals(c) // not tested right now } /** * Run some general tests on the toString method. This static method is used * in tests for classes that overwrite toString(). * * @param obj * The object to test toString(). This should be an object of a type * that overwrites toString() * */ public static void ToStringTest(final Object obj) { // toString should not return null Assert.assertNotNull("A derived toString() should not return null!", obj.toString()); // toString should not return an empty string Assert.assertFalse("A derived toString() should not return an empty string!", obj.toString() .equals("")); // check that calling it multiple times leads to the same value String value = obj.toString(); for (int i = 0; i < 10; i++) { Assert.assertEquals( "toString() is expected to result in the same result across repeated calls!", value, obj .toString()); } } /** * Run some generic tests on the derived clone-method. * * We need to do this via reflection as the clone()-method in Object is * protected and the Cloneable interface does not include a public "clone()". * * @param obj * The object to test clone for. */ public static void CloneTest(final Cloneable obj) throws Exception { final Method m = obj.getClass().getMethod("clone", new Class[] {}); Assert.assertNotNull("Need to find a method called 'clone' in object of type '" + obj.getClass().getName() + "' in CloneTest!", m); // Assert.assertTrue("Method 'clone' on object of type '" + // obj.getClass().getName() + "' needs to be accessible in // CloneTest!", // m.isAccessible()); // clone should return a different object, not the same again Assert.assertTrue("clone() should not return the object itself in CloneTest!", obj != m.invoke( obj, new Object[] {})); // should return the same type of object Assert.assertTrue( "clone() should return the same type of object (i.e. the same class) in CloneTest!", m .invoke(obj, new Object[] {}).getClass() == obj.getClass()); // cloned objects should be equal to the original object Assert.assertTrue( "clone() should return an object that is equal() to the original object in CloneTest!", m .invoke(obj, new Object[] {}).equals(obj)); } /** * Checks certain assumption that are made for the hashCode() method * * @param obj * An Object that override the hasCode() method. * * @throws Exception */ public static void HashCodeTest(final Object obj, final Object equ) { Assert .assertFalse( "HashCodeTest expects two distinct objects with equal hashCode, but the same object is provided twice!", obj == equ); // The same object returns the same hashCode always final int hash = obj.hashCode(); Assert.assertEquals("hashCode() on object returned different hash after some iterations!", hash, obj.hashCode()); Assert.assertEquals("hashCode() on object returned different hash after some iterations!", hash, obj.hashCode()); Assert.assertEquals("hashCode() on object returned different hash after some iterations!", hash, obj.hashCode()); Assert.assertEquals("hashCode() on object returned different hash after some iterations!", hash, obj.hashCode()); Assert.assertEquals("hashCode() on object returned different hash after some iterations!", hash, obj.hashCode()); // equal objects must have the same hashCode // the other way around is not required, // different objects can have the same hashCode!! Assert .assertEquals( "Equal Assert failed, but input to HashCodeTest should be two equal objects! Check if the class implements equals() as well to fullfill this contract", obj, equ); Assert.assertEquals("Equal objects should have equal hashCode() by Java contract!", obj .hashCode(), equ.hashCode()); } @SuppressWarnings( { "unchecked", "rawtypes" }) public static void EnumTest(Enum enumtype, Class enumclass, String element) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { // check valueOf() Assert.assertEquals(enumtype, Enum.valueOf(enumclass, element)); // check values() Method m = enumclass.getMethod("values", (Class[]) null); Object obj = m.invoke(enumtype, (Object[]) null); Assert.assertNotNull(obj); Assert.assertTrue(obj instanceof Object[]); // check existing valeOf() obj = Enum.valueOf(enumclass, element); Assert.assertNotNull(obj); Assert.assertTrue(obj instanceof Enum); // check non-existing valueOf try { Enum.valueOf(enumclass, "nonexistingenumelement"); Assert .fail("Should catch exception IllegalArgumentException when calling Enum.valueOf() with incorrect enum-value!"); } catch (IllegalArgumentException e) { Assert.assertTrue(e.getMessage(), e.getMessage().contains("No enum const class")); } } public static void clearSwingUtilitiesQueue() throws InterruptedException, InvocationTargetException { // we try to wait for all items that were sent via // "SwingUtilities.invokeLater()" in order // to have a deterministic state in the tests where we know that the // asynchronous action // done in any "invokeLater()" was actually finished SwingUtilities.invokeAndWait(new Runnable() { @Override public void run() { // nothing to do here, we just want the runnable to run... } }); // Thread.currentThread(). } public static void waitForThreadToFinish(final String name) throws InterruptedException { int count = Thread.currentThread().getThreadGroup().activeCount(); Thread[] threads = new Thread[count]; /* int received = */Thread.currentThread().getThreadGroup().enumerate(threads); /* * we ignore this check as we can not do anything anyway if we receive not all threads if(count * != received) { throw new IllegalStateException("Could not read all threads: Expected: " + * count + " Found: " + received); } */ for (Thread t : threads) { if (t != null && name.equals(t.getName())) { t.join(); } } } public static void waitForAllWorkToFinishAndCleanup() throws InterruptedException, InvocationTargetException { ObservationManager.clear(); QueueModel.stopRequest(); QueueModel.clear(); FileManager.getInstance().clear(); DirectoryManager.getInstance().clear(); DeviceManager.getInstance().cleanAllDevices(); History.getInstance().clear(); // wait a bit to let deferred actions take place before we shut down JUnitHelpers.waitForThreadToFinish("Cover Refresh Thread"); JUnitHelpers.waitForThreadToFinish("Queue Push Thread"); JUnitHelpers.waitForThreadToFinish("Device Refresh Thread"); JUnitHelpers.waitForThreadToFinish("Playlist Prepare Party Thread"); JUnitHelpers.waitForThreadToFinish("LastFM Update Thread"); JUnitHelpers.waitForThreadToFinish("Parameter Catalog refresh Thread"); JUnitHelpers.waitForThreadToFinish("Manual Refresh Thread"); // clear this for all available events // for(JajukEvents event : JajukEvents.values()) { // JUnitHelpers.waitForThreadToFinish("Event Executor for: " + // event.toString()); // } JUnitHelpers.waitForThreadToFinish("Event Executor for: " + JajukEvents.ALARMS_CHANGE.toString()); JUnitHelpers.waitForThreadToFinish("Event Executor for: " + JajukEvents.ALBUM_CHANGED.toString()); JUnitHelpers.waitForThreadToFinish("Event Executor for: " + JajukEvents.BANNED.toString()); JUnitHelpers.waitForThreadToFinish("Event Executor for: " + JajukEvents.CDDB_WIZARD.toString()); JUnitHelpers.waitForThreadToFinish("Event Executor for: " + JajukEvents.CLEAR_HISTORY.toString()); JUnitHelpers.waitForThreadToFinish("Event Executor for: " + JajukEvents.COVER_NEED_REFRESH.toString()); JUnitHelpers.waitForThreadToFinish("Event Executor for: " + JajukEvents.DEVICE_REFRESH.toString()); JUnitHelpers.waitForThreadToFinish("Event Executor for: " + JajukEvents.FILE_FINISHED.toString()); JUnitHelpers.waitForThreadToFinish("Event Executor for: " + JajukEvents.FILE_LAUNCHED.toString()); JUnitHelpers.waitForThreadToFinish("Event Executor for: " + JajukEvents.FILE_NAME_CHANGED.toString()); JUnitHelpers.waitForThreadToFinish("Event Executor for: " + JajukEvents.LANGUAGE_CHANGED.toString()); JUnitHelpers.waitForThreadToFinish("Event Executor for: " + JajukEvents.MUTE_STATE.toString()); JUnitHelpers .waitForThreadToFinish("Event Executor for: " + JajukEvents.PLAYER_PAUSE.toString()); JUnitHelpers.waitForThreadToFinish("Event Executor for: " + JajukEvents.PLAYER_PLAY.toString()); JUnitHelpers.waitForThreadToFinish("Event Executor for: " + JajukEvents.PLAYER_RESUME.toString()); JUnitHelpers.waitForThreadToFinish("Event Executor for: " + JajukEvents.PLAYER_STOP.toString()); JUnitHelpers.waitForThreadToFinish("Event Executor for: " + JajukEvents.PLAY_ERROR.toString()); JUnitHelpers .waitForThreadToFinish("Event Executor for: " + JajukEvents.PLAY_OPENING.toString()); JUnitHelpers.waitForThreadToFinish("Event Executor for: " + JajukEvents.PREFERENCES_RESET.toString()); JUnitHelpers.waitForThreadToFinish("Event Executor for: " + JajukEvents.RATE_RESET.toString()); JUnitHelpers.waitForThreadToFinish("Event Executor for: " + JajukEvents.GENRE_NAME_CHANGED.toString()); JUnitHelpers.waitForThreadToFinish("Event Executor for: " + JajukEvents.VOLUME_CHANGED.toString()); JUnitHelpers.waitForThreadToFinish("Event Executor for: " + JajukEvents.WEBRADIO_LAUNCHED.toString()); JUnitHelpers.waitForThreadToFinish("Event Executor for: " + JajukEvents.ZERO.toString()); JUnitHelpers.clearSwingUtilitiesQueue(); } /** * Return a file named "test.tst" on a mounted device. * @return a file named "test.tst" on a mounted device. */ public static org.jajuk.base.File getFile() { return getFile("test.tst", true); } public static org.jajuk.base.File getFile(String name, boolean mount) { Genre genre = getGenre(); Album album = getAlbum("name", 0); album.setProperty(Const.XML_ALBUM_DISCOVERED_COVER, Const.COVER_NONE); // don't read covers for // this test Artist artist = getArtist("myartist"); Year year = getYear(2000); Type type = getType(); Track track = TrackManager.getInstance().registerTrack(name, album, genre, artist, 120, year, 1, type, 1); Device device = getDevice(); if (mount & !device.isMounted()) { try { device.mount(true); } catch (Exception e) { throw new RuntimeException(e); } } Directory dir = JUnitHelpers.getDirectory(); return FileManager.getInstance().registerFile(name, dir, track, 120, 70); } public static Album getAlbum(String name, int discID) { return AlbumManager.getInstance().registerAlbum(name, discID); } public static Album getAlbum() { return getAlbum("name", 0); } public static Artist getArtist(String name) { return ArtistManager.getInstance().registerArtist(name); } public static Artist getArtist() { return getArtist("name"); } public static Genre getGenre(String name) { return GenreManager.getInstance().registerGenre(name); } public static Genre getGenre() { return getGenre("name"); } public static Year getYear(int year) { return YearManager.getInstance().registerYear("" + year); } public static Year getYear() { return getYear(2000); } public static Device getDevice(String name, long type, String url) { return DeviceManager.getInstance().registerDevice(name, type, url); } public static Device getDevice() { Device device = getDevice("name", Device.TYPE_DIRECTORY, ConstTest.PATH_DEVICE); // Create the jajuk test device if required new File(device.getUrl()).mkdirs(); // Create at least a void file in the device try { new File(device.getUrl() + "/audio1.mp3").createNewFile(); } catch (IOException e) { Log.error(e); } return device; } public static Directory getDirectory(String name, Directory parent, Device device) { return DirectoryManager.getInstance().registerDirectory(name, parent, device); } /** The "any" directory is the top dir of the device pointing toward $java.io.tmpdir*/ public static Directory getDirectory() { Device device = getDevice(); Directory topdir = getTopDirectory(); return DirectoryManager.getInstance().registerDirectory("dir", topdir, device); } /** A topdir directory */ public static Directory getTopDirectory() { return DirectoryManager.getInstance().registerDirectory(getDevice()); } @SuppressWarnings("unchecked") public static Type getType() { IPlayerImpl imp = new MockPlayer(); Class cl = (Class) imp.getClass(); return TypeManager.getInstance().registerType("type", "mp3", cl, null); } // needs to be public to be callable from the outside... public static class MockPlayer implements IPlayerImpl { @Override public void stop() throws Exception { } @Override public void setVolume(float fVolume) throws Exception { } @Override public void seek(float fPosition) { } @Override public void resume() throws Exception { } @Override public void play(WebRadio radio, float fVolume) throws Exception { } @Override public void play(org.jajuk.base.File file, float fPosition, long length, float fVolume) throws Exception { } @Override public void pause() throws Exception { } @Override public int getState() { return 0; } @Override public long getElapsedTimeMillis() { return 0; } @Override public float getCurrentVolume() { return 0; } @Override public float getCurrentPosition() { return 0; } @Override public long getDurationSec() { return 0; } /* (non-Javadoc) * @see org.jajuk.services.players.IPlayerImpl#getActuallyPlayedTimeMillis() */ @Override public long getActuallyPlayedTimeMillis() { // TODO Auto-generated method stub return 0; } } public static Track getTrack(int i) { Genre genre = getGenre(); Album album = getAlbum("myalbum", 0); album.setProperty(Const.XML_ALBUM_DISCOVERED_COVER, Const.COVER_NONE); // don't read covers for // this test Artist artist = getArtist("myartist_" + i); Year year = getYear(2000); Type type = getType(); return TrackManager.getInstance().registerTrack("track_" + i, album, genre, artist, 120, year, 1, type, 1); } } jajuk-1.9.6.orig/src/test/java/org/jajuk/ui/0000755000175000017500000000000011720500104020453 5ustar drazzibdrazzibjajuk-1.9.6.orig/src/test/java/org/jajuk/ui/helpers/0000755000175000017500000000000011720500104022115 5ustar drazzibdrazzibjajuk-1.9.6.orig/src/test/java/org/jajuk/ui/helpers/TestPlayerStateMediator.java0000644000175000017500000002105011720500104027540 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.helpers; import java.util.List; import java.util.Properties; import java.util.Set; import org.jajuk.JUnitHelpers; import org.jajuk.JajukTestCase; import org.jajuk.base.Album; import org.jajuk.base.Artist; import org.jajuk.base.Device; import org.jajuk.base.Directory; import org.jajuk.base.DirectoryManager; import org.jajuk.base.File; import org.jajuk.base.FileManager; import org.jajuk.base.Genre; import org.jajuk.base.Track; import org.jajuk.base.TrackManager; import org.jajuk.base.Type; import org.jajuk.base.Year; import org.jajuk.events.JajukEvent; import org.jajuk.events.JajukEvents; import org.jajuk.services.notification.NotificatorTypes; import org.jajuk.services.players.Player; import org.jajuk.services.players.QueueModel; import org.jajuk.services.players.StackItem; import org.jajuk.services.webradio.WebRadio; import org.jajuk.ui.actions.ActionManager; import org.jajuk.util.Conf; import org.jajuk.util.Const; /** * DOCUMENT_ME. */ public class TestPlayerStateMediator extends JajukTestCase { /* (non-Javadoc) * @see org.jajuk.JajukTestCase#setUp() */ @Override protected void setUp() throws Exception { // to install actions... ActionManager.getInstance(); super.setUp(); } /** * Test method for. * * {@link org.jajuk.ui.helpers.PlayerStateMediator#getInstance()}. */ public final void testGetInstance() { PlayerStateMediator med = PlayerStateMediator.getInstance(); assertNotNull(med); // once again to cover other if-branch med = PlayerStateMediator.getInstance(); assertNotNull(med); } /** * Test method for. * * {@link org.jajuk.ui.helpers.PlayerStateMediator#getRegistrationKeys()}. */ public final void testGetRegistrationKeys() { PlayerStateMediator med = PlayerStateMediator.getInstance(); Set set = med.getRegistrationKeys(); assertTrue(set.toString(), set.contains(JajukEvents.PLAYER_PLAY)); assertTrue(set.toString(), set.contains(JajukEvents.VOLUME_CHANGED)); assertTrue(set.toString(), set.contains(JajukEvents.MUTE_STATE)); } /** * Test method for. * * @throws Exception the exception * {@link org.jajuk.ui.helpers.PlayerStateMediator#update(org.jajuk.events.JajukEvent)} * . */ public final void testUpdatePlay() throws Exception { PlayerStateMediator med = PlayerStateMediator.getInstance(); med.update(new JajukEvent(JajukEvents.PLAYER_PLAY, null)); } /** * Test update stop. * DOCUMENT_ME */ public final void testUpdateStop() { PlayerStateMediator med = PlayerStateMediator.getInstance(); med.update(new JajukEvent(JajukEvents.PLAYER_STOP, null)); } /** * Test update stop queue model. * DOCUMENT_ME * * @throws Exception the exception */ public final void testUpdateStopQueueModel() throws Exception { PlayerStateMediator med = PlayerStateMediator.getInstance(); // test with queue size > 0 Device device = JUnitHelpers.getDevice(); // no files without a directory List files = device.getFilesRecursively(); assertEquals(0, files.size()); // no file available Directory dir = DirectoryManager.getInstance().registerDirectory(device); File file = getFile(9, dir); QueueModel.insert(new StackItem(file), 0); assertTrue(QueueModel.getQueue().toString(), QueueModel.getQueue().size() > 0); // run the method med.update(new JajukEvent(JajukEvents.PLAYER_STOP, null)); } /** * Gets the file. * * @param i DOCUMENT_ME * @param dir DOCUMENT_ME * @return the file */ private File getFile(int i, Directory dir) { Genre genre = JUnitHelpers.getGenre(); Album album = JUnitHelpers.getAlbum("name", 0); album.setProperty(Const.XML_ALBUM_DISCOVERED_COVER, Const.COVER_NONE); // don't read covers for // this test Artist artist = JUnitHelpers.getArtist("name"); Year year = JUnitHelpers.getYear(2000); Type type = JUnitHelpers.getType(); Track track = TrackManager.getInstance().registerTrack("name", album, genre, artist, 120, year, 1, type, 1); return FileManager.getInstance().registerFile(Integer.valueOf(i).toString(), "test.tst", dir, track, 120, 70); } /** * Test update paused. * DOCUMENT_ME */ public final void testUpdatePaused() { PlayerStateMediator med = PlayerStateMediator.getInstance(); med.update(new JajukEvent(JajukEvents.PLAYER_PAUSE, null)); } /** * Test update resume. * DOCUMENT_ME */ public final void testUpdateResume() { PlayerStateMediator med = PlayerStateMediator.getInstance(); med.update(new JajukEvent(JajukEvents.PLAYER_RESUME, null)); } /** * Test update opening error. * DOCUMENT_ME */ public final void testUpdateOpeningError() { PlayerStateMediator med = PlayerStateMediator.getInstance(); med.update(new JajukEvent(JajukEvents.PLAY_OPENING, null)); } /** * Test update zero. * DOCUMENT_ME */ public final void testUpdateZero() { PlayerStateMediator med = PlayerStateMediator.getInstance(); med.update(new JajukEvent(JajukEvents.ZERO, null)); } /** * Test update webradio. * DOCUMENT_ME */ public final void testUpdateWebradio() { PlayerStateMediator med = PlayerStateMediator.getInstance(); med.update(new JajukEvent(JajukEvents.WEBRADIO_LAUNCHED, null)); } /** * Test update webradio notifcator. * DOCUMENT_ME */ public final void testUpdateWebradioNotifcator() { // enable Tooltip/Notification Conf.setProperty(Const.CONF_UI_NOTIFICATOR_TYPE, NotificatorTypes.TOAST.name()); Properties prop = new Properties(); prop.put(Const.DETAIL_CONTENT, new WebRadio("test", "testurl")); PlayerStateMediator med = PlayerStateMediator.getInstance(); med.update(new JajukEvent(JajukEvents.WEBRADIO_LAUNCHED, prop)); } /** * Test update file launched. * DOCUMENT_ME * * @throws Exception the exception */ public final void testUpdateFileLaunched() throws Exception { // enable Tooltip/Notification Conf.setProperty(Const.CONF_UI_NOTIFICATOR_TYPE, NotificatorTypes.TOAST.name()); Device device = JUnitHelpers.getDevice(); device.setUrl(System.getProperty("java.io.tmpdir")); Directory dir = DirectoryManager.getInstance().registerDirectory(device); File file = getFile(3, dir); Properties prop = new Properties(); prop.put(Const.DETAIL_CURRENT_FILE_ID, file.getID()); PlayerStateMediator med = PlayerStateMediator.getInstance(); med.update(new JajukEvent(JajukEvents.FILE_LAUNCHED, prop)); JUnitHelpers.clearSwingUtilitiesQueue(); } /** * Test update file launched null. * DOCUMENT_ME */ public final void testUpdateFileLaunchedNull() { // enable Tooltip/Notification Conf.setProperty(Const.CONF_UI_NOTIFICATOR_TYPE, NotificatorTypes.TOAST.name()); // just provide empty properties Properties prop = new Properties(); PlayerStateMediator med = PlayerStateMediator.getInstance(); med.update(new JajukEvent(JajukEvents.FILE_LAUNCHED, prop)); } /** * Test update volume. * DOCUMENT_ME */ public final void testUpdateVolume() { PlayerStateMediator med = PlayerStateMediator.getInstance(); med.update(new JajukEvent(JajukEvents.VOLUME_CHANGED, null)); } /** * Test update mute. * DOCUMENT_ME * * @throws Exception the exception */ public final void testUpdateMute() throws Exception { PlayerStateMediator med = PlayerStateMediator.getInstance(); med.update(new JajukEvent(JajukEvents.MUTE_STATE, null)); JUnitHelpers.clearSwingUtilitiesQueue(); // test with muted player Player.mute(); med.update(new JajukEvent(JajukEvents.MUTE_STATE, null)); JUnitHelpers.clearSwingUtilitiesQueue(); Player.mute(false); med.update(new JajukEvent(JajukEvents.MUTE_STATE, null)); } } jajuk-1.9.6.orig/src/test/java/org/jajuk/ui/helpers/TestDuration.java0000644000175000017500000000476311720500104025417 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.helpers; import static org.junit.Assert.assertEquals; import org.jajuk.JUnitHelpers; import org.junit.Test; /** * DOCUMENT_ME. */ public class TestDuration { /** * Test method for {@link org.jajuk.ui.helpers.Duration#hashCode()}. */ @Test public void testHashCode() { Duration dur = new Duration(123); Duration equ = new Duration(123); JUnitHelpers.HashCodeTest(dur, equ); } /** * Test method for {@link org.jajuk.ui.helpers.Duration#Duration(long)}. */ @Test public void testDuration() { new Duration(23); } /** * Test method for {@link org.jajuk.ui.helpers.Duration#toString()}. */ @Test public void testToString() { JUnitHelpers.ToStringTest(new Duration(993)); } /** * Test method for. * * {@link org.jajuk.ui.helpers.Duration#equals(java.lang.Object)}. */ @Test public void testEqualsObject() { Duration dur = new Duration(234); Duration equal = new Duration(234); Duration notequal = new Duration(233); JUnitHelpers.EqualsTest(dur, equal, notequal); } /** * Test method for. * * {@link org.jajuk.ui.helpers.Duration#compareTo(org.jajuk.ui.helpers.Duration)} * . */ @Test public void testCompareTo() { Duration dur = new Duration(234); Duration equal = new Duration(234); Duration notequal = new Duration(233); JUnitHelpers.CompareToTest(dur, equal, notequal); } /** * Test method for {@link org.jajuk.ui.helpers.Duration#getDuration()}. */ @Test public void testGetDuration() { Duration dur = new Duration(234); Duration dur2 = new Duration(233); assertEquals(234, dur.getDuration()); assertEquals(233, dur2.getDuration()); } } jajuk-1.9.6.orig/src/test/java/org/jajuk/ui/wizard/0000755000175000017500000000000011720500104021753 5ustar drazzibdrazzibjajuk-1.9.6.orig/src/test/java/org/jajuk/ui/wizard/TestDigitalDJWizard.java0000644000175000017500000001677311720500104026450 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.wizard; import java.awt.HeadlessException; import org.jajuk.JajukTestCase; import org.jajuk.services.dj.AmbienceManager; import org.jajuk.services.dj.DigitalDJ; import org.jajuk.services.dj.DigitalDJManager; import org.jajuk.services.dj.TransitionDigitalDJ; import org.qdwizard.Screen; /** * DOCUMENT_ME. */ public class TestDigitalDJWizard extends JajukTestCase { /** * Test method for. * * @throws Exception the exception * {@link org.jajuk.ui.wizard.DigitalDJWizard#getPreviousScreen(java.lang.Class)} * . */ public void testGetPreviousScreenClassOfQextendsScreen() throws Exception { try { DigitalDJWizard wizard = new DigitalDJWizard(); assertNull(wizard.getPreviousScreen(null)); assertNotNull(wizard.getNextScreen(null)); // do some dummy things with this panel... Screen screen = wizard.getNextScreen(null).newInstance(); screen.initUI(); assertNotNull(screen.getDescription()); assertNotNull(screen.getName()); assertNull(wizard.getPreviousScreen(null)); // always null until // "actionPerformed" } catch (HeadlessException e) { // on some servers we cannot initalize any ui and thus cannot test this } } /** * Test method for. * * @throws Exception the exception * {@link org.jajuk.ui.wizard.DigitalDJWizard#getNextScreen(java.lang.Class)}. */ public void testGetNextScreenClassOfQextendsScreen() throws Exception { try { DigitalDJWizard wizard = new DigitalDJWizard(); assertNotNull(wizard.getNextScreen(null)); // do some dummy things with this panel... Screen screen = wizard.getNextScreen(null).newInstance(); screen.initUI(); } catch (HeadlessException e) { // on some servers we cannot initalize any ui and thus cannot test this } } /** * Test method for. * * {@link org.jajuk.ui.wizard.DigitalDJWizard#DigitalDJWizard()}. */ public void testDigitalDJWizard() { try { new DigitalDJWizard(); } catch (HeadlessException e) { // on some servers we cannot initalize any ui and thus cannot test this } } /** * Test panels action selection. * DOCUMENT_ME */ public void testPanelsActionSelection() { try { // to initialize static data..., // TODO: this looks a bit weird in the code of Wizard and Screen, why is // it needed? new DigitalDJWizard(); coverScreen(new DigitalDJWizard.ActionSelectionPanel()); } catch (HeadlessException e) { // on some servers we cannot initalize any ui and thus cannot test this } } /** * Test panels ambience. * DOCUMENT_ME */ public void testPanelsAmbience() { try { // to initialize static data..., // TODO: this looks a bit weird in the code of Wizard and Screen, why is // it needed? new DigitalDJWizard(); // we need to load ambiences before this will work AmbienceManager.getInstance().load(); coverScreen(new DigitalDJWizard.AmbiencePanel()); } catch (HeadlessException e) { // on some servers we cannot initalize any ui and thus cannot test this } } /** * Test panels change. * DOCUMENT_ME */ public void testPanelsChange() { try { // to initialize static data..., // TODO: this looks a bit weird in the code of Wizard and Screen, why is // it needed? new DigitalDJWizard(); coverScreen(new DigitalDJWizard.ChangePanel()); // also cover the case when a digital dj is registered DigitalDJ dj = new TransitionDigitalDJ("1"); DigitalDJManager.getInstance().register(dj); coverScreen(new DigitalDJWizard.ChangePanel()); } catch (HeadlessException e) { // on some servers we cannot initalize any ui and thus cannot test this } } /** * Test panels general option. * DOCUMENT_ME */ public void testPanelsGeneralOption() { try { // to initialize static data..., // TODO: this looks a bit weird in the code of Wizard and Screen, why is // it needed? new DigitalDJWizard(); coverScreen(new DigitalDJWizard.GeneralOptionsPanel()); } catch (HeadlessException e) { // on some servers we cannot initalize any ui and thus cannot test this } } /** * Test panels proportions. * DOCUMENT_ME */ public void testPanelsProportions() { try { // to initialize static data..., // TODO: this looks a bit weird in the code of Wizard and Screen, why is // it needed? new DigitalDJWizard(); coverScreen(new DigitalDJWizard.ProportionsPanel()); } catch (HeadlessException e) { // on some servers we cannot initalize any ui and thus cannot test this } } /** * Test panels remove. * DOCUMENT_ME */ public void testPanelsRemove() { try { // to initialize static data..., // TODO: this looks a bit weird in the code of Wizard and Screen, why is // it needed? new DigitalDJWizard(); DigitalDJ dj = new TransitionDigitalDJ("1"); DigitalDJManager.getInstance().register(dj); coverScreen(new DigitalDJWizard.RemovePanel()); } catch (HeadlessException e) { // on some servers we cannot initalize any ui and thus cannot test this } } /** * Test panels transition. * DOCUMENT_ME */ public void testPanelsTransition() { try { // to initialize static data..., // TODO: this looks a bit weird in the code of Wizard and Screen, why is // it needed? new DigitalDJWizard(); coverScreen(new DigitalDJWizard.TransitionsPanel()); } catch (HeadlessException e) { // on some servers we cannot initalize any ui and thus cannot test this } } /** * Test panels type selection. * DOCUMENT_ME */ public void testPanelsTypeSelection() { try { // to initialize static data..., // TODO: this looks a bit weird in the code of Wizard and Screen, why is // it needed? new DigitalDJWizard(); coverScreen(new DigitalDJWizard.TypeSelectionPanel()); } catch (HeadlessException e) { // on some servers we cannot initalize any ui and thus cannot test this } } /** * Cover screen. * DOCUMENT_ME * * @param screen DOCUMENT_ME */ private void coverScreen(Screen screen) { screen.initUI(); assertNotNull(screen.getDescription()); assertNotNull(screen.getName()); // JUnitHelpers.ToStringTest(screen); } /** * Test method for {@link org.jajuk.ui.wizard.DigitalDJWizard#finish()}. */ public void testFinish() { // TODO: find out how to test this... /* * coverScreen(new DigitalDJWizard.TypeSelectionPanel()); * * DigitalDJWizard wizard = new DigitalDJWizard(); wizard.finish(); */ } } jajuk-1.9.6.orig/src/test/java/org/jajuk/ui/actions/0000755000175000017500000000000011720500104022113 5ustar drazzibdrazzibjajuk-1.9.6.orig/src/test/java/org/jajuk/ui/actions/TestPreparePartyAction.java0000644000175000017500000001155011720500104027374 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.actions; import java.awt.HeadlessException; import java.awt.event.ActionEvent; import java.util.ArrayList; import java.util.List; import javax.swing.JButton; import org.apache.commons.io.FileUtils; import org.jajuk.JUnitHelpers; import org.jajuk.JajukTestCase; import org.jajuk.base.Album; import org.jajuk.base.Artist; import org.jajuk.base.Device; import org.jajuk.base.Directory; import org.jajuk.base.DirectoryManager; import org.jajuk.base.File; import org.jajuk.base.FileManager; import org.jajuk.base.Genre; import org.jajuk.base.Playlist; import org.jajuk.base.PlaylistManager; import org.jajuk.base.Track; import org.jajuk.base.TrackManager; import org.jajuk.base.Type; import org.jajuk.base.Year; import org.jajuk.util.Const; import org.jajuk.util.log.Log; /** * DOCUMENT_ME. */ public class TestPreparePartyAction extends JajukTestCase { /** * Test method for. * * {@link org.jajuk.ui.actions.PreparePartyAction#perform(java.awt.event.ActionEvent)} * . */ public void testPerform() { new PreparePartyAction(); } /** * Test method for. * * @throws Exception the exception * {@link org.jajuk.ui.actions.PreparePartyAction#PreparePartyAction()}. */ public void testPreparePartyAction() throws Exception { PreparePartyAction action = new PreparePartyAction(); // once with empty properties, this is called from the menu try { action.perform(new ActionEvent(new JButton(), 1, null)); } catch (HeadlessException e) { // happens when tests are run on servers without ui } // then with a single and with a list of playlists, this is called from the // PlaylistView JButton button = new JButton(); button.putClientProperty(Const.DETAIL_SELECTION, getPlaylist(10, false)); try { action.perform(new ActionEvent(button, 1, null)); // once with empty // properties } catch (HeadlessException e) { // happens when tests are run on servers without ui } List list = new ArrayList(); list.add(getPlaylist(11, false)); button.putClientProperty(Const.DETAIL_SELECTION, list); try { action.perform(new ActionEvent(button, 1, null)); // once with empty // properties } catch (HeadlessException e) { // happens when tests are run on servers without ui } } /** * Gets the playlist. * * @param i DOCUMENT_ME * @param register DOCUMENT_ME * @return the playlist * @throws Exception the exception */ private static Playlist getPlaylist(int i, boolean register) throws Exception { Genre genre = JUnitHelpers.getGenre(); Album album = JUnitHelpers.getAlbum("name", 23); album.setProperty(Const.XML_ALBUM_DISCOVERED_COVER, Const.COVER_NONE); // don't read covers for // this test Artist artist = JUnitHelpers.getArtist("name"); Year year = JUnitHelpers.getYear(2000); Type type = JUnitHelpers.getType(); Track track = TrackManager.getInstance().registerTrack("name", album, genre, artist, 120, year, 1, type, 1); Device device = JUnitHelpers.getDevice(); if (!device.isMounted()) { device.mount(true); } Directory dir = DirectoryManager.getInstance().registerDirectory(device); Log.debug("Dir: " + dir.getFio()); dir.getFio().mkdirs(); java.io.File f = java.io.File.createTempFile("jajukFile", ".mp3", dir.getFio()); File file = FileManager.getInstance().registerFile(Integer.valueOf(i).toString(), f.getName(), dir, track, 120, 70); final Playlist list; if (register) { list = PlaylistManager.getInstance().registerPlaylistFile( "test-" + Integer.valueOf(i).toString(), "My Playlist-" + Integer.valueOf(i).toString(), dir); } else { list = new Playlist(Integer.valueOf(i).toString(), "New list", dir); } // write the playlist so we can add files to it if (!list.getFIO().exists()) { // just create an empty file, # is a comment here FileUtils.writeStringToFile(list.getFIO(), "#"); } // add a file to the playlist list.addFile(file); return list; } } jajuk-1.9.6.orig/src/test/java/org/jajuk/ui/actions/TestDebugLogAction.java0000644000175000017500000000321411720500104026444 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.actions; import java.awt.HeadlessException; import org.jajuk.JajukTestCase; import org.jajuk.util.log.Log; /** * DOCUMENT_ME. */ public class TestDebugLogAction extends JajukTestCase { /** * Test method for. * * {@link org.jajuk.ui.actions.DebugLogAction#perform(java.awt.event.ActionEvent)} * . */ public void testPerform() { // initialize Log Log.init(); DebugLogAction action = new DebugLogAction(); try { action.perform(null); // it doesn't look at the actionevent at all right // now... } catch (HeadlessException e) { // thrown on Hudson/Sonar as they do not support tests that require UI } } /** * Test method for. * * {@link org.jajuk.ui.actions.DebugLogAction#DebugLogAction()}. */ public void testDebugLogAction() { new DebugLogAction(); } } jajuk-1.9.6.orig/src/test/java/org/jajuk/ui/actions/TestFindDuplicateTracksAction.java0000644000175000017500000002005411720500104030640 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.actions; import java.util.List; import org.jajuk.JUnitHelpers; import org.jajuk.JajukTestCase; import org.jajuk.base.Album; import org.jajuk.base.AlbumArtist; import org.jajuk.base.AlbumArtistManager; import org.jajuk.base.Artist; import org.jajuk.base.Directory; import org.jajuk.base.File; import org.jajuk.base.FileManager; import org.jajuk.base.Genre; import org.jajuk.base.Track; import org.jajuk.base.TrackManager; import org.jajuk.base.Type; import org.jajuk.util.Const; /** * Test find dups action. */ public class TestFindDuplicateTracksAction extends JajukTestCase { /** DOCUMENT_ME. */ Type type; /** DOCUMENT_ME. */ Artist artist; /** DOCUMENT_ME. */ Album album; /** DOCUMENT_ME. */ Genre genre; /** DOCUMENT_ME. */ org.jajuk.base.Year year; /** DOCUMENT_ME. */ FindDuplicateTracksAction action; /** DOCUMENT_ME. */ Directory dir; /** DOCUMENT_ME. */ AlbumArtist albumArtist; /* (non-Javadoc) * @see org.jajuk.JajukTestCase#setUp() */ @Override public void setUp() throws Exception { super.setUp(); // Populate tracks and files dir = JUnitHelpers.getDirectory(); dir.getDevice().mount(false); type = JUnitHelpers.getType(); artist = JUnitHelpers.getArtist(); album = JUnitHelpers.getAlbum(); genre = JUnitHelpers.getGenre(); year = JUnitHelpers.getYear(); action = new FindDuplicateTracksAction(); albumArtist = AlbumArtistManager.getInstance().registerAlbumArtist(Const.UNKNOWN_ARTIST); } /** * Test method for. * * {@link org.jajuk.ui.actions.FindDuplicateTracksAction#perform(java.awt.event.ActionEvent)} * . * Test 1 : none dups */ public void testPopulateDups1() { Track track11 = TrackManager.getInstance().registerTrack("track11", album, genre, artist, 10l, year, 1l, type, 1l); track11.setAlbumArtist(albumArtist); FileManager.getInstance().registerFile("file11", dir, track11, 10, 128); Track track12 = TrackManager.getInstance().registerTrack("track12", album, genre, artist, 10l, year, 1l, type, 1l); track12.setAlbumArtist(albumArtist); FileManager.getInstance().registerFile("file12", dir, track12, 10, 128); Track track21 = TrackManager.getInstance().registerTrack("track21", album, genre, artist, 10l, year, 1l, type, 1l); track21.setAlbumArtist(albumArtist); FileManager.getInstance().registerFile("file21", dir, track21, 10, 218); Track track22 = TrackManager.getInstance().registerTrack("track22", album, genre, artist, 10l, year, 1l, type, 1l); track22.setAlbumArtist(albumArtist); FileManager.getInstance().registerFile("file22", dir, track22, 10, 128); action.populateDups(); List> dups = action.duplicateTracksList; assertTrue(dups.size() == 0); } /** * Test method for. * * {@link org.jajuk.ui.actions.FindDuplicateTracksAction#perform(java.awt.event.ActionEvent)} * . * Test 2 : multi-files track : filex1 and filex2 are in the same track */ public void testPopulateDups2() { Track track11 = TrackManager.getInstance().registerTrack("track11", album, genre, artist, 10l, year, 1l, type, 1l); track11.setAlbumArtist(albumArtist); FileManager.getInstance().registerFile("file11", dir, track11, 10, 128); FileManager.getInstance().registerFile("file12", dir, track11, 10, 128); Track track21 = TrackManager.getInstance().registerTrack("track21", album, genre, artist, 10l, year, 1l, type, 1l); track21.setAlbumArtist(albumArtist); FileManager.getInstance().registerFile("file21", dir, track21, 10, 218); FileManager.getInstance().registerFile("file22", dir, track21, 10, 128); action.populateDups(); List> dups = action.duplicateTracksList; assertTrue(dups.size() == 2); List dup0 = dups.get(0); assertTrue(dup0.size() == 2); List dup1 = dups.get(1); assertTrue(dup1.size() == 2); } /** * Test method for. * * {@link org.jajuk.ui.actions.FindDuplicateTracksAction#perform(java.awt.event.ActionEvent)} * . * Test 3 : single dup : track11 and track12 have fuzzy match */ public void testPopulateDups3() { Track track11 = TrackManager.getInstance().registerTrack("track", album, genre, artist, 10l, year, 1l, type, 1l); track11.setAlbumArtist(albumArtist); FileManager.getInstance().registerFile("file11", dir, track11, 10, 128); Track track12 = TrackManager.getInstance().registerTrack("trAck", album, genre, artist, 10l, year, 1l, type, 1l); track12.setAlbumArtist(albumArtist); FileManager.getInstance().registerFile("file12", dir, track12, 10, 128); action.populateDups(); List> dups = action.duplicateTracksList; assertTrue(dups.size() == 1); List dup0 = dups.get(0); assertTrue(dup0.size() == 2); } /** * Test method for. * * {@link org.jajuk.ui.actions.FindDuplicateTracksAction#perform(java.awt.event.ActionEvent)} * . * Test 4 : mix : file11/file12 have the same track : track1, * file21/file22 have the same track : track2, * track1 =~ track2 */ public void testPopulateDups4() { Track track1 = TrackManager.getInstance().registerTrack("track", album, genre, artist, 10l, year, 1l, type, 1l); track1.setAlbumArtist(albumArtist); FileManager.getInstance().registerFile("file11", dir, track1, 10, 128); FileManager.getInstance().registerFile("file12", dir, track1, 10, 128); Track track2 = TrackManager.getInstance().registerTrack("trAck", album, genre, artist, 10l, year, 1l, type, 1l); track2.setAlbumArtist(albumArtist); FileManager.getInstance().registerFile("file21", dir, track2, 10, 128); FileManager.getInstance().registerFile("file22", dir, track2, 10, 128); action.populateDups(); List> dups = action.duplicateTracksList; assertTrue(dups.size() == 1); List dup0 = dups.get(0); assertTrue(dup0.size() == 4); } /** * Test method for. * * {@link org.jajuk.ui.actions.FindDuplicateTracksAction#perform(java.awt.event.ActionEvent)} * . * Test 5 : file11/file12 have the same track : track1, * file21/file22 have different tracks ; track21 and track 21, * track1 =~ track21 != track22 */ public void testPopulateDups5() { Track track1 = TrackManager.getInstance().registerTrack("track", album, genre, artist, 10l, year, 1l, type, 1l); track1.setAlbumArtist(albumArtist); FileManager.getInstance().registerFile("file11", dir, track1, 10, 128); FileManager.getInstance().registerFile("file12", dir, track1, 10, 128); Track track21 = TrackManager.getInstance().registerTrack("trAck", album, genre, artist, 10l, year, 1l, type, 1l); track21.setAlbumArtist(albumArtist); FileManager.getInstance().registerFile("file21", dir, track21, 10, 128); Track track22 = TrackManager.getInstance().registerTrack("trAck2", album, genre, artist, 10l, year, 1l, type, 1l); track22.setAlbumArtist(albumArtist); FileManager.getInstance().registerFile("file22", dir, track22, 10, 128); action.populateDups(); List> dups = action.duplicateTracksList; assertTrue(dups.size() == 1); List dup0 = dups.get(0); assertTrue(dup0.size() == 3); } } jajuk-1.9.6.orig/src/test/java/org/jajuk/ui/views/0000755000175000017500000000000011720500104021610 5ustar drazzibdrazzibjajuk-1.9.6.orig/src/test/java/org/jajuk/ui/views/TestCoverView.java0000644000175000017500000001632211720500104025230 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.views; import java.awt.Component; import java.awt.Container; import java.awt.event.ActionEvent; import java.awt.event.ComponentEvent; import java.util.Set; import org.jajuk.JUnitHelpers; import org.jajuk.JajukTestCase; import org.jajuk.base.Album; import org.jajuk.base.Artist; import org.jajuk.base.Device; import org.jajuk.base.Directory; import org.jajuk.base.DirectoryManager; import org.jajuk.base.File; import org.jajuk.base.FileManager; import org.jajuk.base.Genre; import org.jajuk.base.Track; import org.jajuk.base.TrackManager; import org.jajuk.base.Type; import org.jajuk.base.Year; import org.jajuk.events.JajukEvent; import org.jajuk.events.JajukEvents; import org.jajuk.util.Conf; import org.jajuk.util.Const; /** * DOCUMENT_ME. */ public class TestCoverView extends JajukTestCase { /** * Test method for. * * {@link org.jajuk.ui.views.CoverView#componentResized(java.awt.event.ComponentEvent)} * . */ public final void testComponentResized() { CoverView view = new CoverView(); // this expects the UI to be available view.initUI(); view.componentResized(new ComponentEvent(new Component() { private static final long serialVersionUID = 1L; }, 9)); // resize immediately again to cover the time delay mechanism view.componentResized(new ComponentEvent(new Component() { private static final long serialVersionUID = 1L; }, 9)); } /** * Test method for {@link org.jajuk.ui.views.CoverView#CoverView()}. */ public final void testCoverView() { new CoverView(); } /** * Test method for. * * {@link org.jajuk.ui.views.CoverView#CoverView(org.jajuk.base.File)}. */ public final void testCoverViewFile() { new CoverView(getFile()); } /** * Gets the file. * * @return the file */ private File getFile() { Genre genre = JUnitHelpers.getGenre(); Album album = JUnitHelpers.getAlbum("name", 0); Artist artist = JUnitHelpers.getArtist("name"); Year year = JUnitHelpers.getYear(2000); Type type = JUnitHelpers.getType(); Track track = TrackManager.getInstance().registerTrack("name", album, genre, artist, 120, year, 1, type, 1); Device device = JUnitHelpers.getDevice(); Directory dir = DirectoryManager.getInstance().registerDirectory(device); File file = FileManager.getInstance().registerFile("test.tst", dir, track, 120, 70); return file; } /** * Test method for {@link org.jajuk.ui.views.CoverView#initUI()}. */ public final void testInitUI() { CoverView view = new CoverView(); view.initUI(); } /** * Test method for {@link org.jajuk.ui.views.CoverView#initUI(boolean)}. */ public final void testInitUIBoolean() { { CoverView view = new CoverView(); view.initUI(true); } { CoverView view = new CoverView(); view.initUI(false); } } /** * Test method for. * * {@link org.jajuk.ui.views.CoverView#actionPerformed(java.awt.event.ActionEvent)} * . */ public final void testActionPerformed() { CoverView view = new CoverView(); view.initUI(); // disable confirmations to not show UI during running tests Conf.setProperty(Const.CONF_CONFIRMATIONS_DELETE_COVER, "false"); // different source, will not trigger anything view.actionPerformed(new ActionEvent("testsource", 1, "test")); // now try to trigger actions on each of the components in the view recursiveActionPerformed(view, view); } /** * Recursive action performed. * DOCUMENT_ME * * @param cmp DOCUMENT_ME * @param view DOCUMENT_ME */ private void recursiveActionPerformed(Container cmp, CoverView view) { for (int i = 0; i < cmp.getComponentCount(); i++) { // first call actionPerfomed with this component view.actionPerformed(new ActionEvent(cmp.getComponent(i), 1, "test")); // then again with CTRL-Mask set to trigger all parts view.actionPerformed(new ActionEvent(cmp.getComponent(i), 1, "test", ActionEvent.CTRL_MASK)); // set // CTRL_MASK // to // trigger // all // code // then recusively step into this components if (cmp.getComponent(i) instanceof Container) { recursiveActionPerformed((Container) cmp.getComponent(i), view); } } } /** * Test method for. * * {@link org.jajuk.ui.views.CoverView#createQuery(org.jajuk.base.File)}. */ public final void testCreateQuery() { CoverView view = new CoverView(); // NPE: view.createQuery(null); view.createQuery(getFile()); } /** * Test method for {@link org.jajuk.ui.views.CoverView#getDesc()}. */ public final void testGetDesc() { CoverView view = new CoverView(); assertNotNull(view.getDesc()); assertFalse(view.getDesc().isEmpty()); } /** * Test method for {@link org.jajuk.ui.views.CoverView#getRegistrationKeys()}. */ public final void testGetRegistrationKeys() { CoverView view = new CoverView(); Set eventSubjectSet = view.getRegistrationKeys(); assertNotNull(eventSubjectSet); assertTrue(eventSubjectSet.size() > 0); } /** * Test method for {@link org.jajuk.ui.views.CoverView#searching(boolean)}. */ public final void testSearching() { CoverView view = new CoverView(); view.initUI(); view.searching(true); view.searching(false); } /** * Test method for {@link org.jajuk.ui.views.CoverView#getCurrentImage()}. * * @throws Exception the exception */ public final void testGetCurrentImage() throws Exception { CoverView view = new CoverView(); // need to cover initialized view.initUI(); // there is always a dummy image... assertNotNull(view.getCurrentImage()); } /** * Test method for. * * {@link org.jajuk.ui.views.CoverView#update(org.jajuk.events.JajukEvent)}. */ public final void testUpdateJajukEvent() { CoverView view = new CoverView(); // this expects the UI to be available view.initUI(); // this is not catched currently, but should still not cause trouble view.update(new JajukEvent(JajukEvents.ALARMS_CHANGE)); // these are catched and handled currently view.update(new JajukEvent(JajukEvents.FILE_LAUNCHED)); view.update(new JajukEvent(JajukEvents.WEBRADIO_LAUNCHED)); view.update(new JajukEvent(JajukEvents.ZERO)); view.update(new JajukEvent(JajukEvents.PLAYER_STOP)); view.update(new JajukEvent(JajukEvents.COVER_NEED_REFRESH)); } } jajuk-1.9.6.orig/src/test/java/org/jajuk/ui/views/TestTracksTreeView.java0000644000175000017500000003722011720500104026221 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.views; import java.awt.Component; import java.awt.HeadlessException; import java.awt.event.ActionEvent; import java.awt.event.InputEvent; import java.awt.event.MouseEvent; import java.util.Set; import javax.swing.Icon; import javax.swing.JTree; import javax.swing.event.TreeExpansionEvent; import javax.swing.event.TreeSelectionEvent; import javax.swing.tree.TreePath; import org.jajuk.JUnitHelpers; import org.jajuk.JajukTestCase; import org.jajuk.base.Album; import org.jajuk.base.Artist; import org.jajuk.base.Genre; import org.jajuk.base.Track; import org.jajuk.base.TrackManager; import org.jajuk.base.Year; import org.jajuk.events.JajukEvents; import org.jajuk.ui.actions.ActionManager; import org.jajuk.ui.views.TracksTreeView.TracksMouseAdapter; import org.jajuk.util.Conf; import org.jajuk.util.Const; /** * DOCUMENT_ME. */ public class TestTracksTreeView extends JajukTestCase { /* (non-Javadoc) * @see org.jajuk.JajukTestCase#setUp() */ @Override protected void setUp() throws Exception { try { // initialize the actions ActionManager.getInstance(); } catch (HeadlessException e) { // this is thrown in automated tests on Hudson/Sonar } super.setUp(); } /** * Test method for {@link org.jajuk.ui.views.TracksTreeView#initUI()}. */ public final void testInitUI() { TracksTreeView view = new TracksTreeView(); tryInitUI(view); } /** * Try init ui. * DOCUMENT_ME * * @param view DOCUMENT_ME */ private void tryInitUI(TracksTreeView view) { try { view.initUI(); } catch (ExceptionInInitializerError e) { // reported on headless settings } catch (HeadlessException e) { // reported on headless settings } catch (NullPointerException e) { // sometimes reported deep inside Swing components, I could not find out // why... } } /** * Test method for {@link org.jajuk.ui.views.TracksTreeView#populateTree()}. */ public final void testPopulateTree() { TracksTreeView view = new TracksTreeView(); tryInitUI(view); try { view.populateTree(); } catch (NullPointerException e) { // reported on headless settings } // try with different settings Conf.setProperty(Const.CONF_LOGICAL_TREE_SORT_ORDER, "0"); try { view.populateTree(); } catch (NullPointerException e) { // reported on headless settings } Conf.setProperty(Const.CONF_LOGICAL_TREE_SORT_ORDER, "1"); try { view.populateTree(); } catch (NullPointerException e) { // reported on headless settings } Conf.setProperty(Const.CONF_LOGICAL_TREE_SORT_ORDER, "2"); try { view.populateTree(); } catch (NullPointerException e) { // reported on headless settings } Conf.setProperty(Const.CONF_LOGICAL_TREE_SORT_ORDER, "3"); try { view.populateTree(); } catch (NullPointerException e) { // reported on headless settings } Conf.setProperty(Const.CONF_LOGICAL_TREE_SORT_ORDER, "4"); try { view.populateTree(); } catch (NullPointerException e) { // reported on headless settings } Conf.setProperty(Const.CONF_LOGICAL_TREE_SORT_ORDER, "5"); try { view.populateTree(); } catch (NullPointerException e) { // reported on headless settings } Conf.setProperty(Const.CONF_LOGICAL_TREE_SORT_ORDER, "6"); try { view.populateTree(); } catch (NullPointerException e) { // reported on headless settings } Conf.setProperty(Const.CONF_LOGICAL_TREE_SORT_ORDER, "7"); try { view.populateTree(); } catch (NullPointerException e) { // reported on headless settings } } /** * Test method for {@link org.jajuk.ui.views.TracksTreeView#expand()}. */ public final void testExpand() { TracksTreeView view = new TracksTreeView(); try { view.expand(); } catch (NullPointerException e) { // reported on headless settings } } /** * Test method for {@link org.jajuk.ui.views.TracksTreeView#getDesc()}. */ public final void testGetDesc() { TracksTreeView view = new TracksTreeView(); assertNotNull(view.getDesc()); } /** * Test method for {@link org.jajuk.ui.views.TracksTreeView#TracksTreeView()}. */ public final void testTracksTreeView() { new TracksTreeView(); } /** * Test method for. * * {@link org.jajuk.ui.views.TracksTreeView#getRegistrationKeys()}. */ public final void testGetRegistrationKeys() { TracksTreeView view = new TracksTreeView(); Set set = view.getRegistrationKeys(); assertNotNull(set); assertTrue(set.contains(JajukEvents.FILE_LAUNCHED)); } /** * Test method for. * * {@link org.jajuk.ui.views.TracksTreeView#populateTreeByGenre()}. */ public final void testPopulateTreeByGenre() { TracksTreeView view = new TracksTreeView(); try { view.populateTreeByGenre(); } catch (NullPointerException e) { // reported on headless settings } } /** * Test method for. * * {@link org.jajuk.ui.views.TracksTreeView#populateTreeByArtist()}. */ public final void testPopulateTreeByArtist() { TracksTreeView view = new TracksTreeView(); try { view.populateTreeByArtist(); } catch (NullPointerException e) { // reported on headless settings } } /** * Test method for. * * {@link org.jajuk.ui.views.TracksTreeView#populateTreeByYear()}. */ public final void testPopulateTreeByYear() { TracksTreeView view = new TracksTreeView(); try { view.populateTreeByYear(); } catch (NullPointerException e) { // reported on headless settings } } /** * Test method for. * * {@link org.jajuk.ui.views.TracksTreeView#populateTreeByAlbum()}. */ public final void testPopulateTreeByAlbum() { TracksTreeView view = new TracksTreeView(); try { view.populateTreeByAlbum(); } catch (NullPointerException e) { // reported on headless settings } } /** * Test method for. * * {@link org.jajuk.ui.views.TracksTreeView#populateTreeByDiscovery()}. */ public final void testPopulateTreeByDiscovery() { TracksTreeView view = new TracksTreeView(); try { view.populateTreeByDiscovery(); } catch (NullPointerException e) { // reported on headless settings } } /** * Test method for. * * {@link org.jajuk.ui.views.TracksTreeView#populateTreeByRate()}. */ public final void testPopulateTreeByRate() { TracksTreeView view = new TracksTreeView(); try { view.populateTreeByRate(); } catch (NullPointerException e) { // reported on headless settings } } /** * Test method for. * * {@link org.jajuk.ui.views.TracksTreeView#populateTreeByHits()}. */ public final void testPopulateTreeByHits() { TracksTreeView view = new TracksTreeView(); try { view.populateTreeByHits(); } catch (NullPointerException e) { // reported on headless settings } } /** * Test method for. * * {@link org.jajuk.ui.views.TracksTreeView#actionPerformed(java.awt.event.ActionEvent)} * . */ public final void testActionPerformed() { TracksTreeView view = new TracksTreeView(); view.actionPerformed(new ActionEvent(this, 1, "")); } /** * Test tracks tree selection listener. * DOCUMENT_ME */ public final void testTracksTreeSelectionListener() { TracksTreeView view = new TracksTreeView(); TracksTreeView.TracksTreeSelectionListener task = view.new TracksTreeSelectionListener(); try { task.valueChanged(new TreeSelectionEvent(this, new TreePath("test"), false, null, null)); } catch (NullPointerException e) { // reported on headless settings } } /** * Test tracks mouse adapter. * DOCUMENT_ME */ public final void testTracksMouseAdapter() { TracksTreeView view = new TracksTreeView(); TracksMouseAdapter ad = view.new TracksMouseAdapter(null); assertNotNull(ad); MouseEvent event = new MouseEvent(new Component() { private static final long serialVersionUID = 1L; }, 1, 2l, 3, 2, 2, 3, true); assertTrue(event.isPopupTrigger()); try { ad.handlePopup(event); } catch (NullPointerException e) { // reported on headless settings } // popup trigger try { ad.mousePressed(event); } catch (NullPointerException e) { // reported on headless settings } // normal event with CTRL is handled here event = new MouseEvent(new Component() { private static final long serialVersionUID = 1L; }, 1, 2l, InputEvent.CTRL_DOWN_MASK, 2, 2, 3, false); try { ad.mousePressed(event); } catch (NullPointerException e) { // reported on headless settings } event = new MouseEvent(new Component() { private static final long serialVersionUID = 1L; }, 1, 2l, 0, 2, 2, 3, true); try { ad.mouseReleased(event); } catch (NullPointerException e) { // reported on headless settings } } /** * Test genre node. * DOCUMENT_ME */ public final void testGenreNode() { GenreNode ad = new GenreNode(getGenre()); assertNotNull(ad); JUnitHelpers.ToStringTest(ad); assertNotNull(ad.getGenre()); assertEquals("name", ad.getGenre().getName()); } /** * Gets the genre. * * @return the genre */ private Genre getGenre() { return JUnitHelpers.getGenre(); } /** * Test artist node. * DOCUMENT_ME */ public final void testArtistNode() { ArtistNode ad = new ArtistNode(getArtist()); assertNotNull(ad); JUnitHelpers.ToStringTest(ad); assertNotNull(ad.getArtist()); assertEquals("name", ad.getArtist().getName()); } /** * Gets the artist. * * @return the artist */ private Artist getArtist() { return JUnitHelpers.getArtist("name"); } /** * Test year node. * DOCUMENT_ME */ public final void testYearNode() { YearNode ad = new YearNode(getYear()); assertNotNull(ad); JUnitHelpers.ToStringTest(ad); assertNotNull(ad.getYear()); assertEquals("2000", ad.getYear().getName()); } /** * Gets the year. * * @return the year */ private Year getYear() { return JUnitHelpers.getYear(2000); } /** * Test album node. * DOCUMENT_ME */ public final void testAlbumNode() { AlbumNode ad = new AlbumNode(getAlbum()); assertNotNull(ad); JUnitHelpers.ToStringTest(ad); assertNotNull(ad.getAlbum()); assertEquals("name", ad.getAlbum().getName()); } /** * Gets the album. * * @return the album */ private Album getAlbum() { return JUnitHelpers.getAlbum("name", 234); } /** * Test track node. * DOCUMENT_ME */ public final void testTrackNode() { TrackNode ad = new TrackNode(getTrack()); assertNotNull(ad); JUnitHelpers.ToStringTest(ad); assertNotNull(ad.getTrack()); assertEquals("name", ad.getTrack().getName()); } /** * Gets the track. * * @return the track */ private Track getTrack() { return TrackManager.getInstance().registerTrack("name", getAlbum(), getGenre(), getArtist(), 123, getYear(), 1, JUnitHelpers.getType(), 1); } /** * Test discovery date node. * DOCUMENT_ME */ public final void testDiscoveryDateNode() { DiscoveryDateNode ad = new DiscoveryDateNode(null); assertNotNull(ad); } /** * Test tracks tree cell renderer. * DOCUMENT_ME */ public final void testTracksTreeCellRenderer() { TracksTreeCellRenderer ad = new TracksTreeCellRenderer(); assertNotNull(ad); Icon icon = ad.getIcon(); // make sure we have a different icon after each call assertNotNull(ad.getTreeCellRendererComponent(new JTree(), new GenreNode(getGenre()), true, true, true, 1, true)); assertFalse(ad.getIcon().equals(icon)); icon = ad.getIcon(); assertNotNull(ad.getTreeCellRendererComponent(new JTree(), new ArtistNode(getArtist()), true, true, true, 1, true)); assertFalse(icon.equals(ad.getIcon())); icon = ad.getIcon(); assertNotNull(ad.getTreeCellRendererComponent(new JTree(), new YearNode(getYear()), true, true, true, 1, true)); assertFalse(icon.equals(ad.getIcon())); icon = ad.getIcon(); assertNotNull(ad.getTreeCellRendererComponent(new JTree(), new AlbumNode(getAlbum()), true, true, true, 1, true)); assertFalse(icon.equals(ad.getIcon())); icon = ad.getIcon(); assertNotNull(ad.getTreeCellRendererComponent(new JTree(), new TrackNode(getTrack()), true, true, true, 1, true)); assertFalse(icon.equals(ad.getIcon())); icon = ad.getIcon(); assertNotNull(ad.getTreeCellRendererComponent(new JTree(), new DiscoveryDateNode("str"), true, true, true, 1, true)); assertFalse(icon.equals(ad.getIcon())); icon = ad.getIcon(); assertNotNull(ad.getTreeCellRendererComponent(new JTree(), "unknown object", true, true, true, 1, true)); assertFalse(icon.equals(ad.getIcon())); icon = ad.getIcon(); } /** * Test tracks tree expansion listener. * DOCUMENT_ME */ public final void testTracksTreeExpansionListener() { TracksTreeExpansionListener ad = new TracksTreeExpansionListener(); assertNotNull(ad); { Genre genre = getGenre(); assertNull(genre.getProperties().get(Const.XML_EXPANDED)); ad.treeExpanded(new TreeExpansionEvent("dummy", new TreePath(new GenreNode(genre)))); assertEquals(true, genre.getProperties().get(Const.XML_EXPANDED)); ad.treeCollapsed(new TreeExpansionEvent("dummy", new TreePath(new GenreNode(genre)))); assertNull(genre.getProperties().get(Const.XML_EXPANDED)); } { Artist genre = getArtist(); assertNull(genre.getProperties().get(Const.XML_EXPANDED)); ad.treeExpanded(new TreeExpansionEvent("dummy", new TreePath(new ArtistNode(genre)))); assertEquals(true, genre.getProperties().get(Const.XML_EXPANDED)); ad.treeCollapsed(new TreeExpansionEvent("dummy", new TreePath(new ArtistNode(genre)))); assertNull(genre.getProperties().get(Const.XML_EXPANDED)); } { Album genre = getAlbum(); assertNull(genre.getProperties().get(Const.XML_EXPANDED)); ad.treeExpanded(new TreeExpansionEvent("dummy", new TreePath(new AlbumNode(genre)))); assertEquals(true, genre.getProperties().get(Const.XML_EXPANDED)); ad.treeCollapsed(new TreeExpansionEvent("dummy", new TreePath(new AlbumNode(genre)))); assertNull(genre.getProperties().get(Const.XML_EXPANDED)); } { Year genre = getYear(); assertNull(genre.getProperties().get(Const.XML_EXPANDED)); ad.treeExpanded(new TreeExpansionEvent("dummy", new TreePath(new YearNode(genre)))); assertEquals(true, genre.getProperties().get(Const.XML_EXPANDED)); ad.treeCollapsed(new TreeExpansionEvent("dummy", new TreePath(new YearNode(genre)))); assertNull(genre.getProperties().get(Const.XML_EXPANDED)); } } } jajuk-1.9.6.orig/src/test/java/org/jajuk/ui/views/TestParameterView.java0000644000175000017500000001167511720500104026100 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.ui.views; import java.awt.Component; import java.awt.ItemSelectable; import java.awt.event.ActionEvent; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import java.util.Properties; import java.util.Set; import org.apache.commons.lang.StringUtils; import org.jajuk.JUnitHelpers; import org.jajuk.JajukTestCase; import org.jajuk.events.JajukEvent; import org.jajuk.events.JajukEvents; import org.jajuk.util.Const; import org.jajuk.util.log.Log; /** * DOCUMENT_ME. */ public class TestParameterView extends JajukTestCase { /** * Test method for {@link org.jajuk.ui.views.ParameterView#ParameterView()}. */ public void testParameterView() { new ParameterView(); } /** * Test method for. * * @throws Exception the exception * {@link org.jajuk.ui.views.ParameterView#actionPerformed(java.awt.event.ActionEvent)} * . */ public void testActionPerformed() throws Exception { ParameterView view = new ParameterView(); view.initUI(); JUnitHelpers.waitForAllWorkToFinishAndCleanup(); // make sure the logger is initialized Log.init(); // iterate over all components of the view for (Component comp : view.getComponents()) { System.out.println("Comp: " + comp.toString()); ActionEvent event = new ActionEvent(comp, 1, "test"); view.actionPerformed(event); } } /** * Test method for {@link org.jajuk.ui.views.ParameterView#getDesc()}. */ public void testGetDesc() { ParameterView view = new ParameterView(); assertTrue(StringUtils.isNotBlank(view.getDesc())); } /** * Test method for. * * {@link org.jajuk.ui.views.ParameterView#getRegistrationKeys()}. */ public void testGetRegistrationKeys() { ParameterView view = new ParameterView(); Set set = view.getRegistrationKeys(); assertTrue(set.toString(), set.contains(JajukEvents.PARAMETERS_CHANGE)); } /** * Test method for {@link org.jajuk.ui.views.ParameterView#initUI()}. */ public void testInitUI() { ParameterView view = new ParameterView(); view.initUI(); } /** * Test method for. * * {@link org.jajuk.ui.views.ParameterView#itemStateChanged(java.awt.event.ItemEvent)} * . */ public void testItemStateChanged() { ParameterView view = new ParameterView(); view.initUI(); // iterate over all components of the view for (Component comp : view.getComponents()) { ItemEvent event = new ItemEvent(new MyItemSelectable(), 1, comp, 2); view.itemStateChanged(event); } } /** * Test method for. * * {@link org.jajuk.ui.views.ParameterView#stateChanged(javax.swing.event.ChangeEvent)} * . */ public void testStateChanged() { ParameterView view = new ParameterView(); view.initUI(); view.stateChanged(null); } /** * Test method for. * * @throws Exception the exception * {@link org.jajuk.ui.views.ParameterView#update(org.jajuk.events.JajukEvent)} * . */ public void testUpdateJajukEvent() throws Exception { ParameterView view = new ParameterView(); view.initUI(); // once without details view.update(new JajukEvent(JajukEvents.PARAMETERS_CHANGE, null)); // wait for invokeLater to finish(); JUnitHelpers.clearSwingUtilitiesQueue(); // then with details Properties prop = new Properties(); prop.put(Const.DETAIL_ORIGIN, view); view.update(new JajukEvent(JajukEvents.PARAMETERS_CHANGE, prop)); // wait for invokeLater to finish(); JUnitHelpers.clearSwingUtilitiesQueue(); } /** * DOCUMENT_ME. */ private final class MyItemSelectable implements ItemSelectable { /* (non-Javadoc) * @see java.awt.ItemSelectable#removeItemListener(java.awt.event.ItemListener) */ @Override public void removeItemListener(ItemListener l) { } /* (non-Javadoc) * @see java.awt.ItemSelectable#getSelectedObjects() */ @Override public Object[] getSelectedObjects() { return null; } /* (non-Javadoc) * @see java.awt.ItemSelectable#addItemListener(java.awt.event.ItemListener) */ @Override public void addItemListener(ItemListener l) { } } } jajuk-1.9.6.orig/src/test/java/org/jajuk/events/0000755000175000017500000000000011720500104021342 5ustar drazzibdrazzibjajuk-1.9.6.orig/src/test/java/org/jajuk/events/TestObserverRegistry.java0000644000175000017500000002574211720500104026377 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.events; import java.util.HashSet; import java.util.Set; import java.util.concurrent.atomic.AtomicInteger; import org.jajuk.JajukTestCase; import org.jajuk.ThreadTestHelper; /** * DOCUMENT_ME. */ public class TestObserverRegistry extends JajukTestCase { /** The Constant NUMBER_OF_THREADS. DOCUMENT_ME */ private static final int NUMBER_OF_THREADS = 15; // 15 is the limit on // concurrent events /** The Constant NUMBER_OF_TESTS. DOCUMENT_ME */ private static final int NUMBER_OF_TESTS = 1000; /** DOCUMENT_ME. */ private AtomicInteger called = new AtomicInteger(0); /** * Test method for. * * {@link org.jajuk.events.ObserverRegistry#notifySync(org.jajuk.events.JajukEvent)} * . */ public void testNotifySync() { ObserverRegistry registry = new ObserverRegistry(); registry.notifySync(new JajukEvent(JajukEvents.PLAYER_PLAY)); } /** * Test method for. * * {@link org.jajuk.events.ObserverRegistry#register(org.jajuk.events.JajukEvents, org.jajuk.events.Observer)} * . */ public void testRegister() { ObserverRegistry registry = new ObserverRegistry(); registry.register(JajukEvents.PLAYER_PLAY, new LocalObserver(called)); } /** * Test method for. * * {@link org.jajuk.events.ObserverRegistry#unregister(org.jajuk.events.JajukEvents, org.jajuk.events.Observer)} * . */ public void testUnregister() { ObserverRegistry registry = new ObserverRegistry(); registry.unregister(JajukEvents.PLAYER_PLAY, new LocalObserver(called)); } /** * Test below zero. * DOCUMENT_ME */ public void testBelowZero() { ObserverRegistry registry = new ObserverRegistry(); Observer observer = new LocalObserver(called); // first register registry.register(JajukEvents.FILE_FINISHED, observer); assertEquals(0, called.get()); // then notifySync registry.notifySync(new JajukEvent(JajukEvents.FILE_FINISHED)); assertEquals(1, called.get()); // then unregister again registry.unregister(JajukEvents.FILE_FINISHED, observer); } /** * Test exception. * DOCUMENT_ME */ public void testException() { ObserverRegistry registry = new ObserverRegistry(); Observer observer = new LocalObserver(true, called); // first register registry.register(JajukEvents.FILE_FINISHED, observer); assertEquals(0, called.get()); // then notifySync, this will not return an error even if an exception // occurred registry.notifySync(new JajukEvent(JajukEvents.FILE_FINISHED)); assertEquals(1, called.get()); // then unregister again registry.unregister(JajukEvents.FILE_FINISHED, observer); } /** * Test multiple threads. * DOCUMENT_ME * * @throws Exception the exception */ public void testMultipleThreads() throws Exception { final ObserverRegistry registry = new ObserverRegistry(); Observer observer = new LocalObserver(called); // first register registry.register(JajukEvents.FILE_FINISHED, observer); assertEquals(0, called.get()); ThreadTestHelper helper = new ThreadTestHelper(NUMBER_OF_THREADS, NUMBER_OF_TESTS); helper.executeTest(new ThreadTestHelper.TestRunnable() { @Override public void doEnd(int threadnum) throws Exception { // nothing to do } @Override public void run(int threadnum, int iter) { // then notifySync registry.notifySync(new JajukEvent(JajukEvents.FILE_FINISHED)); } }); assertEquals(NUMBER_OF_THREADS * NUMBER_OF_TESTS, called.get()); // then unregister again registry.unregister(JajukEvents.FILE_FINISHED, observer); } /** * Test multiple threads wait. * DOCUMENT_ME * * @throws Exception the exception */ public void testMultipleThreadsWait() throws Exception { final ObserverRegistry registry = new ObserverRegistry(); // set 100ms wait time to reach event queue size on normal speed machines Observer observer = new LocalObserver(100, called); // first register registry.register(JajukEvents.FILE_FINISHED, observer); assertEquals(0, called.get()); // more threads so that we reach the limit of 15 concurrent events // a bit fewer tests as they will need some time ThreadTestHelper helper = new ThreadTestHelper(NUMBER_OF_THREADS * 2, NUMBER_OF_TESTS / 20); helper.executeTest(new ThreadTestHelper.TestRunnable() { @Override public void doEnd(int threadnum) throws Exception { // nothing to do } @Override public void run(int threadnum, int iter) { // then notifySync registry.notifySync(new JajukEvent(JajukEvents.FILE_FINISHED)); } }); // can not test this as we have overflows here! // assertEquals(NUMBER_OF_THREADS * NUMBER_OF_TESTS, called.get()); // then unregister again registry.unregister(JajukEvents.FILE_FINISHED, observer); } /** * Test multiple threads multiple observers. * DOCUMENT_ME * * @throws Exception the exception */ public void testMultipleThreadsMultipleObservers() throws Exception { final ObserverRegistry registry = new ObserverRegistry(); Observer observer1 = new LocalObserver(called); Observer observer2 = new LocalObserver(called); // first register registry.register(JajukEvents.FILE_FINISHED, observer1); registry.register(JajukEvents.FILE_FINISHED, observer2); assertEquals(0, called.get()); ThreadTestHelper helper = new ThreadTestHelper(NUMBER_OF_THREADS, NUMBER_OF_TESTS); helper.executeTest(new ThreadTestHelper.TestRunnable() { @Override public void doEnd(int threadnum) throws Exception { // nothing to do } @Override public void run(int threadnum, int iter) { // then notifySync registry.notifySync(new JajukEvent(JajukEvents.FILE_FINISHED)); } }); // now we were called twice as many times because of two observers... assertEquals(2 * NUMBER_OF_THREADS * NUMBER_OF_TESTS, called.get()); // then unregister again registry.unregister(JajukEvents.FILE_FINISHED, observer2); registry.unregister(JajukEvents.FILE_FINISHED, observer1); } /** * Test high priority observer. * DOCUMENT_ME * * @throws Exception the exception */ public void testHighPriorityObserver() throws Exception { final ObserverRegistry registry = new ObserverRegistry(); LocalObserver observer1 = new LocalObserver(called); Observer observer2 = new LocalHighPriorityObserver(observer1, called); // first register registry.register(JajukEvents.FILE_FINISHED, observer1); registry.register(JajukEvents.FILE_FINISHED, observer2); assertEquals(0, called.get()); ThreadTestHelper helper = new ThreadTestHelper(NUMBER_OF_THREADS, NUMBER_OF_TESTS); helper.executeTest(new ThreadTestHelper.TestRunnable() { @Override public void doEnd(int threadnum) throws Exception { // nothing to do } @Override public void run(int threadnum, int iter) { // then notifySync registry.notifySync(new JajukEvent(JajukEvents.FILE_FINISHED)); } }); // now we were called twice as many times because of two observers... assertEquals(2 * NUMBER_OF_THREADS * NUMBER_OF_TESTS, called.get()); // then unregister again registry.unregister(JajukEvents.FILE_FINISHED, observer2); registry.unregister(JajukEvents.FILE_FINISHED, observer1); } /** * DOCUMENT_ME. */ static class LocalObserver implements Observer { /** DOCUMENT_ME. */ boolean invoked = false; /** DOCUMENT_ME. */ int wait = 0; /** DOCUMENT_ME. */ boolean exception = false; /** DOCUMENT_ME. */ AtomicInteger called; /** * Instantiates a new local observer. * * @param called DOCUMENT_ME */ public LocalObserver(AtomicInteger called) { super(); this.called = called; } /** * Instantiates a new local observer. * * @param wait DOCUMENT_ME * @param called DOCUMENT_ME */ public LocalObserver(int wait, AtomicInteger called) { super(); this.wait = wait; this.called = called; } /** * Instantiates a new local observer. * * @param exception DOCUMENT_ME * @param called DOCUMENT_ME */ public LocalObserver(boolean exception, AtomicInteger called) { super(); this.exception = exception; this.called = called; } /* * (non-Javadoc) * * @see org.jajuk.events.Observer#getRegistrationKeys() */ @Override public Set getRegistrationKeys() { // only used in ObservationManager, not used in this testcase Set set = new HashSet(); set.add(JajukEvents.ALBUM_CHANGED); set.add(JajukEvents.PLAY_ERROR); return set; } /* * (non-Javadoc) * * @see org.jajuk.events.Observer#update(org.jajuk.events.JajukEvent) */ @Override public void update(JajukEvent event) { called.incrementAndGet(); if (exception) { throw new RuntimeException("Exception requested in update..."); } if (wait > 0) { try { Thread.sleep(wait); } catch (InterruptedException e) { throw new RuntimeException(e); } } } } /** * DOCUMENT_ME. */ private class LocalHighPriorityObserver extends LocalObserver implements HighPriorityObserver { /** DOCUMENT_ME. */ LocalObserver lowprioobserver; // to check if other was not yet called /** * Instantiates a new local high priority observer. * * @param lowprioobserver DOCUMENT_ME * @param called DOCUMENT_ME */ public LocalHighPriorityObserver(LocalObserver lowprioobserver, AtomicInteger called) { super(called); this.lowprioobserver = lowprioobserver; } /* * (non-Javadoc) * * @see * org.jajuk.events.TestObserverRegistry.LocalObserver#update(org.jajuk. * events.JajukEvent) */ @Override public void update(JajukEvent event) { if (lowprioobserver.invoked) { throw new RuntimeException("LocalObserver was called before HighPriorityObserver!"); } super.update(event); } } } jajuk-1.9.6.orig/src/test/java/org/jajuk/events/TestObservationManager.java0000644000175000017500000001421611720500104026637 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.events; import java.util.Properties; import java.util.Set; import java.util.concurrent.atomic.AtomicInteger; import org.jajuk.JUnitHelpers; import org.jajuk.JajukTestCase; /** * DOCUMENT_ME. */ public class TestObservationManager extends JajukTestCase { /** DOCUMENT_ME. */ AtomicInteger called = new AtomicInteger(0); /* * (non-Javadoc) * * @see junit.framework.TestCase#tearDown() */ @Override protected void tearDown() throws Exception { super.tearDown(); } /** * Test method for. * * {@link org.jajuk.events.ObservationManager#register(org.jajuk.events.Observer)} * . */ public void testRegister() { ObservationManager.register(new TestObserverRegistry.LocalObserver(called)); } /** * Test method for. * * {@link org.jajuk.events.ObservationManager#unregister(org.jajuk.events.JajukEvents, org.jajuk.events.Observer)} * . */ public void testUnregister() { ObservationManager.unregister(new TestObserverRegistry.LocalObserver(called)); } /** * Test unregister null. * DOCUMENT_ME */ public void testUnregisterNull() { ObservationManager.unregister(new Observer() { @Override public void update(JajukEvent event) { // nothing to do } @Override public Set getRegistrationKeys() { // just return null here to check what happens inside Observer // unregister return null; } }); } /** * Test method for. * * {@link org.jajuk.events.ObservationManager#notify(org.jajuk.events.JajukEvent)} * . */ public void testNotifyJajukEvent() { ObservationManager.notify(new JajukEvent(JajukEvents.VOLUME_CHANGED)); } /** * Test method for. * * {@link org.jajuk.events.ObservationManager#notifySync(org.jajuk.events.JajukEvent)} * . */ public void testNotifySync() { ObservationManager.notifySync(new JajukEvent(JajukEvents.PLAY_ERROR)); } /** * Test method for. * * {@link org.jajuk.events.ObservationManager#containsEvent(org.jajuk.events.JajukEvents)} * . */ public void testContainsEvent() { assertFalse(ObservationManager.containsEvent(JajukEvents.CDDB_WIZARD)); ObservationManager.notifySync(new JajukEvent(JajukEvents.CDDB_WIZARD)); assertTrue(ObservationManager.containsEvent(JajukEvents.CDDB_WIZARD)); } /** * Test method for. * * {@link org.jajuk.events.ObservationManager#notify(org.jajuk.events.JajukEvent, boolean)} * . */ public void testNotifyJajukEventBoolean() { ObservationManager.notify(new JajukEvent(JajukEvents.VOLUME_CHANGED)); ObservationManager.notifySync(new JajukEvent(JajukEvents.VOLUME_CHANGED)); } /** * Test method for. * * {@link org.jajuk.events.ObservationManager#getDetailLastOccurence(org.jajuk.events.JajukEvents, java.lang.String)} * . */ public void testGetDetailLastOccurence() { assertNull(ObservationManager.getDetailLastOccurence(JajukEvents.ALARMS_CHANGE, "notexists")); Properties prop = new Properties(); prop.setProperty("test", "value"); ObservationManager.notifySync(new JajukEvent(JajukEvents.VOLUME_CHANGED, prop)); assertEquals("value", ObservationManager.getDetailLastOccurence(JajukEvents.VOLUME_CHANGED, "test")); } /** * Test method for. * * {@link org.jajuk.events.ObservationManager#getDetail(org.jajuk.events.JajukEvent, java.lang.String)} * . */ public void testGetDetail() { Properties prop = new Properties(); prop.setProperty("test", "value"); assertEquals("value", ObservationManager.getDetail(new JajukEvent(JajukEvents.VOLUME_CHANGED, prop), "test")); } /** * Test get detail null. * DOCUMENT_ME */ public void testGetDetailNull() { Properties prop = new Properties(); prop.setProperty("test", "value"); assertNull(ObservationManager.getDetail(new JajukEvent(JajukEvents.VOLUME_CHANGED, prop), "notexisting")); assertNull(ObservationManager.getDetail(new JajukEvent(JajukEvents.VOLUME_CHANGED), "notexisting")); } /** * Test method for. * * {@link org.jajuk.events.ObservationManager#getDetailsLastOccurence(org.jajuk.events.JajukEvents)} * . */ public void testGetDetailsLastOccurence() { assertNull(ObservationManager.getDetailLastOccurence(JajukEvents.ALARMS_CHANGE, "notexists")); Properties prop = new Properties(); prop.setProperty("test", "value"); ObservationManager.notifySync(new JajukEvent(JajukEvents.VOLUME_CHANGED, prop)); assertNotNull(ObservationManager.getDetailsLastOccurence(JajukEvents.VOLUME_CHANGED)); assertEquals("value", ObservationManager.getDetailsLastOccurence(JajukEvents.VOLUME_CHANGED) .get("test")); } // helper method to emma-coverage of the unused constructor /** * Test private constructor. * DOCUMENT_ME * * @throws Exception the exception */ public void testPrivateConstructor() throws Exception { // For EMMA code-coverage tests JUnitHelpers.executePrivateConstructor(ObservationManager.class); } /** * Test exception. * DOCUMENT_ME */ public void testException() { Observer observer = new TestObserverRegistry.LocalObserver(true, called); ObservationManager.register(observer); ObservationManager.notifySync(new JajukEvent(JajukEvents.ALBUM_CHANGED)); ObservationManager.unregister(observer); } } jajuk-1.9.6.orig/src/test/java/org/jajuk/events/TestJajukEvent.java0000644000175000017500000001104611720500104025115 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.events; import java.util.Properties; import org.jajuk.JUnitHelpers; import org.jajuk.JajukTestCase; /** * DOCUMENT_ME. */ public class TestJajukEvent extends JajukTestCase { /** * Test method for {@link org.jajuk.events.JajukEvent#hashCode()}. */ public void testHashCode() { JajukEvent event1 = new JajukEvent(JajukEvents.VOLUME_CHANGED); JajukEvent event2 = new JajukEvent(JajukEvents.VOLUME_CHANGED); JUnitHelpers.HashCodeTest(event1, event2); } /** * Test hash code2. * DOCUMENT_ME */ public void testHashCode2() { Properties prop1 = new Properties(); prop1.setProperty("test", "value"); Properties prop2 = new Properties(); prop2.setProperty("test", "value"); JajukEvent event1 = new JajukEvent(JajukEvents.VOLUME_CHANGED, prop1); JajukEvent event2 = new JajukEvent(JajukEvents.VOLUME_CHANGED, prop2); JUnitHelpers.HashCodeTest(event1, event2); } /** * Test method for. * * {@link org.jajuk.events.JajukEvent#JajukEvent(org.jajuk.events.JajukEvents, java.util.Properties)} * . */ public void testJajukEventJajukEventsProperties() { Properties prop1 = new Properties(); prop1.setProperty("test", "value"); new JajukEvent(JajukEvents.VOLUME_CHANGED, prop1); } /** * Test method for. * * {@link org.jajuk.events.JajukEvent#JajukEvent(org.jajuk.events.JajukEvents)} * . */ public void testJajukEventJajukEvents() { new JajukEvent(JajukEvents.VOLUME_CHANGED); } /** * Test method for {@link org.jajuk.events.JajukEvent#getDetails()}. */ public void testGetDetails() { Properties prop1 = new Properties(); prop1.setProperty("test", "value"); JajukEvent event1 = new JajukEvent(JajukEvents.VOLUME_CHANGED, prop1); assertNotNull(event1.getDetails()); assertNotNull(event1.getDetails().get("test")); assertNull(event1.getDetails().get("notexist")); JajukEvent event2 = new JajukEvent(JajukEvents.VOLUME_CHANGED); assertNull(event2.getDetails()); } /** * Test method for {@link org.jajuk.events.JajukEvent#getSubject()}. */ public void testGetSubject() { Properties prop1 = new Properties(); prop1.setProperty("test", "value"); JajukEvent event1 = new JajukEvent(JajukEvents.VOLUME_CHANGED, prop1); assertEquals(JajukEvents.VOLUME_CHANGED, event1.getSubject()); } /** * Test method for {@link org.jajuk.events.JajukEvent#toString()}. */ public void testToString() { Properties prop1 = new Properties(); prop1.setProperty("test", "value"); JajukEvent event1 = new JajukEvent(JajukEvents.VOLUME_CHANGED, prop1); JajukEvent event2 = new JajukEvent(JajukEvents.VOLUME_CHANGED); JUnitHelpers.ToStringTest(event1); JUnitHelpers.ToStringTest(event2); } /** * Test method for. * * {@link org.jajuk.events.JajukEvent#equals(java.lang.Object)}. */ public void testEqualsObject() { JajukEvent event1 = new JajukEvent(JajukEvents.VOLUME_CHANGED); JajukEvent event2 = new JajukEvent(JajukEvents.VOLUME_CHANGED); JajukEvent event3 = new JajukEvent(JajukEvents.FILE_FINISHED); JUnitHelpers.EqualsTest(event1, event2, event3); } /** * Test equals object2. * DOCUMENT_ME */ public void testEqualsObject2() { Properties prop1 = new Properties(); prop1.setProperty("test", "value"); Properties prop2 = new Properties(); prop2.setProperty("test", "value"); Properties prop3 = new Properties(); prop3.setProperty("test", "diffvalue"); JajukEvent event1 = new JajukEvent(JajukEvents.VOLUME_CHANGED, prop1); JajukEvent event2 = new JajukEvent(JajukEvents.VOLUME_CHANGED, prop2); JajukEvent event3 = new JajukEvent(JajukEvents.VOLUME_CHANGED, prop3); JUnitHelpers.EqualsTest(event1, event2, event3); } } jajuk-1.9.6.orig/src/test/java/org/jajuk/base/0000755000175000017500000000000011720500104020750 5ustar drazzibdrazzibjajuk-1.9.6.orig/src/test/java/org/jajuk/base/TestItemManager.java0000644000175000017500000004146111720500104024652 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.base; import ext.services.xml.XMLUtils; import java.util.Date; import java.util.Iterator; import java.util.List; import javax.swing.ImageIcon; import org.apache.commons.collections.Predicate; import org.apache.commons.lang.StringUtils; import org.jajuk.JajukTestCase; import org.jajuk.services.startup.StartupCollectionService; import org.jajuk.util.Const; import org.jajuk.util.Messages; /** * DOCUMENT_ME. */ public class TestItemManager extends JajukTestCase { /** * Test method for {@link org.jajuk.base.ItemManager#ItemManager()}. */ public final void testItemManager() { new LocalIM(); } /** * Test method for. * * {@link org.jajuk.base.ItemManager#switchAllManagersToOrderState()}. */ public final void testSwitchAllManagersToOrderState() { // without Managers this will do nothing ItemManager.switchAllManagersToOrderState(); StartupCollectionService.registerItemManagers(); // now it should do more ItemManager.switchAllManagersToOrderState(); } /** * Test method for {@link org.jajuk.base.ItemManager#switchToOrderState()}. */ public final void testSwitchToOrderState() { ItemManager man = new LocalIM(); man.switchToOrderState(); } /** * Test method for. * * {@link org.jajuk.base.ItemManager#registerItemManager(java.lang.Class, org.jajuk.base.ItemManager)} * . */ public final void testRegisterItemManager() { ItemManager man = new LocalIM(); ItemManager.registerItemManager(String.class, man); } /** * Test method for {@link org.jajuk.base.ItemManager#getLabel()}. */ public final void testGetLabel() { ItemManager man = new LocalIM(); assertEquals("TestLabel", man.getLabel()); } /** * Test method for. * * {@link org.jajuk.base.ItemManager#getMetaInformation(java.lang.String)}. */ public final void testGetMetaInformation() { ItemManager man = new LocalIM(); assertNotNull(man.getMetaInformation(Const.XML_ID)); assertNull(man.getMetaInformation("unknown_property")); } /** * Test method for. * * {@link org.jajuk.base.ItemManager#getHumanType(java.lang.String)}. */ public final void testGetHumanType() { assertEquals("anykey", Messages.getHumanPropertyName("anykey")); assertFalse(Messages.getHumanPropertyName("disc_number"), "disc_number".equals(Messages .getHumanPropertyName("disc_number"))); } /** * Test method for. * * {@link org.jajuk.base.ItemManager#removeProperty(java.lang.String)}. */ public final void testRemoveProperty() { ItemManager man = new LocalIM(); // one not existing man.removeProperty("notexisting"); // another one existing man.removeProperty(Const.XML_ID); } /** * Test method for. * * {@link org.jajuk.base.ItemManager#applyRemoveProperty(org.jajuk.base.PropertyMetaInformation)} * . */ public final void testApplyRemoveProperty() { ItemManager man = new LocalIM(); PropertyMetaInformation meta = man.getMetaInformation(Const.XML_ID); // register some item before man.registerItem(new TestItem("3", "name")); man.applyRemoveProperty(meta); man.applyNewProperty(meta); } /** * Test method for. * * {@link org.jajuk.base.ItemManager#applyNewProperty(org.jajuk.base.PropertyMetaInformation)} * . */ public final void testApplyNewProperty() { // tested above } /** * Test method for {@link org.jajuk.base.ItemManager#toXML()}. */ public final void testToXML() { ItemManager man = new LocalIM(); String xml = man.toXML(); assertTrue(StringUtils.isNotBlank(xml)); StringBuilder sb = new StringBuilder(xml); sb.append("'); // valid xml? assertNotNull(sb.toString(), XMLUtils.getDocument(sb.toString())); } /** * Test method for {@link org.jajuk.base.ItemManager#getProperties()}. */ public final void testGetProperties() { ItemManager man = new LocalIM(); assertNotNull(man.getProperties()); assertEquals(1, man.getProperties().size()); // only one property registered } /** * Test method for {@link org.jajuk.base.ItemManager#getCustomProperties()}. */ public final void testGetCustomProperties() { ItemManager man = new LocalIM(); assertNotNull(man.getCustomProperties()); assertEquals(0, man.getCustomProperties().size()); // add a custom property. man.registerProperty(new PropertyMetaInformation("testprop", true, true, false, false, false, String.class, null)); assertNotNull(man.getCustomProperties()); assertEquals(1, man.getCustomProperties().size()); // now one property is // registered } /** * Test method for {@link org.jajuk.base.ItemManager#getVisibleProperties()}. */ public final void testGetVisibleProperties() { ItemManager man = new LocalIM(); assertNotNull(man.getVisibleProperties()); assertEquals(0, man.getVisibleProperties().size()); // add a custom property. man.registerProperty(new PropertyMetaInformation("testprop", true, true, true, false, false, String.class, null)); assertNotNull(man.getVisibleProperties()); assertEquals(1, man.getVisibleProperties().size()); // now one visible // property is // registered } /** * Test method for. * * {@link org.jajuk.base.ItemManager#getItemManager(java.lang.String)}. */ public final void testGetItemManagerString() { assertNotNull(ItemManager.getItemManager(Const.XML_DEVICE)); assertNotNull(ItemManager.getItemManager(Const.XML_TRACK)); assertNotNull(ItemManager.getItemManager(Const.XML_ALBUM)); assertNotNull(ItemManager.getItemManager(Const.XML_ARTIST)); assertNotNull(ItemManager.getItemManager(Const.XML_GENRE)); assertNotNull(ItemManager.getItemManager(Const.XML_DIRECTORY)); assertNotNull(ItemManager.getItemManager(Const.XML_FILE)); assertNotNull(ItemManager.getItemManager(Const.XML_PLAYLIST_FILE)); assertNotNull(ItemManager.getItemManager(Const.XML_TYPE)); assertNull(ItemManager.getItemManager("notexisting")); } /** * Test method for. * * {@link org.jajuk.base.ItemManager#getItemManager(java.lang.Class)}. */ public final void testGetItemManagerClassOfQ() { StartupCollectionService.registerItemManagers(); assertNotNull(ItemManager.getItemManager(org.jajuk.base.Album.class)); assertNotNull(ItemManager.getItemManager(org.jajuk.base.Artist.class)); assertNotNull(ItemManager.getItemManager(org.jajuk.base.File.class)); // take care, String.class is used for LocalIM which might be registered... assertNull(ItemManager.getItemManager(Date.class)); } /** * Test method for {@link org.jajuk.base.ItemManager#getItemManagers()}. */ public final void testGetItemManagers() { // cannot check the count as there can be some from previous tests assertNotNull(ItemManager.getItemManagers()); } /** * Test method for {@link org.jajuk.base.ItemManager#cleanup()}. */ public final void testCleanup() { ItemManager man = new LocalIM(); man.cleanup(); // TODO: add more sophisticated testing here } /** * Test method for. * * {@link org.jajuk.base.ItemManager#cleanOrphanTracks(org.jajuk.base.Item)}. */ public final void testCleanOrphanTracks() { ItemManager man = new LocalIM(); man.cleanOrphanTracks(null); // TODO: add more sophisticated testing here } /** * Test method for. * * {@link org.jajuk.base.ItemManager#removeItem(org.jajuk.base.Item)}. */ public final void testRemoveItem() { ItemManager man = new LocalIM(); man.removeItem(null); Item item = new TestItem("4", "name4"); man.registerItem(item); assertEquals(1, man.getItems().size()); man.removeItem(item); assertEquals(0, man.getItems().size()); } /** * Test method for. * * {@link org.jajuk.base.ItemManager#registerItem(org.jajuk.base.Item)}. */ public final void testRegisterItem() { // tested in previous test } /** * Test method for. * * {@link org.jajuk.base.ItemManager#registerProperty(org.jajuk.base.PropertyMetaInformation)} * . */ public final void testRegisterProperty() { // tested in testGetCustomProperties() } /** * Test method for. * * @throws Exception the exception * {@link org.jajuk.base.ItemManager#changeItem(org.jajuk.base.Item, java.lang.String, java.lang.Object, java.util.Set)} * . */ public final void testChangeItem() throws Exception { ItemManager man = new LocalIM(); Item item = new TestItem("5", "name5"); man.registerItem(item); ItemManager.changeItem(item, Const.XML_ID, "6", null); // TODO: add more sophisticated testing here } /** * Test method for {@link org.jajuk.base.ItemManager#getElementCount()}. */ public final void testGetElementCount() { ItemManager man = new LocalIM(); assertEquals(0, man.getElementCount()); Item item = new TestItem("5", "name5"); man.registerItem(item); assertEquals(1, man.getElementCount()); } /** * Test method for. * * {@link org.jajuk.base.ItemManager#getItemByID(java.lang.String)}. */ public final void testGetItemByID() { ItemManager man = new LocalIM(); Item item = new TestItem("5", "name5"); man.registerItem(item); assertNotNull(man.getItemByID("5")); assertNull(man.getItemByID("6")); } /** * Test method for {@link org.jajuk.base.ItemManager#getItems()}. */ public final void testGetItems() { ItemManager man = new LocalIM(); Item item = new TestItem("7", "name7"); man.registerItem(item); item = new TestItem("8", "name8"); man.registerItem(item); assertEquals(man.getItems().toString(), 2, man.getItems().size()); } /** * Test method for. * * {@link org.jajuk.base.ItemManager#getFilteredItems(org.apache.commons.collections.Predicate)} * . */ public final void testGetFilteredItems() { ItemManager man = new LocalIM(); Item item = new TestItem("7", "name7"); man.registerItem(item); item = new TestItem("8", "name8"); man.registerItem(item); // first find all List list = man.getFilteredItems(new Predicate() { @Override public boolean evaluate(Object obj) { return true; } }); assertEquals(list.toString(), 2, list.size()); // then none list = man.getFilteredItems(new Predicate() { @Override public boolean evaluate(Object obj) { return false; } }); assertEquals(list.toString(), 0, list.size()); } /** * Test method for {@link org.jajuk.base.ItemManager#getItemsIterator()}. */ public final void testGetItemsIterator() { ItemManager man = new LocalIM(); Item item = new TestItem("9", "name9"); man.registerItem(item); item = new TestItem("10", "name10"); man.registerItem(item); Iterator items = man.getItemsIterator(); assertNotNull(items); assertTrue(items.hasNext()); } /** * Test method for {@link org.jajuk.base.ItemManager#clear()}. */ public final void testClear() { ItemManager man = new LocalIM(); Item item = new TestItem("9", "name9"); man.registerItem(item); item = new TestItem("10", "name10"); man.registerItem(item); assertEquals(2, man.getElementCount()); man.clear(); assertEquals(0, man.getElementCount()); } /** * Test method for {@link org.jajuk.base.ItemManager#forceSorting()}. */ public final void testForceSorting() { ItemManager man = new LocalIM(); Item item = new TestItem("9", "name9"); man.registerItem(item); item = new TestItem("10", "name10"); man.registerItem(item); // now the order is in there, first 9, then 10 Iterator it = man.getItemsIterator(); assertEquals("9", it.next().getID()); assertEquals("10", it.next().getID()); assertEquals(2, man.getElementCount()); man.forceSorting(); // still the same size assertEquals(2, man.getElementCount()); // the iterator should still return 9 before 10 it = man.getItemsIterator(); assertEquals("9", it.next().getID()); assertEquals("10", it.next().getID()); } /** * Test sorting. * DOCUMENT_ME */ public final void testSorting() { // first run without "ordered state" ItemManager man = new LocalIM(); runSortingTest(man, true); // now use one with ordered state man = new LocalIM(); man.switchToOrderState(); runSortingTest(man, false); } /** * Run sorting test. * DOCUMENT_ME * * @param man DOCUMENT_ME * @param notYetOrderedState DOCUMENT_ME */ private void runSortingTest(ItemManager man, boolean notYetOrderedState) { Item item = new TestItem("9", "name9"); man.registerItem(item); item = new TestItem("10", "name10"); man.registerItem(item); item = new TestItem("8", "name8"); man.registerItem(item); item = new TestItem("11", "name11"); man.registerItem(item); // will be added again because there is no exists-checking done item = new TestItem("8", "name8"); man.registerItem(item); item = new TestItem("7", "name7"); man.registerItem(item); item = new TestItem("12", "name12"); man.registerItem(item); // only ordered as long as we have not switched to ordered state if (notYetOrderedState) { // now the order is in there, first 9, then 10 Iterator it = man.getItemsIterator(); assertEquals("9", it.next().getID()); assertEquals("10", it.next().getID()); assertEquals("8", it.next().getID()); assertEquals("11", it.next().getID()); assertEquals("8", it.next().getID()); assertEquals("7", it.next().getID()); assertEquals("12", it.next().getID()); } // in ordered state we do not add items multiple times if (notYetOrderedState) { assertEquals(7, man.getElementCount()); } else { assertEquals(6, man.getElementCount()); } man.forceSorting(); // still the same size // in ordered state we do not add items multiple times if (notYetOrderedState) { assertEquals(7, man.getElementCount()); } else { assertEquals(6, man.getElementCount()); } if (notYetOrderedState) { // the iterator should still return 9 before 10 Iterator it = man.getItemsIterator(); assertEquals("9", it.next().getID()); assertEquals("10", it.next().getID()); assertEquals("8", it.next().getID()); assertEquals("11", it.next().getID()); assertEquals("8", it.next().getID()); assertEquals("7", it.next().getID()); assertEquals("12", it.next().getID()); } } /** * DOCUMENT_ME. */ private static class LocalIM extends ItemManager { /* (non-Javadoc) * @see org.jajuk.base.ItemManager#getLabel() */ @Override public String getLabel() { return "TestLabel"; } /** * Instantiates a new local im. */ public LocalIM() { super(); registerProperty(new PropertyMetaInformation(Const.XML_ID, false, true, false, false, false, String.class, null)); } } /** * DOCUMENT_ME. */ private static class TestItem extends Item implements Comparable { /* (non-Javadoc) * @see java.lang.Comparable#compareTo(java.lang.Object) */ @Override public int compareTo(Item o) { return getID().compareTo(o.getID()); } /** * Instantiates a new test item. * * @param id DOCUMENT_ME * @param name DOCUMENT_ME */ public TestItem(String id, String name) { super(id, name); } /* (non-Javadoc) * @see org.jajuk.base.Item#getDesc() */ @Override public String getDesc() { return "desc"; } /* (non-Javadoc) * @see org.jajuk.base.Item#getIconRepresentation() */ @Override public ImageIcon getIconRepresentation() { return null; } /** * Gets the label. * * @return the label */ @Override String getLabel() { return "Test"; } } } jajuk-1.9.6.orig/src/test/java/org/jajuk/base/TestPlaylist.java0000644000175000017500000010036311720500104024257 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.base; import java.awt.HeadlessException; import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.List; import org.apache.commons.lang.StringUtils; import org.jajuk.ConstTest; import org.jajuk.JUnitHelpers; import org.jajuk.JajukTestCase; import org.jajuk.services.bookmark.Bookmarks; import org.jajuk.services.players.QueueModel; import org.jajuk.services.players.StackItem; import org.jajuk.services.startup.StartupCollectionService; import org.jajuk.util.Conf; import org.jajuk.util.Const; import org.jajuk.util.error.JajukException; import org.jajuk.util.log.Log; /** * DOCUMENT_ME. */ public class TestPlaylist extends JajukTestCase { /** * Test method for {@link org.jajuk.base.Playlist#hashCode()}. */ public final void testHashCode() { Playlist play = new Playlist("1", "name", null); Playlist equ = new Playlist("1", "name", null); JUnitHelpers.HashCodeTest(play, equ); } /** * Test method for {@link org.jajuk.base.Playlist#getDesc()}. */ public final void testGetDesc() { Playlist play = new Playlist("1", "name", null); assertFalse(StringUtils.isBlank(play.getDesc())); } /** * Test method for {@link org.jajuk.base.Playlist#equals(java.lang.Object)}. */ public final void testEqualsObject() { Playlist play = new Playlist(Playlist.Type.NORMAL, "1", "name", null); Playlist equ = new Playlist(Playlist.Type.NORMAL, "1", "name", null); // equals looks at id and type Playlist nonequ1 = new Playlist(Playlist.Type.NORMAL, "2", "name", null); Playlist nonequ2 = new Playlist(Playlist.Type.NORMAL, "2", "name2", null); Playlist nonequ3 = new Playlist(Playlist.Type.NORMAL, "2", "name3", JUnitHelpers.getDirectory()); JUnitHelpers.EqualsTest(play, equ, nonequ1); JUnitHelpers.EqualsTest(play, equ, nonequ2); JUnitHelpers.EqualsTest(play, equ, nonequ3); } /** * Test method for {@link org.jajuk.base.Playlist#getLabel()}. */ public final void testGetLabel() { Playlist play = new Playlist("1", "name", null); assertTrue(StringUtils.isNotBlank(play.getLabel())); } /** * Test method for. * * @throws Exception the exception * {@link org.jajuk.base.Playlist#getHumanValue(java.lang.String)}. */ public final void testGetHumanValue() throws Exception { Playlist play = createPlaylist(); DirectoryManager.getInstance().registerDirectory(play.getDirectory().getDevice()); // this is what we read here... play.setProperty(Const.XML_DIRECTORY, play.getDirectory().getDevice().getID()); String str1 = ConstTest.PATH_DEVICE; String str2 = play.getHumanValue(Const.XML_DIRECTORY); str1 = StringUtils.stripEnd(str1, java.io.File.separator); str2 = StringUtils.stripEnd(str2, java.io.File.separator); assertEquals(str1, str2); assertEquals("", play.getHumanValue("notexist")); // define property StartupCollectionService.registerItemManagers(); ItemManager.getItemManager(Playlist.class).registerProperty( new PropertyMetaInformation("testkey", true, true, true, true, true, String.class, "defaultval")); play.setProperty("testkey", "testval"); assertEquals("testval", play.getHumanValue("testkey")); play.removeProperty("testkey"); assertEquals("defaultval", play.getHumanValue("testkey")); } /** * Creates the playlist. * DOCUMENT_ME * * @return the playlist * @throws Exception the exception */ private Playlist createPlaylist() throws Exception { Device device = JUnitHelpers.getDevice(); Directory topdir = JUnitHelpers.getDirectory(); try { topdir.getDevice().mount(true); } catch (Exception e) { Log.error(e); } Directory dir = JUnitHelpers.getDirectory("testdir", topdir, device); // cleanup dir.getFio().delete(); dir.getFio().mkdirs(); java.io.File fioPlaylist = new java.io.File(dir.getAbsolutePath() + "/playlist.m3u"); Playlist play = PlaylistManager.getInstance().registerPlaylistFile(fioPlaylist, dir); List list = new ArrayList(); list.add(JUnitHelpers.getFile("file1", false)); list.add(JUnitHelpers.getFile("file1", false)); play.setFiles(list); try { play.commit(); } catch (JajukException e) { Log.error(e); } return play; } /** * Test method for {@link org.jajuk.base.Playlist#getIconRepresentation()}. */ public final void testGetIconRepresentation() { Playlist play = new Playlist("1", "name", null); assertNotNull(play.getIconRepresentation()); } /** * Test method for {@link org.jajuk.base.Playlist#getRate()}. * * @throws Exception the exception */ public final void testGetRate() throws Exception { Playlist play = createPlaylist(); play.remove(0); play.remove(0); assertEquals(0, play.getRate()); File file = JUnitHelpers.getFile("file1", false); file.getTrack().setRate(2); play.addFile(file); // we use 2 above assertEquals(2, play.getRate()); // multiple files round the rate file = JUnitHelpers.getFile("file2", false); file.getTrack().setRate(4); play.addFile(file); assertEquals(3, play.getRate()); play.addFile(JUnitHelpers.getFile("file3", false)); play.getFiles().get(2).getTrack().setRate(3); assertEquals(3, play.getRate()); } /** * Test get rate null. * DOCUMENT_ME * * @throws Exception the exception */ public final void testGetRateNull() throws Exception { Playlist play = createPlaylist(); play.setFiles(null); assertEquals(0, play.getRate()); } /** * Test method for. * * {@link org.jajuk.base.Playlist#Playlist(org.jajuk.base.Playlist.Type, java.lang.String, java.lang.String, org.jajuk.base.Directory)} * . */ public final void testPlaylistTypeStringStringDirectory() { new SmartPlaylist(Playlist.Type.BESTOF, "1", "name", null); } /** * Test method for. * * {@link org.jajuk.base.Playlist#Playlist(java.lang.String, java.lang.String, org.jajuk.base.Directory)} * . */ public final void testPlaylistStringStringDirectory() { new Playlist("1", "name", null); } /** * Test method for. * * @throws Exception the exception * {@link org.jajuk.base.Playlist#addFile(org.jajuk.base.File)}. */ public final void testAddFileFile() throws Exception { Playlist play = createPlaylist(); play.remove(0); play.remove(0); play.addFile(JUnitHelpers.getFile("file1", false)); assertEquals(1, play.getFiles().size()); } /** * Test add file queue. * DOCUMENT_ME * * @throws Exception the exception */ public final void testAddFileQueue() throws Exception { Playlist play = getPlaylistQueue(); File file = JUnitHelpers.getFile("file1", false); file.getDirectory().getDevice().mount(true); play.addFile(file); // wait a bit to let the "push" be done in a separate thread JUnitHelpers.waitForThreadToFinish("Queue Push Thread"); assertEquals(1, QueueModel.getQueueSize()); file = JUnitHelpers.getFile("file1", false); play.addFile(1, file); // wait a bit to let the "push" be done in a separate thread JUnitHelpers.waitForThreadToFinish("Queue Push Thread"); assertEquals(2, QueueModel.getQueueSize()); assertEquals(2, play.getFiles().size()); // test with repeat as well to see if we get repeat set for the new track as // well QueueModel.getItem(0).setRepeat(true); file = JUnitHelpers.getFile("file1", false); play.addFile(1, file); // wait a bit to let the "push" be done in a separate thread JUnitHelpers.waitForThreadToFinish("Queue Push Thread"); assertEquals(3, QueueModel.getQueueSize()); assertEquals(3, play.getFiles().size()); } /** * Test method for {@link org.jajuk.base.Playlist#getType()}. */ public final void testGetType() { Playlist play = getPlaylistBookmark(); assertEquals(Playlist.Type.BOOKMARK, play.getType()); } /** * Test method for. * * @throws Exception the exception * {@link org.jajuk.base.Playlist#addFile(int, org.jajuk.base.File)}. */ public final void testAddFileIntFile() throws Exception { Playlist play = createPlaylist(); play.remove(0); play.remove(0); play.addFile(JUnitHelpers.getFile("test.tst", false)); assertEquals(1, play.getFiles().size()); File file = JUnitHelpers.getFile("othername", false); file.setName("othername"); play.addFile(1, file); // this should now be at pos 1 assertEquals("test.tst", play.getFiles().get(0).getName()); assertEquals("othername", play.getFiles().get(1).getName()); file = JUnitHelpers.getFile("file3", false); file.setName("yetanother"); play.addFile(1, file); assertEquals("test.tst", play.getFiles().get(0).getName()); assertEquals("yetanother", play.getFiles().get(1).getName()); assertEquals("othername", play.getFiles().get(2).getName()); } /** * Test method for {@link org.jajuk.base.Playlist#addFiles(java.util.List)}. * * @throws Exception the exception */ public final void testAddFiles() throws Exception { Playlist play = createPlaylist(); play.remove(0); play.remove(0); List files = new ArrayList(); // empty add does not do anything play.addFiles(files, 0); assertEquals(0, play.getFiles().size()); // add some files files.add(JUnitHelpers.getFile("file1", false)); files.add(JUnitHelpers.getFile("file1", false)); files.add(JUnitHelpers.getFile("file1", false)); files.add(JUnitHelpers.getFile("file1", false)); assertEquals(0, play.getFiles().size()); play.addFiles(files, 0); assertEquals(4, play.getFiles().size()); } /** * Test method for {@link org.jajuk.base.Playlist#clear()}. * * @throws Exception the exception */ public final void testClear() throws Exception { Playlist play = createPlaylist(); // nothing happens without content play.clear(); play.addFile(JUnitHelpers.getFile("file1", false)); play.addFile(JUnitHelpers.getFile("file1", false)); play.addFile(JUnitHelpers.getFile("file1", false)); play.addFile(JUnitHelpers.getFile("file1", false)); assertEquals(4, play.getFiles().size()); // now clear clears out the class play.clear(); assertEquals(0, play.getFiles().size()); } /** * Test clear empty list. * DOCUMENT_ME * * @throws Exception the exception */ public final void testClearEmptyList() throws Exception { Device device = JUnitHelpers.getDevice(); device.mount(true); Playlist play = new Playlist(Playlist.Type.NORMAL, "1", "playlist.m3u", JUnitHelpers .getDirectory()); play.clear(); } /** * Test clear queue. * DOCUMENT_ME */ public final void testClearQueue() { Playlist play = getPlaylistQueue(); play.clear(); } /** * Test clear bookmark. * DOCUMENT_ME */ public final void testClearBookmark() { Playlist play = getPlaylistBookmark(); play.clear(); } /** * Test method for {@link org.jajuk.base.Playlist#commit()}. * * @throws Exception the exception */ public final void testCommit() throws Exception { Playlist playlist = createPlaylist(); playlist.commit(); } /** * Test method for. * * {@link org.jajuk.base.Playlist#compareTo(org.jajuk.base.Playlist)}. */ public final void testCompareTo() { Playlist play = new Playlist("1", "name", null); Playlist equ = new Playlist("1", "name", null); Playlist equ2 = new Playlist("4", "name", null); // different id still // compares as we just look // at name and directory... Playlist nonequ1 = new Playlist("2", "name3", null); Playlist nonequ2 = new Playlist("5", "name2", null); Playlist nonequ3 = new Playlist("2", "name", JUnitHelpers.getDirectory()); JUnitHelpers.CompareToTest(play, equ, nonequ1); JUnitHelpers.CompareToTest(play, equ, nonequ2); JUnitHelpers.CompareToTest(play, equ, nonequ3); JUnitHelpers.CompareToTest(play, equ2, nonequ1); JUnitHelpers.CompareToTest(play, equ2, nonequ2); JUnitHelpers.CompareToTest(play, equ2, nonequ3); } /** * Test method for {@link org.jajuk.base.Playlist#containsExtFiles()}. */ public final void testContainsExtFiles() { Playlist play = new Playlist("1", "name", null); // false usually assertFalse(play.containsExtFiles()); // TODO: add test that loads a playlist with unavailable files so that this // is set to true... } /** * Test method for {@link org.jajuk.base.Playlist#down(int)}. * * @throws Exception the exception */ public final void testDown() throws Exception { Playlist play = createPlaylist(); play.remove(0); play.remove(0); File file = JUnitHelpers.getFile("file1", false); file.setName("name1"); play.addFile(file); file = JUnitHelpers.getFile("file2", false); file.setName("name2"); play.addFile(file); file = JUnitHelpers.getFile("file3", false); file.setName("name3"); play.addFile(file); file = JUnitHelpers.getFile("file4", false); file.setName("name4"); play.addFile(file); assertEquals(4, play.getFiles().size()); play.down(0); assertEquals("name2", play.getFiles().get(0).getName()); assertEquals("name1", play.getFiles().get(1).getName()); assertEquals("name3", play.getFiles().get(2).getName()); assertEquals("name4", play.getFiles().get(3).getName()); play.down(2); assertEquals("name2", play.getFiles().get(0).getName()); assertEquals("name1", play.getFiles().get(1).getName()); assertEquals("name4", play.getFiles().get(2).getName()); assertEquals("name3", play.getFiles().get(3).getName()); play.up(1); assertEquals("name1", play.getFiles().get(0).getName()); assertEquals("name2", play.getFiles().get(1).getName()); assertEquals("name4", play.getFiles().get(2).getName()); assertEquals("name3", play.getFiles().get(3).getName()); play.up(3); assertEquals("name1", play.getFiles().get(0).getName()); assertEquals("name2", play.getFiles().get(1).getName()); assertEquals("name3", play.getFiles().get(2).getName()); assertEquals("name4", play.getFiles().get(3).getName()); } /** * Test down bookmark. * DOCUMENT_ME */ public final void testDownBookmark() { Playlist play = getPlaylistBookmark(); play.down(0); play.up(0); } /** * Gets the playlist bookmark. * * @return the playlist bookmark */ private Playlist getPlaylistBookmark() { return new Playlist(Playlist.Type.BOOKMARK, "1", "name", null); } /** * Test down queue. * DOCUMENT_ME */ public final void testDownQueue() { Playlist play = getPlaylistQueue(); play.down(-1); play.up(0); } /** * Gets the playlist queue. * * @return the playlist queue */ private Playlist getPlaylistQueue() { // make sure the Queue is empty before creating a playlist on it QueueModel.clear(); return new Playlist(Playlist.Type.QUEUE, "1", "name", null); } /** * Test method for {@link org.jajuk.base.Playlist#forceRefresh()}. * * @throws Exception the exception */ public final void testForceRefresh() throws Exception { // make sure we have a playlist stored before Playlist play = createPlaylist(); play.forceRefresh(); } /** * Test method for {@link org.jajuk.base.Playlist#getAbsolutePath()}. * * @throws Exception the exception */ public final void testGetAbsolutePath() throws Exception { Playlist play = createPlaylist(); assertEquals(ConstTest.PATH_DEVICE + java.io.File.separator + "dir" + java.io.File.separator + "testdir" + java.io.File.separator + "playlist.m3u", play.getAbsolutePath()); // call it a second time to use the cached version assertEquals(ConstTest.PATH_DEVICE + java.io.File.separator + "dir" + java.io.File.separator + "testdir" + java.io.File.separator + "playlist.m3u", play.getAbsolutePath()); } /** * Test get absolute path not normal. * DOCUMENT_ME */ public final void testGetAbsolutePathNotNormal() { Playlist play = new Playlist(Playlist.Type.BESTOF, "1", "name", null); assertTrue(StringUtils.isBlank(play.getAbsolutePath())); play.setFIO(new java.io.File("testfile")); assertTrue(StringUtils.isNotBlank(play.getAbsolutePath())); } /** * Test method for {@link org.jajuk.base.Playlist#getDirectory()}. */ public final void testGetDirectory() { Playlist play = new Playlist("1", "name", null); assertNull(play.getDirectory()); play = new Playlist(Playlist.Type.NORMAL, "1", "playlist.m3u", JUnitHelpers.getDirectory()); assertNotNull(play.getDirectory()); } /** * Test method for {@link org.jajuk.base.Playlist#getFiles()}. * * @throws Exception the exception */ public final void testGetFiles() throws Exception { Playlist play = createPlaylist(); play.remove(0); play.remove(0); assertEquals(0, play.getFiles().size()); play.addFile(JUnitHelpers.getFile("file1", false)); assertEquals(1, play.getFiles().size()); } /** * Test get files null. * DOCUMENT_ME * * @throws Exception the exception */ public final void testGetFilesNull() throws Exception { Playlist play = createPlaylist(); play.setFiles(null); // null as list! assertEquals(2, play.getFiles().size()); } /** * Test get files novelities. * DOCUMENT_ME * * @throws Exception the exception */ public final void testGetFilesNovelities() throws Exception { Device device = JUnitHelpers.getDevice(); Directory dir = JUnitHelpers.getDirectory(); device.mount(true); Playlist play = new SmartPlaylist(Playlist.Type.NOVELTIES, "1", "playlist.m3u", dir); assertNotNull(play.getFiles()); } /** * Test get files best of. * DOCUMENT_ME * * @throws Exception the exception */ public final void testGetFilesBestOf() throws Exception { Playlist play = new SmartPlaylist(Playlist.Type.BESTOF, "1", "playlist.m3u", JUnitHelpers .getDirectory()); assertNotNull(play.getFiles()); } /** * Test get files new. * DOCUMENT_ME * * @throws Exception the exception */ public final void testGetFilesNew() throws Exception { Playlist play = new SmartPlaylist(Playlist.Type.NEW, "1", "playlist.m3u", JUnitHelpers .getDirectory()); assertNotNull(play.getFiles()); assertEquals(0, play.getFiles().size()); } /** * Test method for {@link org.jajuk.base.Playlist#getFIO()}. */ public final void testGetAndSetFIO() { Playlist play = new SmartPlaylist(Playlist.Type.BESTOF, "1", "name", null); assertNotNull(play.getFIO()); play.setFIO(null); assertNotNull(play.getFIO()); // recreated... play.setFIO(new java.io.File(System.getProperty("java.io.tmpdir") + java.io.File.separator + "testfio")); assertNotNull(play.getFIO()); } /** * Test method for {@link org.jajuk.base.Playlist#isReady()}. * * @throws Exception the exception */ public final void testIsReady() throws Exception { Playlist play = createPlaylist(); // mounted initially assertTrue(play.isReady()); play.getDirectory().getDevice().unmount(); assertFalse(play.isReady()); } /** * Test method for {@link org.jajuk.base.Playlist#load()}. * * @throws Exception the exception */ public final void testLoad() throws Exception { // first commit a playlist { Playlist play = createPlaylist(); play.addFile(JUnitHelpers.getFile("file1", false)); new java.io.File(System.getProperty("java.io.tmpdir") + java.io.File.separator + "testdir") .mkdir(); play.setFIO(new java.io.File(System.getProperty("java.io.tmpdir") + java.io.File.separator + "testdir" + java.io.File.separator + "playlist.m3u")); play.commit(); } Playlist play = createPlaylist(); List list = play.load(); assertNotNull(list); assertEquals(2, list.size()); assertEquals("file1", list.get(0).getName()); } /** * Test method for {@link org.jajuk.base.Playlist#play()}. * * @throws Exception the exception */ public final void testPlay() throws Exception { Playlist play = createPlaylist(); // some error without files play.play(); play.addFile(JUnitHelpers.getFile("file1", false)); // try again with files play.play(); } /** * Test play null. * DOCUMENT_ME * * @throws Exception the exception */ public final void testPlayNull() throws Exception { Playlist play = createPlaylist(); // some error without files play.setFiles(null); try { play.play(); } catch (HeadlessException e) { // this tries to open a FileChooser... } play.setFiles(new ArrayList()); try { play.play(); } catch (HeadlessException e) { // this tries to open a FileChooser... } } /** * Test method for {@link org.jajuk.base.Playlist#remove(int)}. * * @throws Exception the exception */ public final void testRemove() throws Exception { Playlist play = createPlaylist(); play.addFile(JUnitHelpers.getFile("file1", false)); play.remove(0); } /** * Test remove bookmark. * DOCUMENT_ME * * @throws Exception the exception */ public final void testRemoveBookmark() throws Exception { Bookmarks.getInstance().addFile(JUnitHelpers.getFile("file1", false)); Playlist play = getPlaylistBookmark(); play.remove(0); } /** * Test remove queue. * DOCUMENT_ME */ public final void testRemoveQueue() { Playlist play = getPlaylistQueue(); play.remove(0); } /** * Test method for. * * @throws Exception the exception * {@link org.jajuk.base.Playlist#replaceFile(org.jajuk.base.File, org.jajuk.base.File)} * . */ public final void testReplaceFile() throws Exception { Playlist play = createPlaylist(); play.addFile(JUnitHelpers.getFile("file1", false)); File file = JUnitHelpers.getFile("file1", false); play.setFIO(new java.io.File(System.getProperty("java.io.tmpdir") + java.io.File.separator + "testdir" + java.io.File.separator + "playlist.m3u")); play.replaceFile(play.getFiles().get(0), file); } /** * Test replace file bookmark. * DOCUMENT_ME * * @throws Exception the exception */ public final void testReplaceFileBookmark() throws Exception { Playlist play = getPlaylistBookmark(); play.addFile(JUnitHelpers.getFile("file1", false)); // wait for the thread to finish before doing this JUnitHelpers.waitForThreadToFinish("Queue Push Thread"); play.replaceFile(play.getFiles().get(0), JUnitHelpers.getFile("file1", false)); } /** * Test replace file queue. * DOCUMENT_ME * * @throws Exception the exception */ public final void testReplaceFileQueue() throws Exception { // make sure Queue is empty QueueModel.clear(); Playlist play = getPlaylistQueue(); // for type Queue, we need to push to the Queue File file = JUnitHelpers.getFile("file1", false); file.getDirectory().getDevice().mount(true); QueueModel.insert(new StackItem(file), 0); assertEquals(1, play.getFiles().size()); assertNotNull(play.getFiles().get(0)); play.replaceFile(play.getFiles().get(0), JUnitHelpers.getFile("file1", false)); } /** * Test method for {@link org.jajuk.base.Playlist#reset()}. */ public final void testReset() { Playlist play = new Playlist("1", "name", null); Directory dir = JUnitHelpers.getDirectory(); play.setParentDirectory(dir); play.setFIO(new java.io.File("testfile")); play.reset(); assertNotNull(play.getFIO()); // recreated again... } /** * Test method for {@link org.jajuk.base.Playlist#saveAs()}. * * @throws Exception the exception */ public final void testSaveAs() throws Exception { Playlist play = createPlaylist(); try { play.saveAs(); } catch (InvocationTargetException e) { // this tries to open a FileChooser... } catch (HeadlessException e) { // this tries to open a FileChooser... } } /** * Test save as best of. * DOCUMENT_ME * * @throws Exception the exception */ public final void testSaveAsBestOf() throws Exception { Directory dir = JUnitHelpers.getDirectory(); Playlist play = new Playlist(Playlist.Type.BESTOF, "1", "playlist.m3u", dir); List list = new ArrayList(); list.add(JUnitHelpers.getFile("file1", false)); list.add(JUnitHelpers.getFile("file1", false)); play.setFiles(list); try { play.saveAs(); } catch (InvocationTargetException e) { // this tries to open a FileChooser... } catch (HeadlessException e) { // this tries to open a FileChooser... } } /** * Test save as bookmark. * DOCUMENT_ME * * @throws Exception the exception */ public final void testSaveAsBookmark() throws Exception { Playlist play = getPlaylistBookmark(); try { play.saveAs(); } catch (InvocationTargetException e) { // this tries to open a FileChooser... } catch (HeadlessException e) { // this tries to open a FileChooser... } } /** * Test save as novelities. * DOCUMENT_ME * * @throws Exception the exception */ public final void testSaveAsNovelities() throws Exception { Directory dir = JUnitHelpers.getDirectory(); Playlist play = new Playlist(Playlist.Type.NOVELTIES, "1", "playlist.m3u", dir); List list = new ArrayList(); list.add(JUnitHelpers.getFile("file1", false)); list.add(JUnitHelpers.getFile("file1", false)); play.setFiles(list); try { play.saveAs(); } catch (InvocationTargetException e) { // this tries to open a FileChooser... } catch (HeadlessException e) { // this tries to open a FileChooser... } } /** * Test save as queue. * DOCUMENT_ME * * @throws Exception the exception */ public final void testSaveAsQueue() throws Exception { Playlist play = getPlaylistQueue(); try { play.saveAs(); } catch (InvocationTargetException e) { // this tries to open a FileChooser... } catch (HeadlessException e) { // this tries to open a FileChooser... } } /** * Test method for {@link org.jajuk.base.Playlist#setFiles(java.util.List)}. * * @throws Exception the exception */ public final void testSetFiles() throws Exception { Playlist play = createPlaylist(); List list = new ArrayList(); list.add(JUnitHelpers.getFile("file1", false)); play.setFiles(list); assertEquals(1, play.getFiles().size()); } /** * Test method for {@link org.jajuk.base.Playlist#setFIO(java.io.File)}. */ public final void testSetFIO() { // tested above in getFIO(); } /** * Test method for. * * {@link org.jajuk.base.Playlist#setParentDirectory(org.jajuk.base.Directory)} * . */ public final void testSetParentDirectory() { Playlist play = new Playlist("1", "name", null); assertNull(play.getDirectory()); Directory dir = JUnitHelpers.getDirectory(); play.setParentDirectory(dir); assertNotNull(play.getDirectory()); // also try setting it to null play.setParentDirectory(null); assertNull(play.getDirectory()); } /** * Test method for {@link org.jajuk.base.Playlist#shouldBeHidden()}. * * @throws Exception the exception */ public final void testShouldBeHidden() throws Exception { Directory dir = JUnitHelpers.getDirectory(); Playlist play = new Playlist("1", "name", dir); // related configuration Conf.setProperty(Const.CONF_OPTIONS_HIDE_UNMOUNTED, "false"); // always false as long as conf is set to "false" assertFalse(play.shouldBeHidden()); // related configuration Conf.setProperty(Const.CONF_OPTIONS_HIDE_UNMOUNTED, "true"); // now "true" because device is not mounted assertTrue(play.shouldBeHidden()); // now mount the device dir.getDevice().mount(true); // now "false" again, as we have the device mounted assertFalse(play.shouldBeHidden()); } /** * Test method for {@link org.jajuk.base.Playlist#toString()}. */ public final void testToString() { Playlist play = new Playlist("1", "name", null); // first test without directory JUnitHelpers.ToStringTest(play); Directory dir = JUnitHelpers.getDirectory(); // then with a directory play = new Playlist("1", "name", dir); JUnitHelpers.ToStringTest(play); } /** * Test method for {@link org.jajuk.base.Playlist#up(int)}. */ public final void testUp() { // tested as part of testDown() } /** * Test method for {@link org.jajuk.base.Playlist#getHits()}. * * @throws Exception the exception */ public final void testGetHits() throws Exception { FileManager.getInstance().clear(); Playlist play = createPlaylist(); // first without files assertEquals(0, play.getHits()); // then with some files play.addFile(JUnitHelpers.getFile("file11", false)); // still zero as file has no hits set assertEquals(0, play.getHits()); // now add a file with hit-count set File file = JUnitHelpers.getFile("file12", false); file.getTrack().setHits(3); play.addFile(file); // now hits are set assertEquals(3, play.getHits()); // add another file with different hit-count file = JUnitHelpers.getFile("file14", false); file.getTrack().setHits(11); play.addFile(file); // now hits accumulate assertEquals(14, play.getHits()); } /** * Test get hits null. * DOCUMENT_ME * * @throws Exception the exception */ public final void testGetHitsNull() throws Exception { Playlist play = createPlaylist(); play.setFiles(null); // first without files assertEquals(0, play.getHits()); } /** * Test method for {@link org.jajuk.base.Playlist#getDuration()}. * * @throws Exception the exception */ public final void testGetDuration() throws Exception { Playlist play = createPlaylist(); play.remove(0); play.remove(0); // at first no duration at all assertEquals(0, play.getDuration()); // when we add tracks, duration accumulates play.addFile(JUnitHelpers.getFile("file1", false)); // we use 120 seconds as length in "JUnitHelpers.getFile("file1", false)" assertEquals(120, play.getDuration()); // another file play.addFile(JUnitHelpers.getFile("file1", false)); // sums up two times 120 assertEquals(240, play.getDuration()); } /** * Test get duration null. * DOCUMENT_ME * * @throws Exception the exception */ public final void testGetDurationNull() throws Exception { Playlist play = createPlaylist(); play.setFiles(null); // at first no duration at all assertEquals(0, play.getDuration()); } /** * Test method for {@link org.jajuk.base.Playlist#getNbOfTracks()}. * * @throws Exception the exception */ public final void testGetNbOfTracks() throws Exception { Playlist play = createPlaylist(); play.remove(0); play.remove(0); assertEquals(0, play.getNbOfTracks()); play.addFile(JUnitHelpers.getFile("file1", false)); assertEquals(1, play.getNbOfTracks()); // another file play.addFile(JUnitHelpers.getFile("file1", false)); assertEquals(2, play.getNbOfTracks()); } /** * Test get nb of tracks null. * DOCUMENT_ME * * @throws Exception the exception */ public final void testGetNbOfTracksNull() throws Exception { Playlist play = createPlaylist(); play.setFiles(null); assertEquals(0, play.getNbOfTracks()); } } jajuk-1.9.6.orig/src/test/java/org/jajuk/base/TestAlbumManager.java0000644000175000017500000006424011720500104025014 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.base; import java.util.ArrayList; import java.util.List; import java.util.Set; import org.jajuk.JUnitHelpers; import org.jajuk.JajukTestCase; import org.jajuk.events.JajukEvent; import org.jajuk.events.JajukEvents; import org.jajuk.services.covers.Cover; import org.jajuk.services.players.IPlayerImpl; import org.jajuk.services.players.QueueModel; import org.jajuk.services.players.StackItem; import org.jajuk.services.startup.StartupCollectionService; import org.jajuk.services.tags.ITagImpl; import org.jajuk.services.webradio.WebRadio; import org.jajuk.util.Const; import org.jaudiotagger.tag.FieldDataInvalidException; import org.jaudiotagger.tag.KeyNotFoundException; /** * DOCUMENT_ME. */ public class TestAlbumManager extends JajukTestCase { /* * (non-Javadoc) * * @see junit.framework.TestCase#setUp() */ @Override protected void setUp() throws Exception { super.setUp(); } /** * Test method for {@link org.jajuk.base.AlbumManager#getLabel()}. */ public void testGetLabel() { assertEquals(Const.XML_ALBUMS, AlbumManager.getInstance().getLabel()); } /** * Test method for {@link org.jajuk.base.AlbumManager#getRegistrationKeys()}. */ public void testGetRegistrationKeys() { Set events = AlbumManager.getInstance().getRegistrationKeys(); assertTrue(events.contains(JajukEvents.FILE_LAUNCHED)); } /** * Test method for {@link org.jajuk.base.AlbumManager#getInstance()}. */ public void testGetInstance() { assertNotNull(AlbumManager.getInstance()); } /** * Test method for. * * {@link org.jajuk.base.AlbumManager#createID(java.lang.String, java.lang.String, long)} * . */ public void testCreateID() { assertNotNull(AlbumManager.createID("name", 3)); // other cases... assertNotNull(AlbumManager.createID("name", 0)); } /** * Test method for. * * {@link org.jajuk.base.AlbumManager#registerAlbum(java.lang.String, java.lang.String, long)} * . */ public void testRegisterAlbumStringStringStringLong() { assertNotNull(AlbumManager.getInstance().registerAlbum("1", "name1", 1)); assertNotNull(AlbumManager.getInstance().getAlbumByID("1")); } /** * Test register album empty artist. * DOCUMENT_ME */ public void testRegisterAlbumEmptyArtist() { AlbumManager.getInstance().clear(); assertNotNull(AlbumManager.getInstance().registerAlbum("1", "name1", 1)); } /** * Test method for. * * {@link org.jajuk.base.AlbumManager#registerAlbum(java.lang.String, java.lang.String, long)} * . */ public void testRegisterAlbumStringStringLong() { assertNotNull(AlbumManager.getInstance().registerAlbum("2", "name2", 1)); assertNotNull(AlbumManager.getInstance().getAlbumByName("name2")); } /** * Test method for. * * @throws Exception the exception * {@link org.jajuk.base.AlbumManager#changeAlbumName(org.jajuk.base.Album, java.lang.String)} * . */ public void testChangeAlbumName() throws Exception { StartupCollectionService.registerItemManagers(); Album album = AlbumManager.getInstance().registerAlbum("name3", 1); assertNotNull(album); AlbumManager.getInstance().changeAlbumName(album, "name4"); assertNull(AlbumManager.getInstance().getAlbumByName("name3")); assertNotNull(AlbumManager.getInstance().getAlbumByName("name4")); } /** * Test change album name with track. * DOCUMENT_ME * * @throws Exception the exception */ public void testChangeAlbumNameWithTrack() throws Exception { Album album = AlbumManager.getInstance().registerAlbum("name3", 1); assertNotNull(album); getTrack(5, album); getTrack(6, album); AlbumManager.getInstance().changeAlbumName(album, "name4"); assertNull(AlbumManager.getInstance().getAlbumByName("name3")); assertNotNull(AlbumManager.getInstance().getAlbumByName("name4")); } /** * Test change album name with queue. * DOCUMENT_ME * * @throws Exception the exception */ public void testChangeAlbumNameWithQueue() throws Exception { StartupCollectionService.registerItemManagers(); Album album = AlbumManager.getInstance().registerAlbum("name3", 1); assertNotNull(album); getTrack(5, album); getTrack(6, album); QueueModel.insert(new StackItem(album.getTracksCache().get(0).getFiles().get(0)), 0); QueueModel.goTo(0); AlbumManager.getInstance().changeAlbumName(album, "name4"); assertNull(AlbumManager.getInstance().getAlbumByName("name3")); assertNotNull(AlbumManager.getInstance().getAlbumByName("name4")); } /** * Test change album name same name. * DOCUMENT_ME * * @throws Exception the exception */ public void testChangeAlbumNameSameName() throws Exception { StartupCollectionService.registerItemManagers(); Album album = AlbumManager.getInstance().registerAlbum("3", "name3", 1); assertNotNull(album); // nothing happens if we use the same name Album album2 = AlbumManager.getInstance().changeAlbumName(album, "name3"); // we expect the same physical item assertTrue(album2.toString(), album == album2); } /** * Test method for. * * {@link org.jajuk.base.AlbumManager#format(java.lang.String)}. */ public void testFormat() { Album album = AlbumManager.getInstance().registerAlbum("3", "name3", 1); assertNotNull(album); assertEquals("Name1", AlbumManager.format("name1")); assertEquals("Name1", AlbumManager.format(" name1")); assertEquals("Name1", AlbumManager.format("name1 ")); assertEquals("Name1", AlbumManager.format(" name1 ")); assertEquals(" name1", AlbumManager.format("--_name1")); assertEquals("Na me1", AlbumManager.format("na-_me1")); assertEquals("Name1 name2", AlbumManager.format("name1 name2")); } /** * Test method for. * * {@link org.jajuk.base.AlbumManager#getAlbumByID(java.lang.String)}. */ public void testGetAlbumByID() { // tested above } /** * Test method for {@link org.jajuk.base.AlbumManager#getAlbums()}. */ public void testGetAlbums() { AlbumManager.getInstance().clear(); assertNotNull(AlbumManager.getInstance().registerAlbum("1", "name1", 1)); assertNotNull(AlbumManager.getInstance().registerAlbum("2", "name2", 1)); assertEquals(2, AlbumManager.getInstance().getAlbums().size()); } /** * Test method for {@link org.jajuk.base.AlbumManager#getAlbumsIterator()}. */ public void testGetAlbumsIterator() { AlbumManager.getInstance().clear(); assertNotNull(AlbumManager.getInstance().registerAlbum("1", "name1", 1)); assertNotNull(AlbumManager.getInstance().registerAlbum("2", "name2", 1)); assertTrue(AlbumManager.getInstance().getAlbumsIterator().hasNext()); } /** * Test method for. * * @throws Exception the exception * {@link org.jajuk.base.AlbumManager#getAssociatedAlbums(org.jajuk.base.Item)} * . */ public void testGetAssociatedAlbums() throws Exception { Album album = AlbumManager.getInstance().registerAlbum("1", "name1", 1); Track track = getTrack(1, album); List albums = AlbumManager.getInstance().getAssociatedAlbums(track); assertNotNull(albums); assertEquals(albums.toString(), 1, albums.size()); Genre genre = track.getGenre(); Artist artist = track.getArtist(); Year year = track.getYear(); albums = AlbumManager.getInstance().getAssociatedAlbums(genre); assertNotNull(albums); assertEquals(albums.toString(), 1, albums.size()); albums = AlbumManager.getInstance().getAssociatedAlbums(artist); assertNotNull(albums); assertEquals(albums.toString(), 1, albums.size()); albums = AlbumManager.getInstance().getAssociatedAlbums(year); assertNotNull(albums); assertEquals(albums.toString(), 1, albums.size()); } /** * Test method for. * * @throws Exception the exception * {@link org.jajuk.base.AlbumManager#getBestOfAlbums(boolean, int)}. */ public void testGetBestOfAlbums() throws Exception { AlbumManager.getInstance().clear(); Album album = AlbumManager.getInstance().registerAlbum("1", "name1", 1); getTrack(2, album); getTrack(3, album); album = AlbumManager.getInstance().registerAlbum("2", "name2", 1); getTrack(4, album); getTrack(5, album); album = AlbumManager.getInstance().registerAlbum("name3", 1); getTrack(4, album); getTrack(5, album); album = AlbumManager.getInstance().registerAlbum("name4", 1); getTrack(4, album); getTrack(5, album); album = AlbumManager.getInstance().registerAlbum("name5", 1); getTrack(4, album); getTrack(5, album); List albums = AlbumManager.getInstance().getBestOfAlbums(false, 3); assertEquals(albums.toString(), 3, albums.size()); // TODO verify with many albums and actual data } /** * Test get best of albums less. * DOCUMENT_ME * * @throws Exception the exception */ public void testGetBestOfAlbumsLess() throws Exception { AlbumManager.getInstance().clear(); Album album = AlbumManager.getInstance().registerAlbum("1", "name1", 1); getTrack(2, album); getTrack(3, album); album = AlbumManager.getInstance().registerAlbum("2", "name2", 1); getTrack(4, album); getTrack(5, album); album = AlbumManager.getInstance().registerAlbum("name3", 1); getTrack(4, album); getTrack(5, album); album = AlbumManager.getInstance().registerAlbum("name4", 1); getTrack(4, album); getTrack(5, album); album = AlbumManager.getInstance().registerAlbum("name5", 1); getTrack(4, album); getTrack(5, album); // check if we request more than we have, currently we get back some less // for some reason... List albums = AlbumManager.getInstance().getBestOfAlbums(false, 10); assertEquals(albums.toString(), 4, albums.size()); } /** * Test get best of album zero. * DOCUMENT_ME */ public void testGetBestOfAlbumZero() { AlbumManager.getInstance().clear(); List albums = AlbumManager.getInstance().getBestOfAlbums(false, 3); assertEquals(albums.toString(), 0, albums.size()); } /** * Test method for. * * @throws Exception the exception * {@link org.jajuk.base.AlbumManager#getNewestAlbums(boolean, int)}. */ public void testGetNewestAlbums() throws Exception { Album album = AlbumManager.getInstance().registerAlbum("name1", 1); getTrack(2, album); getTrack(3, album); album = AlbumManager.getInstance().registerAlbum("name2", 1); getTrack(4, album); getTrack(5, album); album = AlbumManager.getInstance().registerAlbum("name3", 1); getTrack(6, album); getTrack(7, album); album = AlbumManager.getInstance().registerAlbum("name4", 1); getTrack(8, album); getTrack(9, album); album = AlbumManager.getInstance().registerAlbum("name5", 1); getTrack(10, album); getTrack(11, album); List albums = AlbumManager.getInstance().getNewestAlbums(false, 3); assertEquals(albums.toString(), 3, albums.size()); // TODO verify with many albums and actual data } /** * Test method for. * * @throws Exception the exception * {@link org.jajuk.base.AlbumManager#getRarelyListenAlbums(boolean, int)}. */ public void testGetRarelyListenAlbums() throws Exception { AlbumManager.getInstance().clear(); Album album = AlbumManager.getInstance().registerAlbum("name1", 1); getTrack(2, album); getTrack(3, album); album = AlbumManager.getInstance().registerAlbum("name2", 1); getTrack(4, album); getTrack(5, album); album = AlbumManager.getInstance().registerAlbum("name3", 1); getTrack(6, album); getTrack(7, album); album = AlbumManager.getInstance().registerAlbum("name4", 1); getTrack(8, album); getTrack(9, album); album = AlbumManager.getInstance().registerAlbum("name5", 1); getTrack(10, album); getTrack(11, album); List albums = AlbumManager.getInstance().getRarelyListenAlbums(false, 3); assertEquals(albums.toString(), 3, albums.size()); // TODO verify with many albums and actual data } /** * Test method for {@link org.jajuk.base.AlbumManager#getMaxRate()}. * * @throws Exception the exception */ public void testGetMaxRate() throws Exception { AlbumManager.getInstance().clear(); Album album = AlbumManager.getInstance().registerAlbum("name1", 1); Track track = getTrack(1, album); track.setRate(12); track = getTrack(2, album); track.setRate(14); album = AlbumManager.getInstance().registerAlbum("name2", 1); track = getTrack(3, album); track.setRate(10); track = getTrack(4, album); track.setRate(15); album = AlbumManager.getInstance().registerAlbum("name3", 1); track = getTrack(5, album); track.setRate(10); track = getTrack(6, album); track.setRate(15); album = AlbumManager.getInstance().registerAlbum("name4", 1); track = getTrack(7, album); track.setRate(10); track = getTrack(8, album); track.setRate(15); album = AlbumManager.getInstance().registerAlbum("name5", 1); track = getTrack(9, album); track.setRate(10); track = getTrack(10, album); track.setRate(15); // zero without refresh assertEquals(0, AlbumManager.getInstance().getMaxRate()); // refresh it now AlbumManager.getInstance().refreshMaxRating(); // now it should be ok, it is the combined rate of all tracks assertEquals(26, AlbumManager.getInstance().getMaxRate()); } /** * Test method for {@link org.jajuk.base.AlbumManager#refreshMaxRating()}. */ public void testRefreshMaxRating() { // tested above } /** * Test method for. * * {@link org.jajuk.base.AlbumManager#update(org.jajuk.events.JajukEvent)}. */ public void testUpdate() { // do it a number of times to trigger the refreshMax after 10 times AlbumManager.getInstance().update(new JajukEvent(JajukEvents.FILE_LAUNCHED, null)); AlbumManager.getInstance().update(new JajukEvent(JajukEvents.FILE_LAUNCHED, null)); AlbumManager.getInstance().update(new JajukEvent(JajukEvents.FILE_LAUNCHED, null)); AlbumManager.getInstance().update(new JajukEvent(JajukEvents.FILE_LAUNCHED, null)); AlbumManager.getInstance().update(new JajukEvent(JajukEvents.FILE_LAUNCHED, null)); AlbumManager.getInstance().update(new JajukEvent(JajukEvents.FILE_LAUNCHED, null)); AlbumManager.getInstance().update(new JajukEvent(JajukEvents.FILE_LAUNCHED, null)); AlbumManager.getInstance().update(new JajukEvent(JajukEvents.FILE_LAUNCHED, null)); AlbumManager.getInstance().update(new JajukEvent(JajukEvents.FILE_LAUNCHED, null)); AlbumManager.getInstance().update(new JajukEvent(JajukEvents.FILE_LAUNCHED, null)); AlbumManager.getInstance().update(new JajukEvent(JajukEvents.FILE_LAUNCHED, null)); AlbumManager.getInstance().update(new JajukEvent(JajukEvents.FILE_LAUNCHED, null)); AlbumManager.getInstance().update(new JajukEvent(JajukEvents.FILE_LAUNCHED, null)); AlbumManager.getInstance().update(new JajukEvent(JajukEvents.FILE_LAUNCHED, null)); AlbumManager.getInstance().update(new JajukEvent(JajukEvents.FILE_LAUNCHED, null)); AlbumManager.getInstance().update(new JajukEvent(JajukEvents.FILE_LAUNCHED, null)); } /** * Test method for. * * {@link org.jajuk.base.AlbumManager#getAlbumByName(java.lang.String)}. */ public void testGetAlbumByName() { // tested above } /** * Test method for {@link org.jajuk.base.AlbumManager#orderCache()}. * * @throws Exception the exception */ public void testOrderCache() throws Exception { AlbumManager.getInstance().clear(); Album album = AlbumManager.getInstance().registerAlbum("1", "name1", 1); getTrack(2, album); getTrack(3, album); album = AlbumManager.getInstance().registerAlbum("2", "name2", 1); getTrack(4, album); getTrack(5, album); AlbumManager.getInstance().orderCache(); } /** * Gets the track. * * @param i DOCUMENT_ME * @param album DOCUMENT_ME * @return the track * @throws Exception the exception */ @SuppressWarnings("unchecked") private Track getTrack(int i, Album album) throws Exception { Genre genre = JUnitHelpers.getGenre("name"); album.setProperty(Const.XML_ALBUM_DISCOVERED_COVER, Const.COVER_NONE); // don't read covers for this test Artist artist = JUnitHelpers.getArtist("atist_" + i); Year year = YearManager.getInstance().registerYear(Integer.valueOf(i).toString()); IPlayerImpl imp = new MockPlayer(); Class cl = (Class) imp.getClass(); ITagImpl tagimp = new MyTagImpl(); Class tl = (Class) tagimp.getClass(); Type type = new Type(Integer.valueOf(i).toString(), "name", "mp3", cl, tl); Track track = TrackManager.getInstance().registerTrack("track_" + i, album, genre, artist, 120, year, 1, type, 1); Device device = JUnitHelpers.getDevice(); Directory dir = JUnitHelpers.getDirectory(); if (!device.isMounted()) { device.mount(true); } File file = FileManager.getInstance().registerFile("file_" + i + ".tst", dir, track, 200, 100); file.getFIO().createNewFile(); track.addFile(file); TypeManager.getInstance().registerType("test", "tst", cl, tl); return track; } /** * DOCUMENT_ME. */ public static class MyTagImpl implements ITagImpl { /* * (non-Javadoc) * * @see org.jajuk.services.tags.ITagImpl#commit() */ @Override public void commit() throws Exception { } /* * (non-Javadoc) * * @see org.jajuk.services.tags.ITagImpl#getAlbumArtist() */ @Override public String getAlbumArtist() throws Exception { return null; } /* * (non-Javadoc) * * @see org.jajuk.services.tags.ITagImpl#getAlbumName() */ @Override public String getAlbumName() throws Exception { return null; } /* * (non-Javadoc) * * @see org.jajuk.services.tags.ITagImpl#getName() */ @Override public String getArtistName() throws Exception { return null; } /* * (non-Javadoc) * * @see org.jajuk.services.tags.ITagImpl#getComment() */ @Override public String getComment() throws Exception { return null; } /* * (non-Javadoc) * * @see org.jajuk.services.tags.ITagImpl#getDiscNumber() */ @Override public long getDiscNumber() throws Exception { return 0; } /* * (non-Javadoc) * * @see org.jajuk.services.tags.ITagImpl#getLength() */ @Override public long getLength() throws Exception { return 0; } /* * (non-Javadoc) * * @see org.jajuk.services.tags.ITagImpl#getOrder() */ @Override public long getOrder() throws Exception { return 0; } /* * (non-Javadoc) * * @see org.jajuk.services.tags.ITagImpl#getQuality() */ @Override public long getQuality() throws Exception { return 0; } /* * (non-Javadoc) * * @see org.jajuk.services.tags.ITagImpl#getGenreName() */ @Override public String getGenreName() throws Exception { return null; } /* * (non-Javadoc) * * @see org.jajuk.services.tags.ITagImpl#getTrackName() */ @Override public String getTrackName() throws Exception { return null; } /* * (non-Javadoc) * * @see org.jajuk.services.tags.ITagImpl#getYear() */ @Override public String getYear() throws Exception { return null; } /* * (non-Javadoc) * * @see org.jajuk.services.tags.ITagImpl#setAlbumArtist(java.lang.String) */ @Override public void setAlbumArtist(String sAlbumArtist) throws Exception { } /* * (non-Javadoc) * * @see org.jajuk.services.tags.ITagImpl#setAlbumName(java.lang.String) */ @Override public void setAlbumName(String sAlbumName) throws Exception { } /* * (non-Javadoc) * * @see org.jajuk.services.tags.ITagImpl#setArtistName(java.lang.String) */ @Override public void setArtistName(String sArtistName) throws Exception { } /* * (non-Javadoc) * * @see org.jajuk.services.tags.ITagImpl#setComment(java.lang.String) */ @Override public void setComment(String sComment) throws Exception { } /* * (non-Javadoc) * * @see org.jajuk.services.tags.ITagImpl#setDiscNumber(long) */ @Override public void setDiscNumber(long discnumber) throws Exception { } /* * (non-Javadoc) * * @see org.jajuk.services.tags.ITagImpl#setFile(java.io.File) */ @Override public void setFile(java.io.File fio) throws Exception { } /* * (non-Javadoc) * * @see org.jajuk.services.tags.ITagImpl#setOrder(long) */ @Override public void setOrder(long lOrder) throws Exception { } /* * (non-Javadoc) * * @see org.jajuk.services.tags.ITagImpl#setGenreName(java.lang.String) */ @Override public void setGenreName(String genre) throws Exception { } /* * (non-Javadoc) * * @see org.jajuk.services.tags.ITagImpl#setTrackName(java.lang.String) */ @Override public void setTrackName(String sTrackName) throws Exception { } /* * (non-Javadoc) * * @see org.jajuk.services.tags.ITagImpl#setYear(java.lang.String) */ @Override public void setYear(String sYear) throws Exception { } /* * (non-Javadoc) * * @see org.jajuk.services.tags.ITagImpl#getTagField(java.lang.String) */ @Override public String getTagField(String tagFieldKey) throws Exception { return null; } /* * (non-Javadoc) * * @see org.jajuk.services.tags.ITagImpl#setTagField(java.lang.String, java.lang.String) */ @Override public void setTagField(String tagFieldKey, String tagFieldValue) throws FieldDataInvalidException, KeyNotFoundException { } /* * (non-Javadoc) * * @see org.jajuk.services.tags.ITagImpl#deleteLyrics() */ @Override public void deleteLyrics() throws Exception { } /* * (non-Javadoc) * * @see org.jajuk.services.tags.ITagImpl#getLyrics() */ @Override public String getLyrics() throws Exception { return null; } /* * (non-Javadoc) * * @see org.jajuk.services.tags.ITagImpl#setLyrics(java.lang.String) */ @Override public void setLyrics(String sLyrics) throws Exception { } /* * (non-Javadoc) * * @see org.jajuk.services.tags.ITagImpl#getSupportedTagFields() */ @Override public ArrayList getSupportedTagFields() { // TODO Auto-generated method stub return null; } /* (non-Javadoc) * @see org.jajuk.services.tags.ITagImpl#getCovers() */ @Override public List getCovers() throws Exception { // TODO Auto-generated method stub return null; } } // needs to be public to be callable from the outside... /** * DOCUMENT_ME. */ public static class MockPlayer implements IPlayerImpl { /* (non-Javadoc) * @see org.jajuk.services.players.IPlayerImpl#stop() */ @Override public void stop() throws Exception { } /* (non-Javadoc) * @see org.jajuk.services.players.IPlayerImpl#setVolume(float) */ @Override public void setVolume(float fVolume) throws Exception { } /* (non-Javadoc) * @see org.jajuk.services.players.IPlayerImpl#seek(float) */ @Override public void seek(float fPosition) { } /* (non-Javadoc) * @see org.jajuk.services.players.IPlayerImpl#resume() */ @Override public void resume() throws Exception { } /* (non-Javadoc) * @see org.jajuk.services.players.IPlayerImpl#play(org.jajuk.services.webradio.WebRadio, float) */ @Override public void play(WebRadio radio, float fVolume) throws Exception { } /* (non-Javadoc) * @see org.jajuk.services.players.IPlayerImpl#play(org.jajuk.base.File, float, long, float) */ @Override public void play(File file, float fPosition, long length, float fVolume) throws Exception { } /* (non-Javadoc) * @see org.jajuk.services.players.IPlayerImpl#pause() */ @Override public void pause() throws Exception { } /* (non-Javadoc) * @see org.jajuk.services.players.IPlayerImpl#getState() */ @Override public int getState() { return 0; } /* (non-Javadoc) * @see org.jajuk.services.players.IPlayerImpl#getElapsedTime() */ @Override public long getElapsedTimeMillis() { return 0; } /* (non-Javadoc) * @see org.jajuk.services.players.IPlayerImpl#getCurrentVolume() */ @Override public float getCurrentVolume() { return 0; } /* (non-Javadoc) * @see org.jajuk.services.players.IPlayerImpl#getCurrentPosition() */ @Override public float getCurrentPosition() { return 0; } /* (non-Javadoc) * @see org.jajuk.services.players.IPlayerImpl#getCurrentLength() */ @Override public long getDurationSec() { return 0; } /* (non-Javadoc) * @see org.jajuk.services.players.IPlayerImpl#getActuallyPlayedTimeMillis() */ @Override public long getActuallyPlayedTimeMillis() { // TODO Auto-generated method stub return 0; } } } jajuk-1.9.6.orig/src/test/java/org/jajuk/base/TestAlbum.java0000644000175000017500000005006511720500104023521 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.base; import java.util.Date; import org.apache.commons.io.FileUtils; import org.jajuk.JUnitHelpers; import org.jajuk.JajukTestCase; import org.jajuk.services.startup.StartupCollectionService; import org.jajuk.util.Const; import org.jajuk.util.Messages; /** * DOCUMENT_ME. */ public class TestAlbum extends JajukTestCase { /** * Test method for {@link org.jajuk.base.Album#getDesc()}. */ public final void testGetDesc() { Album album = new Album("1", "name", 123); assertNotNull(album.getDesc()); assertFalse(album.getDesc().isEmpty()); } /** * Test method for {@link org.jajuk.base.Album#getAny()}. */ public final void testGetAny() { // need item managers to do this step StartupCollectionService.registerItemManagers(); Album album = new Album("1", "name", 123); /* * album.getTracksCache().add(getTrack(album)); * * album.setProperty(Const.XML_TRACK_DISCOVERY_DATE, System.) String str = album.getAny(); * assertFalse(str.isEmpty()); */ // add a genre and year and check again album.getTracksCache().add(getTrack(album)); assertFalse(album.getAny().isEmpty()); /* * assertFalse("getAny() should return differently as soon as we have genre and year" , * str.equals(album.getAny())); */ } /** * Test get any album artist. * DOCUMENT_ME */ public final void testGetAnyAlbumArtist() { // need item managers to do this step StartupCollectionService.registerItemManagers(); Album album = new Album("1", "name", 123); /* * album.getTracksCache().add(getTrack(album)); * * album.setProperty(Const.XML_TRACK_DISCOVERY_DATE, System.) String str = album.getAny(); * assertFalse(str.isEmpty()); */ // add a genre and year and check again Track track = getTrack(album); track.setAlbumArtist(new AlbumArtist("4", "artist")); album.getTracksCache().add(track); assertFalse(album.getAny().isEmpty()); /* * assertFalse("getAny() should return differently as soon as we have genre and year" , * str.equals(album.getAny())); */ } /** * Gets the track. * * @param album DOCUMENT_ME * @return the track */ private Track getTrack(Album album) { return new Track("1", "trackname", album, getGenre(), getArtist(), 123, getYear(), 1, new Type( "3", "typename", "ext", null, null), 1); } /** * Gets the artist. * * @return the artist */ private Artist getArtist() { return new Artist("1", "artistname"); } /** * Gets the genre. * * @return the genre */ private Genre getGenre() { return new Genre("1", "genrename"); } /** * Gets the year. * * @return the year */ private Year getYear() { return new Year("1", "yearname"); } /** * Test method for {@link org.jajuk.base.Album#getLabel()}. */ public final void testGetLabel() { Album album = new Album("1", "name", 123); assertFalse(album.getLabel().isEmpty()); } /** * Test method for. * * {@link org.jajuk.base.Album#getHumanValue(java.lang.String)}. */ public final void testGetHumanValue() { // some of the lines below can require the ItemManagers to be registered // correctly StartupCollectionService.registerItemManagers(); Album album = new Album("1", "name", 123); assertFalse(album.getHumanValue(Const.XML_ALBUM).isEmpty()); // things are empty before adding a track... assertTrue(album.getHumanValue(Const.XML_ARTIST).isEmpty()); assertTrue(album.getHumanValue(Const.XML_GENRE).isEmpty()); assertTrue(album.getHumanValue(Const.XML_YEAR).isEmpty()); // add a genre and year Track track = getTrack(album); track.setProperty(Const.XML_TRACK_DISCOVERY_DATE, new Date()); album.getTracksCache().add(track); assertFalse(album.getHumanValue(Const.XML_GENRE).isEmpty()); assertFalse(album.getHumanValue(Const.XML_ARTIST).isEmpty()); assertFalse(album.getHumanValue(Const.XML_YEAR).isEmpty()); assertFalse(album.getHumanValue(Const.XML_TRACK_RATE).isEmpty()); assertFalse(album.getHumanValue(Const.XML_TRACK_LENGTH).isEmpty()); assertFalse(album.getHumanValue(Const.XML_TRACKS).isEmpty()); assertFalse(album.getHumanValue(Const.XML_TRACK_DISCOVERY_DATE).isEmpty()); assertEquals("Value: " + album.getHumanValue(Const.XML_TRACK_HITS), "0", album .getHumanValue(Const.XML_TRACK_HITS)); assertFalse(album.getHumanValue(Const.XML_ANY).isEmpty()); assertTrue(album.getHumanValue(Const.XML_ALBUM_ARTIST).isEmpty()); assertTrue(album.getHumanValue(Const.XML_ALBUM_DISCOVERED_COVER).isEmpty()); } /** * Test method for {@link org.jajuk.base.Album#getIconRepresentation()}. */ public final void testGetIconRepresentation() { Album album = new Album("1", "name", 123); assertNotNull(album.getIconRepresentation()); } /** * Test method for {@link org.jajuk.base.Album#getRate()}. */ public final void testGetRate() { Album album = new Album("1", "name", 123); assertEquals(0, album.getRate()); // add track to have some useful rate Track track = getTrack(album); track.setRate(3); album.getTracksCache().add(track); assertEquals(3, album.getRate()); } /** * Test method for. * * {@link org.jajuk.base.Album#Album(java.lang.String, java.lang.String, java.lang.String, long)} * . */ public final void testAlbum() { new Album("1", "name", 123); } /** * Test method for {@link org.jajuk.base.Album#getDiscID()}. */ public final void testGetDiscID() { Album album = new Album("1", "name", 123); assertEquals(123, album.getDiscID()); } /** * Test method for {@link org.jajuk.base.Album#getName2()}. */ public final void testGetName2() { Album album = new Album("1", "name", 123); assertEquals("name", album.getName2()); album = new Album("1", Const.UNKNOWN_ALBUM, 123); assertEquals(Messages.getString(Const.UNKNOWN_ALBUM), album.getName2()); } /** * Test method for {@link org.jajuk.base.Album#toString()}. */ public final void testToString() { Album album = new Album("1", "name", 123); JUnitHelpers.ToStringTest(album); } /** * Test method for. * * {@link org.jajuk.base.Album#compareTo(org.jajuk.base.Album)}. */ public final void testCompareTo() { Album album = new Album("1", "name", 123); Album equal = new Album("1", "name", 123); Album nonequal = new Album("2", "name", 123); JUnitHelpers.CompareToTest(album, equal, nonequal); } /** * Test method for {@link org.jajuk.base.Album#isUnknown()}. */ public final void testIsUnknown() { Album album = new Album("1", "name", 123); assertFalse(album.isUnknown()); album = new Album("1", Const.UNKNOWN_ALBUM, 123); assertTrue(album.isUnknown()); } /** * Test method for {@link org.jajuk.base.Album#findCover()}. * * @throws Exception the exception */ public final void testGetCoverFile() throws Exception { Album album = new Album("1", "name", 123); // no file at first assertNull(album.findCover()); // none album.setProperty(Const.XML_ALBUM_DISCOVERED_COVER, Const.COVER_NONE); assertNull(album.findCover()); // set a cover file which does not exist // We need to make the cover inside a known device Device tmpDevice = DeviceManager.getInstance().registerDevice("tmp", "tmpDevice", Device.TYPE_DIRECTORY, System.getProperty("java.io.tmpdir")); tmpDevice.mount(false); new java.io.File(System.getProperty("java.io.tmpdir"), "cover.tst").delete(); album.setProperty(Const.XML_ALBUM_DISCOVERED_COVER, System.getProperty("java.io.tmpdir") + java.io.File.separator + "cover.tst"); assertNull(album.findCover()); // then create the file and try again FileUtils.writeStringToFile( new java.io.File(System.getProperty("java.io.tmpdir"), "cover.tst"), ""); album.setProperty(Const.XML_ALBUM_DISCOVERED_COVER, System.getProperty("java.io.tmpdir") + java.io.File.separator + "cover.tst"); assertNotNull(album.findCover()); // try with a track and no cover file set album.removeProperty(Const.XML_ALBUM_DISCOVERED_COVER); Track track = getTrack(album); track.addFile(getFile(7, track)); track.addFile(getFile(8, track)); album.getTracksCache().add(track); assertNull(album.findCover()); // Unregister the tmp device DeviceManager.getInstance().removeDevice(tmpDevice); // TODO: some code is still not covered here, need to find out how to do // that... } /** * Test method for {@link org.jajuk.base.Album#getThumbnail(int)}. * * @throws Exception the exception */ public final void testGetThumbnail() throws Exception { JUnitHelpers.createSessionDirectory(); Album album = new Album("1", "name", 123); assertNotNull(album.getThumbnail(100)); // TODO: actual code is not well covered right now, need to add some more // test-code here... } /** * Test method for {@link org.jajuk.base.Album#getGenre()}. */ public final void testGetGenre() { Album album = new Album("1", "name", 123); // now genre without track assertNull(album.getGenre()); // genre with at least one track album.getTracksCache().add(getTrack(album)); assertNotNull(album.getGenre()); } /** * Test method for {@link org.jajuk.base.Album#getArtist()}. */ public final void testGetArtist() { Album album = new Album("1", "name", 123); // no artist without track assertNull(album.getArtist()); album.getTracksCache().add(getTrack(album)); assertNotNull(album.getGenre()); // add a second track with different artist Track track = new Track("2", "trackname2", album, getGenre(), new Artist("2", "artistname2"), 123, getYear(), 1, new Type("4", "typename2", "ext", null, null), 1); album.getTracksCache().add(track); // now null again as multiple different artists are in the list assertNull(album.getArtist()); } /** * Test method for {@link org.jajuk.base.Album#getYear()}. */ public final void testGetYear() { Album album = new Album("1", "name", 123); // no artist without track assertNull(album.getYear()); album.getTracksCache().add(getTrack(album)); assertNotNull(album.getYear()); // add a second track with different year Track track = new Track("2", "trackname2", album, getGenre(), getArtist(), 123, new Year("2", "yearname2"), 1, new Type("4", "typename2", "ext", null, null), 1); album.getTracksCache().add(track); // now null again as multiple different artists are in the list assertNull(album.getYear()); } /** * Test method for {@link org.jajuk.base.Album#getDuration()}. */ public final void testGetDuration() { Album album = new Album("1", "name", 123); // zero without any track assertEquals(0, album.getDuration()); // add a track with duration 123 album.getTracksCache().add(getTrack(album)); assertEquals(123, album.getDuration()); // another one, this is summed up album.getTracksCache().add(getTrack(album)); assertEquals(246, album.getDuration()); } /** * Test method for {@link org.jajuk.base.Album#getNbOfTracks()}. */ public final void testGetNbOfTracks() { Album album = new Album("1", "name", 123); // zero without any track assertEquals(0, album.getNbOfTracks()); // add a track with duration 123 album.getTracksCache().add(getTrack(album)); assertEquals(1, album.getNbOfTracks()); // another one, this is summed up album.getTracksCache().add(getTrack(album)); assertEquals(2, album.getNbOfTracks()); } /** * Test method for {@link org.jajuk.base.Album#getHits()}. */ public final void testGetHits() { Album album = new Album("1", "name", 123); // zero without any track assertEquals(0, album.getHits()); // still zero as tracks have zero hits usually album.getTracksCache().add(getTrack(album)); assertEquals(0, album.getHits()); // another one, this has some hits Track track = getTrack(album); track.setHits(3); album.getTracksCache().add(track); assertEquals(3, album.getHits()); // and another one, now it sums up track = getTrack(album); track.setHits(5); album.getTracksCache().add(track); assertEquals(8, album.getHits()); } /** * Gets the file. * * @param i DOCUMENT_ME * @param track DOCUMENT_ME * @return the file * @throws Exception the exception */ private File getFile(int i, Track track) throws Exception { Device device = JUnitHelpers.getDevice(); if (!device.isMounted()) { device.mount(true); } Directory dir = new Directory(Integer.valueOf(i).toString(), "", null, device); return new org.jajuk.base.File(Integer.valueOf(i).toString(), "test.tst", dir, track, 120, 70); } /** * Test method for {@link org.jajuk.base.Album#containsReadyFiles()}. * * @throws Exception the exception */ public final void testContainsReadyFiles() throws Exception { Album album = new Album("1", "name", 123); // no files assertFalse(album.containsReadyFiles()); // add a track/file Track track = getTrack(album); track.addFile(getFile(6, track)); album.getTracksCache().add(track); assertTrue(album.containsReadyFiles()); } /** * Test method for {@link org.jajuk.base.Album#getDiscoveryDate()}. */ public final void testGetDiscoveryDate() { Album album = new Album("1", "name", 123); assertNull(album.getDiscoveryDate()); Track track = getTrack(album); track.setDiscoveryDate(new Date()); album.getTracksCache().add(track); assertNotNull(album.getDiscoveryDate()); } /** * Test method for. * * {@link org.jajuk.base.Album#matches(java.lang.String, java.lang.String)}. */ public final void testMatches() { Album album = new Album("1", "myname", 123); // true if either of both is null !? assertTrue(album.matches(null, null)); assertTrue(album.matches(Const.XML_ALBUM, null)); assertTrue(album.matches(null, ".*art.*")); // false when not "ALBUM" or "GENRE" assertFalse(album.matches(Const.XML_ALBUM_ARTIST, ".*art.*")); // useful match? assertTrue(album.matches(Const.XML_ALBUM, "my")); assertTrue(album.matches(Const.XML_ALBUM, "name")); assertFalse(album.matches(Const.XML_ALBUM, "notexist")); // false without Genre assertFalse(album.matches(Const.XML_GENRE, ".")); Track track = getTrack(album); album.getTracksCache().add(track); // now the genre should be found as well assertTrue(album.matches(Const.XML_GENRE, "genrename")); } /** * Test method for {@link org.jajuk.base.Album#resetTracks()}. */ public final void testResetTracks() { Album album = new Album("1", "name", 123); // nothing happens without tracks album.resetTracks(); // add tracks Track track = getTrack(album); album.getTracksCache().add(track); assertEquals(1, album.getTracksCache().size()); // reset purges the tracks album.resetTracks(); assertEquals(0, album.getTracksCache().size()); } /** * Test method for {@link org.jajuk.base.Album#getTracksCache()}. */ public final void testGetTracksCache() { // tested in the other tests } /** * Test method for {@link org.jajuk.base.Album#getAnyTrack()}. */ public final void testGetAnyTrack() { Album album = new Album("1", "name", 123); // nothing to return without tracks assertNull(album.getAnyTrack()); // add tracks Track track = getTrack(album); album.getTracksCache().add(track); // now we get back the first track assertNotNull(album.getAnyTrack()); } /** * Test method for. * * {@link org.jajuk.base.Album#setAvailableThumb(int, boolean)}. */ public final void testSetAndIsAvailableThumb() { Album album = new Album("1", "name", 123); assertFalse(album.isThumbAvailable(50)); album.setAvailableThumb(50, true); assertTrue(album.isThumbAvailable(50)); // test once more with a new album to create the thumbs-array there as well album = new Album("1", "name", 123); album.setAvailableThumb(100, false); } /** * Test get artist or album artist_ unknown. * DOCUMENT_ME */ public final void testGetArtistOrAlbumArtist_Unknown() { StartupCollectionService.registerItemManagers(); Album album = new Album("1", "name", 123); // unknown artist is returned without a track assertEquals(Const.UNKNOWN_ARTIST, album.getArtistOrALbumArtist()); } /** * Test get artist or album artist_ album artist. * DOCUMENT_ME */ public final void testGetArtistOrAlbumArtist_AlbumArtist() { // need item managers to do this step StartupCollectionService.registerItemManagers(); Album album = new Album("1", "name", 123); // add a genre and year and check again Track track = getTrack(album); track.setAlbumArtist(new AlbumArtist("4", "albumartist")); album.getTracksCache().add(track); album.getTracksCache().add( new Track("1", "trackname", album, getGenre(), new Artist("2", "artistname2"), 123, getYear(), 1, new Type("3", "typename", "ext", null, null), 1)); // here we should get the album artist from the Track because we have two tracks with different // artists assertEquals("albumartist", album.getArtistOrALbumArtist()); } /** * Test get artist or album artist_ track artist. * DOCUMENT_ME */ public final void testGetArtistOrAlbumArtist_TrackArtist() { // need item managers to do this step StartupCollectionService.registerItemManagers(); Album album = new Album("1", "name", 123); // add a genre and year and check again Track track = getTrack(album); album.getTracksCache().add(track); // here we should get the artist from the Track as no album artist is set assertEquals("artistname", album.getArtistOrALbumArtist()); } /** * Test get artist or album artist_ track artist2. * DOCUMENT_ME */ public final void testGetArtistOrAlbumArtist_TrackArtist2() { // need item managers to do this step StartupCollectionService.registerItemManagers(); Album album = new Album("1", "name", 123); // add a genre and year and check again Track track = getTrack(album); track.setAlbumArtist(new AlbumArtist("4", "albumartist")); album.getTracksCache().add(track); // here we should get the artist from the Track as all tracks have the same artist assertEquals("artistname", album.getArtistOrALbumArtist()); } /** * Test get artist or album artist_ album artist unknown. * DOCUMENT_ME */ public final void testGetArtistOrAlbumArtist_AlbumArtistUnknown() { // need item managers to do this step StartupCollectionService.registerItemManagers(); Album album = new Album("1", "name", 123); // add a genre and year and check again Track track = getTrack(album); track.setAlbumArtist(new AlbumArtist("4", Const.UNKNOWN_ARTIST)); album.getTracksCache().add(track); album.getTracksCache().add( new Track("1", "trackname", album, getGenre(), new Artist("2", "artistname2"), 123, getYear(), 1, new Type("3", "typename", "ext", null, null), 1)); // here we should get the artist from the first Track as the album artist is "unknown" assertEquals("artistname", album.getArtistOrALbumArtist()); } } jajuk-1.9.6.orig/src/test/java/org/jajuk/base/TestTrack.java0000644000175000017500000001707711720500104023533 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision: 3132 $ */ package org.jajuk.base; import org.jajuk.JUnitHelpers; import org.jajuk.JajukTestCase; import org.junit.Test; /** * */ public class TestTrack extends JajukTestCase { @Override protected void setUp() throws Exception { super.setUp(); } /** * Test method for {@link org.jajuk.base.Track#getDesc()}. */ @Test public void testGetDesc() { //TODO To be implemented } /** * Test method for {@link org.jajuk.base.Track#getAny()}. */ @Test public void testGetAny() { //TODO To be implemented } /** * Test method for {@link org.jajuk.base.Track#getLabel()}. */ @Test public void testGetLabel() { //TODO To be implemented } /** * Test method for {@link org.jajuk.base.Track#getHumanValue(java.lang.String)}. */ @Test public void testGetHumanValue() { //TODO To be implemented } /** * Test method for {@link org.jajuk.base.Track#getIconRepresentation()}. */ @Test public void testGetIconRepresentation() { //TODO To be implemented } /** * Test method for {@link org.jajuk.base.Track#getRate()}. */ @Test public void testGetRate() { //TODO To be implemented } /** * Test method for {@link org.jajuk.base.Track#toString()}. */ @Test public void testToString() { //TODO To be implemented } /** * Test method for {@link org.jajuk.base.Track#Track(java.lang.String, java.lang.String, org.jajuk.base.Album, org.jajuk.base.Genre, org.jajuk.base.Artist, long, org.jajuk.base.Year, long, org.jajuk.base.Type, long)}. */ @Test public void testTrack() { //TODO To be implemented } /** * Test method for {@link org.jajuk.base.Track#compareTo(org.jajuk.base.Track)}. */ @Test public void testCompareTo() { //TODO To be implemented } /** * Test method for {@link org.jajuk.base.Track#getAlbum()}. */ @Test public void testGetAlbum() { //TODO To be implemented } /** * Test method for {@link org.jajuk.base.Track#getFiles()}. */ @Test public void testGetFiles() { //TODO To be implemented } /** * Test method for {@link org.jajuk.base.Track#removeFile(org.jajuk.base.File)}. */ @Test public void testRemoveFile() { // Set-up... File file = JUnitHelpers.getFile(); Track track = file.getTrack(); // Remove the reference track.removeFile(file); // Check that associated track no more contains this file assertFalse(file.getTrack().getFiles().contains(file)); } /** * Test method for {@link org.jajuk.base.Track#getFiles(java.util.Set)}. */ @Test public void testGetFilesSetOfFile() { //TODO To be implemented } /** * Test method for {@link org.jajuk.base.Track#getReadyFiles()}. */ @Test public void testGetReadyFiles() { //TODO To be implemented } /** * Test method for {@link org.jajuk.base.Track#getReadyFiles(java.util.Set)}. */ @Test public void testGetReadyFilesSetOfFile() { //TODO To be implemented } /** * Test method for {@link org.jajuk.base.Track#getTotalSize()}. */ @Test public void testGetTotalSize() { //TODO To be implemented } /** * Test method for {@link org.jajuk.base.Track#getBestFile(boolean)}. */ @Test public void testGetBestFile() { //TODO To be implemented } /** * Test method for {@link org.jajuk.base.Track#getHits()}. */ @Test public void testGetHits() { //TODO To be implemented } /** * Test method for {@link org.jajuk.base.Track#getComment()}. */ @Test public void testGetComment() { //TODO To be implemented } /** * Test method for {@link org.jajuk.base.Track#getOrder()}. */ @Test public void testGetOrder() { //TODO To be implemented } /** * Test method for {@link org.jajuk.base.Track#getDiscNumber()}. */ @Test public void testGetDiscNumber() { //TODO To be implemented } /** * Test method for {@link org.jajuk.base.Track#getAlbumArtist()}. */ @Test public void testGetAlbumArtist() { //TODO To be implemented } /** * Test method for {@link org.jajuk.base.Track#getAlbumArtistOrArtist()}. */ @Test public void testGetAlbumArtistOrArtist() { //TODO To be implemented } /** * Test method for {@link org.jajuk.base.Track#getYear()}. */ @Test public void testGetYear() { //TODO To be implemented } /** * Test method for {@link org.jajuk.base.Track#getDuration()}. */ @Test public void testGetDuration() { //TODO To be implemented } /** * Test method for {@link org.jajuk.base.Track#getDiscoveryDate()}. */ @Test public void testGetDiscoveryDate() { //TODO To be implemented } /** * Test method for {@link org.jajuk.base.Track#getType()}. */ @Test public void testGetType() { //TODO To be implemented } /** * Test method for {@link org.jajuk.base.Track#getArtist()}. */ @Test public void testGetArtist() { //TODO To be implemented } /** * Test method for {@link org.jajuk.base.Track#getGenre()}. */ @Test public void testGetGenre() { //TODO To be implemented } /** * Test method for {@link org.jajuk.base.Track#addFile(org.jajuk.base.File)}. */ @Test public void testAddFile() { //TODO To be implemented } /** * Test method for {@link org.jajuk.base.Track#setHits(long)}. */ @Test public void testSetHits() { //TODO To be implemented } /** * Test method for {@link org.jajuk.base.Track#incHits()}. */ @Test public void testIncHits() { //TODO To be implemented } /** * Test method for {@link org.jajuk.base.Track#setPreference(long)}. */ @Test public void testSetPreference() { //TODO To be implemented } /** * Test method for {@link org.jajuk.base.Track#updateRate()}. */ @Test public void testUpdateRate() { //TODO To be implemented } /** * Test method for {@link org.jajuk.base.Track#setRate(long)}. */ @Test public void testSetRate() { //TODO To be implemented } /** * Test method for {@link org.jajuk.base.Track#setComment(java.lang.String)}. */ @Test public void testSetComment() { //TODO To be implemented } /** * Test method for {@link org.jajuk.base.Track#setAlbumArtist(org.jajuk.base.AlbumArtist)}. */ @Test public void testSetAlbumArtist() { //TODO To be implemented } /** * Test method for {@link org.jajuk.base.Track#setDiscoveryDate(java.util.Date)}. */ @Test public void testSetDiscoveryDate() { //TODO To be implemented } /** * Test method for {@link org.jajuk.base.Track#shouldBeHidden()}. */ @Test public void testShouldBeHidden() { //TODO To be implemented } /** * Test method for {@link org.jajuk.base.Track#getFilesString()}. */ @Test public void testGetFilesString() { //TODO To be implemented } } jajuk-1.9.6.orig/src/test/java/org/jajuk/base/TestYear.java0000644000175000017500000000654611720500104023366 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.base; import junit.framework.TestCase; import org.jajuk.JUnitHelpers; import org.jajuk.util.Const; /** * DOCUMENT_ME. */ public class TestYear extends TestCase { /** * Test method for {@link org.jajuk.base.Year#getDesc()}. */ public void testGetDesc() { Year year = new Year("1", "1998"); assertNotNull(year.getDesc()); assertTrue(year.getDesc().contains("1998")); } /** * Test method for {@link org.jajuk.base.Year#getLabel()}. */ public void testGetLabel() { Year year = new Year("1", "1998"); assertEquals(Const.XML_YEAR, year.getLabel()); } /** * Test method for {@link org.jajuk.base.Year#getIconRepresentation()}. */ public void testGetIconRepresentation() { Year year = new Year("1", "1998"); assertNotNull(year.getIconRepresentation()); } /** * Test method for. * * {@link org.jajuk.base.Year#Year(java.lang.String, java.lang.String)}. */ public void testYear() { Year year = new Year("1", "1998"); assertNotNull(year); } /** * Test method for {@link org.jajuk.base.Year#toString()}. */ public void testToString() { JUnitHelpers.ToStringTest(new Year("1", "1998")); JUnitHelpers.ToStringTest(new Year("1", null)); JUnitHelpers.ToStringTest(new Year(null, "1998")); JUnitHelpers.ToStringTest(new Year(null, null)); } /** * Test method for {@link org.jajuk.base.Year#getValue()}. */ public void testGetValue() { Year year = new Year("1", "1998"); assertEquals(1998l, year.getValue()); } /** * Test method for {@link org.jajuk.base.Year#compareTo(org.jajuk.base.Year)}. */ public void testCompareTo() { Year year = new Year("1", "1998"); Year yeareq = new Year("2", "1998"); Year yearne = new Year("3", "1997"); JUnitHelpers.CompareToTest(year, yeareq, yearne); } /** * Test method for {@link org.jajuk.base.Year#getName2()}. */ public void testGetName2() { Year year = new Year("1", "1998"); assertNotNull(year.getName2()); // test with zero-year year = new Year("1", "0"); assertNotNull(year.getName2()); } /** * Test method for {@link org.jajuk.base.Year#looksValid()}. */ public void testLooksValid() { // we currently check > 1000 and < 3000 assertTrue(new Year("1", "1998").looksValid()); assertTrue(new Year("1", "1001").looksValid()); assertTrue(new Year("1", "2999").looksValid()); assertFalse(new Year("1", "1000").looksValid()); assertFalse(new Year("1", "-340").looksValid()); assertFalse(new Year("1", "10000").looksValid()); } } jajuk-1.9.6.orig/src/test/java/org/jajuk/base/TestArtist.java0000644000175000017500000000737011720500104023730 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.base; import org.apache.commons.lang.StringUtils; import org.jajuk.JUnitHelpers; import org.jajuk.JajukTestCase; import org.jajuk.services.startup.StartupCollectionService; import org.jajuk.util.Const; /** * DOCUMENT_ME. */ public class TestArtist extends JajukTestCase { /** * Test method for {@link org.jajuk.base.Artist#getDesc()}. */ public final void testGetDesc() { Artist artist = JUnitHelpers.getArtist(); assertTrue(StringUtils.isNotBlank(artist.getDesc())); } /** * Test method for {@link org.jajuk.base.Artist#getLabel()}. */ public final void testGetLabel() { Artist artist = JUnitHelpers.getArtist(); assertEquals(Const.XML_ARTIST, artist.getLabel()); } /** * Test method for. * * {@link org.jajuk.base.Artist#getHumanValue(java.lang.String)}. */ public final void testGetHumanValue() { // need ArtistManager for MetaInformation here... StartupCollectionService.registerItemManagers(); Artist artist = JUnitHelpers.getArtist(); assertEquals("name", artist.getHumanValue(Const.XML_NAME)); } /** * Test method for {@link org.jajuk.base.Artist#getIconRepresentation()}. */ public final void testGetIconRepresentation() { Artist artist = JUnitHelpers.getArtist(); assertNotNull(artist.getIconRepresentation()); } /** * Test method for. * * {@link org.jajuk.base.Artist#Artist(java.lang.String, java.lang.String)}. */ public final void testArtist() { JUnitHelpers.getArtist(); } /** * Test method for {@link org.jajuk.base.Artist#getName2()}. */ public final void testGetName2() { Artist artist = JUnitHelpers.getArtist(); // usually equal to getName() assertEquals("name", artist.getName2()); // only different for unknown_artist artist = JUnitHelpers.getArtist(Const.UNKNOWN_ARTIST); // should be replaced by some localized string assertFalse(artist.getName2().equals(Const.UNKNOWN_ARTIST)); } /** * Test method for {@link org.jajuk.base.Artist#toString()}. */ public final void testToString() { Artist artist = new Artist("1", "name"); JUnitHelpers.ToStringTest(artist); artist = new Artist("1", null); JUnitHelpers.ToStringTest(artist); } /** * Test method for. * * {@link org.jajuk.base.Artist#compareTo(org.jajuk.base.Artist)}. */ public final void testCompareTo() { Artist artist = new Artist("1", "name"); Artist equal = new Artist("1", "name"); Artist notequal1 = new Artist("1", "name2"); Artist notequal2 = new Artist("2", "name"); JUnitHelpers.CompareToTest(artist, equal, notequal1); JUnitHelpers.CompareToTest(artist, equal, notequal2); } /** * Test method for {@link org.jajuk.base.Artist#isUnknown()}. */ public final void testIsUnknown() { Artist artist = JUnitHelpers.getArtist(); assertFalse(artist.isUnknown()); artist = JUnitHelpers.getArtist(Const.UNKNOWN_ARTIST); assertTrue(artist.isUnknown()); } } jajuk-1.9.6.orig/src/test/java/org/jajuk/base/TestDirectory.java0000644000175000017500000003656011720500104024431 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.base; import java.util.List; import java.util.Set; import org.apache.commons.io.FileUtils; import org.apache.commons.lang.StringUtils; import org.jajuk.JUnitHelpers; import org.jajuk.JUnitHelpers.MockPlayer; import org.jajuk.JajukTestCase; import org.jajuk.services.players.IPlayerImpl; import org.jajuk.services.startup.StartupCollectionService; import org.jajuk.util.Conf; import org.jajuk.util.Const; /** * TODO: some more coverage is possible by enhancing the tests accordingly. */ public class TestDirectory extends JajukTestCase { /** Sample device named "device1" and located at /tmp/device1 *. */ Device device1; /** Sample top dir named "topdir1" and located at /tmp/device1/topdir1 *. */ Directory topdir1; /** Sample dir named "dir1" and located at /tmp/device1/topdir1/dir1 *. */ Directory dir1; /** Sample dir named "dir2" and located at /tmp/device1/topdir1/dir2 *. */ Directory dir2; /* * (non-Javadoc) * * @see junit.framework.TestCase#setUp() */ @Override protected void setUp() throws Exception { // reset some conf-options Conf.setProperty(Const.CONF_OPTIONS_HIDE_UNMOUNTED, "false"); super.setUp(); // Create generic items String pathDevice1 = System.getProperty("java.io.tmpdir") + "/device1"; // Cleanup any existing directory and create again the directory new java.io.File(pathDevice1).delete(); new java.io.File(pathDevice1).mkdirs(); // create 2 directories to avoid getting a wanring dialog that device is void new java.io.File(pathDevice1 + "/dir1").mkdirs(); new java.io.File(pathDevice1 + "/dir2").mkdirs(); device1 = DeviceManager.getInstance().registerDevice("device1", Device.TYPE_DIRECTORY, pathDevice1); topdir1 = DirectoryManager.getInstance().registerDirectory(device1); dir1 = DirectoryManager.getInstance().registerDirectory("dir1", topdir1, device1); dir2 = DirectoryManager.getInstance().registerDirectory("dir2", topdir1, device1); } /** * Test method for {@link org.jajuk.base.Directory#getDesc()}. */ public void testGetDesc() { Directory dir = dir1; assertTrue(dir.toString(), StringUtils.isNotBlank(dir.getDesc())); } /** * Test method for {@link org.jajuk.base.Directory#getLabel()}. */ public void testGetLabel() { Directory dir = dir1; assertEquals(dir.toString(), Const.XML_DIRECTORY, dir.getLabel()); } /** * Test method for {@link org.jajuk.base.Directory#getHumanValue(java.lang.String)}. */ public void testGetHumanValue() { Device dev = device1; assertNotNull(dev); Directory dir = dir1; assertEquals(dir.toString(), dir.getParentDirectory().getFio(), new java.io.File(dir .getHumanValue(Const.XML_DIRECTORY_PARENT))); assertEquals(dir.toString(), "device1", dir.getHumanValue(Const.XML_DEVICE)); assertTrue(dir.toString(), StringUtils.isNotBlank(dir.getHumanValue(Const.XML_NAME))); assertEquals(dir.toString(), "", dir.getHumanValue("notexisting")); } /** * Test method for {@link org.jajuk.base.Directory#getIconRepresentation()}. */ public void testGetIconRepresentation() { StartupCollectionService.registerItemManagers(); Directory dir = dir1; assertNotNull(dir.getIconRepresentation()); } /** * Test method for {@link org.jajuk.base.Directory#Directory(java.lang.String, java.lang.String, org.jajuk.base.Directory, org.jajuk.base.Device)}. */ public void testDirectory() { Directory dir = dir1; assertNotNull(dir); } /** * Test method for {@link org.jajuk.base.Directory#toString()}. */ public void testToString() { Directory dir = dir1; JUnitHelpers.ToStringTest(dir); } /** * Test to string parent. * DOCUMENT_ME */ public void testToStringParent() { Directory dir = dir1; JUnitHelpers.ToStringTest(dir); } /** * Test method for {@link org.jajuk.base.Directory#getAbsolutePath()}. */ public void testGetAbsolutePath() { Directory dir = dir1; assertTrue(dir.toString(), StringUtils.isNotBlank(dir.getAbsolutePath())); } /** * Test method for {@link org.jajuk.base.Directory#getDevice()}. */ public void testGetDevice() { Directory dir = dir1; assertNotNull(dir.getDevice()); } /** * Test method for {@link org.jajuk.base.Directory#getParentDirectory()}. */ public void testGetParentDirectory() { Directory dir = topdir1; assertNull(dir.getParentDirectory()); } /** * Test method for {@link org.jajuk.base.Directory#getDirectories()}. */ public void testGetDirectories() { Directory dir = dir1; Set dirs = dir.getDirectories(); // no dirs without registered directories assertEquals(0, dirs.size()); DirectoryManager.getInstance().registerDirectory("sub1", dir, dir.getDevice()); DirectoryManager.getInstance().registerDirectory("sub2", dir, dir.getDevice()); DirectoryManager.getInstance().registerDirectory("sub3", dir, dir.getDevice()); dirs = dir.getDirectories(); assertEquals(3, dirs.size()); } /** * Test method for {@link org.jajuk.base.Directory#getFiles()}. * * @throws Exception the exception */ public void testGetFiles() throws Exception { Directory dir = dir1; Set files = dir.getFiles(); // no files are available currently assertEquals(0, files.size()); getFileInDir(3, dir); getFileInDir(4, dir); files = dir.getFiles(); assertEquals(2, dir.getFiles().size()); } /** * Gets the file in dir. * * @param i DOCUMENT_ME * @param dir DOCUMENT_ME * @return the file in dir * @throws Exception the exception */ @SuppressWarnings("unchecked") public static org.jajuk.base.File getFileInDir(int i, Directory dir) throws Exception { Genre genre = JUnitHelpers.getGenre("name"); Album album = JUnitHelpers.getAlbum("myalbum", 0); album.setProperty(Const.XML_ALBUM_DISCOVERED_COVER, Const.COVER_NONE); // don't read covers for // this test Artist artist = JUnitHelpers.getArtist("name"); Year year = new Year(Integer.valueOf(i).toString(), "2000"); IPlayerImpl imp = new MockPlayer(); Class cl = (Class) imp.getClass(); Type type = new Type(Integer.valueOf(i).toString(), "name", "mp3", cl, null); Track track = new Track(Integer.valueOf(i).toString(), "name", album, genre, artist, 120, year, 1, type, 1); return FileManager.getInstance().registerFile("test_" + i + ".tst", dir, track, 120, 70); } /** * Test method for {@link org.jajuk.base.Directory#getPlaylistFiles()}. */ public void testGetPlaylistFiles() { Directory dir = dir1; Set files = dir.getPlaylistFiles(); // no files are available currently assertEquals(0, files.size()); PlaylistManager.getInstance().registerPlaylistFile( new java.io.File(System.getProperty("java.io.tmpdir") + java.io.File.separator + "testfile1"), dir); PlaylistManager.getInstance().registerPlaylistFile( new java.io.File(System.getProperty("java.io.tmpdir") + java.io.File.separator + "testfile2"), dir); PlaylistManager.getInstance().registerPlaylistFile( new java.io.File(System.getProperty("java.io.tmpdir") + java.io.File.separator + "testfile3"), dir); PlaylistManager.getInstance().registerPlaylistFile( new java.io.File(System.getProperty("java.io.tmpdir") + java.io.File.separator + "testfile4"), dir); files = dir.getPlaylistFiles(); assertEquals(4, files.size()); } /** * Test get playlist recursively. * DOCUMENT_ME */ public void testGetPlaylistRecursively() { PlaylistManager.getInstance().clear(); Directory dir = dir1; List files = dir.getPlaylistsRecursively(); // no files are available currently assertEquals(0, files.size()); Directory dir1 = DirectoryManager.getInstance().registerDirectory("sub1", dir, dir.getDevice()); Directory dir2 = DirectoryManager.getInstance().registerDirectory("sub2", dir, dir.getDevice()); Directory dir3 = DirectoryManager.getInstance().registerDirectory("sub3", dir, dir.getDevice()); PlaylistManager.getInstance().registerPlaylistFile( new java.io.File(System.getProperty("java.io.tmpdir") + java.io.File.separator + "testfile1"), dir1); PlaylistManager.getInstance().registerPlaylistFile( new java.io.File(System.getProperty("java.io.tmpdir") + java.io.File.separator + "testfile2"), dir2); PlaylistManager.getInstance().registerPlaylistFile( new java.io.File(System.getProperty("java.io.tmpdir") + java.io.File.separator + "testfile3"), dir2); PlaylistManager.getInstance().registerPlaylistFile( new java.io.File(System.getProperty("java.io.tmpdir") + java.io.File.separator + "testfile4"), dir3); files = dir.getPlaylistsRecursively(); } /** * Test method for {@link org.jajuk.base.Directory#getFilesFromFile(org.jajuk.base.File)}. * * @throws Exception the exception */ public void testGetFilesFromFile() throws Exception { Directory dir = dir1; assertNull(dir.getFilesFromFile(null)); getFileInDir(3, dir); getFileInDir(4, dir); File file = getFileInDir(5, dir); getFileInDir(6, dir); List list = dir.getFilesFromFile(file); assertTrue("Size: " + list.size(), list.size() > 0); } /** * Test method for {@link org.jajuk.base.Directory#getFilesRecursively()}. * * @throws Exception the exception */ public void testGetFilesRecursively() throws Exception { FileManager.getInstance().clear(); Directory dir = JUnitHelpers.getDirectory(); List files = dir.getFilesRecursively(); // no files are available currently assertEquals(0, files.size()); Directory dir1 = DirectoryManager.getInstance().registerDirectory("sub1", dir, dir.getDevice()); Directory dir2 = DirectoryManager.getInstance().registerDirectory("sub2", dir, dir.getDevice()); Directory dir3 = DirectoryManager.getInstance().registerDirectory("sub3", dir, dir.getDevice()); getFileInDir(3, dir1); getFileInDir(4, dir2); getFileInDir(5, dir2); getFileInDir(6, dir3); files = dir.getFilesRecursively(); assertEquals(4, files.size()); } /** * Test method for {@link org.jajuk.base.Directory#hasAncestor(org.jajuk.base.Directory)}. * * @throws Exception the exception */ public void testHasAncestor() throws Exception { assertTrue(dir1.hasAncestor(topdir1)); assertFalse(dir1.hasAncestor(dir2)); assertFalse(dir1.hasAncestor(dir1)); } /** * Test method for {@link org.jajuk.base.Directory#getDirectoriesRecursively()}. * * @throws Exception the exception */ public void testGetDirectoriesRecursively() throws Exception { List dirs = topdir1.getDirectoriesRecursively(); assertTrue(dirs.size() == 2); assertFalse(dirs.contains(topdir1)); assertTrue(dirs.contains(dir1)); assertTrue(dirs.contains(dir2)); } /** * Test method for {@link org.jajuk.base.Directory#scan(boolean, org.jajuk.ui.helpers.RefreshReporter)}. */ public void testScan() { Directory dir = dir1; // this scan will not do much because there are no files in this dir dir.scan(true, null); } /** * Test scan actual. * DOCUMENT_ME * * @throws Exception the exception */ public void testScanActual() throws Exception { StartupCollectionService.registerItemManagers(); StartupCollectionService.registerTypes(); // create temp file Device dev = DeviceManager.getInstance().registerDevice("test1", Device.TYPE_DIRECTORY, System.getProperty("java.io.tmpdir")); Directory dir = dir1; new java.io.File(dev.getUrl()).mkdirs(); FileUtils.writeStringToFile(new java.io.File(dev.getUrl() + java.io.File.separator + "testScan" + java.io.File.separator + "test1.mp3"), "teststring"); dir.scan(true, null); } /** * Test method for {@link org.jajuk.base.Directory#reset()}. */ public void testReset() { Directory dir = dir1; dir.reset(); } /** * Test method for {@link org.jajuk.base.Directory#getRelativePath()}. */ public void testGetRelativePath() { Directory dir = dir1; assertNotNull(dir.getRelativePath()); } /** * Test method for {@link org.jajuk.base.Directory#getFio()}. */ public void testGetFio() { Directory dir = dir1; assertNotNull(dir.getFio()); } /** * Test method for {@link org.jajuk.base.Directory#compareTo(org.jajuk.base.Directory)}. */ public void testCompareTo() { Directory dir1 = new Directory("1", "", null, new Device("2", "test")); dir1.getDevice().setUrl(System.getProperty("java.io.tmpdir")); Directory dir2 = new Directory("1", "", null, new Device("2", "test")); dir2.getDevice().setUrl(System.getProperty("java.io.tmpdir")); Directory dir3a = new Directory("3", "", null, new Device("2", "test3")); dir3a.getDevice().setUrl(System.getProperty("java.io.tmpdir")); Directory dir3b = new Directory("2", "", null, new Device("2", "test")); dir3b.getDevice().setUrl(System.getProperty("java.io.tmpdir") + java.io.File.separator + "1"); JUnitHelpers.CompareToTest(dir1, dir2, dir3a); JUnitHelpers.CompareToTest(dir1, dir2, dir3b); } /** * Test method for {@link org.jajuk.base.Directory#shouldBeHidden()}. * * @throws Exception the exception */ public void testShouldBeHidden() throws Exception { Directory dir = dir1; // not mounted by default assertFalse(dir.getDevice().isMounted()); // false because option is not set assertFalse(dir.shouldBeHidden()); Conf.setProperty(Const.CONF_OPTIONS_HIDE_UNMOUNTED, "true"); // now true because option to hide unmounted is set assertTrue(dir.shouldBeHidden()); dir.getDevice().setUrl(System.getProperty("java.io.tmpdir")); dir.getDevice().mount(true); // now false because device is mounted now assertFalse(dir.shouldBeHidden()); } /** * Test method for {@link org.jajuk.base.Directory#setName(java.lang.String)}. */ public void testSetName() { Directory dir = dir1; assertEquals("dir1", dir.getName()); dir.setName("newname"); assertEquals("newname", dir.getName()); } /** * Test method for {@link org.jajuk.base.Directory#cleanRemovedFiles()}. */ public void testCleanRemovedFiles() { Directory dir = dir1; dir.cleanRemovedFiles(); } /** * Test method for {@link org.jajuk.base.Directory#isChildOf(org.jajuk.base.Directory)}. */ public void testIsChildOf() { assertFalse(topdir1.isChildOf(dir2)); assertTrue(dir2.isChildOf(topdir1)); } } jajuk-1.9.6.orig/src/test/java/org/jajuk/base/TestAlbumComparator.java0000644000175000017500000003770511720500104025557 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.base; import java.util.Date; import org.jajuk.JajukTestCase; /** * TODO : most of this test class should rewritten as the case we test * here is not actually possible : * Album album = new Album("1", "name", 2); * Album equal = new Album("1", "name", 2); * Album notequal = new Album("1", "name", 2); * is an impossible state as two albums with the same name must * be the same album (endorsed by the AlbumManager) * * We should also drop the direct items instantiations but use managers instead. */ public class TestAlbumComparator extends JajukTestCase { /** * Test method for {@link org.jajuk.base.AlbumComparator#AlbumComparator(int)} * . */ public final void testAlbumComparator() { new AlbumComparator(0); } /* * 0 .. genre 1 .. artist 2 .. album 3 .. year 4 .. discovery date 5 .. rate 6 * .. hits */ /** * Test method for. * * {@link org.jajuk.base.AlbumComparator#compare(org.jajuk.base.Album, org.jajuk.base.Album)} * . */ public final void testCompareGenre() { AlbumComparator compare = new AlbumComparator(0); Album album = new Album("1", "name", 2); Album equal = new Album("1", "name", 2); Album notequal = new Album("1", "name", 2); // just differ in Genre album.getTracksCache().add(getTrack(album)); equal.getTracksCache().add(getTrack(album)); notequal.getTracksCache().add( new Track("2", "name2", album, new Genre("7", "name7"), new Artist("4", "name4"), 10, new Year("5", "name5"), 1, new Type("6", "name6", "ext", null, null), 3)); assertEquals(0, compare.compare(album, equal)); assertTrue(0 < compare.compare(album, notequal) || 0 > compare.compare(album, notequal)); } /** * Test compare genre2. * DOCUMENT_ME */ public final void testCompareGenre2() { AlbumComparator compare = new AlbumComparator(0); Album album = new Album("1", "name", 2); Album equal = new Album("1", "name", 2); Album notequal = new Album("1", "name", 2); // just differ in Genre, this time we have the physical same genre Genre genre = new Genre("8", "name8"); album.getTracksCache().add(getTrack(album, genre, new Year("5", "name5"))); equal.getTracksCache().add(getTrack(album, genre, new Year("5", "name5"))); notequal.getTracksCache().add( new Track("2", "name2", album, new Genre("7", "name7"), new Artist("4", "name4"), 10, new Year("5", "name5"), 1, new Type("6", "name6", "ext", null, null), 3)); assertEquals(0, compare.compare(album, equal)); assertTrue(0 < compare.compare(album, notequal) || 0 > compare.compare(album, notequal)); } /** * Test compare genre4 album artist different. * DOCUMENT_ME */ public final void testCompareGenre4AlbumArtistDifferent() { AlbumComparator compare = new AlbumComparator(0); Album album = new Album("1", "name", 2); Album equal = new Album("1", "name", 2); Album notequal = new Album("1", "name", 2); // just differ in Genre, this time we have the physical same genre Genre genre = new Genre("8", "name8"); album.getTracksCache().add(getTrack(album, genre, new Year("5", "name5"))); equal.getTracksCache().add(getTrack(album, genre, new Year("5", "name5"))); notequal.getTracksCache().add( new Track("2", "name2", album, new Genre("7", "name7"), new Artist("4", "name4"), 10, new Year("5", "name5"), 1, new Type("6", "name6", "ext", null, null), 3)); assertEquals(0, compare.compare(album, equal)); assertTrue(0 < compare.compare(album, notequal) || 0 > compare.compare(album, notequal)); } /** * Test compare genre3 same year. * DOCUMENT_ME */ public final void testCompareGenre3SameYear() { AlbumComparator compare = new AlbumComparator(0); Album album = new Album("1", "name", 2); Album equal = new Album("1", "name", 2); Album notequal = new Album("1", "name", 2); // just differ in Genre, this time we have the physical same genre Genre genre = new Genre("8", "name8"); Year year = new Year("5", "name5"); album.getTracksCache().add(getTrack(album, genre, year)); equal.getTracksCache().add(getTrack(album, genre, year)); notequal.getTracksCache().add( new Track("2", "name2", album, new Genre("7", "name7"), new Artist("4", "name4"), 10, new Year("5", "name5"), 1, new Type("6", "name6", "ext", null, null), 3)); assertEquals(0, compare.compare(album, equal)); assertTrue(0 < compare.compare(album, notequal) || 0 > compare.compare(album, notequal)); } /** * Test compare artist. * DOCUMENT_ME */ public final void testCompareArtist() { AlbumComparator compare = new AlbumComparator(1); Album album = new Album("1", "name", 2); Album equal = new Album("1", "name", 2); Album notequal = new Album("1", "name", 2); // just differ in Artist album.getTracksCache().add(getTrack(album)); equal.getTracksCache().add(getTrack(equal)); notequal.getTracksCache().add(getTrack(notequal, new Artist("5", "name5"))); /* * notequal.getTracksCache().add( new Track("2", "name2", album, new * Genre("3", "name3"), new Artist("7", "name7"), 10, new Year("5", * "name5"), 1, new Type("6", "name6", "ext", null, null), 3)); */ assertEquals(0, compare.compare(album, equal)); assertTrue(0 < compare.compare(album, notequal) || 0 > compare.compare(album, notequal)); } /** * Test compare artist same year. * DOCUMENT_ME */ public final void testCompareArtistSameYear() { AlbumComparator compare = new AlbumComparator(1); Album album = new Album("1", "name", 2); Album equal = new Album("1", "name", 2); Album notequal = new Album("1", "name", 2); // just differ in Artist Genre genre = new Genre("8", "name8"); Year year = new Year("5", "name5"); album.getTracksCache().add(getTrack(album, genre, year)); equal.getTracksCache().add(getTrack(equal, genre, year)); notequal.getTracksCache().add(getTrack(notequal, new Artist("5", "name5"))); /* * notequal.getTracksCache().add( new Track("2", "name2", album, new * Genre("3", "name3"), new Artist("7", "name7"), 10, new Year("5", * "name5"), 1, new Type("6", "name6", "ext", null, null), 3)); */ assertEquals(0, compare.compare(album, equal)); assertTrue(0 < compare.compare(album, notequal) || 0 > compare.compare(album, notequal)); } /** * Test compare album. * DOCUMENT_ME */ public final void testCompareAlbum() { AlbumComparator compare = new AlbumComparator(2); Album album = new Album("1", "name", 2); Album equal = new Album("1", "name", 2); Album notequal = new Album("2", "name2", 2); assertEquals(0, compare.compare(album, equal)); assertTrue(0 < compare.compare(album, notequal) || 0 > compare.compare(album, notequal)); } /** * Test compare year. * DOCUMENT_ME */ public final void testCompareYear() { AlbumComparator compare = new AlbumComparator(3); Album album = new Album("1", "name", 2); Album equal = new Album("1", "name", 2); Album notequal = new Album("1", "name", 2); // just differ in Year album.getTracksCache().add(getTrack(album)); equal.getTracksCache().add(getTrack(album)); notequal.getTracksCache().add( new Track("2", "name2", album, new Genre("3", "name3"), new Artist("4", "name4"), 10, new Year("7", "name7"), 1, new Type("6", "name6", "ext", null, null), 3)); assertEquals(0, compare.compare(album, equal)); assertTrue(0 < compare.compare(album, notequal) || 0 > compare.compare(album, notequal)); } /** * Test compare year same year. * DOCUMENT_ME */ public final void testCompareYearSameYear() { AlbumComparator compare = new AlbumComparator(3); Album album = new Album("1", "name", 2); Album equal = new Album("1", "name", 2); Album notequal = new Album("1", "name", 2); // just differ in Year Genre genre = new Genre("8", "name8"); Year year = new Year("5", "name5"); album.getTracksCache().add(getTrack(album, genre, year)); equal.getTracksCache().add(getTrack(album, genre, year)); notequal.getTracksCache().add( new Track("2", "name2", album, new Genre("3", "name3"), new Artist("4", "name4"), 10, new Year("7", "name7"), 1, new Type("6", "name6", "ext", null, null), 3)); assertEquals(0, compare.compare(album, equal)); assertTrue(0 < compare.compare(album, notequal) || 0 > compare.compare(album, notequal)); } /** * Test compare year same year diff artist. * DOCUMENT_ME */ public final void testCompareYearSameYearDiffArtist() { AlbumComparator compare = new AlbumComparator(3); Album album = new Album("1", "name", 2); Album equal = new Album("1", "name", 2); Album notequal = new Album("1", "name", 2); // just differ in Year Genre genre = new Genre("8", "name8"); Year year = new Year("5", "name5"); album.getTracksCache().add(getTrack(album, genre, year)); equal.getTracksCache().add(getTrack(album, genre, year)); notequal.getTracksCache().add( new Track("2", "name2", album, new Genre("3", "name3"), new Artist("5", "name5"), 10, new Year("7", "name7"), 1, new Type("6", "name6", "ext", null, null), 3)); assertEquals(0, compare.compare(album, equal)); assertTrue(0 < compare.compare(album, notequal) || 0 > compare.compare(album, notequal)); } /** * Test compare discovery date. * DOCUMENT_ME */ public final void testCompareDiscoveryDate() { AlbumComparator compare = new AlbumComparator(4); Album album = new Album("1", "name", 2); Album equal = new Album("1", "name", 2); Album notequal = new Album("1", "name", 2); Date date1 = new Date(); Date date2 = new Date(12345); // needs to be different to date1 // just differ in DiscoverDate album.getTracksCache().add(getTrack(album)); album.getTracksCache().get(0).setDiscoveryDate(date1); equal.getTracksCache().add(getTrack(album)); equal.getTracksCache().get(0).setDiscoveryDate(date1); notequal.getTracksCache().add(getTrack(album)); notequal.getTracksCache().get(0).setDiscoveryDate(date2); assertEquals(0, compare.compare(album, equal)); assertTrue(0 < compare.compare(album, notequal) || 0 > compare.compare(album, notequal)); } /** * Test compare rate. * DOCUMENT_ME */ public final void testCompareRate() { AlbumComparator compare = new AlbumComparator(5); Album album = new Album("1", "name", 2); Album equal = new Album("1", "name", 2); Album notequal = new Album("1", "name", 2); // just differ in Rate album.getTracksCache().add(getTrack(album)); album.getTracksCache().get(0).setRate(3); equal.getTracksCache().add(getTrack(album)); equal.getTracksCache().get(0).setRate(3); notequal.getTracksCache().add(getTrack(album)); notequal.getTracksCache().get(0).setRate(4); assertEquals(0, compare.compare(album, equal)); assertTrue(0 > compare.compare(album, notequal)); } /** * Test compare rate gt. * DOCUMENT_ME */ public final void testCompareRateGT() { AlbumComparator compare = new AlbumComparator(5); Album album = new Album("1", "name", 2); Album equal = new Album("1", "name", 2); Album notequal = new Album("1", "name", 2); // just differ in Rate album.getTracksCache().add(getTrack(album)); album.getTracksCache().get(0).setRate(4); equal.getTracksCache().add(getTrack(album)); equal.getTracksCache().get(0).setRate(4); notequal.getTracksCache().add(getTrack(album)); notequal.getTracksCache().get(0).setRate(3); assertEquals(0, compare.compare(album, equal)); assertTrue(0 < compare.compare(album, notequal)); } /** * Test compare hits. * DOCUMENT_ME */ public final void testCompareHits() { AlbumComparator compare = new AlbumComparator(6); Album album = new Album("1", "name", 2); Album equal = new Album("1", "name", 2); Album notequal = new Album("1", "name", 2); // just differ in Hits album.getTracksCache().add(getTrack(album)); album.getTracksCache().get(0).setHits(3); equal.getTracksCache().add(getTrack(album)); equal.getTracksCache().get(0).setHits(3); notequal.getTracksCache().add(getTrack(album)); notequal.getTracksCache().get(0).setHits(4); assertEquals(0, compare.compare(album, equal)); assertTrue(0 > compare.compare(album, notequal)); } /** * Test compare hits gt. * DOCUMENT_ME */ public final void testCompareHitsGT() { AlbumComparator compare = new AlbumComparator(6); Album album = new Album("1", "name", 2); Album equal = new Album("1", "name", 2); Album notequal = new Album("1", "name", 2); // just differ in Hits album.getTracksCache().add(getTrack(album)); album.getTracksCache().get(0).setHits(4); equal.getTracksCache().add(getTrack(album)); equal.getTracksCache().get(0).setHits(4); notequal.getTracksCache().add(getTrack(album)); notequal.getTracksCache().get(0).setHits(3); assertEquals(0, compare.compare(album, equal)); assertTrue(0 < compare.compare(album, notequal)); } /** * Gets the track. * * @param album DOCUMENT_ME * @return the track */ private Track getTrack(Album album) { return new Track("2", "name2", album, new Genre("3", "name3"), new Artist("4", "name4"), 10, new Year("5", "name5"), 1, new Type("6", "name6", "ext", null, null), 3); } /** * Gets the track. * * @param album DOCUMENT_ME * @param artist DOCUMENT_ME * @return the track */ private Track getTrack(Album album, Artist artist) { return new Track("2", "name2", album, new Genre("3", "name3"), artist, 10, new Year("5", "name5"), 1, new Type("6", "name6", "ext", null, null), 3); } /** * Gets the track. * * @param album DOCUMENT_ME * @param genre DOCUMENT_ME * @param year DOCUMENT_ME * @return the track */ private Track getTrack(Album album, Genre genre, Year year) { return new Track("2", "name2", album, genre, new Artist("4", "name4"), 10, year, 1, new Type( "6", "name6", "ext", null, null), 3); } /** * Test compare no track. * DOCUMENT_ME */ public final void testCompareNoTrack() { AlbumComparator compare = new AlbumComparator(0); Album album = new Album("1", "name", 2); Album equal = new Album("1", "name", 2); Album notequal = new Album("2", "name2", 2); // without actual tracks, anything compares... assertEquals(0, compare.compare(album, equal)); assertEquals(0, compare.compare(album, notequal)); } /** * Test compare criteria outside. * DOCUMENT_ME */ public final void testCompareCriteriaOutside() { AlbumComparator compare = new AlbumComparator(99); Album album = new Album("1", "name", 2); Album equal = new Album("1", "name", 2); Album notequal = new Album("2", "name2", 2); // add the same type of track in all albums to not stop comparison early album.getTracksCache().add(getTrack(album)); equal.getTracksCache().add(getTrack(equal)); notequal.getTracksCache().add(getTrack(notequal)); // with invalid "criteria", anything compares assertEquals(0, compare.compare(album, equal)); assertEquals(0, compare.compare(album, notequal)); } } jajuk-1.9.6.orig/src/test/java/org/jajuk/base/TestDevice.java0000644000175000017500000006614011720500104023661 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2009 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision: 3132 $ */ package org.jajuk.base; import java.awt.HeadlessException; import java.lang.reflect.InvocationTargetException; import java.util.List; import org.apache.commons.lang.StringUtils; import org.jajuk.JUnitHelpers; import org.jajuk.JajukTestCase; import org.jajuk.base.TestAlbumManager.MockPlayer; import org.jajuk.services.core.ExitService; import org.jajuk.services.players.IPlayerImpl; import org.jajuk.services.players.QueueModel; import org.jajuk.services.players.StackItem; import org.jajuk.services.startup.StartupCollectionService; import org.jajuk.util.Conf; import org.jajuk.util.Const; import org.jajuk.util.error.JajukException; import org.jajuk.util.log.Log; import org.xml.sax.Attributes; /** * */ public class TestDevice extends JajukTestCase { /* * (non-Javadoc) * * @see junit.framework.TestCase#setUp() */ @Override public void setUp() throws Exception { super.setUp(); } /** * Test method for {@link org.jajuk.base.Device#getDesc()}. */ public void testGetDesc() { Device device = new Device("1", "testname"); assertNotNull(device.getDesc()); assertFalse(device.getDesc().length() == 0); } /** * Test method for {@link org.jajuk.base.Device#getLabel()}. */ public void testGetLabel() { Device device = JUnitHelpers.getDevice(); assertEquals(Const.XML_DEVICE, device.getLabel()); } /** * Test method for * {@link org.jajuk.base.Device#populateProperties(org.xml.sax.Attributes)}. */ public void testPopulateProperties() { StartupCollectionService.registerItemManagers(); Device device = new Device("1", "name"); DeviceManager.getInstance().registerProperty( new PropertyMetaInformation("att1", true, false, true, false, false, String.class, null)); DeviceManager.getInstance().registerProperty( new PropertyMetaInformation("att2", true, false, true, false, false, String.class, null)); DeviceManager.getInstance().registerProperty( new PropertyMetaInformation("att3", true, false, true, false, false, String.class, null)); DeviceManager.getInstance().registerProperty( new PropertyMetaInformation(Const.XML_DEVICE_AUTO_REFRESH, true, false, true, false, false, Double.class, null)); device.populateProperties(new MockAttributes()); device = DeviceManager.getInstance().registerDevice("name", Device.TYPE_CD, System.getProperty("java.io.tmpdir")); device.populateProperties(new MockAttributes()); device = DeviceManager.getInstance().registerDevice("name", Device.TYPE_NETWORK_DRIVE, System.getProperty("java.io.tmpdir")); device.populateProperties(new MockAttributes()); device = DeviceManager.getInstance().registerDevice("name", Device.TYPE_EXT_DD, System.getProperty("java.io.tmpdir")); device.populateProperties(new MockAttributes()); device = DeviceManager.getInstance().registerDevice("name", Device.TYPE_PLAYER, System.getProperty("java.io.tmpdir")); device.populateProperties(new MockAttributes()); } /** * Test method for * {@link org.jajuk.base.Device#getHumanValue(java.lang.String)}. */ public void testGetHumanValue() { // we need the managers registered here StartupCollectionService.registerItemManagers(); StartupCollectionService.registerDevicesTypes(); Device device = new Device("1", "testname"); assertEquals("", device.getHumanValue("notexists")); // TODO: capture correct use of this method as well DeviceManager.getInstance().registerProperty( new PropertyMetaInformation("att1", true, false, true, false, false, String.class, null)); DeviceManager.getInstance().registerProperty( new PropertyMetaInformation("att2", true, false, true, false, false, String.class, null)); DeviceManager.getInstance().registerProperty( new PropertyMetaInformation("att3", true, false, true, false, false, String.class, null)); DeviceManager.getInstance().registerProperty( new PropertyMetaInformation(Const.XML_DEVICE_AUTO_REFRESH, true, false, true, false, false, Double.class, null)); device.populateProperties(new MockAttributes()); assertNotNull(device.getHumanValue("att1")); device.setProperty(Const.XML_TYPE, 2l); assertTrue(StringUtils.isNotBlank(device.getHumanValue(Const.XML_TYPE))); } /** * Test method for {@link org.jajuk.base.Device#getIconRepresentation()}. * * @throws Exception */ public void testGetIconRepresentation() throws Exception { // we need the managers registered here StartupCollectionService.registerItemManagers(); Device device = JUnitHelpers.getDevice(); assertNotNull(device.getIconRepresentation()); device.setProperty(Const.XML_TYPE, (long) Device.TYPE_DIRECTORY); assertNotNull(device.getIconRepresentation()); device.setProperty(Const.XML_TYPE, (long) Device.TYPE_CD); assertNotNull(device.getIconRepresentation()); device.setProperty(Const.XML_TYPE, (long) Device.TYPE_NETWORK_DRIVE); assertNotNull(device.getIconRepresentation()); device.setProperty(Const.XML_TYPE, (long) Device.TYPE_EXT_DD); assertNotNull(device.getIconRepresentation()); device.setProperty(Const.XML_TYPE, (long) Device.TYPE_PLAYER); assertNotNull(device.getIconRepresentation()); // test with invalid type device.setProperty(Const.XML_TYPE, (long) -1); assertNull(device.getIconRepresentation()); // test with mounted device device.setUrl(System.getProperty("java.io.tmpdir")); device.mount(true); device.setProperty(Const.XML_TYPE, (long) Device.TYPE_PLAYER); assertNotNull(device.getIconRepresentation()); } /** * Test method for * {@link org.jajuk.base.Device#Device(java.lang.String, java.lang.String)}. */ public void testDevice() { new Device("1", "name"); } /** * Test method for * {@link org.jajuk.base.Device#addDirectory(org.jajuk.base.Directory)}. */ public void testAddDirectory() { Device device = JUnitHelpers.getDevice(); Directory dir1 = DirectoryManager.getInstance().registerDirectory("dir1", JUnitHelpers.getDirectory(), device); Directory dir2 = DirectoryManager.getInstance().registerDirectory("dir2", JUnitHelpers.getDirectory(), device); assertEquals(0, device.getDirectories().size()); device.addDirectory(dir1); assertEquals(1, device.getDirectories().size()); device.addDirectory(dir2); assertEquals(2, device.getDirectories().size()); } /** * Test method for {@link org.jajuk.base.Device#cleanRemovedFiles()}. */ public void testCleanRemovedFiles() throws Exception { JUnitHelpers.createSessionDirectory(); Device device = JUnitHelpers.getDevice(); device.mount(true); device.setUrl("notexisting/testparent\\anotherclientparentthing"); // clean without any stuff assertFalse(device.cleanRemovedFiles(null)); // add some directory, then the remove should kick in! Directory topdir = DirectoryManager.getInstance().registerDirectory(device); Directory dir = DirectoryManager.getInstance().registerDirectory("notexistingdir", topdir, device); device.addDirectory(dir); DirectoryManager.getInstance().registerDirectory(device); File file = getFile(8, dir); PlaylistManager.getInstance().registerPlaylistFile(file.getFIO(), dir); // ensure we are not exiting, this would invalidate the test assertFalse(ExitService.isExiting()); // now we have removals assertTrue(device.cleanRemovedFiles(null)); // enable history to also clean that Conf.setProperty(Const.CONF_HISTORY, "10"); // no removals any more now assertFalse(device.cleanRemovedFiles(null)); } /** * Test method for * {@link org.jajuk.base.Device#compareTo(org.jajuk.base.Device)}. */ public void testCompareTo() { Device device = new Device("1", "name"); Device equal = new Device("1", "name"); Device notequal = new Device("1", "name1"); // compares only on name JUnitHelpers.CompareToTest(device, equal, notequal); } /** * Test method for {@link org.jajuk.base.Device#getDateLastRefresh()}. */ public void testGetDateLastRefresh() throws Exception { Device device = JUnitHelpers.getDevice(); assertEquals(0, device.getDateLastRefresh()); device.mount(false); device.refreshCommand(false, false, null); // now it should be set assertNotNull(device.getDateLastRefresh()); } /** * Test method for {@link org.jajuk.base.Device#getDeviceTypeS()}. */ public void testGetDeviceTypeS() { StartupCollectionService.registerDevicesTypes(); Device device = JUnitHelpers.getDevice(); assertNotNull(device.getDeviceTypeS()); } /** * Test method for {@link org.jajuk.base.Device#getDirectories()}. */ public void testGetDirectories() { Device device = JUnitHelpers.getDevice(); assertEquals(0, device.getDirectories().size()); Directory dir = JUnitHelpers.getDirectory(); device.addDirectory(dir); assertEquals(1, device.getDirectories().size()); } /** * Test method for {@link org.jajuk.base.Device#getFilesRecursively()}. */ public void testGetFilesRecursively() { Device device = JUnitHelpers.getDevice(); device.setUrl(System.getProperty("java.io.tmpdir") + System.currentTimeMillis()); // no files without a directory List files = device.getFilesRecursively(); assertEquals(0, files.size()); // no file available Directory dir = DirectoryManager.getInstance().registerDirectory(device); // still no files without files being registered files = device.getFilesRecursively(); assertEquals(0, files.size()); // no file available getFile(100, dir); // now it should find some files = device.getFilesRecursively(); assertEquals(1, files.size()); } @SuppressWarnings("unchecked") private File getFile(int i, Directory dir) { Genre genre = JUnitHelpers.getGenre("name"); Album album = JUnitHelpers.getAlbum("myalbum", 0); album.setProperty(Const.XML_ALBUM_DISCOVERED_COVER, Const.COVER_NONE); // don't read covers for // this test Artist artist = JUnitHelpers.getArtist("name"); Year year = new Year(Integer.valueOf(i).toString(), "2000"); IPlayerImpl imp = new MockPlayer(); Class cl = (Class) imp.getClass(); Type type = new Type(Integer.valueOf(i).toString(), "name", "mp3", cl, null); Track track = new Track(Integer.valueOf(i).toString(), "name", album, genre, artist, 120, year, 1, type, 1); return FileManager.getInstance().registerFile( "test" + Long.valueOf(System.currentTimeMillis()).toString() + ".tst", dir, track, 120, 70); } /** * Test method for {@link org.jajuk.base.Device#getFio()}. */ public void testGetFio() { Device device = new Device("1", "name"); assertNull(device.getFio()); device.setUrl(System.getProperty("java.io.tmpdir")); assertNotNull(device.getFio()); } /** * Test method for {@link org.jajuk.base.Device#getRootDirectory()}. * * @throws Exception */ public void testGetRootDirectory() throws Exception { // create a unique id here... Device device = DeviceManager.getInstance().registerDevice("getRootDirectory", Device.TYPE_CD, "/foo"); assertNull(device.getRootDirectory()); java.io.File file = java.io.File.createTempFile("test", "tst"); device.setUrl(file.getAbsolutePath()); DirectoryManager.getInstance().registerDirectory(device); assertNotNull(device.getRootDirectory()); } /** * Test method for {@link org.jajuk.base.Device#getType()}. */ public void testGetType() { Device device = JUnitHelpers.getDevice(); assertEquals(0, device.getType()); device.setProperty(Const.XML_TYPE, 2l); assertEquals(2, device.getType()); } /** * Test method for {@link org.jajuk.base.Device#getUrl()}. */ public void testGetUrl() { Device device = new Device("1", "name"); assertNull(device.getUrl()); device.setUrl(System.getProperty("java.io.tmpdir")); assertNotNull(device.getUrl()); } /** * Test method for {@link org.jajuk.base.Device#isMounted()}. * * @throws Exception */ public void testIsMounted() throws Exception { Device device = new Device("1", "name"); device.setUrl(System.getProperty("java.io.tmpdir")); assertFalse(device.isMounted()); device.mount(true); assertTrue(device.isMounted()); } /** * Test method for {@link org.jajuk.base.Device#isReady()}. * * @throws Exception */ public void testIsReady() throws Exception { Device device = new Device("1", "name"); device.setUrl(System.getProperty("java.io.tmpdir")); assertFalse(device.isReady()); device.mount(true); assertTrue(device.isReady()); } /** * Test method for {@link org.jajuk.base.Device#isRefreshing()}. */ public void testIsRefreshing() { Device device = JUnitHelpers.getDevice(); assertFalse(device.isRefreshing()); } /** * Test method for {@link org.jajuk.base.Device#isSynchronizing()}. */ public void testIsSynchronizing() { Device device = JUnitHelpers.getDevice(); assertFalse(device.isSynchronizing()); } /** * Test method for {@link org.jajuk.base.Device#prepareRefresh(boolean)}. * * @throws Exception */ public void testPrepareRefresh() throws Exception { Device device = new Device("1", "name"); device.setUrl(System.getProperty("java.io.tmpdir")); device.prepareRefresh(false); } public void testPrepareRefreshAsk() throws Exception { Device device = new Device("1", "name"); device.setUrl(System.getProperty("java.io.tmpdir")); try { device.prepareRefresh(true); } catch (HeadlessException e) { // ignore this on non-ui machines } } public void testPrepareRefreshAskCD() throws Exception { Device device = DeviceManager.getInstance().registerDevice("name", Device.TYPE_CD, System.getProperty("java.io.tmpdir")); try { device.prepareRefresh(true); } catch (HeadlessException e) { // ignore this on non-ui machines } } public void testPrepareRefreshAskNetworkDrive() throws Exception { Device device = DeviceManager.getInstance().registerDevice("name", Device.TYPE_NETWORK_DRIVE, System.getProperty("java.io.tmpdir")); try { device.prepareRefresh(true); } catch (HeadlessException e) { // ignore this on non-ui machines } } public void testPrepareRefreshAskExtDD() throws Exception { Device device = DeviceManager.getInstance().registerDevice("name", Device.TYPE_EXT_DD, System.getProperty("java.io.tmpdir")); try { device.prepareRefresh(true); } catch (HeadlessException e) { // ignore this on non-ui machines } } public void testPrepareRefreshAskPlayer() throws Exception { Device device = DeviceManager.getInstance().registerDevice("name", Device.TYPE_PLAYER, System.getProperty("java.io.tmpdir")); try { device.prepareRefresh(true); } catch (HeadlessException e) { // ignore this on non-ui machines } } /** * Test method for {@link org.jajuk.base.Device#mount(boolean)}. * * @throws Exception */ public void testMount() throws Exception { Device device = new Device("1", "name"); device.setUrl(System.getProperty("java.io.tmpdir")); device.mount(true); // try a second time, should fail try { device.mount(true); fail(); } catch (Exception e) { Log.error(e); } // try a device that has an invalid URL device = new Device("1", "name"); device.setUrl("notexisting/not/adsf\\dtest"); try { device.mount(true); } catch (JajukException e) { assertEquals(11, e.getCode()); } } /** * Test method for {@link org.jajuk.base.Device#refresh(boolean)}. * * @throws Exception */ public void testRefreshBoolean() throws Exception { Device device = new Device("1", "name"); device.setUrl(System.getProperty("java.io.tmpdir")); try { device.refresh(false, false, false, null); } catch (RuntimeException e) { // there can be a hidden HeadlessException here assertTrue(e.getCause().getMessage(), e.getCause() instanceof InvocationTargetException); // assertTrue(e.getCause().getCause().getMessage(), // e.getCause().getCause()instanceof InvocationTargetException); // assertTrue(e.getCause().getCause().getCause().getMessage(), // e.getCause().getCause().getCause()instanceof HeadlessException); } device.refresh(true, false, false, null); } /** * Test method for {@link org.jajuk.base.Device#refresh(boolean, boolean)}. * * @throws Exception */ public void testRefreshBooleanBoolean() throws Exception { Device device = new Device("1", "name"); device.setUrl(System.getProperty("java.io.tmpdir")); try { device.refresh(false, false, false, null); } catch (RuntimeException e) { // there can be a hidden HeadlessException here assertTrue(e.getCause().getMessage(), e.getCause() instanceof InvocationTargetException); } device.refresh(true, false, false, null); } /** * Test method for {@link org.jajuk.base.Device#refreshCommand(boolean)}. */ public void testRefreshCommand() { Device device = JUnitHelpers.getDevice(); try { device.mount(false); } catch (Exception e) { Log.error(e); fail(); } device.refreshCommand(false, false, null); } /** * Test method for {@link org.jajuk.base.Device#refreshCommand(boolean)}. * @throws Exception */ public void testRefreshCommandNoMoreAvailable() throws Exception { // We check that a device mounted but no more available cannot be refreshed Device device = new Device("1", "name"); // Prepare a sample directory with at least a single file java.io.File fileOKDir = new java.io.File(System.getProperty("java.io.tmpdir") + "/foo643"); fileOKDir.mkdir(); java.io.File sampleFile = new java.io.File(fileOKDir.getAbsoluteFile() + "/foo.mp3"); sampleFile.createNewFile(); device.setUrl(fileOKDir.getAbsolutePath()); device.mount(false); device.refreshCommand(false, false, null); // fine, now rename the directory sampleFile.delete(); fileOKDir.delete(); // An error should happen here device.refreshCommand(false, false, null); } // test for a regression that was added public void testRefreshCommandDontReaddTopDirectory() throws Exception { Device device = JUnitHelpers.getDevice(); device.mount(true); device.refreshCommand(false, false, null); // we should not have more than one top-directory! assertEquals(1, device.getDirectories().size()); // even if we refresh some more, we should only have one, not multiple device.refreshCommand(false, false, null); // we should not have more than one top-directory! assertEquals(1, device.getDirectories().size()); device.refreshCommand(false, false, null); // we should not have more than one top-directory! assertEquals(1, device.getDirectories().size()); device.refreshCommand(false, false, null); // we should not have more than one top-directory! assertEquals(1, device.getDirectories().size()); device.refreshCommand(false, false, null); // we should not have more than one top-directory! assertEquals(1, device.getDirectories().size()); } /** * Test method for {@link org.jajuk.base.Device#setUrl(java.lang.String)}. * * @throws Exception */ public void testSetUrl() throws Exception { Device device = JUnitHelpers.getDevice(); // add some directory, then the remove should kick in! Directory dir = JUnitHelpers.getDirectory(); device.addDirectory(dir); File file = getFile(8, dir); PlaylistManager.getInstance().registerPlaylistFile(file.getFIO(), dir); // now also the playlist should be reset device.setUrl(System.getProperty("java.io.tmpdir")); } /** * Test method for {@link org.jajuk.base.Device#synchronize(boolean)}. */ public void testSynchronize() { Device device = JUnitHelpers.getDevice(); device.synchronize(true); // nothing much happens here as there is no synchro-device set device.synchronize(false); } public void testSynchronizeConfSet() { Device device = JUnitHelpers.getDevice(); Device dSrc = JUnitHelpers.getDevice("src", 0, "/tmp"); assertNotNull(dSrc); assertNotNull(dSrc.getID()); assertNotNull(DeviceManager.getInstance().getDeviceByID(dSrc.getID())); // set the synchro-device device.setProperty(Const.XML_DEVICE_SYNCHRO_SOURCE, dSrc.getID()); assertNotNull(DeviceManager.getInstance().getDeviceByID(dSrc.getID())); assertNotNull(DeviceManager.getInstance().getDeviceByID(device.getID())); device.synchronize(false); assertNotNull(DeviceManager.getInstance().getDeviceByID(dSrc.getID())); assertNotNull(DeviceManager.getInstance().getDeviceByID(device.getID())); device.synchronize(true); assertNotNull(DeviceManager.getInstance().getDeviceByID(dSrc.getID())); assertNotNull(DeviceManager.getInstance().getDeviceByID(device.getID())); } /** * Test method for {@link org.jajuk.base.Device#synchronizeCommand()}. */ public void testSynchronizeCommand() { Device device = JUnitHelpers.getDevice(); device.synchronizeCommand(); // TODO do some real testing here } public void testSynchronizeCommandSyncDevice() { Device device = JUnitHelpers.getDevice(); try { device.mount(false); } catch (Exception e) { Log.error(e); fail(); } // set the synchro-device Device sync = DeviceManager.getInstance().registerDevice("name2", 0, System.getProperty("java.io.tmpdir") + "/device2"); device.setProperty(Const.XML_DEVICE_SYNCHRO_SOURCE, sync.getID()); device.synchronizeCommand(); } public void testSynchronizeCommandSyncDeviceBidi() { Device device = JUnitHelpers.getDevice(); try { if (!device.mount(false)) { fail(); } } catch (Exception e) { Log.error(e); fail(); } // set the synchro-device Device sync = DeviceManager.getInstance().registerDevice("name2", 0, System.getProperty("java.io.tmpdir") + "/jajuk_tests/device_2"); try { new java.io.File(sync.getUrl()).mkdirs(); new java.io.File(sync.getUrl() + "/audio1.mp3").createNewFile(); if (!sync.mount(false)) { fail(); } } catch (Exception e) { Log.error(e); fail(); } device.setProperty(Const.XML_DEVICE_SYNCHRO_SOURCE, sync.getID()); device.setProperty(Const.XML_DEVICE_SYNCHRO_MODE, Const.DEVICE_SYNCHRO_MODE_BI); sync.setProperty(Const.XML_DEVICE_SYNCHRO_SOURCE, device.getID()); sync.setProperty(Const.XML_DEVICE_SYNCHRO_MODE, Const.DEVICE_SYNCHRO_MODE_BI); device.synchronizeCommand(); new java.io.File(sync.getUrl()).delete(); } /** * Test method for {@link org.jajuk.base.Device#test()}. */ public void testTest() { Device device = JUnitHelpers.getDevice("notexist", Device.TYPE_DIRECTORY, "notexisting"); assertFalse(device.test()); } public void testTestMounted() { Device device = JUnitHelpers.getDevice(); device.setUrl(System.getProperty("java.io.tmpdir")); assertTrue(device.test()); } /** * Test method for {@link org.jajuk.base.Device#toString()}. */ public void testToString() { Device device = JUnitHelpers.getDevice(); JUnitHelpers.ToStringTest(device); device = JUnitHelpers.getDevice(); JUnitHelpers.ToStringTest(device); device = new Device(null, null); JUnitHelpers.ToStringTest(device); } /** * Test method for {@link org.jajuk.base.Device#unmount()}. * * @throws Exception */ public void testUnmount() throws Exception { Device device = JUnitHelpers.getDevice(); assertFalse(device.isMounted()); device.unmount(); device.mount(true); assertTrue(device.isMounted()); device.unmount(); assertFalse(device.isMounted()); } /** * Test method for {@link org.jajuk.base.Device#unmount(boolean, boolean)}. * * @throws Exception */ public void testUnmountBooleanBoolean() throws Exception { Device device = JUnitHelpers.getDevice(); assertFalse(device.isMounted()); device.unmount(false, false); device.mount(true); assertTrue(device.isMounted()); device.unmount(false, false); assertFalse(device.isMounted()); } public void testUnmountBooleanBooleanQueue() throws Exception { Device device = JUnitHelpers.getDevice(); device.mount(true); assertTrue(device.isMounted()); Directory dir = JUnitHelpers.getDirectory(); device.addDirectory(dir); File file = getFile(9, dir); QueueModel.insert(new StackItem(file), 0); QueueModel.goTo(0); device.unmount(false, false); assertTrue(device.isMounted()); // still mounted because there is a file // used on this device.... } private class MockAttributes implements Attributes { @Override public String getValue(String uri, String localName) { return null; } @Override public String getValue(String qName) { return null; } @Override public String getValue(int index) { switch (index) { case 0: return "value1"; case 1: return "value2"; case 2: return "value3"; case 3: return "true"; default: fail("invalid index: " + index); break; } return null; } @Override public String getURI(int index) { return null; } @Override public String getType(String uri, String localName) { return null; } @Override public String getType(String qName) { return null; } @Override public String getType(int index) { return null; } @Override public String getQName(int index) { switch (index) { case 0: return "att1"; case 1: return "att2"; case 2: return "att3"; case 3: return Const.XML_DEVICE_AUTO_REFRESH; default: fail("invalid index: " + index); } return null; } @Override public String getLocalName(int index) { return null; } @Override public int getLength() { return 4; } @Override public int getIndex(String uri, String localName) { return 0; } @Override public int getIndex(String qName) { return 0; } } } jajuk-1.9.6.orig/src/test/java/org/jajuk/base/TestFileManager.java0000644000175000017500000000565611720500104024641 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision: 3132 $ */ package org.jajuk.base; import java.io.IOException; import java.util.List; import org.jajuk.JUnitHelpers; import org.jajuk.JajukTestCase; import org.jajuk.util.error.JajukException; import org.junit.Test; /** * */ public class TestFileManager extends JajukTestCase { @Override protected void setUp() throws Exception { super.setUp(); } /** * Test method for {@link org.jajuk.base.FileManager#removeFile(File)}. * @throws IOException */ @Test public void testRemoveFile() { // Set-up... File file = JUnitHelpers.getFile(); // Remove the reference FileManager.getInstance().removeFile(file); // 1- Check that the collection no more contains the file assertTrue(FileManager.getInstance().getFileByID(file.getID()) == null); // 2- check that associated track no more contains this file assertFalse(file.getTrack().getFiles().contains(file)); } /** * Test method for {@link org.jajuk.base.FileManager#changeFileDirectory(org.jajuk.base.File, org.jajuk.base.Directory)}. * @throws IOException */ @Test public void testChangeFileDirectory() throws IOException, JajukException { // Set-up... File oldFile = JUnitHelpers.getFile(); oldFile.getDirectory().getFio().mkdirs(); oldFile.getFIO().createNewFile(); String newDirName = "top2"; // Create a top2 directory just bellow device root Directory newDir = JUnitHelpers.getDirectory(newDirName, oldFile.getDevice().getRootDirectory(), oldFile.getDevice()); // Create the physical directory if required newDir.getFio().mkdirs(); // Perform the move File newFile = FileManager.getInstance().changeFileDirectory(oldFile, newDir); // Now test ... //1- Does the new file exist ? assertTrue(new java.io.File(newDir.getAbsolutePath() + '/' + oldFile.getName()).exists()); //2- Does the old file is removed ? assertFalse(oldFile.getFIO().exists()); //3- Does the associated track contains the right file (and only it) List files = newFile.getTrack().getFiles(); assertTrue(files.size() == 1 && files.get(0).equals(newFile)); } } jajuk-1.9.6.orig/src/test/java/org/jajuk/base/TestSearchResult.java0000644000175000017500000001122011720500104025053 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.base; import junit.framework.TestCase; import org.jajuk.JUnitHelpers; import org.jajuk.base.SearchResult.SearchResultType; import org.jajuk.services.webradio.WebRadio; /** * DOCUMENT_ME. */ public class TestSearchResult extends TestCase { /** * Test method for {@link org.jajuk.base.SearchResult#hashCode()}. * * @throws Exception the exception */ public void testHashCode() throws Exception { // TODO: this fails currently because there is no equals in SearchResult, should we add one? For now we just cover hashCode() // hashcode only looks at "sResu" parameter SearchResult res = new SearchResult(JUnitHelpers.getFile("file2", true)); SearchResult equ = new SearchResult(JUnitHelpers.getFile("file2", true)); assertEquals(res.hashCode(), equ.hashCode()); //JUnitHelpers.HashCodeTest(res, equ); // res = new SearchResult(new WebRadio("web", "url"), "webradio"); // equ = new SearchResult(new WebRadio("web", "url"), "webradio"); // JUnitHelpers.HashCodeTest(res, equ); } /** * Test method for {@link org.jajuk.base.SearchResult#SearchResult(org.jajuk.base.File)}. * * @throws Exception the exception */ public void testSearchResultFile() throws Exception { SearchResult res = new SearchResult(JUnitHelpers.getFile("file2", true)); assertNotNull(res); } /** * Test method for {@link org.jajuk.base.SearchResult#SearchResult(org.jajuk.base.File, java.lang.String)}. * * @throws Exception the exception */ public void testSearchResultFileString() throws Exception { SearchResult res = new SearchResult(JUnitHelpers.getFile("file2", true), "testresult"); assertNotNull(res); } /** * Test method for {@link org.jajuk.base.SearchResult#SearchResult(org.jajuk.services.webradio.WebRadio, java.lang.String)}. */ public void testSearchResultWebRadioString() { SearchResult res = new SearchResult(new WebRadio("web", "testurl"), "testresult"); assertNotNull(res); } /** * Test method for {@link org.jajuk.base.SearchResult#compareTo(org.jajuk.base.SearchResult)}. * * @throws Exception the exception */ public void testCompareTo() throws Exception { // compareTo only looks at sResu-parameter SearchResult res = new SearchResult(JUnitHelpers.getFile("file2", true), "testresu"); SearchResult equ = new SearchResult(JUnitHelpers.getFile("file2", true), "testresu"); SearchResult notequ = new SearchResult(JUnitHelpers.getFile("file2", true), "testresu1"); JUnitHelpers.CompareToTest(res, equ, notequ); } /** * Test method for {@link org.jajuk.base.SearchResult#getFile()}. * * @throws Exception the exception */ public void testGetFile() throws Exception { SearchResult res = new SearchResult(JUnitHelpers.getFile("file2", true), "testresu"); assertEquals("file2", res.getFile().getName()); } /** * Test method for {@link org.jajuk.base.SearchResult#getType()}. * * @throws Exception the exception */ public void testGetType() throws Exception { SearchResult res = new SearchResult(JUnitHelpers.getFile("file2", true), "testresu"); assertEquals(SearchResultType.FILE, res.getType()); res = new SearchResult(new WebRadio("web", "testurl"), "testresu"); assertEquals(SearchResultType.WEBRADIO, res.getType()); } /** * Test method for {@link org.jajuk.base.SearchResult#getWebradio()}. */ public void testGetWebradio() { SearchResult res = new SearchResult(new WebRadio("web1", "testurl"), "testresu"); assertEquals(SearchResultType.WEBRADIO, res.getType()); assertEquals("web1", res.getWebradio().getName()); } /** * Test method for {@link org.jajuk.base.SearchResult#getResu()}. */ public void testGetResu() { SearchResult res = new SearchResult(new WebRadio("web", "testurl"), "testresu1"); assertEquals("testresu1", res.getResu()); } } jajuk-1.9.6.orig/src/test/java/org/jajuk/base/TestArtistManager.java0000644000175000017500000004453411720500104025226 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.base; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import org.apache.commons.lang.StringUtils; import org.jajuk.JUnitHelpers; import org.jajuk.JajukTestCase; import org.jajuk.ThreadTestHelper; import org.jajuk.services.covers.Cover; import org.jajuk.services.players.IPlayerImpl; import org.jajuk.services.players.QueueModel; import org.jajuk.services.players.StackItem; import org.jajuk.services.startup.StartupCollectionService; import org.jajuk.services.tags.ITagImpl; import org.jajuk.util.Const; import org.jajuk.util.ReadOnlyIterator; import org.jaudiotagger.tag.FieldDataInvalidException; import org.jaudiotagger.tag.KeyNotFoundException; /** * DOCUMENT_ME. */ public class TestArtistManager extends JajukTestCase { /** The Constant NUMBER_OF_TESTS. DOCUMENT_ME */ private static final int NUMBER_OF_TESTS = 10; /** The Constant NUMBER_OF_THREADS. DOCUMENT_ME */ private static final int NUMBER_OF_THREADS = 10; /** * Test method for {@link org.jajuk.base.ArtistManager#getLabel()}. */ public final void testGetLabel() { assertEquals(Const.XML_ARTISTS, ArtistManager.getInstance().getLabel()); } /** * Test method for {@link org.jajuk.base.ArtistManager#getInstance()}. */ public final void testGetInstance() { assertNotNull(ArtistManager.getInstance()); } /** * Test method for. * * {@link org.jajuk.base.ArtistManager#registerArtist(java.lang.String)}. */ public final void testRegisterArtistString() { Artist artist = ArtistManager.getInstance().registerArtist("name"); assertNotNull(artist); assertTrue(StringUtils.isNotBlank(artist.getID())); assertEquals("name", artist.getName()); } /** * Test method for. * * {@link org.jajuk.base.ArtistManager#createID(java.lang.String)}. */ public final void testCreateID() { String id = ItemManager.createID("name"); // same for same name assertEquals(id, ItemManager.createID("name")); // different for other name assertFalse(id.equals(ItemManager.createID("name2"))); } /** * Test method for. * * {@link org.jajuk.base.ArtistManager#registerArtist(java.lang.String, java.lang.String)} * . */ public final void testRegisterArtistStringString() { Artist artist = ArtistManager.getInstance().registerArtist("4", "name"); assertNotNull(artist); assertEquals("4", artist.getID()); assertEquals("name", artist.getName()); } /** * Test method for. * * @throws Exception the exception * {@link org.jajuk.base.ArtistManager#changeArtistName(org.jajuk.base.Artist, java.lang.String)} * . */ public final void testChangeArtistName() throws Exception { StartupCollectionService.registerItemManagers(); Artist artistold = JUnitHelpers.getArtist("nameold"); // we get the same object back if we have the same name assertTrue(artistold == ArtistManager.getInstance().changeArtistName(artistold, "nameold")); // now try with a new name Artist artist = ArtistManager.getInstance().changeArtistName(artistold, "namenew"); assertFalse(artistold == artist); // not null assertFalse("4".equals(artist.getID())); // new ID assertTrue(StringUtils.isNotBlank(artist.getID())); // useful ID assertEquals("namenew", artist.getName()); // correct name // test with Tracks for the artist and Queue Model playing that file File track1 = getFile(14, artist); List list = new ArrayList(); list.add(new StackItem(track1)); QueueModel.insert(list, 0); QueueModel.goTo(0); // to have the Queue in playing mode // verify that Queue is playing now assertFalse(QueueModel.isStopped()); assertNotNull(QueueModel.getPlayingFile()); assertNotNull(QueueModel.getPlayingFile().getTrack()); assertNotNull(QueueModel.getPlayingFile().getTrack().getArtist()); assertEquals(track1.getTrack(), QueueModel.getPlayingFile().getTrack()); assertEquals(artist, QueueModel.getPlayingFile().getTrack().getArtist()); // now try to change again with the track and the item playing in the queue artist = ArtistManager.getInstance().changeArtistName(artist, "namenewnew"); assertFalse(artistold == artist); // not null assertFalse("4".equals(artist.getID())); // new ID assertTrue(StringUtils.isNotBlank(artist.getID())); // useful ID assertEquals("namenewnew", artist.getName()); // correct name } // test this in a thread as well to cover the synchronized block... /** * Test change artist name threads. * DOCUMENT_ME * * @throws Exception the exception */ public final void testChangeArtistNameThreads() throws Exception { StartupCollectionService.registerItemManagers(); final Artist artistold = JUnitHelpers.getArtist("nameold"); // we get the same object back if we have the same name assertTrue(artistold == ArtistManager.getInstance().changeArtistName(artistold, "nameold")); ThreadTestHelper helper = new ThreadTestHelper(NUMBER_OF_THREADS, NUMBER_OF_TESTS); helper.executeTest(new ThreadTestHelper.TestRunnable() { @Override public void doEnd(int threadnum) throws Exception { // do stuff at the end, nothing here for now } @Override public void run(int threadnum, int iter) throws Exception { // just call the method in a thread multiple times at the same time ArtistManager.getInstance().changeArtistName(artistold, "namenew"); } }); } /** * Test multiple threads. * DOCUMENT_ME */ public void testMultipleThreads() { } /** * Gets the file. * * @param i DOCUMENT_ME * @param artist DOCUMENT_ME * @return the file * @throws Exception the exception */ @SuppressWarnings("unchecked") private File getFile(int i, Artist artist) throws Exception { Genre genre = JUnitHelpers.getGenre("name"); Album album = JUnitHelpers.getAlbum("myalbum", 0); album.setProperty(Const.XML_ALBUM_DISCOVERED_COVER, Const.COVER_NONE); // don't read // covers for // this test Year year = new Year(Integer.valueOf(i).toString(), "2000"); IPlayerImpl imp = new JUnitHelpers.MockPlayer(); Class cl = (Class) imp.getClass(); Type type = TypeManager.getInstance().registerType("name", "tst", cl, MyTagImpl.class); Track track = TrackManager.getInstance().registerTrack("name", album, genre, artist, 120, year, 1, type, 1); Device device = JUnitHelpers.getDevice(); device.mount(true); Directory dir = JUnitHelpers.getDirectory(); File file = new org.jajuk.base.File(Integer.valueOf(i).toString(), "test.tst", dir, track, 120, 70); track.addFile(file); return file; } /** * Test method for. * * {@link org.jajuk.base.ArtistManager#format(java.lang.String)}. */ public final void testFormat() { assertEquals("Testname", ItemManager.format("testname")); // trim spaces assertEquals("Testname", ItemManager.format(" testname ")); // - assertEquals("Te s tname", ItemManager.format(" te-s-tname ")); // _ assertEquals("Te s tname", ItemManager.format(" te_s_tname ")); // all of them assertEquals("TE s tnam e ", ItemManager.format(" tE_s_tnam--e- ")); } /** * Test method for {@link org.jajuk.base.ArtistManager#getArtistsList()}. */ public final void testGetArtistsList() { List list = ArtistManager.getArtistsList(); assertNotNull(list); // not sure how many elements we should expect as this is static and other // tests // could already have added some items, let's just try to add a new one int i = list.size(); ArtistManager.getInstance().registerArtist("newandnotanywhereelseusedname"); // the vector should be updated directly, we use the same in the // combobox-models, // this is the reason for using Vector in the first place! assertEquals(i + 1, list.size()); } /** * Test method for. * * {@link org.jajuk.base.ArtistManager#getArtistByID(java.lang.String)}. */ public final void testGetArtistByID() { Artist artist = ArtistManager.getInstance().registerArtist("anothernewartist"); Artist artist2 = ArtistManager.getInstance().getArtistByID(artist.getID()); assertEquals("anothernewartist", artist2.getName()); } /** * Test method for {@link org.jajuk.base.ArtistManager#getArtists()}. */ public final void testGetArtists() { List list = ArtistManager.getInstance().getArtists(); assertNotNull(list); // not sure how many elements we should expect as this is static and other // tests // could already have added some items, let's just try to add a new one int i = list.size(); ArtistManager.getInstance().registerArtist("newname"); // the list is a copy, so we need to get it again list = ArtistManager.getInstance().getArtists(); assertEquals(i + 1, list.size()); } /** * Test method for {@link org.jajuk.base.ArtistManager#getArtistsIterator()}. */ public final void testGetArtistsIterator() { ArtistManager.getInstance().registerArtist("anothernewname"); ReadOnlyIterator it = ArtistManager.getInstance().getArtistsIterator(); assertNotNull(it); assertTrue(it.hasNext()); // there can be items from before, so just expect // at least one item... } /** * Test method for. * * @throws Exception the exception * {@link org.jajuk.base.ArtistManager#getAssociatedArtists(org.jajuk.base.Item)} * . */ public final void testGetAssociatedArtists() throws Exception { // empty list with invalid item List list = ArtistManager.getInstance().getAssociatedArtists(null); assertNotNull(list); assertEquals(0, list.size()); Artist artist = ArtistManager.getInstance().registerArtist("myartisthere"); File file = getFile(15, artist); // also registers the Track list = ArtistManager.getInstance().getAssociatedArtists(file.getTrack()); assertNotNull(list); assertEquals(1, list.size()); assertEquals("myartisthere", list.get(0).getName()); Album album = file.getTrack().getAlbum(); album.getTracksCache().add(file.getTrack()); list = ArtistManager.getInstance().getAssociatedArtists(album); assertNotNull(list); assertEquals(1, list.size()); assertEquals("myartisthere", list.get(0).getName()); } /** * Test method for. * * {@link org.jajuk.base.ArtistManager#getArtistByName(java.lang.String)}. */ public final void testGetArtistByName() { Artist artist = ArtistManager.getInstance().registerArtist("anothernewartist"); Artist artist2 = ArtistManager.getInstance().getArtistByName("anothernewartist"); assertEquals(artist.getID(), artist2.getID()); } /** * Test sorting. * DOCUMENT_ME */ public final void testSorting() { // make sure we have "ordered state" ArtistManager.getInstance().switchToOrderState(); List ids = new ArrayList(); ids.add(ArtistManager.getInstance().registerArtist("anothernewartist").getID()); ids.add(ArtistManager.getInstance().registerArtist("yet another artist").getID()); ids.add(ArtistManager.getInstance().registerArtist("one more artist").getID()); ids.add(ArtistManager.getInstance().registerArtist("number 10").getID()); ids.add(ArtistManager.getInstance().registerArtist("number 11").getID()); // now they are sorted by name Iterator it = ArtistManager.getInstance().getItemsIterator(); assertEquals("anothernewartist", it.next().getName()); assertEquals("number 10", it.next().getName()); assertEquals("number 11", it.next().getName()); assertEquals("one more artist", it.next().getName()); assertEquals("yet another artist", it.next().getName()); assertFalse(it.hasNext()); // make sure we can fetch all of these by ID for (String id : ids) { assertNotNull("Did not find ID: " + id, ArtistManager.getInstance().getArtistByID(id)); } assertNull(ArtistManager.getInstance().getArtistByID("notexisting")); assertNull(ArtistManager.getInstance().getArtistByID("number 12")); assertNull(ArtistManager.getInstance().getArtistByID("number 09")); } /** * DOCUMENT_ME. */ public static class MyTagImpl implements ITagImpl { /* (non-Javadoc) * @see org.jajuk.services.tags.ITagImpl#commit() */ @Override public void commit() throws Exception { } /* (non-Javadoc) * @see org.jajuk.services.tags.ITagImpl#getAlbumArtist() */ @Override public String getAlbumArtist() throws Exception { return null; } /* (non-Javadoc) * @see org.jajuk.services.tags.ITagImpl#getAlbumName() */ @Override public String getAlbumName() throws Exception { return null; } /* (non-Javadoc) * @see org.jajuk.services.tags.ITagImpl#getArtistName() */ @Override public String getArtistName() throws Exception { return null; } /* (non-Javadoc) * @see org.jajuk.services.tags.ITagImpl#getComment() */ @Override public String getComment() throws Exception { return null; } /* (non-Javadoc) * @see org.jajuk.services.tags.ITagImpl#getDiscNumber() */ @Override public long getDiscNumber() throws Exception { return 0; } /* (non-Javadoc) * @see org.jajuk.services.tags.ITagImpl#getLength() */ @Override public long getLength() throws Exception { return 0; } /* (non-Javadoc) * @see org.jajuk.services.tags.ITagImpl#getOrder() */ @Override public long getOrder() throws Exception { return 0; } /* (non-Javadoc) * @see org.jajuk.services.tags.ITagImpl#getQuality() */ @Override public long getQuality() throws Exception { return 0; } /* (non-Javadoc) * @see org.jajuk.services.tags.ITagImpl#getGenreName() */ @Override public String getGenreName() throws Exception { return null; } /* (non-Javadoc) * @see org.jajuk.services.tags.ITagImpl#getTrackName() */ @Override public String getTrackName() throws Exception { return null; } /* (non-Javadoc) * @see org.jajuk.services.tags.ITagImpl#getYear() */ @Override public String getYear() throws Exception { return null; } /* (non-Javadoc) * @see org.jajuk.services.tags.ITagImpl#setAlbumArtist(java.lang.String) */ @Override public void setAlbumArtist(String albumArtist) throws Exception { } /* (non-Javadoc) * @see org.jajuk.services.tags.ITagImpl#setAlbumName(java.lang.String) */ @Override public void setAlbumName(String albumName) throws Exception { } /* (non-Javadoc) * @see org.jajuk.services.tags.ITagImpl#setArtistName(java.lang.String) */ @Override public void setArtistName(String artistName) throws Exception { } /* (non-Javadoc) * @see org.jajuk.services.tags.ITagImpl#setComment(java.lang.String) */ @Override public void setComment(String comment) throws Exception { } /* (non-Javadoc) * @see org.jajuk.services.tags.ITagImpl#setDiscNumber(long) */ @Override public void setDiscNumber(long discnumber) throws Exception { } /* (non-Javadoc) * @see org.jajuk.services.tags.ITagImpl#setFile(java.io.File) */ @Override public void setFile(java.io.File fio) throws Exception { } /* (non-Javadoc) * @see org.jajuk.services.tags.ITagImpl#setOrder(long) */ @Override public void setOrder(long order) throws Exception { } /* (non-Javadoc) * @see org.jajuk.services.tags.ITagImpl#setGenreName(java.lang.String) */ @Override public void setGenreName(String genre) throws Exception { } /* (non-Javadoc) * @see org.jajuk.services.tags.ITagImpl#setTrackName(java.lang.String) */ @Override public void setTrackName(String trackName) throws Exception { } /* (non-Javadoc) * @see org.jajuk.services.tags.ITagImpl#setYear(java.lang.String) */ @Override public void setYear(String year) throws Exception { } /* * (non-Javadoc) * * @see org.jajuk.services.tags.ITagImpl#getTagField(java.lang.String) */ @Override public String getTagField(String tagFieldKey) throws Exception { return null; } /* * (non-Javadoc) * * @see org.jajuk.services.tags.ITagImpl#setTagField(java.lang.String, * java.lang.String) */ @Override public void setTagField(String tagFieldKey, String tagFieldValue) throws FieldDataInvalidException, KeyNotFoundException { } /* * (non-Javadoc) * * @see org.jajuk.services.tags.ITagImpl#deleteLyrics() */ @Override public void deleteLyrics() throws Exception { } /* * (non-Javadoc) * * @see org.jajuk.services.tags.ITagImpl#getLyrics() */ @Override public String getLyrics() throws Exception { return null; } /* * (non-Javadoc) * * @see org.jajuk.services.tags.ITagImpl#setLyrics(java.lang.String) */ @Override public void setLyrics(String sLyrics) throws Exception { } /* (non-Javadoc) * @see org.jajuk.services.tags.ITagImpl#getSupportedTagFields() */ @Override public List getSupportedTagFields() { // TODO Auto-generated method stub return null; } /* (non-Javadoc) * @see org.jajuk.services.tags.ITagImpl#getCovers() */ @Override public List getCovers() throws Exception { // TODO Auto-generated method stub return null; } } } jajuk-1.9.6.orig/src/test/java/org/jajuk/base/TestTrackManager.java0000644000175000017500000001600711720500104025016 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision: 3132 $ */ package org.jajuk.base; import org.jajuk.JUnitHelpers; import org.jajuk.JajukTestCase; import org.junit.Test; /** * */ public class TestTrackManager extends JajukTestCase { @Override protected void setUp() throws Exception { super.setUp(); } /** * Test method for {@link org.jajuk.base.TrackManager#getLabel()}. */ @Test public void testGetLabel() { //TODO To be implemented } /** * Test method for {@link org.jajuk.base.TrackManager#cleanup()}. */ @Test public void testCleanup() { //TODO To be implemented } /** * Test method for {@link org.jajuk.base.TrackManager#getInstance()}. */ @Test public void testGetInstance() { //TODO To be implemented } /** * Test method for {@link org.jajuk.base.TrackManager#registerTrack(java.lang.String, org.jajuk.base.Album, org.jajuk.base.Genre, org.jajuk.base.Artist, long, org.jajuk.base.Year, long, org.jajuk.base.Type, long)}. */ @Test public void testRegisterTrackStringAlbumGenreArtistLongYearLongTypeLong() { //TODO To be implemented } /** * Test method for {@link org.jajuk.base.TrackManager#createID(java.lang.String, org.jajuk.base.Album, org.jajuk.base.Genre, org.jajuk.base.Artist, long, org.jajuk.base.Year, long, org.jajuk.base.Type, long)}. */ @Test public void testCreateIDStringAlbumGenreArtistLongYearLongTypeLong() { //TODO To be implemented } /** * Test method for {@link org.jajuk.base.TrackManager#registerTrack(java.lang.String, java.lang.String, org.jajuk.base.Album, org.jajuk.base.Genre, org.jajuk.base.Artist, long, org.jajuk.base.Year, long, org.jajuk.base.Type, long)}. */ @Test public void testRegisterTrackStringStringAlbumGenreArtistLongYearLongTypeLong() { //TODO To be implemented } /** * Test method for {@link org.jajuk.base.TrackManager#commit()}. */ @Test public void testCommit() { //TODO To be implemented } /** * Test method for {@link org.jajuk.base.TrackManager#changeTrackAlbum(org.jajuk.base.Track, java.lang.String, java.util.Set)}. */ @Test public void testChangeTrackAlbum() { //TODO To be implemented } /** * Test method for {@link org.jajuk.base.TrackManager#changeTrackArtist(org.jajuk.base.Track, java.lang.String, java.util.Set)}. */ @Test public void testChangeTrackArtist() { //TODO To be implemented } /** * Test method for {@link org.jajuk.base.TrackManager#changeTrackGenre(org.jajuk.base.Track, java.lang.String, java.util.Set)}. */ @Test public void testChangeTrackGenre() { //TODO To be implemented } /** * Test method for {@link org.jajuk.base.TrackManager#changeTrackYear(org.jajuk.base.Track, java.lang.String, java.util.Set)}. */ @Test public void testChangeTrackYear() { //TODO To be implemented } /** * Test method for {@link org.jajuk.base.TrackManager#changeTrackComment(org.jajuk.base.Track, java.lang.String, java.util.Set)}. */ @Test public void testChangeTrackComment() { //TODO To be implemented } /** * Test method for {@link org.jajuk.base.TrackManager#changeTrackRate(org.jajuk.base.Track, long)}. */ @Test public void testChangeTrackRate() { //TODO To be implemented } /** * Test method for {@link org.jajuk.base.TrackManager#changeTrackOrder(org.jajuk.base.Track, long, java.util.Set)}. */ @Test public void testChangeTrackOrder() { //TODO To be implemented } /** * Test method for {@link org.jajuk.base.TrackManager#changeTrackName(org.jajuk.base.Track, java.lang.String, java.util.Set)}. */ @Test public void testChangeTrackName() { //TODO To be implemented } /** * Test method for {@link org.jajuk.base.TrackManager#changeTrackAlbumArtist(org.jajuk.base.Track, java.lang.String, java.util.Set)}. */ @Test public void testChangeTrackAlbumArtist() { //TODO To be implemented } /** * Test method for {@link org.jajuk.base.TrackManager#changeTrackDiscNumber(org.jajuk.base.Track, long, java.util.Set)}. */ @Test public void testChangeTrackDiscNumber() { //TODO To be implemented } /** * Test method for {@link org.jajuk.base.TrackManager#removeFile(org.jajuk.base.Track, org.jajuk.base.File)}. */ @Test public void testRemoveFile() { // Set-up... File file = JUnitHelpers.getFile(); // Remove the reference TrackManager.getInstance().removeFile(file); // Check if the collection no more contains the track (as it mapped a single file now removed) assertTrue(TrackManager.getInstance().getTrackByID(file.getTrack().getID()) == null); // Check if the associated track no more contains this file assertFalse(file.getTrack().getFiles().contains(file)); } /** * Test method for {@link org.jajuk.base.TrackManager#getAssociatedTracks(org.jajuk.base.Item, boolean)}. */ @Test public void testGetAssociatedTracksItemBoolean() { //TODO To be implemented } /** * Test method for {@link org.jajuk.base.TrackManager#getAssociatedTracks(java.util.List, boolean)}. */ @Test public void testGetAssociatedTracksListOfItemBoolean() { //TODO To be implemented } /** * Test method for {@link org.jajuk.base.TrackManager#getComparator()}. */ @Test public void testGetComparator() { //TODO To be implemented } /** * Test method for {@link org.jajuk.base.TrackManager#getTrackByID(java.lang.String)}. */ @Test public void testGetTrackByID() { //TODO To be implemented } /** * Test method for {@link org.jajuk.base.TrackManager#getTracks()}. */ @Test public void testGetTracks() { //TODO To be implemented } /** * Test method for {@link org.jajuk.base.TrackManager#getTracksIterator()}. */ @Test public void testGetTracksIterator() { //TODO To be implemented } /** * Test method for {@link org.jajuk.base.TrackManager#search(java.lang.String)}. */ @Test public void testSearch() { //TODO To be implemented } /** * Test method for {@link org.jajuk.base.TrackManager#isAutocommit()}. */ @Test public void testIsAutocommit() { //TODO To be implemented } /** * Test method for {@link org.jajuk.base.TrackManager#setAutocommit(boolean)}. */ @Test public void testSetAutocommit() { //TODO To be implemented } } jajuk-1.9.6.orig/src/test/java/org/jajuk/base/TestCollection.java0000644000175000017500000002052711720500104024554 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.base; import org.apache.commons.io.FileUtils; import org.apache.commons.lang.StringUtils; import org.jajuk.JUnitHelpers; import org.jajuk.JajukTestCase; import org.jajuk.services.startup.StartupCollectionService; import org.jajuk.util.Const; import org.jajuk.util.UtilString; import org.jajuk.util.error.JajukException; import org.xml.sax.SAXException; import org.xml.sax.SAXParseException; /** * DOCUMENT_ME. */ public class TestCollection extends JajukTestCase { /** * Test method for {@link org.jajuk.base.Collection#startDocument()}. */ public final void testStartDocument() { Collection coll = Collection.getInstance(); assertNotNull(coll); // just call it, this is part of the SAX interfaces coll.startDocument(); } /** * Test method for {@link org.jajuk.base.Collection#endDocument()}. */ public final void testEndDocument() { Collection coll = Collection.getInstance(); assertNotNull(coll); // just call it, this is part of the SAX interfaces coll.endDocument(); } /** * Test method for {@link org.jajuk.base.Collection#getInstance()}. */ public final void testGetInstance() { Collection coll = Collection.getInstance(); assertNotNull(coll); } /** * Test method for {@link org.jajuk.base.Collection#commit(java.io.File)}. * * @throws Exception the exception */ public final void testCommit() throws Exception { StartupCollectionService.registerItemManagers(); Collection coll = Collection.getInstance(); assertNotNull(coll); java.io.File file = java.io.File.createTempFile("testcoll", ".xml"); // delete the file before writing the collection assertTrue(file.delete()); // commit without any item Collection.commit(file); // now it should exist and have some content assertTrue(file.exists()); String str = FileUtils.readFileToString(file); assertTrue(str, StringUtils.isNotBlank(str)); assertTrue(str, str.contains("<" + Const.XML_COLLECTION)); // now with some content DeviceManager.getInstance().registerDevice("testdevice", 1, System.getProperty("java.io.tmpdir")); GenreManager.getInstance().registerGenre("cooldown"); { Genre genre = GenreManager.getInstance().registerGenre("name"); Album album = AlbumManager.getInstance().registerAlbum("name", 23); album.setProperty(Const.XML_ALBUM_DISCOVERED_COVER, Const.COVER_NONE); // don't read covers for // this test Artist artist = ArtistManager.getInstance().registerArtist("name"); Year year = YearManager.getInstance().registerYear("2000"); YearManager.getInstance().registerYear("2000"); Type type = TypeManager.getInstance().registerType("MP3", "mp3", null, null); TrackManager.getInstance() .registerTrack("name5", album, genre, artist, 120, year, 1, type, 1); } YearManager.getInstance().registerYear("1900"); Device device = new Device("6", System.getProperty("java.io.tmpdir")); device.setUrl(System.getProperty("java.io.tmpdir")); Directory dir = JUnitHelpers.getDirectory(); PlaylistManager.getInstance().registerPlaylistFile("4", "plf", dir); ArtistManager.getInstance().registerArtist("testartist"); AlbumManager.getInstance().registerAlbum("album2", "artist1", 0); device = DeviceManager.getInstance().registerDevice("7", 0, System.getProperty("java.io.tmpdir")); DirectoryManager.getInstance().registerDirectory(device); device = new Device("6", System.getProperty("java.io.tmpdir")); device.setUrl(System.getProperty("java.io.tmpdir")); FileManager.getInstance().registerFile("thisfile.mp3", dir, TrackManager.getInstance().getTracks().get(0), 120, 100); // delete the file before writing the collection assertTrue(file.delete()); // commit without any item Collection.commit(file); // now it should exist and have some content assertTrue(file.exists()); str = FileUtils.readFileToString(file); assertTrue(str, StringUtils.isNotBlank(str)); assertTrue(str, str.contains("<" + Const.XML_COLLECTION)); // it should also contain the content that we added assertTrue(str, str.contains("testdevice")); assertTrue(str, str.contains("cooldown")); // add test for strange error in this testcase on hudson assertNotNull(UtilString.getAdditionDateFormatter()); // also test loading here Collection.load(file); // TODO: loading needs more testing and verification of results after // loading... } /** * Test method for {@link org.jajuk.base.Collection#load(java.io.File)}. */ public final void testLoad() { // tested above } /** * Test load not exists. * DOCUMENT_ME * * @throws Exception the exception */ public final void testLoadNotExists() throws Exception { try { Collection.load(new java.io.File("Notexistingfile")); fail("Should throw an exception here."); } catch (JajukException e) { assertTrue(e.getMessage(), e.getMessage().contains("Notexistingfile")); } } /** * Test method for {@link org.jajuk.base.Collection#cleanupLogical()}. */ public final void testCleanupLogical() { Collection.cleanupLogical(); } /** * Test method for {@link org.jajuk.base.Collection#clearCollection()}. */ public final void testClearCollection() { Collection.clearCollection(); } /** * Test method for. * * {@link org.jajuk.base.Collection#warning(org.xml.sax.SAXParseException)}. */ public final void testWarningSAXParseException() { Collection coll = Collection.getInstance(); try { coll.warning(new SAXParseException("Testexception", null)); fail("Should throw exception here..."); } catch (SAXException e) { assertTrue(e.getMessage(), e.getMessage().contains("Testexception")); } } /** * Test method for. * * @throws Exception the exception * {@link org.jajuk.base.Collection#error(org.xml.sax.SAXParseException)}. */ public final void testErrorSAXParseException() throws Exception { Collection coll = Collection.getInstance(); try { coll.error(new SAXParseException("Testexception", null)); fail("Should throw exception here..."); } catch (SAXException e) { assertTrue(e.getMessage(), e.getMessage().contains("Testexception")); } } /** * Test method for. * * @throws Exception the exception * {@link org.jajuk.base.Collection#fatalError(org.xml.sax.SAXParseException)} * . */ public final void testFatalErrorSAXParseException() throws Exception { Collection coll = Collection.getInstance(); try { coll.fatalError(new SAXParseException("Testexception", null)); fail("Should throw exception here..."); } catch (SAXException e) { assertTrue(e.getMessage(), e.getMessage().contains("Testexception")); } } /** * Test method for. * * {@link org.jajuk.base.Collection#startElement(java.lang.String, java.lang.String, java.lang.String, org.xml.sax.Attributes)} * . */ public final void testStartElementStringStringStringAttributes() { // tested as part of commit/load } /** * Test method for {@link org.jajuk.base.Collection#getHmWrongRightFileID()}. */ public final void testGetHmWrongRightFileID() { Collection coll = Collection.getInstance(); assertNotNull(coll.getHmWrongRightFileID()); } /** * Test method for {@link org.jajuk.base.Collection#getWrongRightAlbumIDs()}. */ public final void testGetWrongRightAlbumIDs() { Collection coll = Collection.getInstance(); assertNotNull(coll.getWrongRightAlbumIDs()); } } jajuk-1.9.6.orig/src/test/java/org/jajuk/base/TestTypeManager.java0000644000175000017500000001641711720500104024700 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.base; import junit.framework.TestCase; import org.jajuk.services.startup.StartupCollectionService; import org.jajuk.util.Const; /** * DOCUMENT_ME. */ public class TestTypeManager extends TestCase { /* * (non-Javadoc) * * @see junit.framework.TestCase#setUp() */ @Override protected void setUp() throws Exception { // clear to make sure previous tests did not add anything TypeManager.getInstance().clear(); super.setUp(); } /** * Test method for {@link org.jajuk.base.TypeManager#getLabel()}. */ public void testGetLabel() { assertEquals(Const.XML_TYPES, TypeManager.getInstance().getLabel()); } /** * Test method for {@link org.jajuk.base.TypeManager#getInstance()}. */ public void testGetInstance() { assertNotNull(TypeManager.getInstance()); } /** * Test method for. * * {@link org.jajuk.base.TypeManager#registerType(java.lang.String, java.lang.String, java.lang.Class, java.lang.Class)} * . */ public void testRegisterType() { Type type = TypeManager.getInstance().registerType("testtype", "tst", null, null); assertNotNull(type); // try to register the same thing, we get back the same type Type type2 = TypeManager.getInstance().registerType("testtype", "tst", null, null); assertTrue(type == type2); // instance compare on purpose! // register the same type } /** * Test method for. * * {@link org.jajuk.base.TypeManager#isExtensionSupported(java.lang.String)}. */ public void testIsExtensionSupported() { // not supported initially assertFalse(TypeManager.getInstance().isExtensionSupported("tst")); // register a type for it assertNotNull(TypeManager.getInstance().registerType("testtype", "tst", null, null)); // supported now assertTrue(TypeManager.getInstance().isExtensionSupported("tst")); } /** * Test method for. * * {@link org.jajuk.base.TypeManager#getTypeByExtension(java.lang.String)}. */ public void testGetTypeByExtension() { // not supported initially assertNull(TypeManager.getInstance().getTypeByExtension("tst")); // register a type for it assertNotNull(TypeManager.getInstance().registerType("testtype", "tst", null, null)); // supported now assertNotNull(TypeManager.getInstance().getTypeByExtension("tst")); } /** * Test method for {@link org.jajuk.base.TypeManager#getAllMusicTypes()}. * * @throws Exception the exception */ public void testGetAllMusicTypes() throws Exception { // we need the ItemManagers when using properties StartupCollectionService.registerItemManagers(); // no type initially assertEquals(0, TypeManager.getInstance().getAllMusicTypes().size()); // register a type assertNotNull(TypeManager.getInstance().registerType("testtype", "tst", null, null)); // still no type now as it does not have "music" property set assertEquals(0, TypeManager.getInstance().getAllMusicTypes().size()); // add another type with "true" for "music" Type type = TypeManager.getInstance().registerType("testtype2", "tst2", null, null); type.setProperty(Const.XML_TYPE_IS_MUSIC, true); // now we have one music-type assertEquals(1, TypeManager.getInstance().getAllMusicTypes().size()); // add default types TypeManager.registerTypesNoMplayer(); // many types now assertTrue(TypeManager.getInstance().getAllMusicTypes().size() > 1); } /** * Test method for {@link org.jajuk.base.TypeManager#getTypeListString()}. * * @throws Exception the exception */ public void testGetTypeListString() throws Exception { // no type initially assertEquals("", TypeManager.getInstance().getTypeListString()); // register a type assertNotNull(TypeManager.getInstance().registerType("testtype", "tst", null, null)); // one type now assertEquals("tst", TypeManager.getInstance().getTypeListString()); // add default types TypeManager.registerTypesNoMplayer(); // many types now assertTrue(TypeManager.getInstance().getTypeListString().length() > 4); } /** * Test method for. * * {@link org.jajuk.base.TypeManager#getTypeByID(java.lang.String)}. */ public void testGetTypeByID() { // not available initially assertNull(TypeManager.getInstance().getTypeByID("tst")); // add one type assertNotNull(TypeManager.getInstance().registerType("testtype", "tst", null, null)); // available now assertNotNull(TypeManager.getInstance().getTypeByID("tst")); // others still not available assertNull(TypeManager.getInstance().getTypeByID("notexist")); } /** * Test method for {@link org.jajuk.base.TypeManager#getTypes()}. * * @throws Exception the exception */ public void testGetTypes() throws Exception { // no type initially assertEquals(0, TypeManager.getInstance().getTypes().size()); // register a type assertNotNull(TypeManager.getInstance().registerType("testtype", "tst", null, null)); // one type now assertEquals(1, TypeManager.getInstance().getTypes().size()); // add default types TypeManager.registerTypesNoMplayer(); // many types now assertTrue(TypeManager.getInstance().getTypes().size() > 1); } /** * Test method for {@link org.jajuk.base.TypeManager#getTypesIterator()}. * * @throws Exception the exception */ public void testGetTypesIterator() throws Exception { // no type initially assertFalse(TypeManager.getInstance().getTypesIterator().hasNext()); // register a type assertNotNull(TypeManager.getInstance().registerType("testtype", "tst", null, null)); // one type now assertTrue(TypeManager.getInstance().getTypesIterator().hasNext()); // add default types TypeManager.registerTypesNoMplayer(); // many types now assertTrue(TypeManager.getInstance().getTypesIterator().hasNext()); } /** * Test method for {@link org.jajuk.base.TypeManager#registerTypesNoMplayer()} * . * * @throws Exception the exception */ public void testRegisterTypesNoMplayer() throws Exception { TypeManager.registerTypesNoMplayer(); assertTrue(TypeManager.getInstance().getTypes().size() > 1); } /** * Test method for. * * @throws Exception the exception * {@link org.jajuk.base.TypeManager#registerTypesMplayerAvailable()}. */ public void testRegisterTypesMplayerAvailable() throws Exception { TypeManager.registerTypesMplayerAvailable(); assertTrue(TypeManager.getInstance().getTypes().size() > 1); } } jajuk-1.9.6.orig/src/test/java/org/jajuk/base/TestDeviceManager.java0000644000175000017500000003024111720500104025145 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.base; import org.jajuk.JajukTestCase; import org.jajuk.services.startup.StartupCollectionService; import org.jajuk.util.Conf; import org.jajuk.util.Const; /** * DOCUMENT_ME. */ public class TestDeviceManager extends JajukTestCase { /* (non-Javadoc) * @see org.jajuk.JajukTestCase#setUp() */ @Override protected void setUp() throws Exception { // avoid UI: Conf.setProperty(Const.CONF_CONFIRMATIONS_REMOVE_DEVICE, "false"); super.setUp(); } /** * Test method for {@link org.jajuk.base.DeviceManager#getLabel()}. */ public final void testGetLabel() { assertEquals(Const.XML_DEVICES, DeviceManager.getInstance().getLabel()); } /** * Test method for. * * {@link org.jajuk.base.DeviceManager#startAutoRefreshThread()}. */ public final void testStartAutoRefreshThread() { DeviceManager.getInstance().startAutoRefreshThread(); // what happens if done twice? DeviceManager.getInstance().startAutoRefreshThread(); } /** * Test method for {@link org.jajuk.base.DeviceManager#getInstance()}. */ public final void testGetInstance() { assertNotNull(DeviceManager.getInstance()); } /** * Test method for. * * {@link org.jajuk.base.DeviceManager#registerDevice(java.lang.String, long, java.lang.String)} * . */ public final void testRegisterDeviceStringLongString() { assertNotNull(DeviceManager.getInstance().registerDevice("device", 0, System.getProperty("java.io.tmpdir"))); assertNotNull(DeviceManager.getInstance().getDeviceByName("device")); } /** * Test register device twice. * DOCUMENT_ME */ public final void testRegisterDeviceTwice() { assertNotNull(DeviceManager.getInstance().registerDevice("device", 0, System.getProperty("java.io.tmpdir"))); assertNotNull(DeviceManager.getInstance().registerDevice("device", 0, System.getProperty("java.io.tmpdir"))); assertNotNull(DeviceManager.getInstance().getDeviceByName("device")); } /** * Test method for. * * {@link org.jajuk.base.DeviceManager#registerDevice(java.lang.String, java.lang.String, long, java.lang.String)} * . */ public final void testRegisterDeviceStringStringLongString() { assertNotNull(DeviceManager.getInstance().registerDevice("2", "device2", 0, System.getProperty("java.io.tmpdir"))); assertNotNull(DeviceManager.getInstance().getDeviceByName("device2")); } /** * Test method for. * * {@link org.jajuk.base.DeviceManager#createID(java.lang.String)}. */ public final void testCreateID() { assertNotNull(ItemManager.createID("device123")); } /** * Test method for. * * {@link org.jajuk.base.DeviceManager#checkDeviceAvailablity(java.lang.String, int, java.lang.String, boolean)} * . */ public final void testCheckDeviceAvailablityCD() { assertEquals(0, DeviceManager.getInstance().checkDeviceAvailablity("device3", Device.TYPE_CD, System.getProperty("java.io.tmpdir"), true)); } /** * Test check device availablity existing name. * DOCUMENT_ME */ public final void testCheckDeviceAvailablityExistingName() { assertNotNull(DeviceManager.getInstance().registerDevice("device4", Device.TYPE_DIRECTORY, System.getProperty("java.io.tmpdir"))); // error, name already exists assertEquals(19, DeviceManager.getInstance().checkDeviceAvailablity("device4", Device.TYPE_DIRECTORY, System.getProperty("java.io.tmpdir"), true)); } /** * Test check device availablity existing name not new. * DOCUMENT_ME */ public final void testCheckDeviceAvailablityExistingNameNotNew() { assertNotNull(DeviceManager.getInstance().registerDevice("device4", Device.TYPE_DIRECTORY, System.getProperty("java.io.tmpdir"))); // error, name already exists assertEquals(0, DeviceManager.getInstance().checkDeviceAvailablity("device4", Device.TYPE_DIRECTORY, System.getProperty("java.io.tmpdir"), false)); } /** * Test check device availablity parent or descendant. * DOCUMENT_ME */ public final void testCheckDeviceAvailablityParentOrDescendant() { assertNotNull(DeviceManager.getInstance().registerDevice("device5", Device.TYPE_DIRECTORY, System.getProperty("java.io.tmpdir"))); // error, same url assertEquals(29, DeviceManager.getInstance().checkDeviceAvailablity("device3", 0, System.getProperty("java.io.tmpdir"), true)); // error, descendant url assertEquals(29, DeviceManager.getInstance().checkDeviceAvailablity("device3", 0, System.getProperty("java.io.tmpdir") + java.io.File.separator + "test", true)); // error, parent url assertEquals(29, DeviceManager.getInstance().checkDeviceAvailablity("device3", 0, new java.io.File(System.getProperty("java.io.tmpdir")).getParent(), true)); } /** * Test check device availablity not exists. * DOCUMENT_ME */ public final void testCheckDeviceAvailablityNotExists() { assertEquals(143, DeviceManager.getInstance().checkDeviceAvailablity("device3", 0, "notexistingpath", true)); } /** * Test check device availablity exists. * DOCUMENT_ME */ public final void testCheckDeviceAvailablityExists() { assertEquals(0, DeviceManager.getInstance().checkDeviceAvailablity("device3", 0, System.getProperty("java.io.tmpdir"), true)); } /** * Test method for. * * {@link org.jajuk.base.DeviceManager#registerDeviceType(java.lang.String)}. */ public final void testRegisterDeviceType() { DeviceManager.getInstance().registerDeviceType("testtype"); } /** * Test method for {@link org.jajuk.base.DeviceManager#getDeviceTypesNumber()} * . */ public final void testGetDeviceTypesNumber() { int n = DeviceManager.getInstance().getDeviceTypesNumber(); DeviceManager.getInstance().registerDeviceType("testtype2"); assertEquals(n + 1, DeviceManager.getInstance().getDeviceTypesNumber()); // the first can be any of them assertNotNull(DeviceManager.getInstance().getDeviceTypes().next()); // the last one should be the new one from us assertEquals("testtype2", DeviceManager.getInstance().getDeviceType(n)); } /** * Test method for {@link org.jajuk.base.DeviceManager#getDeviceTypes()}. */ public final void testGetDeviceTypes() { // tested above } /** * Test method for {@link org.jajuk.base.DeviceManager#getDeviceType(long)}. */ public final void testGetDeviceType() { // tested above } /** * Test method for. * * {@link org.jajuk.base.DeviceManager#removeDevice(org.jajuk.base.Device)}. */ public final void testRemoveDevice() { assertNotNull(DeviceManager.getInstance().registerDevice("5", "device5", Device.TYPE_DIRECTORY, System.getProperty("java.io.tmpdir"))); assertNotNull(DeviceManager.getInstance().getDeviceByID("5")); DeviceManager.getInstance().removeDevice(DeviceManager.getInstance().getDeviceByID("5")); assertNull(DeviceManager.getInstance().getDeviceByID("5")); } /** * Test remove device mounted. * DOCUMENT_ME * * @throws Exception the exception */ public final void testRemoveDeviceMounted() throws Exception { Device device = DeviceManager.getInstance().registerDevice("14", "device14", Device.TYPE_DIRECTORY, System.getProperty("java.io.tmpdir")); device.mount(true); assertNotNull(DeviceManager.getInstance().getDeviceByID("14")); DeviceManager.getInstance().removeDevice(DeviceManager.getInstance().getDeviceByID("14")); assertNull(DeviceManager.getInstance().getDeviceByID("14")); } /** * Test method for. * * {@link org.jajuk.base.DeviceManager#isAnyDeviceRefreshing()}. */ public final void testIsAnyDeviceRefreshing() { assertNotNull(DeviceManager.getInstance().registerDevice("device8", Device.TYPE_DIRECTORY, System.getProperty("java.io.tmpdir"))); assertNotNull(DeviceManager.getInstance().registerDevice("device9", Device.TYPE_CD, System.getProperty("java.io.tmpdir"))); assertFalse(DeviceManager.getInstance().isAnyDeviceRefreshing()); } /** * Test method for {@link org.jajuk.base.DeviceManager#cleanAllDevices()}. */ public final void testCleanAllDevices() { DeviceManager.getInstance().registerDevice("device6", Device.TYPE_DIRECTORY, System.getProperty("java.io.tmpdir")); DeviceManager.getInstance().registerDevice("device7", Device.TYPE_CD, System.getProperty("java.io.tmpdir")); DeviceManager.getInstance().cleanAllDevices(); } /** * Test method for. * * {@link org.jajuk.base.DeviceManager#getDateLastGlobalRefresh()}. */ public final void testGetDateLastGlobalRefresh() { StartupCollectionService.registerItemManagers(); DeviceManager.getInstance().registerDevice("device6", Device.TYPE_DIRECTORY, System.getProperty("java.io.tmpdir")); DeviceManager.getInstance().registerDevice("device7", Device.TYPE_CD, System.getProperty("java.io.tmpdir")); // first do a refresh DeviceManager.getInstance().refreshAllDevices(); // then the timestamp should be non-zero assertTrue(0 != DeviceManager.getInstance().getDateLastGlobalRefresh()); } /** * Test method for {@link org.jajuk.base.DeviceManager#refreshAllDevices()}. */ public final void testRefreshAllDevices() { StartupCollectionService.registerItemManagers(); DeviceManager.getInstance().registerDevice("device6", Device.TYPE_DIRECTORY, System.getProperty("java.io.tmpdir")); DeviceManager.getInstance().registerDevice("device7", Device.TYPE_CD, System.getProperty("java.io.tmpdir")); DeviceManager.getInstance().refreshAllDevices(); } /** * Test method for. * * {@link org.jajuk.base.DeviceManager#getDeviceByID(java.lang.String)}. */ public final void testGetDeviceByID() { // tested above } /** * Test method for. * * {@link org.jajuk.base.DeviceManager#getDeviceByName(java.lang.String)}. */ public final void testGetDeviceByName() { DeviceManager.getInstance().registerDevice("device10", Device.TYPE_DIRECTORY, System.getProperty("java.io.tmpdir")); DeviceManager.getInstance().registerDevice("device11", Device.TYPE_CD, System.getProperty("java.io.tmpdir")); assertNotNull(DeviceManager.getInstance().getDeviceByName("device10")); assertNull(DeviceManager.getInstance().getDeviceByName("notexistingdevice")); } /** * Test method for {@link org.jajuk.base.DeviceManager#getDevices()}. */ public final void testGetDevices() { assertEquals(0, DeviceManager.getInstance().getDevices().size()); DeviceManager.getInstance().registerDevice("device12", Device.TYPE_DIRECTORY, System.getProperty("java.io.tmpdir")); DeviceManager.getInstance().registerDevice("device13", Device.TYPE_CD, System.getProperty("java.io.tmpdir")); assertEquals(2, DeviceManager.getInstance().getDevices().size()); } /** * Test method for {@link org.jajuk.base.DeviceManager#getDevicesIterator()}. */ public final void testGetDevicesIterator() { assertFalse(DeviceManager.getInstance().getDevicesIterator().hasNext()); DeviceManager.getInstance().registerDevice("device12", Device.TYPE_DIRECTORY, System.getProperty("java.io.tmpdir")); DeviceManager.getInstance().registerDevice("device13", Device.TYPE_CD, System.getProperty("java.io.tmpdir")); assertTrue(DeviceManager.getInstance().getDevicesIterator().hasNext()); } } jajuk-1.9.6.orig/src/test/java/org/jajuk/ConstTest.java0000644000175000017500000000250211720500104022626 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk; import java.io.File; /** * Contains common constants shared by jajuk unit tests. */ public interface ConstTest { // sometimes temporary path has trailing separator, we try to handle this here /** DOCUMENT_ME. */ String PATH_DEVICE = (System.getProperty("java.io.tmpdir").endsWith(File.separator) ? System .getProperty("java.io.tmpdir") + "jajuk_tests" + File.separator + "device_1" : System.getProperty("java.io.tmpdir") + File.separator + "jajuk_tests" + File.separator + "device_1"); } jajuk-1.9.6.orig/src/test/java/org/jajuk/services/0000755000175000017500000000000011720500104021661 5ustar drazzibdrazzibjajuk-1.9.6.orig/src/test/java/org/jajuk/services/alarm/0000755000175000017500000000000011720500104022755 5ustar drazzibdrazzibjajuk-1.9.6.orig/src/test/java/org/jajuk/services/alarm/TestAlarm.java0000644000175000017500000000451711720500104025523 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.services.alarm; import java.util.ArrayList; import java.util.Date; import java.util.List; import org.apache.commons.lang.time.DateUtils; import org.jajuk.JajukTestCase; import org.jajuk.base.File; import org.jajuk.util.Const; /** * DOCUMENT_ME. */ public class TestAlarm extends JajukTestCase { /** * Test method for. * * {@link org.jajuk.services.alarm.Alarm#Alarm(java.util.Date, java.util.List, java.lang.String)} * . */ public void testAlarm() { new Alarm(new Date(), new ArrayList(), "mode"); } /** * Test method for {@link org.jajuk.services.alarm.Alarm#wakeUpSleeper()}. */ public void testWakeUpSleeper() { Alarm alarm = new Alarm(new Date(), new ArrayList(), "mode"); alarm.wakeUpSleeper(); List list = new ArrayList(); alarm = new Alarm(new Date(), list, Const.ALARM_START_ACTION); alarm.wakeUpSleeper(); } /** * Test method for {@link org.jajuk.services.alarm.Alarm#getAlarmTime()}. */ public void testGetAlarmTime() { Date date = new Date(); Alarm alarm = new Alarm(date, new ArrayList(), "mode"); assertEquals(date, alarm.getAlarmTime()); } /** * Test method for {@link org.jajuk.services.alarm.Alarm#nextDay()}. */ public void testNextDay() { Date date = new Date(); Alarm alarm = new Alarm(date, new ArrayList(), "mode"); assertEquals(date, alarm.getAlarmTime()); alarm.nextDay(); Date datenew = alarm.getAlarmTime(); assertEquals(DateUtils.addDays(date, 1), datenew); } } jajuk-1.9.6.orig/src/test/java/org/jajuk/services/alarm/TestAlarmManager.java0000644000175000017500000001074711720500104027020 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.services.alarm; import java.util.Calendar; import java.util.Set; import org.jajuk.JUnitHelpers; import org.jajuk.JajukTestCase; import org.jajuk.base.FileManager; import org.jajuk.events.JajukEvent; import org.jajuk.events.JajukEvents; import org.jajuk.util.Conf; import org.jajuk.util.Const; /** * DOCUMENT_ME. */ public class TestAlarmManager extends JajukTestCase { /* (non-Javadoc) * @see org.jajuk.JajukTestCase#setUp() */ @Override protected void setUp() throws Exception { JUnitHelpers.createSessionDirectory(); // make sure the FileManager is registered correctly for each invocation // this is done during the first access to the singleton FileManager.getInstance(); // clear File Manager to avoid files being left in there and causing trouble FileManager.getInstance().clear(); super.setUp(); } /** * Test method for {@link org.jajuk.services.alarm.AlarmManager#getInstance()} * . * * @throws Exception the exception */ public void testGetInstance() throws Exception { Conf.setProperty(Const.CONF_ALARM_ENABLED, "true"); assertNotNull(AlarmManager.getInstance()); // sleep a bit to let internal thread do some work Thread.sleep(1100); } /** * Test method for. * * {@link org.jajuk.services.alarm.AlarmManager#update(org.jajuk.events.JajukEvent)} * . */ public void testUpdate() { AlarmManager.getInstance().update(new JajukEvent(JajukEvents.ALARMS_CHANGE)); } /** * Test update2. * DOCUMENT_ME */ public void testUpdate2() { Conf.setProperty(Const.CONF_ALARM_ENABLED, "true"); AlarmManager.getInstance().update(new JajukEvent(JajukEvents.ALARMS_CHANGE)); } /** * Test update3. * DOCUMENT_ME */ public void testUpdate3() { Conf.setProperty(Const.CONF_ALARM_ENABLED, "true"); Conf.setProperty(Const.CONF_ALARM_MODE, Const.STARTUP_MODE_ITEM); AlarmManager.getInstance().update(new JajukEvent(JajukEvents.ALARMS_CHANGE)); } /** * Test update4. * DOCUMENT_ME */ public void testUpdate4() { Conf.setProperty(Const.CONF_ALARM_ENABLED, "true"); Conf.setProperty(Const.CONF_ALARM_MODE, Const.STARTUP_MODE_BESTOF); AlarmManager.getInstance().update(new JajukEvent(JajukEvents.ALARMS_CHANGE)); } /** * Test update5. * DOCUMENT_ME */ public void testUpdate5() { Conf.setProperty(Const.CONF_ALARM_ENABLED, "true"); Conf.setProperty(Const.CONF_ALARM_MODE, Const.STARTUP_MODE_NOVELTIES); AlarmManager.getInstance().update(new JajukEvent(JajukEvents.ALARMS_CHANGE)); } /** * Test method for. * * {@link org.jajuk.services.alarm.AlarmManager#getRegistrationKeys()}. */ public void testGetRegistrationKeys() { Set set = AlarmManager.getInstance().getRegistrationKeys(); assertTrue(set.contains(JajukEvents.ALARMS_CHANGE)); } /** * Test trigger alarm. * DOCUMENT_ME * * @throws Exception the exception */ public void testTriggerAlarm() throws Exception { Calendar cal = Calendar.getInstance(); // add one second to let it be triggered immedately cal.add(Calendar.SECOND, 1); Conf.setProperty(Const.CONF_ALARM_ENABLED, "true"); Conf.setProperty(Const.CONF_ALARM_MODE, Const.STARTUP_MODE_ITEM); Conf.setProperty(Const.CONF_ALARM_TIME_HOUR, Integer.toString(cal.get(Calendar.HOUR_OF_DAY))); Conf.setProperty(Const.CONF_ALARM_TIME_MINUTES, Integer.toString(cal.get(Calendar.MINUTE))); Conf.setProperty(Const.CONF_ALARM_TIME_SECONDS, Integer.toString(cal.get(Calendar.SECOND))); AlarmManager.getInstance().update(new JajukEvent(JajukEvents.ALARMS_CHANGE)); // sleep a bit to let internal thread do some work Thread.sleep(2000); } } jajuk-1.9.6.orig/src/test/java/org/jajuk/services/dj/0000755000175000017500000000000011720500104022256 5ustar drazzibdrazzibjajuk-1.9.6.orig/src/test/java/org/jajuk/services/dj/TestAmbienceDigitalDJ.java0000644000175000017500000001221411720500104027200 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.services.dj; import ext.services.xml.XMLUtils; import org.apache.commons.lang.StringUtils; import org.jajuk.JUnitHelpers; import org.jajuk.JajukTestCase; import org.jajuk.base.Album; import org.jajuk.base.Artist; import org.jajuk.base.Device; import org.jajuk.base.Directory; import org.jajuk.base.DirectoryManager; import org.jajuk.base.File; import org.jajuk.base.FileManager; import org.jajuk.base.Genre; import org.jajuk.base.GenreManager; import org.jajuk.base.Track; import org.jajuk.base.TrackManager; import org.jajuk.base.Type; import org.jajuk.base.Year; import org.jajuk.services.startup.StartupCollectionService; import org.jajuk.util.Const; /** * DOCUMENT_ME. */ public class TestAmbienceDigitalDJ extends JajukTestCase { /** * Test method for {@link org.jajuk.services.dj.AmbienceDigitalDJ#toXML()}. */ public final void testToXML() { AmbienceDigitalDJ dj = new AmbienceDigitalDJ("3"); assertTrue(StringUtils.isNotBlank(dj.toXML())); // try to parse the resulting XML XMLUtils.getDocument(dj.toXML()); // set an Ambience GenreManager.getInstance().registerGenre("mystyle"); dj.setAmbience(new Ambience("5", "ambience", new String[] { "mystyle" })); // try to parse the resulting XML XMLUtils.getDocument(dj.toXML()); } /** * Test method for. * * @throws Exception the exception * {@link org.jajuk.services.dj.AmbienceDigitalDJ#generatePlaylist()}. */ public final void testGeneratePlaylist() throws Exception { StartupCollectionService.registerItemManagers(); AmbienceDigitalDJ dj = new AmbienceDigitalDJ("4"); // empty without Ambience set assertEquals(0, dj.generatePlaylist().size()); // set an Ambience Genre genre = GenreManager.getInstance().registerGenre("mystyle"); dj.setAmbience(new Ambience("5", "ambience", new String[] { "mystyle" })); getFile(6, genre); // assert a few conditions to find out why this test fails sometimes when // run in combination with others assertFalse(dj.isTrackUnicity()); assertTrue(FileManager.getInstance().getGlobalShufflePlaylist().size() > 0); assertTrue(dj.getAmbience().getGenres().contains( FileManager.getInstance().getGlobalShufflePlaylist().get(0).getTrack().getGenre())); assertEquals(Const.MIN_TRACKS_NUMBER_WITHOUT_UNICITY, dj.generatePlaylist().size()); // once again with "unicity" dj.setTrackUnicity(true); assertEquals(1, dj.generatePlaylist().size()); } /** * Gets the file. * * @param i DOCUMENT_ME * @param genre DOCUMENT_ME * @return the file * @throws Exception the exception */ private File getFile(int i, Genre genre) throws Exception { Album album = JUnitHelpers.getAlbum("myalbum", 0); album.setProperty(Const.XML_ALBUM_DISCOVERED_COVER, Const.COVER_NONE); // don't read covers for // this test Artist artist = JUnitHelpers.getArtist("name"); Year year = JUnitHelpers.getYear(2000); // IPlayerImpl imp = new MockPlayer(); // Class cl = (Class) imp.getClass(); Type type = JUnitHelpers.getType(); Track track = TrackManager.getInstance().registerTrack("name", album, genre, artist, 120, year, 1, type, 1); Device device = JUnitHelpers.getDevice(); device.mount(true); Directory dir = DirectoryManager.getInstance().registerDirectory(device); return FileManager.getInstance().registerFile(Integer.valueOf(i).toString(), "test.tst", dir, track, 120, 70); } /** * Test method for. * * {@link org.jajuk.services.dj.AmbienceDigitalDJ#AmbienceDigitalDJ(java.lang.String)} * . */ public final void testAmbienceDigitalDJ() { new AmbienceDigitalDJ("9"); } /** * Test method for. * * {@link org.jajuk.services.dj.AmbienceDigitalDJ#getAmbience()}. */ public final void testGetAndSetAmbience() { AmbienceDigitalDJ dj = new AmbienceDigitalDJ("4"); // empty without Ambience set assertNull(dj.getAmbience()); // set an Ambience GenreManager.getInstance().registerGenre("mystyle"); dj.setAmbience(new Ambience("5", "ambience", new String[] { "mystyle" })); assertNotNull(dj.getAmbience()); } /** * Test method for. * * {@link org.jajuk.services.dj.AmbienceDigitalDJ#setAmbience(org.jajuk.services.dj.Ambience)} * . */ public final void testSetAmbience() { // tested above } } jajuk-1.9.6.orig/src/test/java/org/jajuk/services/dj/TestAmbienceManager.java0000644000175000017500000002350511720500104026764 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.services.dj; import java.lang.reflect.Field; import java.util.Enumeration; import java.util.Properties; import org.jajuk.JajukTestCase; import org.jajuk.base.Genre; import org.jajuk.base.GenreManager; import org.jajuk.events.JajukEvent; import org.jajuk.events.JajukEvents; import org.jajuk.util.Conf; import org.jajuk.util.Const; import org.jajuk.util.Messages; import org.jajuk.util.UpgradeManager; /** * DOCUMENT_ME. */ public class TestAmbienceManager extends JajukTestCase { /* (non-Javadoc) * @see org.jajuk.JajukTestCase#setUp() */ @Override protected void setUp() throws Exception { // clean out all leftover ambiences from other testing for (Ambience amb : AmbienceManager.getInstance().getAmbiences()) { AmbienceManager.getInstance().removeAmbience(amb.getID()); } super.setUp(); } /** * Test method for. * * {@link org.jajuk.services.dj.AmbienceManager#getRegistrationKeys()}. */ public final void testGetRegistrationKeys() { java.util.Set set = AmbienceManager.getInstance().getRegistrationKeys(); assertTrue(set.contains(JajukEvents.GENRE_NAME_CHANGED)); } /** * Test method for {@link org.jajuk.services.dj.AmbienceManager#getInstance()} * . */ public final void testGetInstance() { assertNotNull(AmbienceManager.getInstance()); } /** * Test method for {@link org.jajuk.services.dj.AmbienceManager#load()}. * * @throws Exception the exception */ public final void testLoad() throws Exception { // make sure "UpgradeManager.bFirstSession" is not set { Class c = UpgradeManager.class; Field f = c.getDeclaredField("bFirstSession"); f.setAccessible(true); f.setBoolean(null, Boolean.FALSE); } assertFalse(UpgradeManager.isFirstSession()); assertEquals(0, AmbienceManager.getInstance().getAmbiences().size()); // first without any key AmbienceManager.getInstance().load(); // creates the 14 default ambiences assertEquals(14, AmbienceManager.getInstance().getAmbiences().size()); // clean out all leftover ambiences from other testing for (Ambience amb : AmbienceManager.getInstance().getAmbiences()) { AmbienceManager.getInstance().removeAmbience(amb.getID()); } assertEquals(0, AmbienceManager.getInstance().getAmbiences().size()); { // remove all leftover properties Properties properties = Conf.getProperties(); Enumeration e = properties.keys(); while (e.hasMoreElements()) { String sKey = (String) e.nextElement(); if (sKey.matches(Const.AMBIENCE_PREFIX + ".*")) { properties.remove(sKey); } } } // then add set some Ambience-items Genre genre1 = GenreManager.getInstance().registerGenre("genre1"); Genre genre2 = GenreManager.getInstance().registerGenre("genre2"); Conf .setProperty(Const.AMBIENCE_PREFIX + "12/myambience", genre1.getID() + "," + genre2.getID()); assertEquals(0, AmbienceManager.getInstance().getAmbiences().size()); { // check all the conditions to find out why it fails in Hudson assertFalse(UpgradeManager.isFirstSession()); Properties properties = Conf.getProperties(); Enumeration e = properties.keys(); int nMatch = 0; while (e.hasMoreElements()) { String sKey = (String) e.nextElement(); if (sKey.matches(Const.AMBIENCE_PREFIX + ".*")) { if (sKey.substring(Const.AMBIENCE_PREFIX.length()).indexOf('/') == -1) { continue; } nMatch++; } } assertEquals(properties.toString(), 1, nMatch); } AmbienceManager.getInstance().load(); assertEquals(1, AmbienceManager.getInstance().getAmbiences().size()); assertNotNull(AmbienceManager.getInstance().getAmbience("12")); // now test with an ambience with invalid format, i.e. only "12", not // "12/name" for (Ambience amb : AmbienceManager.getInstance().getAmbiences()) { AmbienceManager.getInstance().removeAmbience(amb.getID()); } assertEquals(0, AmbienceManager.getInstance().getAmbiences().size()); Conf.setProperty(Const.AMBIENCE_PREFIX + "12", genre1.getID() + "," + genre2.getID()); Conf.removeProperty(Const.AMBIENCE_PREFIX + "12/myambience"); AmbienceManager.getInstance().load(); // now 14 as this could not be loaded and thus the default ones were // loaded... assertEquals(14, AmbienceManager.getInstance().getAmbiences().size()); UpgradeManager.setFirstSession(); AmbienceManager.getInstance().load(); } /** * Test method for. * * {@link org.jajuk.services.dj.AmbienceManager#getAmbiences()}. */ public final void testGetAmbiences() { // tested above } /** * Test method for. * * {@link org.jajuk.services.dj.AmbienceManager#getAmbience(java.lang.String)} * . */ public final void testGetAmbience() { // this creates the 14 default ambiences AmbienceManager.getInstance().createDefaultAmbiences(); assertNotNull(AmbienceManager.getInstance().getAmbience("0")); } /** * Test method for. * * {@link org.jajuk.services.dj.AmbienceManager#getAmbienceByName(java.lang.String)} * . */ public final void testGetAmbienceByName() { // this creates the 14 default ambiences AmbienceManager.getInstance().createDefaultAmbiences(); assertNotNull(AmbienceManager.getInstance().getAmbienceByName(Messages.getString("Ambience.9"))); } /** * Test get ambience by name invalid. * DOCUMENT_ME */ public final void testGetAmbienceByNameInvalid() { // this creates the 14 default ambiences AmbienceManager.getInstance().createDefaultAmbiences(); assertNull(AmbienceManager.getInstance().getAmbienceByName("notexistingone")); } /** * Test method for. * * {@link org.jajuk.services.dj.AmbienceManager#registerAmbience(org.jajuk.services.dj.Ambience)} * . */ public final void testRegisterAmbience() { assertEquals(0, AmbienceManager.getInstance().getAmbiences().size()); AmbienceManager.getInstance().registerAmbience(new Ambience("20", "ambience1")); assertEquals(1, AmbienceManager.getInstance().getAmbiences().size()); } /** * Test method for. * * {@link org.jajuk.services.dj.AmbienceManager#getSelectedAmbience()}. */ public final void testGetSelectedAmbience() { // first with no ambience and no default set assertNull(AmbienceManager.getInstance().getSelectedAmbience()); // this creates the 14 default ambiences AmbienceManager.getInstance().createDefaultAmbiences(); Conf.setProperty(Const.CONF_DEFAULT_AMBIENCE, "2"); // by ID // now we should find one assertNotNull(AmbienceManager.getInstance().getSelectedAmbience()); } /** * Test method for. * * {@link org.jajuk.services.dj.AmbienceManager#update(org.jajuk.events.JajukEvent)} * . */ public final void testUpdate() { Properties prop = new Properties(); Genre genre1 = GenreManager.getInstance().registerGenre("genre1"); Genre genre2 = GenreManager.getInstance().registerGenre("genre2"); Ambience ambience = new Ambience("23", "testamb", new String[] { "genre1" }); prop.put(Const.DETAIL_OLD, genre1); prop.put(Const.DETAIL_NEW, genre2); AmbienceManager.getInstance().registerAmbience(ambience); AmbienceManager.getInstance().update(new JajukEvent(JajukEvents.GENRE_NAME_CHANGED, prop)); assertEquals(1, AmbienceManager.getInstance().getAmbiences().size()); assertEquals(1, AmbienceManager.getInstance().getAmbiences().iterator().next().getGenres() .size()); assertEquals("genre2", AmbienceManager.getInstance().getAmbiences().iterator().next() .getGenres().iterator().next().getName()); } /** * Test method for {@link org.jajuk.services.dj.AmbienceManager#commit()}. */ public final void testCommit() { // this creates the 14 default ambiences AmbienceManager.getInstance().createDefaultAmbiences(); // set one ambience prefix to have it removed before Conf.setProperty(Const.AMBIENCE_PREFIX + "12/ambience", "testvalue"); AmbienceManager.getInstance().commit(); } /** * Test method for. * * {@link org.jajuk.services.dj.AmbienceManager#removeAmbience(java.lang.String)} * . */ public final void testRemoveAmbience() { assertEquals(0, AmbienceManager.getInstance().getAmbiences().size()); AmbienceManager.getInstance().registerAmbience(new Ambience("30", "nextone")); assertEquals(1, AmbienceManager.getInstance().getAmbiences().size()); AmbienceManager.getInstance().removeAmbience("30"); assertEquals(0, AmbienceManager.getInstance().getAmbiences().size()); } /** * Test method for. * * {@link org.jajuk.services.dj.AmbienceManager#createDefaultAmbiences()}. */ public final void testCreateDefaultAmbiences() { assertEquals(0, AmbienceManager.getInstance().getAmbiences().size()); AmbienceManager.getInstance().createDefaultAmbiences(); // currently 14 ambiences are defined as default ones assertEquals(14, AmbienceManager.getInstance().getAmbiences().size()); } } jajuk-1.9.6.orig/src/test/java/org/jajuk/services/dj/TestAmbience.java0000644000175000017500000001776611720500104025505 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.services.dj; import java.util.HashSet; import java.util.Set; import org.apache.commons.lang.StringUtils; import org.jajuk.JUnitHelpers; import org.jajuk.JajukTestCase; import org.jajuk.base.Genre; import org.jajuk.base.GenreManager; /** * DOCUMENT_ME. */ public class TestAmbience extends JajukTestCase { /** * Test method for {@link org.jajuk.services.dj.Ambience#hashCode()}. */ public final void testHashCode() { Ambience amb = new Ambience("1", "name"); Ambience equal = new Ambience("1", "name"); JUnitHelpers.HashCodeTest(amb, equal); } /** * Test method for. * * {@link org.jajuk.services.dj.Ambience#Ambience(java.lang.String, java.lang.String, java.util.Set)} * . */ public final void testAmbienceStringStringSetOfGenre() { Set genres = new HashSet(); genres.add(JUnitHelpers.getGenre("mygenre")); new Ambience("1", "name", genres); } /** * Test method for. * * {@link org.jajuk.services.dj.Ambience#Ambience(java.lang.String, java.lang.String, java.lang.String[])} * . */ public final void testAmbienceStringStringStringArray() { GenreManager.getInstance().registerGenre("anothergenre"); GenreManager.getInstance().registerGenre("yetanothergenre"); // try with one unknown genre here... new Ambience("1", "name", new String[] { "anothergenre", "yetanothergenre", "unknowngenre" }); } /** * Test method for. * * {@link org.jajuk.services.dj.Ambience#Ambience(java.lang.String, java.lang.String)} * . */ public final void testAmbienceStringString() { new Ambience("1", "name"); } /** * Test method for {@link org.jajuk.services.dj.Ambience#Ambience()}. */ public final void testAmbience() { new Ambience(); } /** * Test method for. * * {@link org.jajuk.services.dj.Ambience#addGenre(org.jajuk.base.Genre)}. */ public final void testAddGenre() { Ambience amb = new Ambience("1", "name"); amb.addGenre(JUnitHelpers.getGenre("anothergenre")); } /** * Test method for. * * {@link org.jajuk.services.dj.Ambience#removeGenre(org.jajuk.base.Genre)}. */ public final void testRemoveGenre() { Ambience amb = new Ambience("1", "name"); Genre genre = JUnitHelpers.getGenre("anothergenre"); assertEquals(0, amb.getGenres().size()); amb.addGenre(genre); assertEquals(1, amb.getGenres().size()); amb.removeGenre(genre); assertEquals(0, amb.getGenres().size()); // try it again amb.removeGenre(genre); assertEquals(0, amb.getGenres().size()); } /** * Test method for {@link org.jajuk.services.dj.Ambience#getName()}. */ public final void testGetName() { Ambience amb = new Ambience("7", "name123"); assertEquals("name123", amb.getName()); amb.setName("123n"); assertEquals("123n", amb.getName()); } /** * Test method for {@link org.jajuk.services.dj.Ambience#getID()}. */ public final void testGetID() { Ambience amb = new Ambience("8", "name1234"); assertEquals("8", amb.getID()); } /** * Test method for. * * {@link org.jajuk.services.dj.Ambience#setName(java.lang.String)}. */ public final void testSetName() { // tested above } /** * Test method for {@link org.jajuk.services.dj.Ambience#getGenres()}. */ public final void testGetGenres() { // tested above } /** * Test method for. * * {@link org.jajuk.services.dj.Ambience#setGenres(java.util.Set)}. */ public final void testSetGenres() { Ambience amb = new Ambience("1", "name"); assertEquals(0, amb.getGenres().size()); Set genres = new HashSet(); genres.add(JUnitHelpers.getGenre("mygenre")); genres.add(JUnitHelpers.getGenre("mygenre2")); genres.add(JUnitHelpers.getGenre("mygenre3")); amb.setGenres(genres); assertEquals(3, amb.getGenres().size()); } /** * Test method for {@link org.jajuk.services.dj.Ambience#getGenresDesc()}. */ public final void testGetGenresDesc() { Ambience amb = new Ambience("1", "name"); // first an empty string results without any genre set assertEquals("", amb.getGenresDesc()); // then add some genres amb.addGenre(JUnitHelpers.getGenre("mygenre")); amb.addGenre(JUnitHelpers.getGenre("mygenre2")); amb.addGenre(JUnitHelpers.getGenre("mygenre3")); assertTrue(StringUtils.isNotBlank(amb.getGenresDesc())); } /** * Test method for {@link org.jajuk.services.dj.Ambience#toString()}. */ public final void testToString() { Ambience amb = new Ambience("1", "name"); JUnitHelpers.ToStringTest(amb); // also when some items are null amb = new Ambience(null, "name"); JUnitHelpers.ToStringTest(amb); amb = new Ambience("1", null); JUnitHelpers.ToStringTest(amb); amb = new Ambience(null, null); JUnitHelpers.ToStringTest(amb); // also with genres amb = new Ambience("9", "name0987"); amb.addGenre(JUnitHelpers.getGenre("mygenre")); amb.addGenre(JUnitHelpers.getGenre("mygenre2")); JUnitHelpers.ToStringTest(amb); } /** * Test method for. * * {@link org.jajuk.services.dj.Ambience#equals(java.lang.Object)}. */ public final void testEqualsObject() { Ambience amb = new Ambience("1", "name"); Ambience equal = new Ambience("1", "name"); // equals compares on name Ambience notequal1 = new Ambience("1", "name1"); // and also compares on genres Ambience notequal2 = new Ambience("1", "name"); notequal2.addGenre(JUnitHelpers.getGenre("mygenre2")); JUnitHelpers.EqualsTest(amb, equal, notequal1); JUnitHelpers.EqualsTest(amb, equal, notequal2); } /** * Test equals object2. * DOCUMENT_ME */ public final void testEqualsObject2() { Ambience amb = new Ambience("1", "name"); amb.addGenre(JUnitHelpers.getGenre("mygenre4")); Ambience equal = new Ambience("1", "name"); equal.addGenre(JUnitHelpers.getGenre("mygenre4")); // equals compares on name Ambience notequal1 = new Ambience("1", "name1"); // and also compares on genres Ambience notequal2 = new Ambience("1", "name"); notequal2.addGenre(JUnitHelpers.getGenre("mygenre2")); JUnitHelpers.EqualsTest(amb, equal, notequal1); JUnitHelpers.EqualsTest(amb, equal, notequal2); } /** * Test method for. * * {@link org.jajuk.services.dj.Ambience#compareTo(org.jajuk.services.dj.Ambience)} * . */ public final void testCompareTo() { Ambience amb = new Ambience("1", "name"); Ambience equal = new Ambience("1", "name"); Ambience notequal = new Ambience("1", "name1"); // only compares on name JUnitHelpers.CompareToTest(amb, equal, notequal); } /** * Test method for {@link org.jajuk.services.dj.Ambience#toXML()}. */ public final void testToXML() { Ambience amb = new Ambience("1", "name"); // just returns a comma-separated list, not a full XML here... // try without any genres, returns an empty string assertEquals("", amb.toXML()); // then add some amb.addGenre(JUnitHelpers.getGenre("mygenre4123")); assertTrue(StringUtils.isNotBlank(amb.toXML())); // and then some more amb.addGenre(JUnitHelpers.getGenre("mygenre4234")); amb.addGenre(JUnitHelpers.getGenre("mygenre834874")); } } jajuk-1.9.6.orig/src/test/java/org/jajuk/services/dj/TestDigitalDJ.java0000644000175000017500000002420011720500104025552 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.services.dj; import ext.services.xml.XMLUtils; import java.util.ArrayList; import java.util.List; import org.apache.commons.lang.StringUtils; import org.jajuk.JUnitHelpers; import org.jajuk.JajukTestCase; import org.jajuk.base.Album; import org.jajuk.base.Artist; import org.jajuk.base.Device; import org.jajuk.base.Directory; import org.jajuk.base.DirectoryManager; import org.jajuk.base.File; import org.jajuk.base.FileManager; import org.jajuk.base.Genre; import org.jajuk.base.Track; import org.jajuk.base.TrackManager; import org.jajuk.base.Type; import org.jajuk.base.Year; import org.jajuk.util.Const; import org.w3c.dom.Document; /** * DOCUMENT_ME. */ public class TestDigitalDJ extends JajukTestCase { /** * Test method for {@link org.jajuk.services.dj.DigitalDJ#hashCode()}. */ public final void testHashCode() { DigitalDJ dj = new AmbienceDigitalDJ("3"); dj.setName("ambience1"); DigitalDJ equ = new AmbienceDigitalDJ("3"); equ.setName("ambience1"); JUnitHelpers.HashCodeTest(dj, equ); } /** * Test method for. * * {@link org.jajuk.services.dj.DigitalDJ#DigitalDJ(java.lang.String)}. */ public final void testDigitalDJ() { DigitalDJ dj = new AmbienceDigitalDJ("3"); assertNotNull(dj); } /** * Test method for {@link org.jajuk.services.dj.DigitalDJ#toString()}. */ public final void testToString() { DigitalDJ dj = new AmbienceDigitalDJ("3"); dj.setName("ambience1"); JUnitHelpers.ToStringTest(dj); // also test null values dj = new AmbienceDigitalDJ(null); dj.setName(null); JUnitHelpers.ToStringTest(dj); } /** * Test method for. * * {@link org.jajuk.services.dj.DigitalDJ#compareTo(org.jajuk.services.dj.DigitalDJ)} * . */ public final void testCompareTo() { DigitalDJ dj = new AmbienceDigitalDJ("3"); dj.setName("ambience1"); DigitalDJ equ = new AmbienceDigitalDJ("3"); equ.setName("ambience1"); DigitalDJ notequ = new AmbienceDigitalDJ("3"); notequ.setName("other"); // only compares on name JUnitHelpers.CompareToTest(dj, equ, notequ); } /** * Test method for {@link org.jajuk.services.dj.DigitalDJ#toXML()}. */ public final void testToXML() { DigitalDJ dj = new AmbienceDigitalDJ("3"); dj.setName("ambience1"); // abstract in DigitalDJ anyway, so no need to test this in detail here... assertTrue(dj.toXML(), StringUtils.isNotBlank(dj.toXML())); } /** * Test method for. * * {@link org.jajuk.services.dj.DigitalDJ#toXMLGeneralParameters()}. */ public final void testToXMLGeneralParameters() { DigitalDJ dj = new AmbienceDigitalDJ("3"); dj.setName("ambience1"); assertTrue(dj.toXMLGeneralParameters(), StringUtils.isNotBlank(dj.toXMLGeneralParameters())); // test xml-validity, need to add closing tag to build complete xml String xml = dj.toXMLGeneralParameters() + ""; Document document = XMLUtils.getDocument(xml); assertNotNull(document); } /** * Test method for. * * @throws Exception the exception * {@link org.jajuk.services.dj.DigitalDJ#filterFilesByRate(java.util.List)}. */ public final void testFilterFilesByRate() throws Exception { DigitalDJ dj = new AmbienceDigitalDJ("3"); dj.setName("ambience1"); List files = new ArrayList(); File file = getFile(1); file.getTrack().setProperty(Const.XML_TRACK_RATE, 1l); files.add(file); file = getFile(2); file.getTrack().setProperty(Const.XML_TRACK_RATE, 26l); files.add(file); file = getFile(3); file.getTrack().setProperty(Const.XML_TRACK_RATE, 51l); files.add(file); // without rating level set nothing happens to the list dj.filterFilesByRate(files); assertEquals(3, files.size()); // set rating level and see if tracks are removed dj.setRatingLevel(2); dj.filterFilesByRate(files); assertEquals(1, files.size()); } /** * Test filter files by max track. * DOCUMENT_ME * * @throws Exception the exception */ public final void testFilterFilesByMaxTrack() throws Exception { DigitalDJ dj = new AmbienceDigitalDJ("3"); dj.setName("ambience1"); List files = new ArrayList(); File file = getFile(1); file.getTrack().setProperty(Const.XML_TRACK_RATE, 1l); files.add(file); file = getFile(2); file.getTrack().setProperty(Const.XML_TRACK_RATE, 26l); files.add(file); file = getFile(3); file.getTrack().setProperty(Const.XML_TRACK_RATE, 51l); files.add(file); // with max-tracks -1 nothing is cut off dj.setMaxTracks(-1); dj.filterFilesByMaxTrack(files); assertEquals(3, files.size()); // nothing happens if max is higher dj.setMaxTracks(4); dj.filterFilesByMaxTrack(files); assertEquals(3, files.size()); // set max level and see if tracks are removed dj.setMaxTracks(2); dj.filterFilesByMaxTrack(files); assertEquals(2, files.size()); } /** * Gets the file. * * @param i DOCUMENT_ME * @return the file * @throws Exception the exception */ private File getFile(int i) throws Exception { Genre genre = JUnitHelpers.getGenre(); Album album = JUnitHelpers.getAlbum("name" + i, 0); album.setProperty(Const.XML_ALBUM_DISCOVERED_COVER, Const.COVER_NONE); // don't read covers for // this test Artist artist = JUnitHelpers.getArtist("name"); Year year = JUnitHelpers.getYear(2000); // IPlayerImpl imp = new MockPlayer(); // Class cl = (Class) imp.getClass(); Type type = JUnitHelpers.getType(); Track track = TrackManager.getInstance().registerTrack("name", album, genre, artist, 120, year, 1, type, 1); Device device = JUnitHelpers.getDevice(); if (!device.isMounted()) { device.mount(true); } Directory dir = DirectoryManager.getInstance().registerDirectory(device); return FileManager.getInstance().registerFile("test.tst", dir, track, 120, 70); } /** * Test method for {@link org.jajuk.services.dj.DigitalDJ#getName()}. */ public final void testGetAndSetName() { DigitalDJ dj = new AmbienceDigitalDJ("3"); assertNull(dj.getName()); dj.setName("ambience1"); assertEquals("ambience1", dj.getName()); } /** * Test method for. * * {@link org.jajuk.services.dj.DigitalDJ#equals(java.lang.Object)}. */ public final void testEqualsObject() { DigitalDJ dj = new AmbienceDigitalDJ("3"); dj.setName("ambience1"); DigitalDJ equ = new AmbienceDigitalDJ("3"); equ.setName("ambience1"); DigitalDJ notequ = new AmbienceDigitalDJ("3"); notequ.setName("other"); // only compares on name JUnitHelpers.EqualsTest(dj, equ, notequ); } /** * Test method for. * * {@link org.jajuk.services.dj.DigitalDJ#setName(java.lang.String)}. */ public final void testSetName() { // tested above } /** * Test method for {@link org.jajuk.services.dj.DigitalDJ#getFadingDuration()} * . */ public final void testGetAndSetFadingDuration() { DigitalDJ dj = new AmbienceDigitalDJ("3"); dj.setName("ambience1"); assertEquals(0, dj.getFadingDuration()); dj.setFadingDuration(3); assertEquals(3, dj.getFadingDuration()); } /** * Test method for. * * {@link org.jajuk.services.dj.DigitalDJ#setFadingDuration(int)}. */ public final void testSetFadingDuration() { // tested above } /** * Test method for {@link org.jajuk.services.dj.DigitalDJ#getRatingLevel()}. */ public final void testGetAndSetRatingLevel() { DigitalDJ dj = new AmbienceDigitalDJ("3"); dj.setName("ambience1"); assertEquals(0, dj.getRatingLevel()); dj.setRatingLevel(3); assertEquals(3, dj.getRatingLevel()); } /** * Test method for {@link org.jajuk.services.dj.DigitalDJ#setRatingLevel(int)} * . */ public final void testSetRatingLevel() { // tested above } /** * Test method for {@link org.jajuk.services.dj.DigitalDJ#generatePlaylist()}. */ public final void testGeneratePlaylist() { DigitalDJ dj = new AmbienceDigitalDJ("3"); dj.setName("ambience1"); // abstract method, do not check result here dj.generatePlaylist(); } /** * Test method for {@link org.jajuk.services.dj.DigitalDJ#getID()}. */ public final void testGetID() { DigitalDJ dj = new AmbienceDigitalDJ("3"); dj.setName("ambience1"); assertEquals("3", dj.getID()); } /** * Test method for {@link org.jajuk.services.dj.DigitalDJ#isTrackUnicity()}. */ public final void testIsAndSetTrackUnicity() { DigitalDJ dj = new AmbienceDigitalDJ("3"); dj.setName("ambience1"); assertFalse(dj.isTrackUnicity()); dj.setTrackUnicity(true); assertTrue(dj.isTrackUnicity()); } /** * Test method for. * * {@link org.jajuk.services.dj.DigitalDJ#setTrackUnicity(boolean)}. */ public final void testSetTrackUnicity() { // tested above } /** * Test method for {@link org.jajuk.services.dj.DigitalDJ#getRatingLevel()}. */ public final void testGetAndSetMaxTracks() { DigitalDJ dj = new AmbienceDigitalDJ("3"); dj.setName("ambience1"); assertEquals(-1, dj.getMaxTracks()); dj.setMaxTracks(3); assertEquals(3, dj.getMaxTracks()); } /** * Test method for {@link org.jajuk.services.dj.DigitalDJ#setRatingLevel(int)} * . */ public final void testSetMaxTracks() { // tested above } } jajuk-1.9.6.orig/src/test/java/org/jajuk/services/lyrics/0000755000175000017500000000000011720500104023166 5ustar drazzibdrazzibjajuk-1.9.6.orig/src/test/java/org/jajuk/services/lyrics/TestLyrics.java0000644000175000017500000001134011720500104026135 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.services.lyrics; import java.io.File; import java.io.IOException; import java.net.SocketTimeoutException; import java.net.URL; import java.util.List; import org.apache.commons.lang.StringUtils; import org.jajuk.JUnitHelpers; import org.jajuk.JajukTestCase; import org.jajuk.services.lyrics.providers.GenericWebLyricsProvider; import org.jajuk.services.lyrics.providers.ILyricsProvider; import org.jajuk.services.lyrics.providers.LyricWikiWebLyricsProvider; import org.jajuk.util.DownloadManager; import org.jajuk.util.log.Log; /** * Lyrics unit tests. */ public class TestLyrics extends JajukTestCase { /** DOCUMENT_ME. */ private final File tmp = new File("test.tmp"); /** The Constant ARTIST. DOCUMENT_ME */ private static final String ARTIST = "Massive Attack"; /** The Constant TITLE. DOCUMENT_ME */ private static final String TITLE = "Dissolved Girl"; /** The Constant TESTED_WORD. DOCUMENT_ME */ private static final String TESTED_WORD = "Day, yesterday"; // LyricsFly put a delay of 1500 ms before we are allowed to query again, we // need to take that into account for some of the tests /** The Constant FLY_DELAY. DOCUMENT_ME */ private static final long FLY_DELAY = 1500 + 200; // helper method to emma-coverage of the unused constructor /** * Test private constructor. * DOCUMENT_ME * * @throws Exception the exception */ public void testPrivateConstructor() throws Exception { // For EMMA code-coverage tests JUnitHelpers.executePrivateConstructor(LyricsService.class); } /** * Test setup. * * @throws IOException Signals that an I/O exception has occurred. */ @Override public void setUp() throws IOException { if (tmp.exists()) { tmp.delete(); } JUnitHelpers.createSessionDirectory(); // to first cover this method while no providers are loaded yet LyricsService.getProviders(); } /** * Test provider loading. */ public void testProvidersLoading() { LyricsService.loadProviders(); List providers = LyricsService.getProviders(); assertNotNull(providers); assertFalse(providers.size() == 0); } /** * Test provider response to get lyrics (shared code). * * @param provider DOCUMENT_ME */ private void testWebService(GenericWebLyricsProvider provider) { String lyrics = provider.getLyrics(ARTIST, TITLE); Log.debug("Resulting Lyrics(" + provider.getProviderHostname() + "): " + lyrics); if (provider.getProviderHostname().equals("api.lyricsfly.com") && lyrics == null) { Log.fatal("In Sonar this can happen, seems we do not have internet access there..."); return; } assertTrue("Lyrics(" + provider.getProviderHostname() + "): " + lyrics, StringUtils.isNotBlank(lyrics)); assertTrue("Lyrics(" + provider.getProviderHostname() + "): " + lyrics, lyrics.indexOf(TESTED_WORD) != -1); } /** * Test provider web site url (shared code). * * @param provider DOCUMENT_ME * @throws IOException Signals that an I/O exception has occurred. */ private void testWeb(GenericWebLyricsProvider provider) throws IOException { URL url = provider.getWebURL(ARTIST, TITLE); assertNotNull(url); try { DownloadManager.download(url, tmp); } catch (SocketTimeoutException e) { Log.fatal("In Sonar this exception occurs, seems we do not have internet access there..."); return; } assertTrue(tmp.exists()); assertTrue(tmp.length() > 0); } /** * Test LyricWiki provider response to get lyrics. */ public void testLyricWikiService() { GenericWebLyricsProvider provider = new LyricWikiWebLyricsProvider(); testWebService(provider); } /** * Test LyricWiki web url availability. * * @throws Exception the exception */ public void testLyricWikiWeb() throws Exception { GenericWebLyricsProvider provider = new LyricWikiWebLyricsProvider(); testWeb(provider); } } jajuk-1.9.6.orig/src/test/java/org/jajuk/services/core/0000755000175000017500000000000011720500104022611 5ustar drazzibdrazzibjajuk-1.9.6.orig/src/test/java/org/jajuk/services/core/TestRatingManager.java0000644000175000017500000001264611720500104027044 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.services.core; import java.util.Set; import org.jajuk.JUnitHelpers; import org.jajuk.JajukTestCase; import org.jajuk.base.Album; import org.jajuk.base.Artist; import org.jajuk.base.Device; import org.jajuk.base.Directory; import org.jajuk.base.DirectoryManager; import org.jajuk.base.File; import org.jajuk.base.FileManager; import org.jajuk.base.Genre; import org.jajuk.base.TestAlbumManager.MockPlayer; import org.jajuk.base.TestAlbumManager.MyTagImpl; import org.jajuk.base.Track; import org.jajuk.base.TrackManager; import org.jajuk.base.Type; import org.jajuk.base.TypeManager; import org.jajuk.base.Year; import org.jajuk.events.JajukEvent; import org.jajuk.events.JajukEvents; import org.jajuk.services.players.IPlayerImpl; import org.jajuk.services.startup.StartupCollectionService; import org.jajuk.services.tags.ITagImpl; import org.jajuk.util.Const; /** * DOCUMENT_ME. */ public class TestRatingManager extends JajukTestCase { /** * Test method for {@link org.jajuk.services.core.RatingManager#run()}. */ public void testRun() { // cannot be tested, is an endless loop: // RatingManager.getInstance().run(); } /** * Test method for {@link org.jajuk.services.core.RatingManager#getInstance()} * . */ public void testGetInstance() { assertNotNull(RatingManager.getInstance()); } /** * Test method for. * * {@link org.jajuk.services.core.RatingManager#getMaxPlaycount()}. */ public void testGetAndSetMaxPlaycount() { // Reset the rating manager RatingManager.getInstance().update(new JajukEvent(JajukEvents.RATE_RESET, null)); assertEquals(0, RatingManager.getMaxPlaycount()); RatingManager.setMaxPlaycount(10); assertEquals(10, RatingManager.getMaxPlaycount()); // set back to 0 as there is special handling RatingManager.setMaxPlaycount(0); } /** * Test method for. * * {@link org.jajuk.services.core.RatingManager#setMaxPlaycount(long)}. */ public void testSetMaxPlaycount() { // tested above } /** * Test method for. * * {@link org.jajuk.services.core.RatingManager#hasRateChanged()}. */ public void testHasAndSetRateChanged() { assertTrue(RatingManager.hasRateChanged()); RatingManager.setRateHasChanged(false); assertFalse(RatingManager.hasRateChanged()); RatingManager.setRateHasChanged(true); assertTrue(RatingManager.hasRateChanged()); } /** * Test method for. * * {@link org.jajuk.services.core.RatingManager#setRateHasChanged(boolean)}. */ public void testSetRateHasChanged() { // tested above } /** * Test method for. * * {@link org.jajuk.services.core.RatingManager#getRegistrationKeys()}. */ public void testGetRegistrationKeys() { Set set = RatingManager.getInstance().getRegistrationKeys(); assertTrue(set.toString(), set.contains(JajukEvents.RATE_RESET)); } /** * Test method for. * * @throws Exception the exception * {@link org.jajuk.services.core.RatingManager#update(org.jajuk.events.JajukEvent)} * . */ public void testUpdate() throws Exception { StartupCollectionService.registerItemManagers(); // update uses some Tracks getTrack(1); getTrack(2); RatingManager.getInstance().update(new JajukEvent(JajukEvents.RATE_RESET, null)); RatingManager.getInstance().update(new JajukEvent(JajukEvents.PREFERENCES_RESET, null)); } /** * Gets the track. * * @param i DOCUMENT_ME * @return the track * @throws Exception the exception */ @SuppressWarnings("unchecked") private Track getTrack(int i) throws Exception { Genre genre = JUnitHelpers.getGenre(); Album album = JUnitHelpers.getAlbum("name", 23); album.setProperty(Const.XML_ALBUM_DISCOVERED_COVER, Const.COVER_NONE); // don't read covers for // this test Artist artist = JUnitHelpers.getArtist("name"); Year year = JUnitHelpers.getYear(2000); IPlayerImpl imp = new MockPlayer(); Class cl = (Class) imp.getClass(); ITagImpl tagimp = new MyTagImpl(); Class tl = (Class) tagimp.getClass(); Type type = JUnitHelpers.getType(); Track track = TrackManager.getInstance().registerTrack(Integer.valueOf(i).toString(), "name", album, genre, artist, 120, year, 1, type, 1); album.getTracksCache().add(track); Device device = JUnitHelpers.getDevice(); Directory dir = DirectoryManager.getInstance().registerDirectory(device); File file = FileManager.getInstance().registerFile("test.tst", dir, track, 120, 70); track.addFile(file); TypeManager.getInstance().registerType("test", "tst", cl, tl); return track; } } jajuk-1.9.6.orig/src/test/java/org/jajuk/services/core/TestExitService.java0000644000175000017500000000413111720500104026545 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.services.core; import org.jajuk.JUnitHelpers; import org.jajuk.JajukTestCase; import org.jajuk.services.startup.StartupCollectionService; /** * DOCUMENT_ME. */ public class TestExitService extends JajukTestCase { /** * Test method for {@link org.jajuk.services.core.ExitService#run()}. * * @throws Exception the exception */ public void testRun() throws Exception { JUnitHelpers.createSessionDirectory(); StartupCollectionService.registerItemManagers(); ExitService service = new ExitService(); service.run(); // once again with sessionidfile SessionService.getSessionIdFile().getParentFile().mkdirs(); SessionService.getSessionIdFile().createNewFile(); service.run(); } /** * Test method for {@link org.jajuk.services.core.ExitService#ExitService()}. */ public void testExitService() { new ExitService(); } /** * Test method for {@link org.jajuk.services.core.ExitService#exit(int)}. */ public void testExit() { ExitService service = new ExitService(); assertNotNull(service); // don't run this as it stops the JVM! service.exit(1); } /** * Test method for {@link org.jajuk.services.core.ExitService#isExiting()}. */ public void testIsExiting() { assertFalse(ExitService.isExiting()); } } jajuk-1.9.6.orig/src/test/java/org/jajuk/services/core/TestSessionService.java0000644000175000017500000001752511720500104027272 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.services.core; import java.io.File; import java.net.URL; import org.apache.commons.io.FileUtils; import org.jajuk.JUnitHelpers; import org.jajuk.JajukTestCase; import org.jajuk.util.Const; import org.jajuk.util.UtilSystem; import org.jajuk.util.error.JajukRuntimeException; /** * DOCUMENT_ME. */ public class TestSessionService extends JajukTestCase { /* * (non-Javadoc) * * @see junit.framework.TestCase#setUp() */ @Override protected void setUp() throws Exception { // reset some of the values... JUnitHelpers.createSessionDirectory(); super.setUp(); } /** * Test method for. * * @throws Exception the exception * {@link org.jajuk.services.core.SessionService#checkOtherSession()}. */ public void testCheckOtherSession() throws Exception { SessionService.checkOtherSession(); } /** * Test method for {@link org.jajuk.services.core.SessionService#isIdeMode()}. */ public void testIsIdeMode() { // depends on startup SessionService.isIdeMode(); } /** * Test method for {@link org.jajuk.services.core.SessionService#isTestMode()} * . */ public void testIsTestMode() { // depends on startup SessionService.isTestMode(); } /** * Test method for. * * @throws Exception the exception * {@link org.jajuk.services.core.SessionService#getWorkspace()}. */ public void testGetWorkspace() throws Exception { assertNotNull(SessionService.getWorkspace()); } /** * Test method for. * * {@link org.jajuk.services.core.SessionService#setTestMode(boolean)}. */ public void testSetTestMode() { SessionService.setTestMode(true); } /** * Test method for. * * {@link org.jajuk.services.core.SessionService#setWorkspace(java.lang.String)} * . */ public void testSetWorkspace() { SessionService.setWorkspace("testworkspace"); } /** * Test method for. * * {@link org.jajuk.services.core.SessionService#getSessionIdFile()}. */ public void testGetSessionIdFile() { assertNotNull(SessionService.getSessionIdFile()); } /** * Test method for. * * {@link org.jajuk.services.core.SessionService#handleCommandline(java.lang.String[])} * . */ public void testHandleCommandline() { SessionService.handleCommandline(new String[] {}); SessionService.handleCommandline(new String[] { "-test", "-ide", "-something" }); assertFalse(parseWorkspaceLocation("")); assertFalse(parseWorkspaceLocation("/foo")); String tmpDir = System.getProperty("java.io.tmpdir"); String rightWorkspaceLocation = tmpDir; assertTrue(parseWorkspaceLocation(rightWorkspaceLocation)); SessionService.handleCommandline(new String[] { "-test", "-ide", "-workspace=" + tmpDir, "-something" }); } /** * Return true if the workspace location is valid. * * @param workspaceLocation DOCUMENT_ME * @return true if the workspace location is valid */ private boolean parseWorkspaceLocation(String workspaceLocation) { try { // next line should throw a runtime exception SessionService.handleCommandline(new String[] { "-test", "-ide", "-something", "-workspace=" + workspaceLocation }); return true; } catch (JajukRuntimeException e) { return false; } } /** * Test method for. * * {@link org.jajuk.services.core.SessionService#handleSystemProperties()}. */ public void testHandleSystemProperties() { SessionService.handleSystemProperties(); System.setProperty("ide", "true"); System.setProperty("test", "true"); SessionService.handleSystemProperties(); } /** * Test method for. * * {@link org.jajuk.services.core.SessionService#createSessionFile()}. */ public void testCreateSessionFile() { SessionService.createSessionFile(); SessionService.setWorkspace("/invalidpath"); SessionService.createSessionFile(); } /** * Test method for. * * @throws Exception the exception * {@link org.jajuk.services.core.SessionService#discoverWorkspace()}. * @TODO : perform more tests */ public void testDiscoverWorkspace() throws Exception { { // ensure that the base jajuk-directory exists, otherwise the // "first time wizard" is run, which blocks the test File bootstrap = new File(SessionService.getBootstrapPath()); // try to create it if it is missing if (!bootstrap.exists()) { String content = "\n"+ ""+UtilSystem.getUserHome()+"\n"+ ""+UtilSystem.getUserHome()+"\n"; FileUtils.writeStringToFile(bootstrap, content); } // needs to be a directory, needs to be readable, ... assertTrue(bootstrap.isFile()); assertTrue(bootstrap.canRead()); } // Reset CLI parameters SessionService.handleCommandline(new String[] { "-test", "-ide", "-something" }); SessionService.discoverWorkspace(); // without test mode... SessionService.setTestMode(false); SessionService.discoverWorkspace(); } /** * Test method for. * * {@link org.jajuk.services.core.SessionService#notifyFirstTimeWizardClosed()} * . */ public void testNotifyFirstTimeWizardClosed() { SessionService.notifyFirstTimeWizardClosed(); } /** * Test method for. * * @throws Exception the exception * {@link org.jajuk.services.core.SessionService#getCachePath(java.net.URL)}. */ public void testGetCachePath() throws Exception { assertNotNull(SessionService.getCachePath(new URL("ftp://example.com/"))); assertNotNull(SessionService.getCachePath(new URL("http://ww.example.com/"))); } /** * Test method for. * * {@link org.jajuk.services.core.SessionService#getConfFileByPath(java.lang.String)} * . */ public void testGetConfFileByPath() { SessionService.getConfFileByPath("/tmp"); SessionService.setTestMode(false); SessionService.getConfFileByPath("/tmp"); SessionService.setTestMode(true); SessionService.getConfFileByPath("/tmp"); } /** * Test method for. * * {@link org.jajuk.services.core.SessionService#getDefaultCollectionPath()}. */ public void testGetDefaultWorkspace() { SessionService.getDefaultCollectionPath(); } /** * Test method for {@link org.jajuk.services.core.SessionService#clearCache()} * . * * @throws Exception the exception */ public void testClearCache() throws Exception { SessionService.clearCache(); // create some dummy file File file = SessionService.getConfFileByPath(Const.FILE_CACHE); assertNotNull(file); File.createTempFile("cache", ".tst", file); SessionService.clearCache(); } // helper method to emma-coverage of the unused constructor // For EMMA code-coverage tests /** * Test private constructor. * DOCUMENT_ME * * @throws Exception the exception */ public void testPrivateConstructor() throws Exception { JUnitHelpers.executePrivateConstructor(SessionService.class); } } jajuk-1.9.6.orig/src/test/java/org/jajuk/services/players/0000755000175000017500000000000011720500104023340 5ustar drazzibdrazzibjajuk-1.9.6.orig/src/test/java/org/jajuk/services/players/TestQueueList.java0000644000175000017500000004100411720500104026762 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.services.players; import java.util.ArrayList; import java.util.HashSet; import java.util.Iterator; import java.util.List; import org.jajuk.JUnitHelpers; import org.jajuk.JajukTestCase; import org.jajuk.base.File; import org.jajuk.util.error.JajukException; /** * DOCUMENT_ME. */ public class TestQueueList extends JajukTestCase { /** * Test method for {@link org.jajuk.services.players.QueueList#add(org.jajuk.services.players.StackItem)}. * * @throws Exception the exception */ public void testAddStackItem() throws Exception { QueueList impl = new QueueList(); impl.add(new StackItem(JUnitHelpers.getFile("file1", false))); assertEquals(1, impl.size()); } /** * Test method for {@link org.jajuk.services.players.QueueList#add(int, org.jajuk.services.players.StackItem)}. * * @throws Exception the exception */ public void testAddIntStackItem() throws Exception { QueueList impl = new QueueList(); File file1 = JUnitHelpers.getFile("file1", false); File file2 = JUnitHelpers.getFile("file2", false); impl.add(new StackItem(file1)); assertEquals(1, impl.size()); impl.add(0, new StackItem(file2)); assertEquals(2, impl.size()); // "2" should be first! assertEquals(file2, impl.get(0).getFile()); } /** * Test method for {@link org.jajuk.services.players.QueueList#addAll(java.util.Collection)}. * * @throws Exception the exception */ public void testAddAllCollectionOfQextendsStackItem() throws Exception { QueueList impl = new QueueList(); prepareQueueImpl(impl); assertEquals(3, impl.size()); } /** * Test method for {@link org.jajuk.services.players.QueueList#addAll(int, java.util.Collection)}. * * @throws Exception the exception */ public void testAddAllIntCollectionOfQextendsStackItem() throws Exception { QueueList impl = new QueueList(); impl.add(new StackItem(JUnitHelpers.getFile("file10", false))); assertEquals(1, impl.size()); File file1 = JUnitHelpers.getFile("file1", false); File file2 = JUnitHelpers.getFile("file2", false); File file3 = JUnitHelpers.getFile("file3", false); List set = new ArrayList(); set.add(new StackItem(file1)); set.add(new StackItem(file2)); set.add(new StackItem(file3)); impl.addAll(0, set); assertEquals(4, impl.size()); assertEquals(file1, impl.get(0).getFile()); } /** * Test method for {@link org.jajuk.services.players.QueueList#clear()}. * * @throws Exception the exception */ public void testClear() throws Exception { QueueList impl = new QueueList(); impl.add(new StackItem(JUnitHelpers.getFile("file10", false))); assertEquals(1, impl.size()); impl.clear(); assertEquals(0, impl.size()); } /** * Test method for {@link org.jajuk.services.players.QueueList#contains(java.lang.Object)}. * * @throws Exception the exception */ public void testContains() throws Exception { QueueList impl = new QueueList(); prepareQueueImpl(impl); assertEquals(3, impl.size()); assertTrue(impl.contains(new StackItem(JUnitHelpers.getFile("file1", false)))); assertFalse(impl.contains(new StackItem(JUnitHelpers.getFile("file4", false)))); } /** * Test method for {@link org.jajuk.services.players.QueueList#containsAll(java.util.Collection)}. * * @throws Exception the exception */ public void testContainsAll() throws Exception { QueueList impl = new QueueList(); List set = prepareQueueImpl(impl); assertEquals(3, impl.size()); assertTrue(impl.containsAll(set)); // add a file that is not in the queue set.add(new StackItem(JUnitHelpers.getFile("file4", false))); assertFalse(impl.containsAll(set)); } /** * Test method for {@link org.jajuk.services.players.QueueList#get(int)}. * * @throws Exception the exception */ public void testGet() throws Exception { // tested above } /** * Test method for {@link org.jajuk.services.players.QueueList#indexOf(java.lang.Object)}. * * @throws Exception the exception */ public void testIndexOf() throws Exception { QueueList impl = new QueueList(); prepareQueueImpl(impl); assertEquals(3, impl.size()); assertEquals(0, impl.indexOf(new StackItem(JUnitHelpers.getFile("file1", false)))); assertEquals(1, impl.indexOf(new StackItem(JUnitHelpers.getFile("file2", false)))); } /** * Test method for {@link org.jajuk.services.players.QueueList#isEmpty()}. * * @throws Exception the exception */ public void testIsEmpty() throws Exception { QueueList impl = new QueueList(); assertTrue(impl.isEmpty()); impl.add(new StackItem(JUnitHelpers.getFile("file1", false))); assertFalse(impl.isEmpty()); } /** * Test method for {@link org.jajuk.services.players.QueueList#iterator()}. * * @throws Exception the exception */ public void testIterator() throws Exception { QueueList impl = new QueueList(); prepareQueueImpl(impl); assertEquals(3, impl.size()); Iterator it = impl.iterator(); assertTrue(it.hasNext()); it.next(); assertTrue(it.hasNext()); it.next(); assertTrue(it.hasNext()); it.next(); assertFalse(it.hasNext()); } /** * Test method for {@link org.jajuk.services.players.QueueList#lastIndexOf(java.lang.Object)}. * * @throws Exception the exception */ public void testLastIndexOf() throws Exception { QueueList impl = new QueueList(); prepareQueueImpl(impl); assertEquals(3, impl.size()); assertEquals(2, impl.lastIndexOf(new StackItem(JUnitHelpers.getFile("file3", false)))); } /** * Test method for {@link org.jajuk.services.players.QueueList#listIterator()}. * * @throws Exception the exception */ public void testListIterator() throws Exception { QueueList impl = new QueueList(); prepareQueueImpl(impl); assertEquals(3, impl.size()); assertNotNull(impl.listIterator()); } /** * Test method for {@link org.jajuk.services.players.QueueList#listIterator(int)}. * * @throws Exception the exception */ public void testListIteratorInt() throws Exception { QueueList impl = new QueueList(); prepareQueueImpl(impl); assertEquals(3, impl.size()); assertNotNull(impl.listIterator(1)); } /** * Test method for {@link org.jajuk.services.players.QueueList#remove(java.lang.Object)}. * * @throws Exception the exception */ public void testRemoveObject() throws Exception { QueueList impl = new QueueList(); prepareQueueImpl(impl); assertEquals(3, impl.size()); // first it works assertTrue(impl.remove(new StackItem(JUnitHelpers.getFile("file2", false)))); // then the element is not found any more assertFalse(impl.remove(new StackItem(JUnitHelpers.getFile("file2", false)))); } /** * Test method for {@link org.jajuk.services.players.QueueList#remove(int)}. * * @throws Exception the exception */ public void testRemoveInt() throws Exception { QueueList impl = new QueueList(); prepareQueueImpl(impl); // first it removes an item assertNotNull(impl.remove(2)); // then there is no more item to remove try { assertNull(impl.remove(2)); fail("Should catch an Exception here"); } catch (IndexOutOfBoundsException e) { assertTrue(e.getMessage(), e.getMessage().contains("Index: 2, Size: 2")); } } /** * Test method for {@link org.jajuk.services.players.QueueList#removeAll(java.util.Collection)}. * * @throws Exception the exception */ public void testRemoveAll() throws Exception { QueueList impl = new QueueList(); List set = prepareQueueImpl(impl); assertTrue(impl.removeAll(set)); assertEquals(0, impl.size()); // no more changes assertFalse(impl.removeAll(set)); } /** * Test method for {@link org.jajuk.services.players.QueueList#retainAll(java.util.Collection)}. * * @throws Exception the exception */ public void testRetainAll() throws Exception { QueueList impl = new QueueList(); List set = prepareQueueImpl(impl); impl.retainAll(set); assertEquals(3, impl.size()); impl.retainAll(new HashSet()); assertEquals(0, impl.size()); } /** * Test method for {@link org.jajuk.services.players.QueueList#set(int, org.jajuk.services.players.StackItem)}. * * @throws Exception the exception */ public void testSet() throws Exception { QueueList impl = new QueueList(); prepareQueueImpl(impl); impl.set(0, new StackItem(JUnitHelpers.getFile("file4", false))); assertEquals("file4", impl.get(0).getFile().getName()); } /** * Test method for {@link org.jajuk.services.players.QueueList#size()}. * * @throws Exception the exception */ public void testSize() throws Exception { // tested above } /** * Test method for {@link org.jajuk.services.players.QueueList#subList(int, int)}. * * @throws Exception the exception */ public void testSubList() throws Exception { QueueList impl = new QueueList(); prepareQueueImpl(impl); List items = impl.subList(1, 3); assertEquals(2, items.size()); } /** * Test method for {@link org.jajuk.services.players.QueueList#toArray()}. * * @throws Exception the exception */ public void testToArray() throws Exception { QueueList impl = new QueueList(); prepareQueueImpl(impl); Object[] arr = impl.toArray(); assertEquals(3, arr.length); } /** * Test method for {@link org.jajuk.services.players.QueueList#toArray(T[])}. * * @throws Exception the exception */ public void testToArrayTArray() throws Exception { QueueList impl = new QueueList(); prepareQueueImpl(impl); StackItem[] arr = impl.toArray(new StackItem[] {}); assertEquals(3, arr.length); } /** * Test method for {@link org.jajuk.services.players.QueueList#getQueue()}. * * @throws Exception the exception */ public void testGetQueue() throws Exception { QueueList impl = new QueueList(); prepareQueueImpl(impl); List queue = impl.getQueue(); assertEquals(3, queue.size()); } /** * Test method for {@link org.jajuk.services.players.QueueList#sizePlanned()}. * * @throws Exception the exception */ public void testSizePlanned() throws Exception { QueueList impl = new QueueList(); prepareQueueImpl(impl); assertEquals(0, impl.sizePlanned()); impl.addPlanned(new StackItem(JUnitHelpers.getFile("file2", false))); assertEquals(1, impl.sizePlanned()); } /** * Test method for {@link org.jajuk.services.players.QueueList#addPlanned(org.jajuk.services.players.StackItem)}. * * @throws Exception the exception */ public void testAddPlannedStackItem() throws Exception { // tested above } /** * Test method for {@link org.jajuk.services.players.QueueList#addPlanned(java.util.List)}. * * @throws Exception the exception */ public void testAddPlannedListOfStackItem() throws Exception { QueueList impl = new QueueList(); prepareQueueImpl(impl); prepareQueueImplPlanned(impl); assertEquals(2, impl.sizePlanned()); } /** * Test method for {@link org.jajuk.services.players.QueueList#getPlanned(int)}. * * @throws Exception the exception */ public void testGetPlannedInt() throws Exception { QueueList impl = new QueueList(); prepareQueueImpl(impl); prepareQueueImplPlanned(impl); assertEquals("file9", impl.getPlanned(0).getFile().getName()); assertEquals("file8", impl.getPlanned(1).getFile().getName()); } /** * Test method for {@link org.jajuk.services.players.QueueList#getPlanned()}. * * @throws Exception the exception */ public void testGetPlanned() throws Exception { QueueList impl = new QueueList(); prepareQueueImpl(impl); prepareQueueImplPlanned(impl); assertEquals(2, impl.getPlanned().size()); } /** * Test method for {@link org.jajuk.services.players.QueueList#removePlannedFromList(java.util.List)}. * * @throws Exception the exception */ public void testRemovePlannedFromList() throws Exception { QueueList impl = new QueueList(); prepareQueueImpl(impl); prepareQueueImplPlanned(impl); List items = new ArrayList(); impl.removePlannedFromList(items); assertEquals(0, items.size()); items.add(JUnitHelpers.getFile("file2", false)); items.add(JUnitHelpers.getFile("file8", false)); // this should be removed items.add(JUnitHelpers.getFile("file11", false)); assertEquals(3, items.size()); impl.removePlannedFromList(items); assertEquals(2, items.size()); assertEquals("file2", items.get(0).getName()); assertEquals("file11", items.get(1).getName()); } /** * Test method for {@link org.jajuk.services.players.QueueList#clearPlanned()}. * * @throws Exception the exception */ public void testClearPlanned() throws Exception { QueueList impl = new QueueList(); prepareQueueImpl(impl); prepareQueueImplPlanned(impl); impl.clearPlanned(); assertEquals(3, impl.size()); assertEquals(0, impl.sizePlanned()); } /** * Test method for {@link org.jajuk.services.players.QueueList#containsRepeat()}. * * @throws Exception the exception */ public void testContainsRepeat() throws Exception { QueueList impl = new QueueList(); prepareQueueImpl(impl); // repeat is not automatically set assertFalse(impl.containsRepeat()); impl.get(1).setRepeat(true); assertTrue(impl.containsRepeat()); impl.get(1).setRepeat(false); assertFalse(impl.containsRepeat()); } /** * Test method for {@link org.jajuk.services.players.QueueList#popNextPlanned()}. * * @throws Exception the exception */ public void testPopNextPlanned() throws Exception { QueueList impl = new QueueList(); prepareQueueImpl(impl); prepareQueueImplPlanned(impl); assertNotNull(impl.popNextPlanned()); assertNotNull(impl.popNextPlanned()); assertNull(impl.popNextPlanned()); } /** * Test method for {@link org.jajuk.services.players.QueueList#containsOnlyRepeat()}. * * @throws Exception the exception */ public void testContainsOnlyRepeat() throws Exception { QueueList impl = new QueueList(); prepareQueueImpl(impl); // repeat is not automatically set assertFalse(impl.containsOnlyRepeat()); impl.get(1).setRepeat(true); assertFalse(impl.containsOnlyRepeat()); impl.get(0).setRepeat(true); impl.get(2).setRepeat(true); assertTrue(impl.containsOnlyRepeat()); impl.get(1).setRepeat(false); assertFalse(impl.containsOnlyRepeat()); } /** * Prepare queue impl. * DOCUMENT_ME * * @param impl DOCUMENT_ME * @return the list * @throws JajukException the jajuk exception * @throws Exception the exception */ private List prepareQueueImpl(QueueList impl) throws JajukException, Exception { List set = new ArrayList(); set.add(new StackItem(JUnitHelpers.getFile("file1", false))); set.add(new StackItem(JUnitHelpers.getFile("file2", false))); set.add(new StackItem(JUnitHelpers.getFile("file3", false))); impl.addAll(set); return set; } /** * Prepare queue impl planned. * DOCUMENT_ME * * @param impl DOCUMENT_ME * @return the list * @throws JajukException the jajuk exception * @throws Exception the exception */ private List prepareQueueImplPlanned(QueueList impl) throws JajukException, Exception { List set = new ArrayList(); set.add(new StackItem(JUnitHelpers.getFile("file9", false))); set.add(new StackItem(JUnitHelpers.getFile("file8", false))); impl.addPlanned(set); return set; } } jajuk-1.9.6.orig/src/test/java/org/jajuk/services/players/TestStackItem.java0000644000175000017500000001234311720500104026732 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.services.players; import org.jajuk.JUnitHelpers; import org.jajuk.JajukTestCase; import org.jajuk.base.File; import org.jajuk.util.error.JajukException; /** * DOCUMENT_ME. */ public class TestStackItem extends JajukTestCase { /** * Test method for {@link org.jajuk.services.players.StackItem#hashCode()}. * * @throws Exception the exception */ public void testHashCode() throws Exception { File file = JUnitHelpers.getFile("file1", true); StackItem item1 = new StackItem(file); StackItem item2 = new StackItem(file); JUnitHelpers.HashCodeTest(item1, item2); } /** * Test method for. * * @throws Exception the exception * {@link org.jajuk.services.players.StackItem#StackItem(org.jajuk.base.File)} * . */ public void testStackItemFile() throws Exception { new StackItem(JUnitHelpers.getFile("file1", true)); // test null input try { new StackItem(null); fail("Should throw exception here."); } catch (JajukException e) { assertEquals(0, e.getCode()); } } /** * Test method for. * * @throws Exception the exception * {@link org.jajuk.services.players.StackItem#StackItem(org.jajuk.base.File, boolean)} * . */ public void testStackItemFileBoolean() throws Exception { new StackItem(JUnitHelpers.getFile("file2", true), true); // test null input try { new StackItem(null, true); fail("Should throw exception here."); } catch (JajukException e) { assertEquals(0, e.getCode()); } } /** * Test method for. * * @throws Exception the exception * {@link org.jajuk.services.players.StackItem#StackItem(org.jajuk.base.File, boolean, boolean)} * . */ public void testStackItemFileBooleanBoolean() throws Exception { new StackItem(JUnitHelpers.getFile("file2", true), true, true); // test null input try { new StackItem(null, true, true); fail("Should throw exception here."); } catch (JajukException e) { assertEquals(0, e.getCode()); } } /** * Test method for {@link org.jajuk.services.players.StackItem#isRepeat()}. * * @throws Exception the exception */ public void testIsAndSetRepeat() throws Exception { StackItem item = new StackItem(JUnitHelpers.getFile("file1", true)); assertFalse(item.isRepeat()); item.setRepeat(true); assertTrue(item.isRepeat()); } /** * Test method for {@link org.jajuk.services.players.StackItem#JUnitHelpers.getFile()}. * * @throws Exception the exception */ public void testgetFile() throws Exception { StackItem item = new StackItem(JUnitHelpers.getFile("file1", true)); assertNotNull(item.getFile()); } /** * Test method for {@link org.jajuk.services.players.StackItem#isUserLaunch()} * . * * @throws Exception the exception */ public void testIsAndSetUserLaunch() throws Exception { StackItem item = new StackItem(JUnitHelpers.getFile("file1", true)); assertFalse(item.isUserLaunch()); item.setUserLaunch(true); assertTrue(item.isUserLaunch()); } /** * Test method for {@link org.jajuk.services.players.StackItem#isPlanned()}. * * @throws Exception the exception */ public void testIsAndSetPlanned() throws Exception { StackItem item = new StackItem(JUnitHelpers.getFile("file1", true)); assertFalse(item.isPlanned()); item.setPlanned(true); assertTrue(item.isPlanned()); } /** * Test method for {@link org.jajuk.services.players.StackItem#clone()}. * * @throws Exception the exception */ public void testClone() throws Exception { StackItem item = new StackItem(JUnitHelpers.getFile("file1", true)); JUnitHelpers.CloneTest(item); } /** * Test method for. * * @throws Exception the exception * {@link org.jajuk.services.players.StackItem#equals(java.lang.Object)}. */ public void testEqualsObject() throws Exception { File file = JUnitHelpers.getFile("file1", true); StackItem item1 = new StackItem(file); StackItem item2 = new StackItem(file); StackItem item3 = new StackItem(JUnitHelpers.getFile("file2", true)); JUnitHelpers.EqualsTest(item1, item2, item3); } /** * Test method for {@link org.jajuk.services.players.StackItem#toString()}. * * @throws Exception the exception */ public void testToString() throws Exception { StackItem item = new StackItem(JUnitHelpers.getFile("file1", true)); JUnitHelpers.ToStringTest(item); } } jajuk-1.9.6.orig/src/test/java/org/jajuk/services/players/TestQueueModel.java0000644000175000017500000011302511720500104027112 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.services.players; import java.util.ArrayList; import java.util.List; import org.apache.commons.io.FileUtils; import org.jajuk.JUnitHelpers; import org.jajuk.JajukTestCase; import org.jajuk.base.Album; import org.jajuk.base.Artist; import org.jajuk.base.Device; import org.jajuk.base.Directory; import org.jajuk.base.DirectoryManager; import org.jajuk.base.File; import org.jajuk.base.FileManager; import org.jajuk.base.Genre; import org.jajuk.base.Track; import org.jajuk.base.TrackManager; import org.jajuk.base.Type; import org.jajuk.base.Year; import org.jajuk.services.core.SessionService; import org.jajuk.services.startup.StartupCollectionService; import org.jajuk.services.webradio.WebRadio; import org.jajuk.util.Conf; import org.jajuk.util.Const; import org.jajuk.util.error.JajukException; /** * DOCUMENT_ME. */ public class TestQueueModel extends JajukTestCase { /* * (non-Javadoc) * * @see junit.framework.TestCase#setUp() */ @Override protected void setUp() throws Exception { // reset before each test to have a clean start for each test as most // data is held statically for QueueModel QueueModel.reset(); QueueModel.itemLast = null; QueueModel.stopRequest(); // reset conf changes to default Conf.setProperty(Const.CONF_STATE_CONTINUE, "false"); Conf.setProperty(Const.CONF_DROP_PLAYED_TRACKS_FROM_QUEUE, "false"); Conf.setProperty(Const.CONF_STATE_CONTINUE, "false"); Conf.setProperty(Const.CONF_STATE_SHUFFLE, "false"); // remove any registered files for (File file : FileManager.getInstance().getFiles()) { FileManager.getInstance().removeFile(file); } super.setUp(); } // helper method to emma-coverage of the unused constructor /** * Test private constructor. * DOCUMENT_ME * * @throws Exception the exception */ public void testPrivateConstructor() throws Exception { // For EMMA code-coverage tests JUnitHelpers.executePrivateConstructor(QueueModel.class); } /* * (non-Javadoc) * * @see junit.framework.TestCase#tearDown() */ @Override protected void tearDown() throws Exception { // make sure that the SwingUtilities.invokeLater() are all done JUnitHelpers.clearSwingUtilitiesQueue(); super.tearDown(); } /** * Test method for {@link org.jajuk.services.players.QueueModel#reset()}. * * @throws Exception the exception */ public void testReset() throws Exception { // nothing to reset up-front QueueModel.reset(); assertEquals(0, QueueModel.getQueueSize()); // things are reset with queued items addItems(10); QueueModel.goTo(4); QueueModel.reset(); assertEquals(0, QueueModel.getQueueSize()); assertEquals(-1, QueueModel.getIndex()); } /** * Test method for. * * {@link org.jajuk.services.players.QueueModel#setRepeatModeToAll(boolean)}. */ public void testSetRepeatModeToAll() { QueueModel.setRepeatModeToAll(false); } /** * Test method for. * * @throws Exception the exception * {@link org.jajuk.services.players.QueueModel#push(java.util.List, boolean)} * . */ public void testPushListOfStackItemBoolean() throws Exception { List list = new ArrayList(); list.add(new StackItem(JUnitHelpers.getFile("file1", true))); QueueModel.push(list, true); // we try to wait for the thread started inside push() to finish JUnitHelpers.waitForThreadToFinish("Queue Push Thread"); assertEquals(1, QueueModel.getQueue().size()); } /** * Test push list of stack item boolean no push. * DOCUMENT_ME * * @throws Exception the exception */ public void testPushListOfStackItemBooleanNoPush() throws Exception { List list = new ArrayList(); list.add(new StackItem(JUnitHelpers.getFile("file1", true))); QueueModel.push(list, false); // we try to wait for the thread started inside push() to finish JUnitHelpers.waitForThreadToFinish("Queue Push Thread"); assertEquals(1, QueueModel.getQueue().size()); } /** * Check right behavior when pushing void list of items. * If run with GUI, you should get a warning popup * * @throws Exception the exception */ public void testPushListOfStackItemVoid() throws Exception { List list = new ArrayList(); QueueModel.push(list, false); // there is a thread started, so delay a bit to let that happen... Thread.sleep(400); assertEquals(0, QueueModel.getQueue().size()); } /** * Test push list of stack item boolean null items. * DOCUMENT_ME * * @throws Exception the exception */ public void testPushListOfStackItemBooleanNullItems() throws Exception { List list = new ArrayList(); list.add(new StackItem(JUnitHelpers.getFile("file1", true))); list.add(null); list.add(new StackItem(JUnitHelpers.getFile("file3", true))); QueueModel.push(list, true); // we try to wait for the thread started inside push() to finish JUnitHelpers.waitForThreadToFinish("Queue Push Thread"); assertEquals(2, QueueModel.getQueue().size()); } /** * Test method for. * * @throws Exception the exception * {@link org.jajuk.services.players.QueueModel#push(java.util.List, boolean, boolean)} * . */ public void testPushListOfStackItemBooleanBoolean() throws Exception { List list = new ArrayList(); list.add(new StackItem(JUnitHelpers.getFile("file1", true))); QueueModel.push(list, true, true); // we try to wait for the thread started inside push() to finish JUnitHelpers.waitForThreadToFinish("Queue Push Thread"); assertEquals(1, QueueModel.getQueue().size()); } /** * Test push list of stack item boolean boolean no push next. * DOCUMENT_ME * * @throws Exception the exception */ public void testPushListOfStackItemBooleanBooleanNoPushNext() throws Exception { List list = new ArrayList(); list.add(new StackItem(JUnitHelpers.getFile("file1", true))); QueueModel.push(list, false, false); // we try to wait for the thread started inside push() to finish JUnitHelpers.waitForThreadToFinish("Queue Push Thread"); assertEquals(1, QueueModel.getQueue().size()); } /** * Test method for. * * @throws Exception the exception * {@link org.jajuk.services.players.QueueModel#push(org.jajuk.services.players.StackItem, boolean)} * . */ public void testPushStackItemBoolean() throws Exception { QueueModel.push(new StackItem(JUnitHelpers.getFile("file1", true)), true); // we try to wait for the thread started inside push() to finish JUnitHelpers.waitForThreadToFinish("Queue Push Thread"); assertEquals(1, QueueModel.getQueue().size()); } /** * Test method for. * * @throws Exception the exception * {@link org.jajuk.services.players.QueueModel#push(org.jajuk.services.players.StackItem, boolean, boolean)} * . */ public void testPushStackItemBooleanBoolean() throws Exception { QueueModel.push(new StackItem(JUnitHelpers.getFile("file1", true)), true, true); // we try to wait for the thread started inside push() to finish JUnitHelpers.waitForThreadToFinish("Queue Push Thread"); assertEquals(1, QueueModel.getQueue().size()); } /** * Adds the items. * DOCUMENT_ME * * @param count number of items to create * @throws Exception the exception */ private void addItems(int count) throws Exception { List list = new ArrayList(); for (int i = 0; i < count; i++) { list.add(new StackItem(JUnitHelpers.getFile("file" + i, true))); } QueueModel.insert(list, 0); } /** * Test method for. * * {@link org.jajuk.services.players.QueueModel#launchRadio(org.jajuk.services.webradio.WebRadio)} * . */ public void testLaunchRadio() { QueueModel.launchRadio(new WebRadio("name", "invalidurl")); } /** * Test method for. * * @throws Exception the exception * {@link org.jajuk.services.players.QueueModel#containsRepeat()}. */ public void testContainsRepeat() throws Exception { addItems(2); assertFalse(QueueModel.containsRepeat()); QueueModel.setRepeatModeToAll(true); assertTrue("Items: " + QueueModel.getQueue(), QueueModel.containsRepeat()); } /** * Test method for {@link org.jajuk.services.players.QueueModel#finished()}. * * @throws Exception the exception */ public void testFinished() throws Exception { // without item it just returns QueueModel.finished(); // with items, it will go to the next ine addItems(10); QueueModel.goTo(0); assertEquals(0, QueueModel.getIndex()); QueueModel.finished(); assertEquals(1, QueueModel.getIndex()); } /** * Test method for. * * @throws Exception the exception * {@link org.jajuk.services.players.QueueModel#finished()}. * Test for feature #1441 (Repeat all shuffle mode) : in repeat * all mode + shuffle mode, queue should be shuffled when reaching its end */ public void testFinishedRepeatAndShuffle() throws Exception { QueueModel.clear(); addItems(5); StackItem firstItem = QueueModel.getItem(0); QueueModel.setRepeatModeToAll(true); Conf.setProperty(Const.CONF_STATE_REPEAT, "false"); Conf.setProperty(Const.CONF_STATE_REPEAT_ALL, "true"); Conf.setProperty(Const.CONF_STATE_SHUFFLE, "true"); assertTrue(QueueModel.containsOnlyRepeat()); QueueModel.finished(); QueueModel.finished(); QueueModel.finished(); QueueModel.finished(); assertTrue(QueueModel.getItem(0).equals(firstItem)); QueueModel.finished(); // Make sure that first item is no more the same assertFalse("Item0: " + QueueModel.getItem(0) + "\nFirstItem: " + firstItem, !(QueueModel .getItem(0).equals(firstItem))); } /** * Test method for. * * @throws Exception the exception * {@link org.jajuk.services.players.QueueModel#finished(boolean)}. */ public void testFinishedBoolean() throws Exception { // without item it just returns QueueModel.finished(true); // with items, it will go to the next line addItems(10); QueueModel.goTo(0); assertEquals(0, QueueModel.getIndex()); QueueModel.finished(true); assertEquals(1, QueueModel.getIndex()); // still 10 as we do not remove items from queue in default setup assertEquals(10, QueueModel.getQueueSize()); } /** * Test finished boolean remove played. * DOCUMENT_ME * * @throws Exception the exception */ public void testFinishedBooleanRemovePlayed() throws Exception { // set config option that we want to test Conf.setProperty(Const.CONF_DROP_PLAYED_TRACKS_FROM_QUEUE, "true"); // without item it just returns QueueModel.finished(true); // with items, it will go to the next line addItems(10); QueueModel.goTo(0); assertEquals(0, QueueModel.getIndex()); QueueModel.finished(true); assertEquals(0, QueueModel.getIndex()); // here we should have 9 now... assertEquals(9, QueueModel.getQueueSize()); } /** * Test finished end of queue no planned. * DOCUMENT_ME * * @throws Exception the exception */ public void testFinishedEndOfQueueNoPlanned() throws Exception { // without item it just returns QueueModel.finished(true); // with items, it will go to the next line addItems(2); QueueModel.goTo(0); assertEquals(0, QueueModel.getIndex()); QueueModel.finished(true); assertEquals(1, QueueModel.getIndex()); // still 2 as we do not remove items from queue in default setup assertEquals(2, QueueModel.getQueueSize()); // next time it will reset the index as we do not "plan" new tracks automatically QueueModel.finished(true); assertEquals(-1, QueueModel.getIndex()); } /** * Test finished end of queue with planned. * DOCUMENT_ME * * @throws Exception the exception */ public void testFinishedEndOfQueueWithPlanned() throws Exception { Conf.setProperty(Const.CONF_STATE_CONTINUE, "true"); // without item it just returns QueueModel.finished(true); // with items, it will go to the next line addItems(2); QueueModel.goTo(0); assertEquals(0, QueueModel.getIndex()); QueueModel.finished(true); assertEquals(1, QueueModel.getIndex()); // still 2 as we do not remove items from queue in default setup assertEquals(2, QueueModel.getQueueSize()); { // start a track List list = new ArrayList(); list.add(new StackItem(JUnitHelpers.getFile("file" + 21, true))); QueueModel.push(list, true); // we try to wait for the thread started inside push() to finish JUnitHelpers.waitForThreadToFinish("Queue Push Thread"); assertEquals(3, QueueModel.getQueue().size()); } // one more to finish now QueueModel.finished(true); // next time it will reset the index as we do not "plan" new tracks automatically QueueModel.finished(true); assertEquals(0, QueueModel.getIndex()); } /** * Test method for. * * @throws Exception the exception * {@link org.jajuk.services.players.QueueModel#finished(boolean)}. */ public void testFinishedRepeatSingleItem() throws Exception { addItems(1); StackItem si = QueueModel.getItem(0); si.setRepeat(true); QueueModel.goTo(0); // Finish the track, should play again QueueModel.finished(); StackItem newSi = QueueModel.getItem(0); assertEquals(0, QueueModel.getIndex()); assertTrue(newSi.isRepeat()); assertEquals(newSi, QueueModel.getCurrentItem()); } /** * Test method for. * * @throws Exception the exception * {@link org.jajuk.services.players.QueueModel#finished(boolean)}. */ public void testFinishedRepeatLastItem() throws Exception { // We want to make sure that everything's ok when current item is in repeat // mode and the last in the queue addItems(10); StackItem si = QueueModel.getItem(9); si.setRepeat(true); QueueModel.goTo(9); // Finish the track, should play again QueueModel.finished(); // same track should be played again as it is in repeat mode and the first // one at index 0 is not StackItem newSi = QueueModel.getCurrentItem(); assertEquals(newSi, si); assertTrue(newSi.isRepeat()); // Now the same with first track in repeat mode QueueModel.getItem(0).setRepeat(true); QueueModel.finished(); newSi = QueueModel.getCurrentItem(); assertEquals(newSi, QueueModel.getItem(0)); assertTrue(newSi.isRepeat()); assertTrue(si.isRepeat()); } /** * Test finished repeat last item not last. * DOCUMENT_ME * * @throws Exception the exception */ public void testFinishedRepeatLastItemNotLast() throws Exception { // We want to make sure that everything's ok when current item is in repeat // mode and the last in the queue addItems(10); StackItem si = QueueModel.getItem(5); si.setRepeat(true); QueueModel.goTo(5); // Finish the track, should play again QueueModel.finished(); // same track should be played again as it is in repeat mode and the first // one at index 0 is not StackItem newSi = QueueModel.getCurrentItem(); assertEquals(newSi, si); assertTrue(newSi.isRepeat()); // Now the same with first track in repeat mode QueueModel.getItem(6).setRepeat(true); QueueModel.finished(); newSi = QueueModel.getCurrentItem(); assertEquals(newSi, QueueModel.getItem(6)); assertTrue(newSi.isRepeat()); assertTrue(si.isRepeat()); } /** * Test method for. * * @throws Exception the exception * {@link org.jajuk.services.players.QueueModel#finished(boolean)}. */ public void testFinishedRepeatNotLastItem() throws Exception { // We want to make sure that everything's ok when current item is in repeat // mode and *not* the last in the queue addItems(10); StackItem si = QueueModel.getItem(5); si.setRepeat(true); QueueModel.goTo(5); // Finish the track, should play again QueueModel.finished(); // same track should be played again as it is in repeat mode and the first // one at index 0 is not StackItem newSi = QueueModel.getCurrentItem(); assertEquals(newSi, si); assertTrue(newSi.isRepeat()); // Now the same with first track in repeat mode QueueModel.getItem(6).setRepeat(true); QueueModel.finished(); newSi = QueueModel.getCurrentItem(); assertEquals(newSi, QueueModel.getItem(6)); assertTrue(newSi.isRepeat()); assertTrue(si.isRepeat()); } /** * Test method for {@link org.jajuk.services.players.QueueModel#goTo(int)} * . * * @throws Exception the exception */ public void testSetAndGetIndex() throws Exception { // with items, it will go to the next ine addItems(10); QueueModel.goTo(0); assertEquals(0, QueueModel.getIndex()); QueueModel.goTo(3); assertEquals(3, QueueModel.getIndex()); } /** * Test method for. * * @throws Exception the exception * {@link org.jajuk.services.players.QueueModel#computesPlanned(boolean)}. */ public void testComputesPlanned() throws Exception { // without tracks it will not do much QueueModel.computesPlanned(false); // with tracks, it will look at planned items addItems(10); QueueModel.computesPlanned(true); } /** * Test computes planned clear. * DOCUMENT_ME * * @throws Exception the exception */ public void testComputesPlannedClear() throws Exception { Conf.setProperty(Const.CONF_STATE_CONTINUE, "true"); // without tracks it will not do much, but it will hit the "clearPlanned" QueueModel.computesPlanned(true); } /** * Test computes planned shuffle. * DOCUMENT_ME * * @throws Exception the exception */ public void testComputesPlannedShuffle() throws Exception { // set Property to hit the "Shuffle" branch Conf.setProperty(Const.CONF_STATE_SHUFFLE, "true"); // with tracks, it will look at planned items addItems(10); QueueModel.computesPlanned(true); } /** * Test method for {@link org.jajuk.services.players.QueueModel#clear()}. * * @throws Exception the exception */ public void testClear() throws Exception { // nothing to reset up-front QueueModel.clear(); assertEquals(0, QueueModel.getQueueSize()); // things are reset with queued items addItems(10); QueueModel.goTo(4); QueueModel.clear(); assertEquals(0, QueueModel.getQueueSize()); assertEquals(-1, QueueModel.getIndex()); } /** * Test method for. * * @throws Exception the exception * {@link org.jajuk.services.players.QueueModel#containsOnlyRepeat()}. */ public void testContainsOnlyRepeat() throws Exception { assertTrue(QueueModel.containsOnlyRepeat()); addItems(10); assertFalse(QueueModel.containsOnlyRepeat()); QueueModel.setRepeatModeToAll(true); assertTrue(QueueModel.containsOnlyRepeat()); } /** * Test method for. * * @throws Exception the exception * {@link org.jajuk.services.players.QueueModel#playPrevious()}. */ public void testPlayPrevious() throws Exception { // do nothing without items QueueModel.playPrevious(); // with items: addItems(10); QueueModel.goTo(2); QueueModel.playPrevious(); assertEquals(1, QueueModel.getIndex()); } /** * Test play previous at zero. * DOCUMENT_ME * * @throws Exception the exception */ public void testPlayPreviousAtZero() throws Exception { // do nothing without items QueueModel.playPrevious(); // with items: addItems(10); QueueModel.goTo(0); QueueModel.playPrevious(); assertEquals(0, QueueModel.getIndex()); } /** * Test play previous at zero with repeat. * DOCUMENT_ME * * @throws Exception the exception */ public void testPlayPreviousAtZeroWithRepeat() throws Exception { // do nothing without items QueueModel.playPrevious(); // with items: addItems(10); QueueModel.goTo(0); QueueModel.getItem(0).setRepeat(true); QueueModel.playPrevious(); assertEquals(0, QueueModel.getIndex()); } /** * Test method for. * * {@link org.jajuk.services.players.QueueModel#playPreviousAlbum()}. */ public void testPlayPreviousAlbum() { QueueModel.playPreviousAlbum(); } /** * Test method for {@link org.jajuk.services.players.QueueModel#playNext()}. * * @throws Exception the exception */ public void testPlayNext() throws Exception { // do nothing without items QueueModel.playNext(); // with items: addItems(10); QueueModel.goTo(2); QueueModel.playNext(); assertEquals(3, QueueModel.getIndex()); } /** * Test method for. * * {@link org.jajuk.services.players.QueueModel#playNextAlbum()}. */ public void testPlayNextAlbum() { QueueModel.playNextAlbum(); } /** * Test method for. * * @throws Exception the exception * {@link org.jajuk.services.players.QueueModel#getPlayingFile()}. */ public void testGetPlayingFile() throws Exception { assertNull(QueueModel.getPlayingFile()); addItems(10); // QueueModel.playNext(); QueueModel.goTo(0); assertFalse(QueueModel.isStopped()); assertNotNull(QueueModel.getPlayingFile()); // we start at 0 assertEquals("file0", QueueModel.getPlayingFile().getName()); } /** * Test get playing file title. * DOCUMENT_ME * * @throws Exception the exception */ public void testGetPlayingFileTitle() throws Exception { assertNull(QueueModel.getPlayingFileTitle()); addItems(10); // QueueModel.playNext(); QueueModel.goTo(0); assertFalse(QueueModel.isStopped()); assertNotNull(QueueModel.getPlayingFileTitle()); // we start at 0 assertTrue(QueueModel.getPlayingFileTitle(), QueueModel.getPlayingFileTitle().contains("file")); } /** * Test method for. * * @throws Exception the exception * {@link org.jajuk.services.players.QueueModel#getCurrentItem()}. */ public void testGetCurrentItem() throws Exception { // no item without items assertNull(QueueModel.getCurrentItem()); addItems(10); QueueModel.goTo(2); assertEquals("file2", QueueModel.getCurrentItem().getFile().getName()); } /** * Test method for {@link org.jajuk.services.players.QueueModel#getItem(int)}. * * @throws Exception the exception */ public void testGetItem() throws Exception { addItems(10); assertEquals("file0", QueueModel.getItem(0).getFile().getName()); } /** * Test method for. * * @throws Exception the exception * {@link org.jajuk.services.players.QueueModel#canUnmount(org.jajuk.base.Device)} * . */ public void testCanUnmount() throws Exception { Device device = JUnitHelpers.getDevice("anydevice", 0, "/foo"); assertTrue(QueueModel.canUnmount(device)); addItems(10); // still true as we are not playing assertTrue(QueueModel.canUnmount(device)); // try to start playing/planning QueueModel.playNext(); assertFalse(QueueModel.canUnmount(QueueModel.getItem(1).getFile().getDevice())); assertTrue(QueueModel.canUnmount(device)); } /** * Test method for {@link org.jajuk.services.players.QueueModel#stopRequest()} * . */ public void testStopRequest() { QueueModel.stopRequest(); } /** * Test method for {@link org.jajuk.services.players.QueueModel#isStopped()}. * * @throws Exception the exception */ public void testIsStopped() throws Exception { assertTrue(QueueModel.isStopped()); addItems(10); // try to start playing/planning QueueModel.playNext(); assertFalse(QueueModel.isStopped()); QueueModel.stopRequest(); assertTrue(QueueModel.isStopped()); } /** * Test method for {@link org.jajuk.services.players.QueueModel#getQueue()}. * * @throws Exception the exception */ public void testGetQueue() throws Exception { assertEquals(0, QueueModel.getQueue().size()); addItems(10); assertEquals(10, QueueModel.getQueue().size()); } /** * Test method for. * * @throws Exception the exception * {@link org.jajuk.services.players.QueueModel#getQueueSize()}. */ public void testGetQueueSize() throws Exception { assertEquals(0, QueueModel.getQueueSize()); addItems(10); assertEquals(10, QueueModel.getQueueSize()); } /** * Test method for {@link org.jajuk.services.players.QueueModel#shuffle()}. * * @throws Exception the exception */ public void testShuffle() throws Exception { // shuffle should not fail if queue is empty QueueModel.shuffle(); addItems(10); // verify that we have them in order before assertEquals("file0", QueueModel.getItem(0).getFile().getName()); assertEquals("file5", QueueModel.getItem(5).getFile().getName()); assertEquals("file9", QueueModel.getItem(9).getFile().getName()); QueueModel.shuffle(); assertFalse("Queue: " + QueueModel.getQueue(), QueueModel.getItem(0).getFile().getName() .equals("file0") && QueueModel.getItem(5).getFile().getName().equals("file5") && QueueModel.getItem(9).getFile().getName().equals("file9")); } /** * Test method for. * * @throws Exception the exception * {@link org.jajuk.services.players.QueueModel#insert(org.jajuk.services.players.StackItem, int)} * . */ public void testInsertStackItemInt() throws Exception { assertEquals(0, QueueModel.getQueueSize()); QueueModel.insert(new StackItem(JUnitHelpers.getFile("file0", true)), 0); assertEquals(1, QueueModel.getQueueSize()); // when we insert the next one at 0, the previous one should be moved QueueModel.insert(new StackItem(JUnitHelpers.getFile("file1", true)), 0); assertEquals(2, QueueModel.getQueueSize()); assertEquals("file1", QueueModel.getItem(0).getFile().getName()); assertEquals("file0", QueueModel.getItem(1).getFile().getName()); // adding in between now, should again adjust the queue accordingly QueueModel.insert(new StackItem(JUnitHelpers.getFile("file2", true)), 1); assertEquals(3, QueueModel.getQueueSize()); assertEquals("file1", QueueModel.getItem(0).getFile().getName()); assertEquals("file2", QueueModel.getItem(1).getFile().getName()); assertEquals("file0", QueueModel.getItem(2).getFile().getName()); // and adding at the end should work as well QueueModel.insert(new StackItem(JUnitHelpers.getFile("file3", true)), 3); assertEquals(4, QueueModel.getQueueSize()); assertEquals("file1", QueueModel.getItem(0).getFile().getName()); assertEquals("file2", QueueModel.getItem(1).getFile().getName()); assertEquals("file0", QueueModel.getItem(2).getFile().getName()); assertEquals("file3", QueueModel.getItem(3).getFile().getName()); } /** * Test method for. * * @throws Exception the exception * {@link org.jajuk.services.players.QueueModel#insert(java.util.List, int)}. */ public void testInsertListOfStackItemInt() throws Exception { assertEquals(0, QueueModel.getQueueSize()); // tested with addItems addItems(256); assertEquals(256, QueueModel.getQueueSize()); } /** * Test method for {@link org.jajuk.services.players.QueueModel#up(int)}. * * @throws Exception the exception */ public void testUp() throws Exception { // first one cannot be put up, returns immediately QueueModel.up(0); addItems(3); // check queue assertEquals(3, QueueModel.getQueueSize()); assertEquals("file0", QueueModel.getItem(0).getFile().getName()); assertEquals("file1", QueueModel.getItem(1).getFile().getName()); assertEquals("file2", QueueModel.getItem(2).getFile().getName()); // now up one QueueModel.up(2); // check queue after move assertEquals(3, QueueModel.getQueueSize()); assertEquals("file0", QueueModel.getItem(0).getFile().getName()); assertEquals("file2", QueueModel.getItem(1).getFile().getName()); assertEquals("file1", QueueModel.getItem(2).getFile().getName()); // up once more QueueModel.up(1); // check queue assertEquals(3, QueueModel.getQueueSize()); assertEquals("file2", QueueModel.getItem(0).getFile().getName()); assertEquals("file0", QueueModel.getItem(1).getFile().getName()); assertEquals("file1", QueueModel.getItem(2).getFile().getName()); } /** * Test method for {@link org.jajuk.services.players.QueueModel#down(int)}. * * @throws Exception the exception */ public void testDown() throws Exception { // first one cannot be put up, returns immediately QueueModel.down(0); addItems(3); // check queue assertEquals(3, QueueModel.getQueueSize()); assertEquals("file0", QueueModel.getItem(0).getFile().getName()); assertEquals("file1", QueueModel.getItem(1).getFile().getName()); assertEquals("file2", QueueModel.getItem(2).getFile().getName()); // now up one QueueModel.down(0); // check queue after move assertEquals(3, QueueModel.getQueueSize()); assertEquals(QueueModel.getQueue().toString(), "file1", QueueModel.getItem(0).getFile() .getName()); assertEquals(QueueModel.getQueue().toString(), "file0", QueueModel.getItem(1).getFile() .getName()); assertEquals(QueueModel.getQueue().toString(), "file2", QueueModel.getItem(2).getFile() .getName()); // up once more QueueModel.down(1); // check queue assertEquals(3, QueueModel.getQueueSize()); assertEquals("file1", QueueModel.getItem(0).getFile().getName()); assertEquals("file2", QueueModel.getItem(1).getFile().getName()); assertEquals("file0", QueueModel.getItem(2).getFile().getName()); } /** * Test method for {@link org.jajuk.services.players.QueueModel#goTo(int)}. * * @throws Exception the exception */ public void testGoTo() throws Exception { QueueModel.goTo(0); addItems(5); QueueModel.goTo(2); QueueModel.goTo(4); assertEquals("file4", QueueModel.getCurrentItem().getFile().getName()); } /** * Test go to repeat. * DOCUMENT_ME * * @throws Exception the exception */ public void testGoToRepeat() throws Exception { addItems(5); QueueModel.goTo(2); { // first choose one that is not set to repeat // now set some repeat QueueModel.getItem(2).setRepeat(true); QueueModel.goTo(4); assertEquals("file4", QueueModel.getCurrentItem().getFile().getName()); } { // and then try to go to a repeated one // now set some repeat QueueModel.getItem(2).setRepeat(true); QueueModel.goTo(2); assertEquals("file2", QueueModel.getCurrentItem().getFile().getName()); // item 2 is now still repeated assertTrue(QueueModel.getItem(2).isRepeat()); } } /** * Test method for. * * @throws Exception the exception * {@link org.jajuk.services.players.QueueModel#remove(int, int)}. */ public void testRemove() throws Exception { QueueModel.remove(0, 0); addItems(10); QueueModel.remove(1, 3); assertEquals(QueueModel.getQueue().toString(), 7, QueueModel.getQueueSize()); } /** * Test method for {@link org.jajuk.services.players.QueueModel#getLast()}. * * @throws Exception the exception */ public void testGetLast() throws Exception { assertNull(QueueModel.getLast()); addItems(10); assertEquals("file9", QueueModel.getLast().getFile().getName()); } /** * Test method for. * * @throws Exception the exception * {@link org.jajuk.services.players.QueueModel#getLastPlayed()}. */ public void testGetLastPlayed() throws Exception { assertNull(QueueModel.getLastPlayed()); addItems(10); QueueModel.playNext(); // maybe we have one now assertNotNull(QueueModel.getLastPlayed()); } /** * Test method for {@link org.jajuk.services.players.QueueModel#getIndex()}. */ public void testGetIndex() { // tested by tests above } /** * Test method for. * * @throws Exception the exception * {@link org.jajuk.services.players.QueueModel#getCountTracksLeft()}. */ public void testGetCountTracksLeft() throws Exception { assertEquals(0, QueueModel.getCountTracksLeft()); addItems(10); assertEquals(10, QueueModel.getCountTracksLeft()); QueueModel.goTo(0); QueueModel.playNext(); QueueModel.playNext(); assertEquals(8, QueueModel.getCountTracksLeft()); } /** * Test method for {@link org.jajuk.services.players.QueueModel#getPlanned()}. * * @throws Exception the exception */ public void testGetPlanned() throws Exception { StartupCollectionService.registerItemManagers(); assertEquals(0, QueueModel.getPlanned().size()); QueueModel.computesPlanned(false); // no tracks are planned when queue is empty assertEquals(0, QueueModel.getPlanned().size()); // now add some items addItems(5); // still no items because default configration states to not continue play QueueModel.computesPlanned(false); assertEquals(0, QueueModel.getPlanned().size()); // we also need to enable continuous play for tracks to be planned Conf.setProperty(Const.CONF_STATE_CONTINUE, "true"); QueueModel.computesPlanned(false); assertTrue(QueueModel.getPlanned().size() > 0); } /** * Test method for {@link org.jajuk.services.players.QueueModel#commit()}. * * @throws Exception the exception */ public void testCommit() throws Exception { JUnitHelpers.createSessionDirectory(); final java.io.File fifo = SessionService.getConfFileByPath(Const.FILE_FIFO); fifo.delete(); assertFalse(fifo.exists()); // we should not have the file now... addItems(10); QueueModel.commit(); // now the file should exist and have some size assertTrue(fifo.exists()); assertNotNull(FileUtils.readFileToString(fifo).length() > 0); } /** * Test method for. * * {@link org.jajuk.services.players.QueueModel#isPlayingRadio()}. */ public void testIsPlayingRadio() { assertFalse(QueueModel.isPlayingRadio()); } /** * Test method for. * * {@link org.jajuk.services.players.QueueModel#getCurrentRadio()}. */ public void testGetCurrentRadio() { // make sure we reset WebRadio QueueModel.launchRadio(null); assertNull(QueueModel.getCurrentRadio()); QueueModel.launchRadio(new WebRadio("name", "invalidurl")); assertNotNull(QueueModel.getCurrentRadio()); } /** * Test method for. * * @throws Exception the exception * {@link org.jajuk.services.players.QueueModel#isPlayingTrack()}. */ public void testIsPlayingTrack() throws Exception { assertTrue(QueueModel.isStopped()); assertFalse(QueueModel.isPlayingTrack()); addItems(3); QueueModel.playNext(); assertTrue(QueueModel.isPlayingTrack()); } /** * Test method for. * * @throws Exception the exception * {@link org.jajuk.services.players.QueueModel#getCurrentFileTitle()}. */ public void testGetCurrentFileTitle() throws Exception { // always returns some string, without file "Read to play" // can be wrong with different settings assertEquals("Ready to play", // QueueModel.getCurrentFileTitle()); assertNotNull(QueueModel.getCurrentFileTitle()); addItems(3); QueueModel.playNext(); assertNotNull(QueueModel.getCurrentFileTitle()); // should not be the same as before assertFalse(QueueModel.getCurrentFileTitle().equals("Ready to play")); } /** * Test method for {@link org.jajuk.services.players.QueueModel#clean()}. * * @throws Exception the exception */ public void testClean() throws Exception { // should work without any items QueueModel.clean(); addItems(10); assertEquals(10, QueueModel.getQueueSize()); // here clean will not remove things as they are correctly listed in the FileManager QueueModel.clean(); assertEquals(10, QueueModel.getQueueSize()); // we can add a dummy-file and check that it is removed Genre genre = JUnitHelpers.getGenre(); Album album = JUnitHelpers.getAlbum("name", 23); album.setProperty(Const.XML_ALBUM_DISCOVERED_COVER, Const.COVER_NONE); // don't read covers for // this test Artist artist = JUnitHelpers.getArtist("name"); Year year = JUnitHelpers.getYear(2000); Type type = JUnitHelpers.getType(); Track track = TrackManager.getInstance().registerTrack("name", album, genre, artist, 120, year, 1, type, 1); Device device = JUnitHelpers.getDevice(); Directory dir = DirectoryManager.getInstance().registerDirectory(device); File file = FileManager.getInstance().registerFile("test.tst", dir, track, 120, 70); QueueModel.insert(new StackItem(file), 0); // now we have 11 elements assertEquals(11, QueueModel.getQueueSize()); FileManager.getInstance().removeFile(file); // here clean will remove one item that is not listed in the FileManager QueueModel.clean(); // should be 10 again now assertEquals(10, QueueModel.getQueueSize()); } } jajuk-1.9.6.orig/src/test/java/org/jajuk/services/players/DummyMPlayerImpl.java0000644000175000017500000000316511720500104027417 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.services.players; /** * DOCUMENT_ME. */ public class DummyMPlayerImpl { /** The Constant POSITION. DOCUMENT_ME */ public final static float POSITION = 17.7f; /** The Constant LENGTH. DOCUMENT_ME */ public final static float LENGTH = 235.28f; /** * The main method. * * @param args the arguments * @throws InterruptedException the interrupted exception */ public static void main(final String[] args) throws InterruptedException { System.out.println("TestMPlayerPlayerImpl was called!"); // simulate normal reply by MPlayer to commands that are sent in System.out.println("ANS_LENGTH=" + new Float(LENGTH).toString()); System.out.println("ANS_TIME_POSITION=" + new Float(POSITION).toString()); Thread.sleep(5000); System.out.println("Exiting... (Quit)"); } } jajuk-1.9.6.orig/src/test/java/org/jajuk/services/notification/0000755000175000017500000000000011720500104024347 5ustar drazzibdrazzibjajuk-1.9.6.orig/src/test/java/org/jajuk/services/notification/TestNotifySendBalloonNotificator.java0000644000175000017500000000603411720500104033650 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.services.notification; import org.jajuk.JajukTestCase; import org.jajuk.TestHelpers; import org.jajuk.base.File; import org.jajuk.services.webradio.WebRadio; /** * DOCUMENT_ME. */ public class TestNotifySendBalloonNotificator extends JajukTestCase { /** * Test method for. * * {@link org.jajuk.services.notification.NotifySendBalloonNotificator#isAvailable()} * . */ public void testIsAvailable() { // should be constructed correctly, however we cannot guarantee if // "isAvailable" will return true or false, it depends // on the "notify-send" to be available, which we cannot guarantee on all // machines running the tests NotifySendBalloonNotificator not = NotifySendBalloonNotificator.getInstance(); // just call it to cover it, we cannot test if it is true or false not.isAvailable(); } /** * Test method for. * * {@link org.jajuk.services.notification.NotifySendBalloonNotificator#notif(org.jajuk.base.File)} * . */ public void testNotifyFile() { // should be constructed correctly, however we cannot guarantee if // "isAvailable" will return true or false, it depends // on the "notify-send" to be available, which we cannot guarantee on all // machines running the tests NotifySendBalloonNotificator notificator = NotifySendBalloonNotificator.getInstance(); // only test this if it is available if (notificator.isAvailable()) { File file = TestHelpers.getMockFile(); notificator.notify(file); } } /** * Test method for. * * {@link org.jajuk.services.notification.JavaBalloonNotificator#notify(org.jajuk.services.webradio.WebRadio)} * . */ public void testNotifyWebradio() { // should be constructed correctly, however we cannot guarantee if // "isAvailable" will return true or false, it depends // on the "notify-send" to be available, which we cannot guarantee on all // machines running the tests NotifySendBalloonNotificator notificator = NotifySendBalloonNotificator.getInstance(); // only test this if it is available if (notificator.isAvailable()) { WebRadio webradio = new WebRadio("a web radio", "http://www.test.org/webradio"); notificator.notify(webradio); } } } jajuk-1.9.6.orig/src/test/java/org/jajuk/services/notification/TestJavaBalloonNotificator.java0000644000175000017500000000661411720500104032453 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.services.notification; import java.awt.HeadlessException; import java.awt.TrayIcon; import org.jajuk.JajukTestCase; import org.jajuk.TestHelpers; import org.jajuk.base.File; import org.jajuk.services.webradio.WebRadio; import org.jajuk.ui.windows.JajukSystray; /** * DOCUMENT_ME. */ public class TestJavaBalloonNotificator extends JajukTestCase { /** * Test method for. * * {@link org.jajuk.services.notification.JavaBalloonNotificator#JavaBalloonNotificator(java.awt.TrayIcon)} * . */ public void testJavaBalloonNotificator() { // should initialize with null correctly., but return false for // "isAvailable" JavaBalloonNotificator notificator = JavaBalloonNotificator.getInstance(); assertFalse(notificator.isAvailable()); try { // should initialize correctly and return true for valid TrayIcon TrayIcon tray = JajukSystray.getInstance().getTrayIcon(); if (tray != null) { notificator = JavaBalloonNotificator.getInstance(); assertTrue(notificator.isAvailable()); } } catch (ExceptionInInitializerError e) { // expected when run without UI support } catch (NoClassDefFoundError e) { // expected when run without UI support } } /** * Test method for. * * {@link org.jajuk.services.notification.JavaBalloonNotificator#isAvailable()} * . */ public void testIsAvailable() { // tested above } /** * Test method for. * * {@link org.jajuk.services.notification.JavaBalloonNotificator#notify(org.jajuk.base.File)} * . */ public void testNotifyFile() { try { JavaBalloonNotificator notificator = JavaBalloonNotificator.getInstance(); if (notificator.isAvailable()) { File file = TestHelpers.getMockFile(); notificator.notify(file); } } catch (NoClassDefFoundError e) { // expected when run without UI support } catch (HeadlessException e) { // expected when run without UI support } } /** * Test method for. * * {@link org.jajuk.services.notification.JavaBalloonNotificator#notify(org.jajuk.services.webradio.WebRadio)} * . */ public void testNotifyWebradio() { try { JavaBalloonNotificator notificator = JavaBalloonNotificator.getInstance(); if (notificator.isAvailable()) { WebRadio webradio = new WebRadio("a web radio", "http://www.test.org/webradio"); notificator.notify(webradio); } } catch (NoClassDefFoundError e) { // expected when run without UI support } catch (HeadlessException e) { // expected when run without UI support } } } jajuk-1.9.6.orig/src/test/java/org/jajuk/services/notification/TestToastNotificator.java0000644000175000017500000000563011720500104031352 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.services.notification; import java.awt.HeadlessException; import org.jajuk.JajukTestCase; import org.jajuk.TestHelpers; import org.jajuk.base.File; import org.jajuk.services.startup.StartupCollectionService; import org.jajuk.services.webradio.WebRadio; /** * DOCUMENT_ME. */ public class TestToastNotificator extends JajukTestCase { /** * Test method for. * * {@link org.jajuk.services.notification.ToastNotificator#ToastNotificator()} * . */ public void testToastNotificator() { try { INotificator notificator = ToastNotificator.getInstance(); assertTrue(notificator.isAvailable()); } catch (ExceptionInInitializerError e) { // expected when run without UI support } catch (NoClassDefFoundError e) { // expected when run without UI support } } /** * Test method for. * * {@link org.jajuk.services.notification.JavaBalloonNotificator#isAvailable()} * . */ public void testIsAvailable() { // tested above } /** * Test method for. * * {@link org.jajuk.services.notification.JavaBalloonNotificator#notify(org.jajuk.base.File)} * . */ public void testNotifyFile() { try { StartupCollectionService.registerItemManagers(); ToastNotificator notificator = ToastNotificator.getInstance(); File file = TestHelpers.getMockFile(); notificator.notify(file); } catch (NoClassDefFoundError e) { // expected when run without UI support } catch (HeadlessException e) { // expected when run without UI support } } /** * Test method for. * * {@link org.jajuk.services.notification.JavaBalloonNotificator#notify(org.jajuk.services.webradio.WebRadio)} * . */ public void testNotifyWebradio() { try { ToastNotificator notificator = ToastNotificator.getInstance(); WebRadio webradio = new WebRadio("a web radio", "http://www.test.org/webradio"); notificator.notify(webradio); } catch (NoClassDefFoundError e) { // expected when run without UI support } catch (HeadlessException e) { // expected when run without UI support } } } jajuk-1.9.6.orig/src/test/java/org/jajuk/services/notification/TestNotificatorFactory.java0000644000175000017500000000526411720500104031672 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.services.notification; import org.jajuk.JajukTestCase; import org.jajuk.util.Conf; import org.jajuk.util.Const; /** * DOCUMENT_ME. */ public class TestNotificatorFactory extends JajukTestCase { /** * Test method for. * * {@link org.jajuk.services.notification.NotificatorFactory#getNotificator()} * . */ public void testNoneNotificator() { // enable Tooltip/Notification Conf.setProperty(Const.CONF_UI_NOTIFICATOR_TYPE, NotificatorTypes.NONE.name()); // now try to get a balloon notificator, but we cannot be sure if this works // on all // machines so we on't assume not null. NotificatorFactory.getNotificator(); } /** * Test method for. * * {@link org.jajuk.services.notification.NotificatorFactory#getNotificator()} * . */ public void testBalloonNotificator() { // enable Tooltip/Notification Conf.setProperty(Const.CONF_UI_NOTIFICATOR_TYPE, NotificatorTypes.BALLOON.name()); // now try to get a balloon notificator, but we cannot be sure if this works // on all // machines so we on't assume not null. NotificatorFactory.getNotificator(); } /** * Test method for. * * {@link org.jajuk.services.notification.NotificatorFactory#getNotificator()} * . */ public void testToastNotificator() { // enable Tooltip/Notification Conf.setProperty(Const.CONF_UI_NOTIFICATOR_TYPE, NotificatorTypes.TOAST.name()); // This swing-implemented notificator should always be available assertNotNull(NotificatorFactory.getNotificator()); } /** * Test get system notificator false. * DOCUMENT_ME */ public void testGetSystemNotificatorFalse() { // disable Tooltip/Notification Conf.setProperty(Const.CONF_UI_NOTIFICATOR_TYPE, NotificatorTypes.NONE.name()); // here we need to get null back as it is disabled assertNull(NotificatorFactory.getNotificator()); } } jajuk-1.9.6.orig/src/test/java/org/jajuk/services/dbus/0000755000175000017500000000000011720500104022616 5ustar drazzibdrazzibjajuk-1.9.6.orig/src/test/java/org/jajuk/services/dbus/TestDBusManager.java0000644000175000017500000000352311720500104026454 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.services.dbus; import org.jajuk.JajukTestCase; /** * DOCUMENT_ME. */ public class TestDBusManager extends JajukTestCase { /** * Test method for {@link org.jajuk.services.dbus.DBusManager#connect()}. */ public final void testGetInstance() { // DBus requires the environment variable DBUS_SESSION_BUS_ADDRESS // but this is typically only set on machines that support D-Bus // cannot check this for null as it won't work in some installations try { DBusManager.connect(); } catch (Exception e) { e.printStackTrace(); } } /** * Test method for {@link org.jajuk.services.dbus.DBusManager#disconnect()}. */ public final void testDisconnect() { // first run it without connecting in getInstance() DBusManager.disconnect(); // then run getInstance() which tries to connect try { DBusManager.connect(); } catch (Exception e) { e.printStackTrace(); } // now again, although getInstance() might not have worked... DBusManager.disconnect(); } } jajuk-1.9.6.orig/src/test/java/org/jajuk/services/dbus/TestDBusSupportImpl.java0000644000175000017500000002015211720500104027375 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.services.dbus; import java.util.Properties; import java.util.Set; import org.jajuk.JajukTestCase; import org.jajuk.events.JajukEvent; import org.jajuk.events.JajukEvents; import org.jajuk.ui.actions.ActionManager; import org.jajuk.util.Const; /** * DOCUMENT_ME. */ public class TestDBusSupportImpl extends JajukTestCase { /* (non-Javadoc) * @see org.jajuk.JajukTestCase#setUp() */ @Override protected void setUp() throws Exception { // make sure this is initialized with Actions ActionManager.getInstance(); super.setUp(); } /** * Test method for {@link org.jajuk.services.dbus.DBusSupportImpl#connect()}. */ public final void testConnect() { DBusSupportImpl impl = new DBusSupportImpl(); // will fail where dbus is not available and report an error to the log... impl.connect(); } /** * Test method for. * * {@link org.jajuk.services.dbus.DBusSupportImpl#disconnect()}. */ public final void testDisconnect() { DBusSupportImpl impl = new DBusSupportImpl(); // should not fail when not connected impl.disconnect(); // try to connect first impl.connect(); // then disconnect impl.disconnect(); } /** * Test method for {@link org.jajuk.services.dbus.DBusSupportImpl#forward()}. * * @throws Exception the exception */ public final void testForward() throws Exception { DBusSupportImpl impl = new DBusSupportImpl(); impl.forward(); } /** * Test method for {@link org.jajuk.services.dbus.DBusSupportImpl#next()}. * * @throws Exception the exception */ public final void testNext() throws Exception { DBusSupportImpl impl = new DBusSupportImpl(); impl.next(); } /** * Test method for {@link org.jajuk.services.dbus.DBusSupportImpl#playPause()} * . * * @throws Exception the exception */ public final void testPlayPause() throws Exception { DBusSupportImpl impl = new DBusSupportImpl(); impl.playPause(); } /** * Test method for {@link org.jajuk.services.dbus.DBusSupportImpl#previous()}. * * @throws Exception the exception */ public final void testPrevious() throws Exception { DBusSupportImpl impl = new DBusSupportImpl(); impl.previous(); } /** * Test method for {@link org.jajuk.services.dbus.DBusSupportImpl#rewind()}. * * @throws Exception the exception */ public final void testRewind() throws Exception { DBusSupportImpl impl = new DBusSupportImpl(); impl.rewind(); } /** * Test method for {@link org.jajuk.services.dbus.DBusSupportImpl#stop()}. * * @throws Exception the exception */ public final void testStop() throws Exception { DBusSupportImpl impl = new DBusSupportImpl(); impl.stop(); } /** * Test method for. * * @throws Exception the exception * {@link org.jajuk.services.dbus.DBusSupportImpl#decreaseVolume()}. */ public final void testDecreaseVolume() throws Exception { DBusSupportImpl impl = new DBusSupportImpl(); impl.decreaseVolume(); } /** * Test method for {@link org.jajuk.services.dbus.DBusSupportImpl#exit()}. */ public final void testExit() { // cannot test this as it stops the process: // DBusSupportImpl impl = new DBusSupportImpl(); // impl.exit(); } /** * Test method for. * * @throws Exception the exception * {@link org.jajuk.services.dbus.DBusSupportImpl#increaseVolume()}. */ public final void testIncreaseVolume() throws Exception { DBusSupportImpl impl = new DBusSupportImpl(); impl.increaseVolume(); } /** * Test method for {@link org.jajuk.services.dbus.DBusSupportImpl#nextAlbum()} * . * * @throws Exception the exception */ public final void testNextAlbum() throws Exception { DBusSupportImpl impl = new DBusSupportImpl(); impl.nextAlbum(); } /** * Test method for. * * @throws Exception the exception * {@link org.jajuk.services.dbus.DBusSupportImpl#previousAlbum()}. */ public final void testPreviousAlbum() throws Exception { DBusSupportImpl impl = new DBusSupportImpl(); impl.previousAlbum(); } /** * Test method for. * * @throws Exception the exception * {@link org.jajuk.services.dbus.DBusSupportImpl#shuffleGlobal()}. */ public final void testShuffleGlobal() throws Exception { DBusSupportImpl impl = new DBusSupportImpl(); impl.shuffleGlobal(); } /** * Test method for {@link org.jajuk.services.dbus.DBusSupportImpl#mute()}. * * @throws Exception the exception */ public final void testMute() throws Exception { DBusSupportImpl impl = new DBusSupportImpl(); impl.mute(); } /** * Test method for. * * @throws Exception the exception * {@link org.jajuk.services.dbus.DBusSupportImpl#currentHTML()}. */ public final void testCurrentHTML() throws Exception { DBusSupportImpl impl = new DBusSupportImpl(); assertNotNull(impl.currentHTML()); } /** * Test method for {@link org.jajuk.services.dbus.DBusSupportImpl#current()}. * * @throws Exception the exception */ public final void testCurrent() throws Exception { DBusSupportImpl impl = new DBusSupportImpl(); assertNotNull(impl.current()); } /** * Test method for. * * @throws Exception the exception * {@link org.jajuk.services.dbus.DBusSupportImpl#banCurrent()}. */ public final void testBanCurrent() throws Exception { DBusSupportImpl impl = new DBusSupportImpl(); impl.banCurrent(); } /** * Test method for {@link org.jajuk.services.dbus.DBusSupportImpl#isRemote()}. */ public final void testIsRemote() { DBusSupportImpl impl = new DBusSupportImpl(); assertFalse(impl.isRemote()); } /** * Test method for. * * {@link org.jajuk.services.dbus.DBusSupportImpl#getRegistrationKeys()}. */ public final void testGetRegistrationKeys() { DBusSupportImpl impl = new DBusSupportImpl(); Set events = impl.getRegistrationKeys(); assertTrue(events.contains(JajukEvents.FILE_LAUNCHED)); } /** * Test method for. * * {@link org.jajuk.services.dbus.DBusSupportImpl#update(org.jajuk.events.JajukEvent)} * . */ public final void testUpdate() { Properties prop = new Properties(); prop.setProperty(Const.DETAIL_CURRENT_FILE_ID, "testfile"); DBusSupportImpl impl = new DBusSupportImpl(); impl.update(new JajukEvent(JajukEvents.FILE_LAUNCHED, null)); } /** * Test update connect. * DOCUMENT_ME */ public final void testUpdateConnect() { Properties prop = new Properties(); prop.setProperty(Const.DETAIL_CURRENT_FILE_ID, "testfile"); DBusSupportImpl impl = new DBusSupportImpl(); // will fail where dbus is not available and report an error to the log... impl.connect(); impl.update(new JajukEvent(JajukEvents.FILE_LAUNCHED, null)); } /** * Test show currently playing. * DOCUMENT_ME * * @throws Exception the exception */ public final void testShowCurrentlyPlaying() throws Exception { DBusSupportImpl impl = new DBusSupportImpl(); impl.showCurrentlyPlaying(); } /** * Test bookmark currently playing. * DOCUMENT_ME * * @throws Exception the exception */ public final void testBookmarkCurrentlyPlaying() throws Exception { DBusSupportImpl impl = new DBusSupportImpl(); impl.bookmarkCurrentlyPlaying(); } } jajuk-1.9.6.orig/src/test/java/org/jajuk/services/dbus/TestDBusSignalImpl.java0000644000175000017500000000274211720500104027143 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.services.dbus; import org.jajuk.JajukTestCase; /** * DOCUMENT_ME. */ public class TestDBusSignalImpl extends JajukTestCase { /** * Test method for {@link org.jajuk.services.dbus.DBusSignalImpl#isRemote()}. */ public final void testIsRemote() { // currently false assertFalse(new DBusSignalImpl().isRemote()); } /** * Test file changed signal. * DOCUMENT_ME * * @throws Exception the exception */ public final void testFileChangedSignal() throws Exception { DBusSignalImpl.FileChangedSignal signal = new DBusSignalImpl.FileChangedSignal("testfile", "/path/test"); assertEquals("testfile", signal.getFilename()); } } jajuk-1.9.6.orig/src/test/java/org/jajuk/services/lastfm/0000755000175000017500000000000011720500104023147 5ustar drazzibdrazzibjajuk-1.9.6.orig/src/test/java/org/jajuk/services/lastfm/TestLastFmManager.java0000644000175000017500000000416511720500104027341 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.services.lastfm; import java.util.Set; import org.jajuk.JUnitHelpers; import org.jajuk.JajukTestCase; import org.jajuk.events.JajukEvent; import org.jajuk.events.JajukEvents; import org.jajuk.util.Conf; import org.jajuk.util.Const; /** * DOCUMENT_ME. */ public class TestLastFmManager extends JajukTestCase { /** * Test method for. * * {@link org.jajuk.services.lastfm.LastFmManager#getInstance()}. */ public void testGetInstance() { assertNotNull(LastFmManager.getInstance()); } /** * Test method for. * * {@link org.jajuk.services.lastfm.LastFmManager#getRegistrationKeys()}. */ public void testGetRegistrationKeys() { Set keys = LastFmManager.getInstance().getRegistrationKeys(); assertTrue(keys.contains(JajukEvents.FILE_FINISHED)); } /** * Test method for. * * @throws Exception the exception * {@link org.jajuk.services.lastfm.LastFmManager#update(org.jajuk.events.JajukEvent)} * . */ public void testUpdate() throws Exception { // nothing happens if { Conf.setProperty(Const.CONF_LASTFM_AUDIOSCROBBLER_ENABLE, "false"); LastFmManager.getInstance().update(new JajukEvent(JajukEvents.FILE_FINISHED, null)); // wait for thread to finish JUnitHelpers.waitForThreadToFinish("LastFM Update Thread"); } } } jajuk-1.9.6.orig/src/test/java/org/jajuk/services/startup/0000755000175000017500000000000011720500104023363 5ustar drazzibdrazzibjajuk-1.9.6.orig/src/test/java/org/jajuk/services/startup/TestStartupEngineService.java0000644000175000017500000003070311720500104031202 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.services.startup; import java.io.BufferedWriter; import java.io.FileWriter; import java.lang.reflect.Field; import java.util.ArrayList; import org.jajuk.JUnitHelpers; import org.jajuk.JajukTestCase; import org.jajuk.base.File; import org.jajuk.base.SearchResult.SearchResultType; import org.jajuk.services.bookmark.History; import org.jajuk.services.core.SessionService; import org.jajuk.services.players.QueueModel; import org.jajuk.services.webradio.WebRadio; import org.jajuk.services.webradio.WebRadioManager; import org.jajuk.util.Conf; import org.jajuk.util.Const; /** * Tests for org.jajuk.services.StartupEngineService */ public class TestStartupEngineService extends JajukTestCase { /** DOCUMENT_ME. */ private File file1; /** DOCUMENT_ME. */ private File file2; /** DOCUMENT_ME. */ private File file3; /** DOCUMENT_ME. */ private WebRadio radio1; /** The Constant POSITION. DOCUMENT_ME */ private static final float POSITION = 0.5f; /* * (non-Javadoc) * * @see junit.framework.TestCase#setUp() */ @Override protected void setUp() throws Exception { super.setUp(); // Populate collection with a few files and associated items // (automatically created with it) file1 = JUnitHelpers.getFile("file1", true); file2 = JUnitHelpers.getFile("file2", true); file3 = JUnitHelpers.getFile("file3", true); // Populate the history with these three files History.getInstance().addItem(file1.getID(), System.currentTimeMillis() - 120000); History.getInstance().addItem(file2.getID(), System.currentTimeMillis() - 110000); History.getInstance().addItem(file3.getID(), System.currentTimeMillis() - 100000); // Add last played radio radio1 = new WebRadio("myRadio", "http://foo.bar"); WebRadioManager.getInstance().addWebRadio(radio1); Conf.setProperty(Const.CONF_DEFAULT_WEB_RADIO, "myRadio"); // Populate FIFO java.io.File fifo = SessionService.getConfFileByPath(Const.FILE_FIFO); fifo.delete(); BufferedWriter bw = new BufferedWriter(new FileWriter(fifo, false)); bw.write(file1.getID() + "\n"); bw.write(file2.getID() + "\n"); bw.write(file3.getID() + "\n"); bw.close(); // Set others properties Conf.setProperty(Const.CONF_STARTUP_LAST_POSITION, POSITION + ""); Conf.setProperty(Const.CONF_STARTUP_STOPPED, "false"); Conf.setProperty(Const.CONF_STARTUP_ITEM, file3.getID()); Conf.setProperty(Const.CONF_WEBRADIO_WAS_PLAYING, "false"); // Reset the queue QueueModel.reset(); // Reset the Startup service Field alToPlay = StartupEngineService.class.getDeclaredField("alToPlay"); alToPlay.setAccessible(true); alToPlay.set(null, new ArrayList()); Field fileToPlay = StartupEngineService.class.getDeclaredField("fileToPlay"); fileToPlay.setAccessible(true); fileToPlay.set(null, null); Field radio = StartupEngineService.class.getDeclaredField("radio"); radio.setAccessible(true); radio.set(null, null); Field index = StartupEngineService.class.getDeclaredField("index"); index.setAccessible(true); index.set(null, 0); } /** * Test nothing. * DOCUMENT_ME * * @throws InterruptedException the interrupted exception */ public final void testNothing() throws InterruptedException { Conf.setProperty(Const.CONF_STARTUP_MODE, Const.STARTUP_MODE_NOTHING); StartupEngineService.launchInitialTrack(); // Wait for track to be actually launched Thread.sleep(100); assertEquals(QueueModel.getPlayingFile(), null); // Check that queue is filled up assertTrue(QueueModel.getQueue().size() == 3); } /** * Test last item. * DOCUMENT_ME * * @throws InterruptedException the interrupted exception */ public final void testLastItem() throws InterruptedException { Conf.setProperty(Const.CONF_STARTUP_MODE, Const.STARTUP_MODE_LAST); StartupEngineService.launchInitialTrack(); // Wait for track to be actually launched Thread.sleep(100); assertEquals(QueueModel.getPlayingFile(), file3); } /** * Test last item last pos. * DOCUMENT_ME * * @throws InterruptedException the interrupted exception */ public final void testLastItemLastPos() throws InterruptedException { Conf.setProperty(Const.CONF_STARTUP_MODE, Const.STARTUP_MODE_LAST_KEEP_POS); StartupEngineService.launchInitialTrack(); // Wait for track to be actually launched Thread.sleep(100); assertEquals(QueueModel.getPlayingFile(), file3); // Cannot test actual position, the mock player always return zero //assertTrue(Player.getCurrentPosition() >= POSITION); } /** * Test novelties. * DOCUMENT_ME * * @throws InterruptedException the interrupted exception */ public final void testNovelties() throws InterruptedException { Conf.setProperty(Const.CONF_STARTUP_MODE, Const.STARTUP_MODE_NOVELTIES); StartupEngineService.launchInitialTrack(); // Wait for track to be actually launched Thread.sleep(100); assertTrue(QueueModel.isPlayingTrack()); } /** * Test bestof. * DOCUMENT_ME * * @throws InterruptedException the interrupted exception */ public final void testBestof() throws InterruptedException { Conf.setProperty(Const.CONF_STARTUP_MODE, Const.STARTUP_MODE_BESTOF); StartupEngineService.launchInitialTrack(); // Wait for track to be actually launched Thread.sleep(100); assertTrue(QueueModel.isPlayingTrack()); } /** * Test first session. * DOCUMENT_ME * * @throws InterruptedException the interrupted exception */ public final void testFirstSession() throws InterruptedException { Conf.setProperty(Const.CONF_STARTUP_ITEM, ""); Conf.setProperty(Const.CONF_STARTUP_MODE, Const.STARTUP_MODE_LAST_KEEP_POS); History.getInstance().clear(); StartupEngineService.launchInitialTrack(); // Wait for track to be actually launched Thread.sleep(100); assertEquals(QueueModel.getPlayingFile(), null); } /** * Test shuffle. * DOCUMENT_ME * * @throws InterruptedException the interrupted exception */ public final void testShuffle() throws InterruptedException { Conf.setProperty(Const.CONF_STARTUP_MODE, Const.STARTUP_MODE_SHUFFLE); StartupEngineService.launchInitialTrack(); // Wait for track to be actually launched Thread.sleep(100); assertTrue(QueueModel.isPlayingTrack()); } /** * Test stopped file. * DOCUMENT_ME * * @throws InterruptedException the interrupted exception */ public final void testStoppedFile() throws InterruptedException { Conf.setProperty(Const.CONF_STARTUP_MODE, Const.STARTUP_MODE_LAST_KEEP_POS); Conf.setProperty(Const.CONF_STARTUP_STOPPED, "true"); StartupEngineService.launchInitialTrack(); // Wait for track to be actually launched Thread.sleep(100); assertFalse(QueueModel.isPlayingRadio()); assertFalse(QueueModel.isPlayingTrack()); // Check that queue is filled up assertTrue(QueueModel.getQueue().size() == 3); } /** * Test stopped radio. * DOCUMENT_ME * * @throws InterruptedException the interrupted exception */ public final void testStoppedRadio() throws InterruptedException { Conf.setProperty(Const.CONF_STARTUP_MODE, Const.STARTUP_MODE_LAST_KEEP_POS); Conf.setProperty(Const.CONF_STARTUP_STOPPED, "true"); StartupEngineService.launchInitialTrack(); // Wait for track to be actually launched Thread.sleep(100); assertFalse(QueueModel.isPlayingRadio()); assertFalse(QueueModel.isPlayingTrack()); } /** * Test start web radio. * DOCUMENT_ME * * @throws InterruptedException the interrupted exception */ public final void testStartWebRadio() throws InterruptedException { Conf.setProperty(Const.CONF_STARTUP_MODE, Const.STARTUP_MODE_LAST_KEEP_POS); Conf.setProperty(Const.CONF_WEBRADIO_WAS_PLAYING, "true"); StartupEngineService.launchInitialTrack(); // Wait for track to be actually launched Thread.sleep(100); assertEquals(QueueModel.getCurrentRadio(), radio1); } /** * User selected a file to launch at startup. * * @throws InterruptedException the interrupted exception */ public final void testStartGivenFile() throws InterruptedException { Conf.setProperty(Const.CONF_STARTUP_MODE, Const.STARTUP_MODE_ITEM); Conf.setProperty(Const.CONF_STARTUP_ITEM, SearchResultType.FILE.name() + "/" + file1.getID()); // Radio was playing but we don't care, we should launch the file Conf.setProperty(Const.CONF_WEBRADIO_WAS_PLAYING, "true"); StartupEngineService.launchInitialTrack(); // Wait for track to be actually launched Thread.sleep(100); assertEquals(QueueModel.getPlayingFile(), file1); // Same without playing radio Conf.setProperty(Const.CONF_WEBRADIO_WAS_PLAYING, "false"); StartupEngineService.launchInitialTrack(); // Wait for track to be actually launched Thread.sleep(100); assertEquals(QueueModel.getPlayingFile(), file1); } /** * User selected a radio to launch at startup. * * @throws InterruptedException the interrupted exception */ public final void testStartGivenRadio() throws InterruptedException { Conf.setProperty(Const.CONF_STARTUP_MODE, Const.STARTUP_MODE_ITEM); Conf.setProperty(Const.CONF_STARTUP_ITEM, SearchResultType.WEBRADIO.name() + "/" + radio1.getName()); // Radio was playing but we don't care, we should launch the file Conf.setProperty(Const.CONF_WEBRADIO_WAS_PLAYING, "true"); StartupEngineService.launchInitialTrack(); // Wait for track to be actually launched Thread.sleep(100); assertEquals(QueueModel.getCurrentRadio(), radio1); // Same without playing radio Conf.setProperty(Const.CONF_WEBRADIO_WAS_PLAYING, "false"); StartupEngineService.launchInitialTrack(); // Wait for track to be actually launched Thread.sleep(100); assertEquals(QueueModel.getCurrentRadio(), radio1); } /** * User selected a radio to launch at startup but it leaved jajuk stopped. * * @throws InterruptedException the interrupted exception */ public final void testStartGivenRadioStopped() throws InterruptedException { Conf.setProperty(Const.CONF_STARTUP_MODE, Const.STARTUP_MODE_ITEM); Conf.setProperty(Const.CONF_STARTUP_ITEM, SearchResultType.WEBRADIO.name() + "/" + radio1.getName()); Conf.setProperty(Const.CONF_STARTUP_STOPPED, "true"); StartupEngineService.launchInitialTrack(); // Wait for track to be actually launched Thread.sleep(100); assertEquals(QueueModel.getCurrentRadio(), null); } /** * - Play last file / last position mode * - User left jajuk playing the radio * Check that the radio is playing and that the queue is still there. * * @throws InterruptedException the interrupted exception */ public final void test1() throws InterruptedException { Conf.setProperty(Const.CONF_STARTUP_MODE, Const.STARTUP_MODE_LAST_KEEP_POS); Conf.setProperty(Const.CONF_WEBRADIO_WAS_PLAYING, "true"); StartupEngineService.launchInitialTrack(); // Wait for track to be actually launched Thread.sleep(100); assertEquals(QueueModel.getPlayingFile(), null); } /** * Regression test for a 2010/11/01 bug : * If startup item is unset, last track doesn't work. * * @throws InterruptedException the interrupted exception */ public final void test2() throws InterruptedException { Conf.setProperty(Const.CONF_STARTUP_MODE, Const.STARTUP_MODE_LAST_KEEP_POS); Conf.setProperty(Const.CONF_STARTUP_ITEM, ""); StartupEngineService.launchInitialTrack(); // Wait for track to be actually launched Thread.sleep(100); assertEquals(QueueModel.getPlayingFile(), file3); } } jajuk-1.9.6.orig/src/test/java/org/jajuk/services/covers/0000755000175000017500000000000011720500104023162 5ustar drazzibdrazzibjajuk-1.9.6.orig/src/test/java/org/jajuk/services/covers/TestCover.java0000644000175000017500000001770111720500104025751 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.services.covers; import java.awt.HeadlessException; import java.io.File; import java.net.URL; import org.apache.commons.io.FileUtils; import org.apache.commons.lang.StringUtils; import org.jajuk.JUnitHelpers; import org.jajuk.JajukTestCase; import org.jajuk.services.covers.Cover.CoverType; import org.jajuk.util.Conf; import org.jajuk.util.Const; /** * DOCUMENT_ME. */ public class TestCover extends JajukTestCase { /** * Test method for {@link org.jajuk.services.covers.Cover#hashCode()}. * * @throws Exception the exception */ public final void testHashCode() throws Exception { Cover cover = new Cover(new URL("http://www.example.com/"), CoverType.STANDARD_COVER); Cover equal = new Cover(new URL("http://www.example.com/"), CoverType.STANDARD_COVER); JUnitHelpers.HashCodeTest(cover, equal); } /* (non-Javadoc) * @see org.jajuk.JajukTestCase#setUp() */ @Override protected void setUp() throws Exception { // Make sure to reset default conf for this option : Conf.restoreValue(Const.FILE_DEFAULT_COVER); } /** * Test method for. * * @throws Exception the exception * {@link org.jajuk.services.covers.Cover#Cover(java.net.URL, org.jajuk.services.covers.Cover.CoverType)} * . */ public final void testCoverURLCoverType() throws Exception { new Cover(new URL("http://www.example.com/"), CoverType.STANDARD_COVER); } /** * Test method for. * * @throws Exception the exception * {@link org.jajuk.services.covers.Cover#Cover(java.io.File, org.jajuk.services.covers.Cover.CoverType)} * . */ public final void testCoverFileCoverType() throws Exception { new Cover(new File("testfile.cov"), CoverType.STANDARD_COVER); } /** * Test method for. * * @throws Exception the exception * {@link org.jajuk.services.covers.Cover#compareTo(org.jajuk.services.covers.Cover)} * . */ public final void testCompareTo() throws Exception { Cover cover = new Cover(new File("/tmp/foo.jpg"), CoverType.STANDARD_COVER); Cover equal = new Cover(new File("/tmp/bar.jpg"), CoverType.STANDARD_COVER); Cover notequal = new Cover(new URL("http://www.example.com/"), CoverType.LOCAL_COVER); Cover notequal2 = new Cover(Const.IMAGES_SPLASHSCREEN, CoverType.NO_COVER); Cover notequal3 = new Cover(new URL("http://www.example.com/"), CoverType.REMOTE_COVER); JUnitHelpers.CompareToTest(cover, equal, notequal); JUnitHelpers.CompareToTest(cover, equal, notequal2); JUnitHelpers.CompareToTest(cover, equal, notequal3); } /** * Test method for. * * @throws Exception the exception * {@link org.jajuk.services.covers.Cover#compareTo(org.jajuk.services.covers.Cover)} * . */ public final void testOrderStandardCovers() throws Exception { Conf.setProperty(Const.FILE_DEFAULT_COVER, "front;back"); Cover cover1 = new Cover(new File("/tmp/front_foo.png"), CoverType.STANDARD_COVER); Cover cover2 = new Cover(new File("/tmp/bar_back_2.jpeg"), CoverType.STANDARD_COVER); Cover cover3 = new Cover(new File("/tmp/front_foo_2.png"), CoverType.STANDARD_COVER); int comparison = cover1.compareTo(cover2); assertTrue(comparison > 0); Conf.setProperty(Const.FILE_DEFAULT_COVER, "jajuk;back;front"); comparison = cover1.compareTo(cover2); assertTrue(comparison < 0); Conf.setProperty(Const.FILE_DEFAULT_COVER, "front"); comparison = cover1.compareTo(cover3); assertTrue(comparison == 0); } /** * Test method for {@link org.jajuk.services.covers.Cover#getType()}. * * @throws Exception the exception */ public final void testGetType() throws Exception { Cover cover = new Cover(new URL("http://www.example.com/"), CoverType.STANDARD_COVER); assertEquals(CoverType.STANDARD_COVER, cover.getType()); } /** * Test method for {@link org.jajuk.services.covers.Cover#getURL()}. * * @throws Exception the exception */ public final void testGetURL() throws Exception { Cover cover = new Cover(new URL("http://www.example.com/"), CoverType.STANDARD_COVER); assertEquals("http://www.example.com/", cover.getURL().toString()); } /** * Test method for {@link org.jajuk.services.covers.Cover#getSize()}. * * @throws Exception the exception */ public final void testGetSize() throws Exception { File file = File.createTempFile("test", ".txt"); // remove it and re-create it with some content assertTrue(file.delete()); FileUtils.writeStringToFile(file, StringUtils.repeat(".", 2000)); Cover cover = new Cover(file, CoverType.STANDARD_COVER); assertEquals("2", cover.getSize()); } /** * Test method for {@link org.jajuk.services.covers.Cover#getImage()}. * * @throws Exception the exception */ public final void testGetImage() throws Exception { File file = File.createTempFile("test", ".txt"); Cover cover = new Cover(file, CoverType.NO_COVER); // for no-cover, we get back a default image assertNotNull(cover.getImage()); cover = new Cover(new URL("http://jajuk.info/skins/jajuk2010/jajuk_logotype.png"), CoverType.REMOTE_COVER); try { assertNotNull(cover.getImage()); } catch (HeadlessException e) { // ignore here... } cover = new Cover(new File("notexists"), CoverType.STANDARD_COVER); try { cover.getImage(); fail("Should throw an exception here..."); } catch (IllegalArgumentException e) { // ok here } // TODO: more testing is necessary here... } /** * Test method for {@link org.jajuk.services.covers.Cover#toString()}. * * @throws Exception the exception */ public final void testToString() throws Exception { // standard toString Cover cover = new Cover(new URL("http://www.example.com/"), CoverType.STANDARD_COVER); JUnitHelpers.ToStringTest(cover); // should also cope with items being null cover = new Cover(new URL("http://www.example.com/"), null); JUnitHelpers.ToStringTest(cover); } /** * Test method for. * * @throws Exception the exception * {@link org.jajuk.services.covers.Cover#equals(java.lang.Object)}. */ public final void testEqualsObject() throws Exception { Cover cover = new Cover(new URL("http://www.example.com/"), CoverType.STANDARD_COVER); Cover equal = new Cover(new URL("http://www.example.com/"), CoverType.STANDARD_COVER); // Cover notequal = new Cover(new URL("http://www.example.com/"), CoverType.LOCAL_COVER); // Cover notequal2 = new Cover(new URL("http://www.example.com/"), CoverType.NO_COVER); Cover notequal3 = new Cover(new URL("http://www.test.com/"), CoverType.STANDARD_COVER); // JUnitHelpers.EqualsTest(cover, equal, notequal); // JUnitHelpers.EqualsTest(cover, equal, notequal2); JUnitHelpers.EqualsTest(cover, equal, notequal3); } /** * Test method for {@link org.jajuk.services.covers.Cover#getFile()}. * * @throws Exception the exception */ public final void testGetFile() throws Exception { Cover cover = new Cover(new URL("http://www.example.com/"), CoverType.REMOTE_COVER); Cover cover2 = new Cover(new File("testfile"), CoverType.STANDARD_COVER); assertNotNull(cover.getFile()); assertNotNull(cover2.getFile()); } } jajuk-1.9.6.orig/src/test/java/org/jajuk/services/bookmark/0000755000175000017500000000000011720500104023466 5ustar drazzibdrazzibjajuk-1.9.6.orig/src/test/java/org/jajuk/services/bookmark/TestBookmarks.java0000644000175000017500000002207511720500104027127 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.services.bookmark; import java.util.ArrayList; import java.util.List; import org.jajuk.JUnitHelpers; import org.jajuk.JajukTestCase; import org.jajuk.base.File; import org.jajuk.util.Conf; import org.jajuk.util.Const; /** * DOCUMENT_ME. */ public class TestBookmarks extends JajukTestCase { /* * (non-Javadoc) * * @see junit.framework.TestCase#setUp() */ @Override protected void setUp() throws Exception { Bookmarks.getInstance().clear(); super.setUp(); } /** * Test method for {@link org.jajuk.services.bookmark.Bookmarks#getInstance()} * . */ public void testGetInstance() { Bookmarks.getInstance(); } /** * Test method for {@link org.jajuk.services.bookmark.Bookmarks#toString()}. * * @throws Exception the exception */ public void testToString() throws Exception { // TODO: this fails currently because it returns an empty string: // JUnitHelpers.ToStringTest(Bookmarks.getInstance()); assertNotNull(Bookmarks.getInstance().toString()); // test with some files Bookmarks.getInstance().addFile(JUnitHelpers.getFile("file1", true)); JUnitHelpers.ToStringTest(Bookmarks.getInstance()); } /** * Test method for {@link org.jajuk.services.bookmark.Bookmarks#getFiles()}. * * @throws Exception the exception */ public void testGetFiles() throws Exception { assertEquals(0, Bookmarks.getInstance().getFiles().size()); // test with some files Bookmarks.getInstance().addFile(JUnitHelpers.getFile("file1", true)); assertEquals(1, Bookmarks.getInstance().getFiles().size()); Bookmarks.getInstance().addFile(JUnitHelpers.getFile("file1", true)); assertEquals(2, Bookmarks.getInstance().getFiles().size()); } /** * Test method for {@link org.jajuk.services.bookmark.Bookmarks#clear()}. * * @throws Exception the exception */ public void testClear() throws Exception { Bookmarks.getInstance().addFile(JUnitHelpers.getFile("file1", true)); assertEquals(1, Bookmarks.getInstance().getFiles().size()); Bookmarks.getInstance().clear(); assertEquals(0, Bookmarks.getInstance().getFiles().size()); } /** * Test method for {@link org.jajuk.services.bookmark.Bookmarks#down(int)}. * * @throws Exception the exception */ public void testDownAndUp() throws Exception { // nothing happens without files Bookmarks.getInstance().down(0); Bookmarks.getInstance().up(0); // add some files Bookmarks.getInstance().addFile(JUnitHelpers.getFile("file1", true)); Bookmarks.getInstance().addFile(JUnitHelpers.getFile("file2", true)); Bookmarks.getInstance().addFile(JUnitHelpers.getFile("file3", true)); // check the order assertEquals("file1", Bookmarks.getInstance().getFiles().get(0).getName()); assertEquals("file2", Bookmarks.getInstance().getFiles().get(1).getName()); assertEquals("file3", Bookmarks.getInstance().getFiles().get(2).getName()); // down some Bookmarks.getInstance().down(1); assertEquals("file1", Bookmarks.getInstance().getFiles().get(0).getName()); assertEquals("file3", Bookmarks.getInstance().getFiles().get(1).getName()); assertEquals("file2", Bookmarks.getInstance().getFiles().get(2).getName()); // up again Bookmarks.getInstance().up(1); assertEquals("file3", Bookmarks.getInstance().getFiles().get(0).getName()); assertEquals("file1", Bookmarks.getInstance().getFiles().get(1).getName()); assertEquals("file2", Bookmarks.getInstance().getFiles().get(2).getName()); // outside Bookmarks.getInstance().down(2); assertEquals("file3", Bookmarks.getInstance().getFiles().get(0).getName()); assertEquals("file1", Bookmarks.getInstance().getFiles().get(1).getName()); assertEquals("file2", Bookmarks.getInstance().getFiles().get(2).getName()); // outside Bookmarks.getInstance().up(0); assertEquals("file3", Bookmarks.getInstance().getFiles().get(0).getName()); assertEquals("file1", Bookmarks.getInstance().getFiles().get(1).getName()); assertEquals("file2", Bookmarks.getInstance().getFiles().get(2).getName()); } /** * Test method for {@link org.jajuk.services.bookmark.Bookmarks#remove(int)}. * * @throws Exception the exception */ public void testRemove() throws Exception { // add some files Bookmarks.getInstance().addFile(JUnitHelpers.getFile("file1", true)); Bookmarks.getInstance().addFile(JUnitHelpers.getFile("file2", true)); Bookmarks.getInstance().addFile(JUnitHelpers.getFile("file3", true)); Bookmarks.getInstance().remove(0); assertEquals("file2", Bookmarks.getInstance().getFiles().get(0).getName()); assertEquals("file3", Bookmarks.getInstance().getFiles().get(1).getName()); } /** * Test method for. * * @throws Exception the exception * {@link org.jajuk.services.bookmark.Bookmarks#addFile(int, org.jajuk.base.File)} * . */ public void testAddFileIntFile() throws Exception { // add some files Bookmarks.getInstance().addFile(JUnitHelpers.getFile("file1", true)); Bookmarks.getInstance().addFile(JUnitHelpers.getFile("file2", true)); Bookmarks.getInstance().addFile(JUnitHelpers.getFile("file3", true)); // check the order assertEquals("file1", Bookmarks.getInstance().getFiles().get(0).getName()); assertEquals("file2", Bookmarks.getInstance().getFiles().get(1).getName()); assertEquals("file3", Bookmarks.getInstance().getFiles().get(2).getName()); Bookmarks.getInstance().addFile(1, JUnitHelpers.getFile("file4", true)); assertEquals("file1", Bookmarks.getInstance().getFiles().get(0).getName()); assertEquals("file4", Bookmarks.getInstance().getFiles().get(1).getName()); assertEquals("file2", Bookmarks.getInstance().getFiles().get(2).getName()); assertEquals("file3", Bookmarks.getInstance().getFiles().get(3).getName()); } /** * Test method for. * * @throws Exception the exception * {@link org.jajuk.services.bookmark.Bookmarks#addFile(org.jajuk.base.File)}. */ public void testAddFileFile() throws Exception { // add some files Bookmarks.getInstance().addFile(JUnitHelpers.getFile("file1", true)); Bookmarks.getInstance().addFile(JUnitHelpers.getFile("file2", true)); Bookmarks.getInstance().addFile(JUnitHelpers.getFile("file3", true)); // check the order assertEquals("file1", Bookmarks.getInstance().getFiles().get(0).getName()); assertEquals("file2", Bookmarks.getInstance().getFiles().get(1).getName()); assertEquals("file3", Bookmarks.getInstance().getFiles().get(2).getName()); } /** * Test method for. * * @throws Exception the exception * {@link org.jajuk.services.bookmark.Bookmarks#addFiles(java.util.List)}. */ public void testAddFiles() throws Exception { List list = new ArrayList(); // add some files list.add(JUnitHelpers.getFile("file1", true)); list.add(JUnitHelpers.getFile("file2", true)); list.add(JUnitHelpers.getFile("file3", true)); Bookmarks.getInstance().addFiles(list); // check the order assertEquals("file1", Bookmarks.getInstance().getFiles().get(0).getName()); assertEquals("file2", Bookmarks.getInstance().getFiles().get(1).getName()); assertEquals("file3", Bookmarks.getInstance().getFiles().get(2).getName()); } // helper method to emma-coverage of the unused constructor /** * Test private constructor. * DOCUMENT_ME * * @throws Exception the exception */ public void testPrivateConstructor() throws Exception { // test with some files Bookmarks.getInstance().addFile(JUnitHelpers.getFile("file1", true)); Bookmarks.getInstance().addFile(JUnitHelpers.getFile("file1", true)); // For EMMA code-coverage tests JUnitHelpers.executePrivateConstructor(Bookmarks.class); } /** * Test coverage. * DOCUMENT_ME * * @throws Exception the exception */ public void testCoverage() throws Exception { Conf.setProperty(Const.CONF_BOOKMARKS, ""); // For EMMA code-coverage tests JUnitHelpers.executePrivateConstructor(Bookmarks.class); Conf.removeProperty(Const.CONF_BOOKMARKS); // For EMMA code-coverage tests JUnitHelpers.executePrivateConstructor(Bookmarks.class); Conf.setProperty(Const.CONF_BOOKMARKS, "1,2,3,4"); // For EMMA code-coverage tests JUnitHelpers.executePrivateConstructor(Bookmarks.class); } } jajuk-1.9.6.orig/src/test/java/org/jajuk/services/bookmark/TestHistoryItem.java0000644000175000017500000000747011720500104027461 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.services.bookmark; import org.jajuk.JUnitHelpers; import org.jajuk.JajukTestCase; import org.jajuk.base.Album; import org.jajuk.base.Artist; import org.jajuk.base.Device; import org.jajuk.base.Directory; import org.jajuk.base.DirectoryManager; import org.jajuk.base.File; import org.jajuk.base.FileManager; import org.jajuk.base.Genre; import org.jajuk.base.Track; import org.jajuk.base.TrackManager; import org.jajuk.base.Type; import org.jajuk.base.Year; import org.jajuk.util.Const; /** * DOCUMENT_ME. */ public class TestHistoryItem extends JajukTestCase { /** * Test method for. * * {@link org.jajuk.services.bookmark.HistoryItem#HistoryItem(java.lang.String, long)} * . */ public final void testHistoryItem() { new HistoryItem("1", 123); } /** * Test method for {@link org.jajuk.services.bookmark.HistoryItem#getDate()}. */ public final void testGetAndSetDate() { long date = System.currentTimeMillis(); HistoryItem item = new HistoryItem("1", date); assertEquals(date, item.getDate()); item.setDate(123); assertEquals(123, item.getDate()); } /** * Test method for {@link org.jajuk.services.bookmark.HistoryItem#getFileId()} * . */ public final void testGetAndSetFileId() { long date = System.currentTimeMillis(); HistoryItem item = new HistoryItem("1", date); assertEquals("1", item.getFileId()); item.setFileId("2"); assertEquals("2", item.getFileId()); } /** * Test method for {@link org.jajuk.services.bookmark.HistoryItem#toString()}. */ public final void testToStringNull() { long date = System.currentTimeMillis(); HistoryItem item = new HistoryItem("1", date); JUnitHelpers.ToStringTest(item); } /** * Test to string file. * DOCUMENT_ME */ public final void testToStringFile() { File file; { Genre genre = JUnitHelpers.getGenre("genrename"); Album album = JUnitHelpers.getAlbum("myalbum", 0); album.setProperty(Const.XML_ALBUM_DISCOVERED_COVER, Const.COVER_NONE); // don't read covers for // this test Artist artist = JUnitHelpers.getArtist("artistname"); Year year = JUnitHelpers.getYear(2000); Type type = JUnitHelpers.getType(); Track track = TrackManager.getInstance().registerTrack("trackname", album, genre, artist, 120, year, 1, type, 1); Device device = JUnitHelpers.getDevice("devicename", Device.TYPE_DIRECTORY, System .getProperty("java.io.tmpdir")); Directory dir = DirectoryManager.getInstance().registerDirectory(device); file = FileManager.getInstance().registerFile("test.tst", dir, track, 120, 70); } long date = System.currentTimeMillis(); HistoryItem item = new HistoryItem(file.getID(), date); // verify toString in general JUnitHelpers.ToStringTest(item); // verify that the necessary information is contained assertTrue(item.toString(), item.toString().contains("trackname")); assertTrue(item.toString(), item.toString().contains("artistname")); } } jajuk-1.9.6.orig/src/test/java/org/jajuk/services/bookmark/TestHistory.java0000644000175000017500000006325411720500104026644 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.services.bookmark; import java.util.Properties; import org.apache.commons.io.FileUtils; import org.jajuk.JUnitHelpers; import org.jajuk.JajukTestCase; import org.jajuk.base.File; import org.jajuk.base.FileManager; import org.jajuk.events.JajukEvent; import org.jajuk.events.JajukEvents; import org.jajuk.events.ObservationManager; import org.jajuk.services.core.SessionService; import org.jajuk.util.Conf; import org.jajuk.util.Const; import org.xml.sax.SAXException; import org.xml.sax.SAXParseException; /** * DOCUMENT_ME. */ public class TestHistory extends JajukTestCase { /* (non-Javadoc) * @see org.jajuk.JajukTestCase#setUp() */ @Override protected void setUp() throws Exception { super.setUp(); } /** * Test method for {@link org.jajuk.services.bookmark.History#startDocument()} * . */ public final void testStartDocument() { History.getInstance().startDocument(); } /** * Test method for {@link org.jajuk.services.bookmark.History#endDocument()}. */ public final void testEndDocument() { History.getInstance().endDocument(); } /** * Test method for {@link org.jajuk.services.bookmark.History#getInstance()}. */ public final void testGetInstance() { assertNotNull(History.getInstance()); } /** * Test method for. * * {@link org.jajuk.services.bookmark.History#getRegistrationKeys()}. */ public final void testGetRegistrationKeys() { assertNotNull(History.getInstance().getRegistrationKeys()); assertTrue(History.getInstance().getRegistrationKeys().contains(JajukEvents.CLEAR_HISTORY)); } /** * Test method for {@link org.jajuk.services.bookmark.History#getHistory()}. * * @throws Exception the exception */ public final void testGetHistory() throws Exception { assertNotNull(History.getInstance().getHistory()); // has size 0 at the beginning assertEquals(0, History.getInstance().getHistory().size()); // try with history disabled, should return without adding Conf.setProperty(Const.CONF_HISTORY, "0"); History.getInstance().addItem("1", 123); assertEquals(0, History.getInstance().getHistory().size()); // enable history, should still not be added unless we have the file in the // FileManager Conf.setProperty(Const.CONF_HISTORY, "1"); History.getInstance().addItem("1", 123); assertEquals(0, History.getInstance().getHistory().size()); // register a new file with the file manager, but still no go as we have a // different id! File file2 = JUnitHelpers.getFile("file2", false); History.getInstance().addItem("1", 123); assertEquals(0, History.getInstance().getHistory().size()); // finally look for the correct file with id "2" History.getInstance().addItem(file2.getID(), 123); assertEquals(1, History.getInstance().getHistory().size()); // now try to update the history with more files File file3 = JUnitHelpers.getFile("file3", false); File file4 = JUnitHelpers.getFile("file4", false); File file5 = JUnitHelpers.getFile("file5", false); History.getInstance().addItem(file3.getID(), 123); History.getInstance().addItem(file4.getID(), 123); History.getInstance().addItem(file5.getID(), 123); assertEquals(4, History.getInstance().getHistory().size()); // now try to add the same file as the last one, the new one should be // added, but not twice History.getInstance().addItem(file5.getID(), 124); // size the same, not one higher assertEquals(4, History.getInstance().getHistory().size()); // new item should be found in history now assertEquals("Item: " + History.getInstance().getHistoryItem(0).getDate(), 124, History .getInstance().getHistoryItem(0).getDate()); } /** * Test get history max size. * DOCUMENT_ME * * @throws Exception the exception */ public final void testGetHistoryMaxSize() throws Exception { // enable history, should still not be added unless we have the file in the // FileManager Conf.setProperty(Const.CONF_HISTORY, "1"); // register enough files (one more than the max size) File[] files = new File[Const.MAX_HISTORY_SIZE]; for (int i = 0; i < Const.MAX_HISTORY_SIZE; i++) { files[i] = JUnitHelpers.getFile("file" + i, false); } // add up to max items for (int i = 0; i < Const.MAX_HISTORY_SIZE; i++) { History.getInstance().addItem(files[i].getID(), 123); assertEquals(i + 1, History.getInstance().getHistory().size()); } // size should at the max now assertEquals(Const.MAX_HISTORY_SIZE, History.getInstance().getHistory().size()); // register one more file File max = JUnitHelpers.getFile("file" + Const.MAX_HISTORY_SIZE, false); // now when we add one item, we should loose the oldest one (i.e. ID "1") History.getInstance().addItem(max.getID(), 123); // size should be equal as the oldest item was purged assertEquals(Const.MAX_HISTORY_SIZE, History.getInstance().getHistory().size()); // new element should be in the History at position 0 now assertEquals(History.getInstance().getHistory().toString(), max.getID(), History.getInstance() .getHistoryItem(0).getFileId()); // check that the existing items were moved by one (items are always added at the front, so // we have to check in reverse order, i.e. the one before the last added one is at pos 1 for (int i = 1; i < Const.MAX_HISTORY_SIZE; i++) { assertEquals(History.getInstance().getHistory().toString(), files[Const.MAX_HISTORY_SIZE - i] .getID(), History.getInstance().getHistoryItem(i).getFileId()); } // also check clear History.getInstance().clear(); // we have to wait for it as it is executed in the background JUnitHelpers.clearSwingUtilitiesQueue(); // size should be zero again now assertEquals(0, History.getInstance().getHistory().size()); } /** * Test method for. * * {@link org.jajuk.services.bookmark.History#addItem(java.lang.String, long)} * . */ public final void testAddItem() { // tested as part of getHistoryMaxSize() above } /** * Test method for {@link org.jajuk.services.bookmark.History#clear()}. */ public final void testClear() { // tested as part of getHistoryMaxSize() above } /** * Test method for {@link org.jajuk.services.bookmark.History#cleanup()}. * * @throws Exception the exception */ public final void testCleanup() throws Exception { // enable history Conf.setProperty(Const.CONF_HISTORY, "1"); // register the file File file2 = JUnitHelpers.getFile("file2", false); // add the file History.getInstance().addItem(file2.getID(), 123); // now it is there assertEquals(1, History.getInstance().getHistory().size()); // cleanup should keep this file as it is registered correctly History.getInstance().cleanup(); // we have to sleep a bit as it is executed in the background JUnitHelpers.clearSwingUtilitiesQueue(); assertEquals(1, History.getInstance().getHistory().size()); // add another file and unregister it from the FileManager File file3 = JUnitHelpers.getFile("file3", false); History.getInstance().addItem(file3.getID(), 123); assertEquals(2, History.getInstance().getHistory().size()); FileManager.getInstance().removeFile(file3); assertEquals(2, History.getInstance().getHistory().size()); // cleanup should now remove one file! History.getInstance().cleanup(); // we have to sleep a bit as it is executed in the background JUnitHelpers.clearSwingUtilitiesQueue(); assertEquals(1, History.getInstance().getHistory().size()); // if we clean out FileManager, cleanup should remove this file as well FileManager.getInstance().clear(); History.getInstance().cleanup(); // we have to sleep a bit as it is executed in the background JUnitHelpers.clearSwingUtilitiesQueue(); assertEquals(0, History.getInstance().getHistory().size()); } /** * Test method for. * * @throws Exception the exception * {@link org.jajuk.services.bookmark.History#changeID(java.lang.String, java.lang.String)} * . */ public final void testChangeID() throws Exception { // enable history Conf.setProperty(Const.CONF_HISTORY, "1"); // register the file File file2 = JUnitHelpers.getFile("file2", false); // add the file History.getInstance().addItem(file2.getID(), 123); // now it is there assertEquals(1, History.getInstance().getHistory().size()); // change from id 2 to 3 History.getInstance().changeID(file2.getID(), "3"); // we have to sleep a bit as it is executed in the background JUnitHelpers.clearSwingUtilitiesQueue(); assertEquals(1, History.getInstance().getHistory().size()); assertEquals("3", History.getInstance().getHistoryItem(0).getFileId()); // it is not automatically changed in FileManager itself! assertNull(FileManager.getInstance().getFileByID("3")); } /** * Test method for {@link org.jajuk.services.bookmark.History#clear(int)}. * * @throws Exception the exception */ public final void testClearInt() throws Exception { // enable history Conf.setProperty(Const.CONF_HISTORY, "1"); // register the file File file2 = JUnitHelpers.getFile("file2", false); // add the file History.getInstance().addItem(file2.getID(), 123); // now it is there assertEquals(1, History.getInstance().getHistory().size()); // minus 1 means endlessly History.getInstance().clear(-1); // we have to sleep a bit as it is executed in the background JUnitHelpers.clearSwingUtilitiesQueue(); assertEquals(1, History.getInstance().getHistory().size()); // stating a day will clean the file History.getInstance().clear(2); // we have to sleep a bit as it is executed in the background JUnitHelpers.clearSwingUtilitiesQueue(); assertEquals(0, History.getInstance().getHistory().size()); } /** * Test clear int keep. * DOCUMENT_ME * * @throws Exception the exception */ public final void testClearIntKeep() throws Exception { addHistoryItem(2, System.currentTimeMillis()); // now it is there assertEquals(1, History.getInstance().getHistory().size()); // stating a day bigger than one will keep the file History.getInstance().clear(2); // we have to sleep a bit as it is executed in the background JUnitHelpers.clearSwingUtilitiesQueue(); assertEquals(1, History.getInstance().getHistory().size()); } /** * Test clear int removed. * DOCUMENT_ME * * @throws Exception the exception */ public final void testClearIntRemoved() throws Exception { addHistoryItem(2, System.currentTimeMillis()); // now it is there assertEquals(1, History.getInstance().getHistory().size()); // cleaning the FileManager will also remove the history for the files FileManager.getInstance().clear(); History.getInstance().clear(2); // we have to sleep a bit as it is executed in the background JUnitHelpers.clearSwingUtilitiesQueue(); assertEquals(0, History.getInstance().getHistory().size()); } /** * Test method for {@link org.jajuk.services.bookmark.History#commit()}. * * @throws Exception the exception */ public final void testCommit() throws Exception { long date = System.currentTimeMillis(); addHistoryItem(2, date); // now it is there assertEquals(1, History.getInstance().getHistory().size()); JUnitHelpers.createSessionDirectory(); // write the list to disc History.commit(); // item still there assertEquals(1, History.getInstance().getHistory().size()); // clear the history, now the item is gone History.getInstance().clear(); // we have to sleep a bit as it is executed in the background JUnitHelpers.clearSwingUtilitiesQueue(); assertEquals(0, History.getInstance().getHistory().size()); // now load the data again History.load(); // the item is there again now assertEquals(1, History.getInstance().getHistory().size()); assertEquals(date, History.getInstance().getHistoryItem(0).getDate()); } /** * Adds the history item. * DOCUMENT_ME * * @param nID DOCUMENT_ME * @param timestamp The timestamp to use for the HistoryItem * @throws NumberFormatException the number format exception * @throws Exception the exception */ private void addHistoryItem(int nID, long timestamp) throws NumberFormatException, Exception { // enable history Conf.setProperty(Const.CONF_HISTORY, "1"); // register the file File file = JUnitHelpers.getFile("file_" + nID, false); // add the file with current date History.getInstance().addItem(file.getID(), timestamp); } /** * Test method for {@link org.jajuk.services.bookmark.History#load()}. */ public final void testLoad() { // tested as part of "testCommit()" } /** * Test load corrupt file. * DOCUMENT_ME * * @throws Exception the exception */ public final void testLoadCorruptFile() throws Exception { JUnitHelpers.createSessionDirectory(); // first try when no file is available java.io.File frt = SessionService.getConfFileByPath(Const.FILE_HISTORY); frt.delete(); assertFalse(frt.exists()); // it will catch an exception internally and handle it... History.load(); // then try with a corrupted file FileUtils.writeStringToFile(frt, ""); } /** * Test method for {@link org.jajuk.services.bookmark.History#getLastFile()}. * * @throws NumberFormatException the number format exception * @throws Exception the exception */ public final void testGetLastFile() throws NumberFormatException, Exception { // null without history assertNull(History.getInstance().getLastFile()); addHistoryItem(2, 123); // now it is there assertEquals(1, History.getInstance().getHistory().size()); // now returns the correct item File file2 = JUnitHelpers.getFile("file_2", false); assertEquals(file2.getID(), History.getInstance().getLastFile()); addHistoryItem(3, 123); File file3 = JUnitHelpers.getFile("file_3", false); assertEquals(file3.getID(), History.getInstance().getLastFile()); // now it is there assertEquals(2, History.getInstance().getHistory().size()); addHistoryItem(2, 123); assertEquals(file2.getID(), History.getInstance().getLastFile()); } /** * Test method for. * * @throws NumberFormatException the number format exception * @throws Exception the exception * {@link org.jajuk.services.bookmark.History#getHistoryItem(int)}. */ public final void testGetHistoryItem() throws NumberFormatException, Exception { // null without any history assertNull(History.getInstance().getHistoryItem(0)); addHistoryItem(2, 123); // now it is there assertEquals(1, History.getInstance().getHistory().size()); // found now File file2 = JUnitHelpers.getFile("file_2", false); assertEquals(file2.getID(), History.getInstance().getHistoryItem(0).getFileId()); // null with index out of bound assertNull(History.getInstance().getHistoryItem(1)); assertNull(History.getInstance().getHistoryItem(-1)); // try with more than one item, the new one is added as first item! addHistoryItem(4, 123); File file4 = JUnitHelpers.getFile("file_4", false); assertEquals(file4.getID(), History.getInstance().getHistoryItem(0).getFileId()); assertEquals(file2.getID(), History.getInstance().getHistoryItem(1).getFileId()); } /** * Test method for. * * {@link org.jajuk.services.bookmark.History#warning(org.xml.sax.SAXParseException)} * . */ public final void testWarningSAXParseException() { try { History.getInstance().warning(new SAXParseException("testmessage", null)); fail("Will throw exception"); } catch (SAXException e) { assertTrue(e.getMessage(), e.getMessage().contains("testmessage")); } } /** * Test method for. * * {@link org.jajuk.services.bookmark.History#error(org.xml.sax.SAXParseException)} * . */ public final void testErrorSAXParseException() { try { History.getInstance().error(new SAXParseException("testmessage", null)); fail("Will throw exception"); } catch (SAXException e) { assertTrue(e.getMessage(), e.getMessage().contains("testmessage")); } } /** * Test method for. * * {@link org.jajuk.services.bookmark.History#fatalError(org.xml.sax.SAXParseException)} * . */ public final void testFatalErrorSAXParseException() { try { History.getInstance().fatalError(new SAXParseException("testmessage", null)); fail("Will throw exception"); } catch (SAXException e) { assertTrue(e.getMessage(), e.getMessage().contains("testmessage")); } } /** * Test method for. * * {@link org.jajuk.services.bookmark.History#startElement(java.lang.String, java.lang.String, java.lang.String, org.xml.sax.Attributes)} * . */ public final void testStartElementStringStringStringAttributes() { // tested as part of "commit/load" } /** * Test method for. * * {@link org.jajuk.services.bookmark.History#endElement(java.lang.String, java.lang.String, java.lang.String)} * . */ public final void testEndElementStringStringString() { // tested as part of "commit/load" } /** * Test method for. * * @throws Exception the exception * {@link org.jajuk.services.bookmark.History#update(org.jajuk.events.JajukEvent)} * . */ public final void testUpdateFileLaunched() throws Exception { // enable history Conf.setProperty(Const.CONF_HISTORY, "1"); addHistoryItem(2, 12345); assertEquals(1, History.getInstance().getHistory().size()); File file3 = JUnitHelpers.getFile("file_3", false); Properties detail = new Properties(); detail.put(Const.DETAIL_CURRENT_FILE_ID, file3.getID()); detail.put(Const.DETAIL_CURRENT_DATE, new Long(12345)); History.getInstance().update(new JajukEvent(JajukEvents.FILE_LAUNCHED, detail)); // we have to sleep a bit as it is executed in the background JUnitHelpers.clearSwingUtilitiesQueue(); // now the file should be added assertEquals(2, History.getInstance().getHistory().size()); assertEquals(file3.getID(), History.getInstance().getHistoryItem(0).getFileId()); } /** * Test update device refresh. * DOCUMENT_ME * * @throws Exception the exception */ public final void testUpdateDeviceRefresh() throws Exception { // enable history Conf.setProperty(Const.CONF_HISTORY, "1"); addHistoryItem(2, 12345); assertEquals(1, History.getInstance().getHistory().size()); // remove the file from the FileManager FileManager.getInstance().clear(); // trigger the refresh-event History.getInstance().update(new JajukEvent(JajukEvents.DEVICE_REFRESH, null)); // we have to sleep a bit as it is executed in the background JUnitHelpers.clearSwingUtilitiesQueue(); // we need to wait a second time because we have an invokeLater() inside // another invokeLater() here... JUnitHelpers.clearSwingUtilitiesQueue(); // now the item is removed because it is not available any more in the // FileManager assertEquals(0, History.getInstance().getHistory().size()); } /** * Test update clear history. * DOCUMENT_ME * * @throws Exception the exception */ public final void testUpdateClearHistory() throws Exception { // enable history Conf.setProperty(Const.CONF_HISTORY, "1"); addHistoryItem(14, 12345); assertEquals(1, History.getInstance().getHistory().size()); // trigger the clear-event History.getInstance().update(new JajukEvent(JajukEvents.CLEAR_HISTORY, null)); // here we actually have to sleep a few times as there are two thread-calls // done, once inside update() and then // another one in clear() itself, one "sleep()" only gives up thread-control // once and then gains control again later JUnitHelpers.clearSwingUtilitiesQueue(); // now the item is cleared // TODO: this test fails in Hudson for some reason, I could not find out // why, it works // in Eclipse as well as in a local Hudson instance that I did set up, so I // can only // disable this check for now... // assertEquals(0, History.getInstance().getHistory().size()); } /** * Test update language changed. * DOCUMENT_ME */ public final void testUpdateLanguageChanged() { History.getInstance().update(new JajukEvent(JajukEvents.LANGUAGE_CHANGED, null)); } /** * Test update file name changed. * DOCUMENT_ME * * @throws Exception the exception */ public final void testUpdateFileNameChanged() throws Exception { // it seems there are some rare cases where we still have some threads doing // some updates, // therefore sleep some more up-front to let that clear out before we start // the test here JUnitHelpers.clearSwingUtilitiesQueue(); // enable history Conf.setProperty(Const.CONF_HISTORY, "1"); // register the file File file11 = JUnitHelpers.getFile("file_11", false); File file3 = JUnitHelpers.getFile("file_3", false); // add the file History.getInstance().addItem(file11.getID(), 123); // now it is there assertEquals(History.getInstance().getHistory().toString(), 1, History.getInstance() .getHistory().size()); // change from id 11 to 3 Properties detail = new Properties(); File file = FileManager.getInstance().getFileByID(file11.getID()); // there needs to be such a file because we added it above... assertNotNull(file); detail.put(Const.DETAIL_OLD, file); // read the file "3" and then remove it from the filemanager to be clean // there as well file = FileManager.getInstance().getFileByID(file3.getID()); // there needs to be such a file because we added it above... assertNotNull(file); detail.put(Const.DETAIL_NEW, file); FileManager.getInstance().removeFile(file); // now trigger the update History.getInstance().update(new JajukEvent(JajukEvents.FILE_NAME_CHANGED, detail)); // we have to wait for the SwingUtilities here as the update is executed in // the background JUnitHelpers.clearSwingUtilitiesQueue(); // we actually execute an invokeLater() in another invokeLater() which means // we need to // wait twice here until all work is guaranteed to be done JUnitHelpers.clearSwingUtilitiesQueue(); // now we only should have the item "3" assertEquals(1, History.getInstance().getHistory().size()); // TODO: this test fails in Hudson for some reason, I could not find out // why, it works // in Eclipse as well as in a local Hudson instance that I did set up, so I // can only // disable this check for now... // assertEquals("3", History.getInstance().getHistoryItem(0).getFileId()); } /** * Test update unhandled event. * DOCUMENT_ME */ public final void testUpdateUnhandledEvent() { History.getInstance().update(new JajukEvent(JajukEvents.BANNED, null)); } /** * Test method for. * * {@link org.jajuk.services.bookmark.History#getDateFormatter()}. */ public final void testGetDateFormatter() { assertNotNull(History.getInstance().getDateFormatter()); } /** * Test constructor already launched. * DOCUMENT_ME * * @throws Exception the exception */ public final void testConstructorAlreadyLaunched() throws Exception { // it seems there are some cases where we still have some Queues doing some // updates, // therefore sleep some more up-front to let that clear out before we start // the test here JUnitHelpers.clearSwingUtilitiesQueue(); Thread.sleep(100); // enable history Conf.setProperty(Const.CONF_HISTORY, "1"); File file3 = JUnitHelpers.getFile("file_3", false); Properties detail = new Properties(); detail.put(Const.DETAIL_CURRENT_FILE_ID, file3.getID()); detail.put(Const.DETAIL_CURRENT_DATE, new Long(12345)); // set the necessary things in the ObservationManager ObservationManager.notifySync(new JajukEvent(JajukEvents.FILE_LAUNCHED, detail)); // make sure we have the correct last-file now assertEquals(file3.getID(), ObservationManager.getDetailLastOccurence( JajukEvents.FILE_LAUNCHED, Const.DETAIL_CURRENT_FILE_ID)); // call the constructor via reflection History hist = JUnitHelpers.executePrivateConstructor(History.class); // we have to wait for the queue to be empty JUnitHelpers.clearSwingUtilitiesQueue(); // it seems there is sometimes still work done by other tests, we saw // failures here, // I added this check here again to see if that actually happens... assertEquals(file3.getID(), ObservationManager.getDetailLastOccurence( JajukEvents.FILE_LAUNCHED, Const.DETAIL_CURRENT_FILE_ID)); // now the file should be in the history already assertEquals(hist.getHistory().toString(), 1, hist.getHistory().size()); assertEquals(file3.getID(), hist.getHistoryItem(0).getFileId()); } } jajuk-1.9.6.orig/src/test/java/org/jajuk/services/cddb/0000755000175000017500000000000011720500104022555 5ustar drazzibdrazzibjajuk-1.9.6.orig/src/test/java/org/jajuk/services/cddb/TestCDDBTrack.java0000644000175000017500000000573311720500104025751 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.services.cddb; import org.jajuk.JUnitHelpers; import org.jajuk.JajukTestCase; import org.jajuk.base.Album; import org.jajuk.base.Artist; import org.jajuk.base.Genre; import org.jajuk.base.Track; import org.jajuk.base.TrackManager; import org.jajuk.base.Type; import org.jajuk.base.Year; import org.jajuk.services.startup.StartupCollectionService; import org.jajuk.util.Const; /** * DOCUMENT_ME. */ public class TestCDDBTrack extends JajukTestCase { /** * Test method for. * * {@link org.jajuk.services.cddb.CDDBTrack#CDDBTrack(org.jajuk.base.Track)}. */ public final void testCDDBTrack() { new CDDBTrack(null); } /** * Test method for {@link org.jajuk.services.cddb.CDDBTrack#getLength()}. */ public final void testGetLength() { CDDBTrack track = new CDDBTrack(getTrack(1)); assertEquals(120, track.getLength()); } /** * Test method for. * * {@link org.jajuk.services.cddb.CDDBTrack#getPreciseLength()}. */ public final void testGetPreciseLength() { CDDBTrack track = new CDDBTrack(getTrack(1)); assertEquals(120f, track.getPreciseLength()); } /** * Test method for {@link org.jajuk.services.cddb.CDDBTrack#getTrack()}. */ public final void testGetTrack() { CDDBTrack track = new CDDBTrack(getTrack(1)); assertNotNull(track.getTrack()); } /** * Test method for {@link org.jajuk.services.cddb.CDDBTrack#toString()}. */ public final void testToString() { StartupCollectionService.registerItemManagers(); CDDBTrack track = new CDDBTrack(getTrack(1)); JUnitHelpers.ToStringTest(track); } /** * Gets the track. * * @param i DOCUMENT_ME * @return the track */ private Track getTrack(int i) { Genre genre = JUnitHelpers.getGenre(); Album album = JUnitHelpers.getAlbum("myalbum", 0); album.setProperty(Const.XML_ALBUM_DISCOVERED_COVER, Const.COVER_NONE); // don't read covers for // this test Artist artist = JUnitHelpers.getArtist("name"); Year year = JUnitHelpers.getYear(2000); Type type = JUnitHelpers.getType(); return TrackManager.getInstance().registerTrack("name" + i, album, genre, artist, 120, year, 1, type, 1); } } jajuk-1.9.6.orig/src/test/java/org/jajuk/TestHelpers.java0000644000175000017500000001106211720500104023143 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk; import java.util.concurrent.atomic.AtomicInteger; import javax.swing.SwingUtilities; import org.jajuk.base.Album; import org.jajuk.base.AlbumManager; import org.jajuk.base.Artist; import org.jajuk.base.ArtistManager; import org.jajuk.base.Device; import org.jajuk.base.DeviceManager; import org.jajuk.base.Directory; import org.jajuk.base.DirectoryManager; import org.jajuk.base.File; import org.jajuk.base.FileManager; import org.jajuk.base.Genre; import org.jajuk.base.GenreManager; import org.jajuk.base.Track; import org.jajuk.base.TrackManager; import org.jajuk.base.Type; import org.jajuk.base.TypeManager; import org.jajuk.base.Year; import org.jajuk.base.YearManager; import org.jajuk.services.players.MPlayerPlayerImpl; import org.jajuk.services.tags.JAudioTaggerTagImpl; /** * DOCUMENT_ME. */ public class TestHelpers extends JajukTestCase { /** DOCUMENT_ME. */ Exception exc = null; /** DOCUMENT_ME. */ boolean finished = false; /** * Test clear swing utilities queue. * DOCUMENT_ME * * @throws Exception the exception */ public void testClearSwingUtilitiesQueue() throws Exception { // verify test-helper to clear the Swing Utilities Queue SwingUtilities.invokeLater(new Runnable() { @Override public void run() { try { Thread.sleep(1000); finished = true; } catch (InterruptedException e) { exc = e; } } }); long now = System.currentTimeMillis(); // after this method returns we expect the above invokeLater to be finished JUnitHelpers.clearSwingUtilitiesQueue(); // now the finished needs to be true assertTrue("Elapsed time(ms): " + (System.currentTimeMillis() - now), finished); } /** DOCUMENT_ME. */ private final int COUNT = 10; /** DOCUMENT_ME. */ private AtomicInteger count = new AtomicInteger(0); /** * Test clear swing utilities queue multiple. * DOCUMENT_ME * * @throws Exception the exception */ public void testClearSwingUtilitiesQueueMultiple() throws Exception { // verify test-helper to clear the Swing Utilities Queue for (int i = 0; i < COUNT; i++) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { try { Thread.sleep(1000 / COUNT); count.incrementAndGet(); } catch (InterruptedException e) { exc = e; } } }); } long now = System.currentTimeMillis(); // after this method returns we expect the above invokeLater to be finished JUnitHelpers.clearSwingUtilitiesQueue(); // now the finished needs to be true assertTrue( "Elapsed time(ms): " + (System.currentTimeMillis() - now) + " Count: " + count.get(), count .get() == COUNT); } /** * Return a mock file for testing purposes. * * @return a mock file for testing purposes */ public static File getMockFile() { Type type = TypeManager.getInstance().registerType("mp3", "mp3", MPlayerPlayerImpl.class, JAudioTaggerTagImpl.class); Album album = AlbumManager.getInstance().registerAlbum("album name", "album artist", 2222l); Genre genre = GenreManager.getInstance().registerGenre("genre name"); Artist artist = ArtistManager.getInstance().registerArtist("artist name"); Year year = YearManager.getInstance().registerYear("2000"); Track track = TrackManager.getInstance().registerTrack("track name", album, genre, artist, 12l, year, 1l, type, 1l); Device device = DeviceManager.getInstance().registerDevice("device name", 1l, "/tmp"); Directory dir = DirectoryManager.getInstance().registerDirectory(device); File file = FileManager.getInstance().registerFile("file name", dir, track, 12, 128); return file; } } jajuk-1.9.6.orig/src/test/java/org/jajuk/util/0000755000175000017500000000000011720500104021013 5ustar drazzibdrazzibjajuk-1.9.6.orig/src/test/java/org/jajuk/util/TestUtilFeatures.java0000644000175000017500000000404211720500104025132 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.util; import java.util.ArrayList; import java.util.List; import org.jajuk.JUnitHelpers; import org.jajuk.JajukTestCase; import org.jajuk.services.players.StackItem; /** * DOCUMENT_ME. */ public class TestUtilFeatures extends JajukTestCase { /* * (non-Javadoc) * * @see junit.framework.TestCase#setUp() */ @Override protected void setUp() throws Exception { super.setUp(); } /** * Test method for. * * @throws Exception the exception * {@link org.jajuk.util.UtilFeatures#forcedShuffle(List)}. */ public void testCopyFileFile() throws Exception { StackItem si1 = new StackItem(JUnitHelpers.getFile("1", true)); StackItem si2 = new StackItem(JUnitHelpers.getFile("2", true)); List items = new ArrayList(2); items.add(si1); items.add(si2); UtilFeatures.forcedShuffle(items); assertFalse(items.get(0).equals(si1)); } // helper method to emma-coverage of the unused constructor /** * Test private constructor. * DOCUMENT_ME * * @throws Exception the exception */ public void testPrivateConstructor() throws Exception { // For EMMA code-coverage tests JUnitHelpers.executePrivateConstructor(UtilFeatures.class); } } jajuk-1.9.6.orig/src/test/java/org/jajuk/util/TestUtilString.java0000644000175000017500000001512311720500104024624 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.util; import org.jajuk.JajukTestCase; import org.junit.Test; /** * DOCUMENT_ME. */ public class TestUtilString extends JajukTestCase { /* * (non-Javadoc) * * @see junit.framework.TestCase#setUp() */ @Override protected void setUp() throws Exception { super.setUp(); } /** * Test method for {@link org.jajuk.util.UtilString#applyPattern(org.jajuk.base.File, java.lang.String, boolean, boolean)}. */ @Test public void testApplyPattern() { //TODO to be implemented } /** * Test method for {@link org.jajuk.util.UtilString#containsNonDigitOrLetters(java.lang.String)}. */ @Test public void testContainsNonDigitOrLetters() { //TODO to be implemented } /** * Test method for {@link org.jajuk.util.UtilString#encodeURL(java.lang.String)}. */ @Test public void testEncodeURL() { //TODO to be implemented } /** * Test method for {@link org.jajuk.util.UtilString#escapeString(java.lang.String)}. */ @Test public void testEscapeString() { //TODO to be implemented } /** * Test method for {@link org.jajuk.util.UtilString#format(java.lang.Object, org.jajuk.base.PropertyMetaInformation, boolean)}. */ @Test public void testFormat() { //TODO to be implemented } /** * Test method for {@link org.jajuk.util.UtilString#getLocaleDateFormatter()}. */ @Test public void testGetLocaleDateFormatter() { //TODO to be implemented } /** * Test method for {@link org.jajuk.util.UtilString#formatPropertyDesc(java.lang.String)}. */ @Test public void testFormatPropertyDesc() { //TODO to be implemented } /** * Test method for {@link org.jajuk.util.UtilString#formatGenre(java.lang.String)}. */ @Test public void testFormatGenre() { //TODO to be implemented } /** * Test method for {@link org.jajuk.util.UtilString#formatTag(java.lang.String)}. */ @Test public void testFormatTag() { //TODO to be implemented } /** * Test method for {@link org.jajuk.util.UtilString#formatTimeBySec(long)}. */ @Test public void testFormatTimeBySec() { //TODO to be implemented } /** * Test method for {@link org.jajuk.util.UtilString#formatXML(java.lang.String)}. */ @Test public void testFormatXML() { //TODO to be implemented } /** * Test method for {@link org.jajuk.util.UtilString#getAdditionDateFormatter()}. */ @Test public void testGetAdditionDateFormatter() { //TODO to be implemented } /** * Test method for {@link org.jajuk.util.UtilString#getAnonymizedJajukProperties()}. */ @Test public void testGetAnonymizedJajukProperties() { //TODO to be implemented } /** * Test method for {@link org.jajuk.util.UtilString#getAnonymizedSystemProperties()}. */ @Test public void testGetAnonymizedSystemProperties() { //TODO to be implemented } /** * Test method for {@link org.jajuk.util.UtilString#getLimitedString(java.lang.String, int)}. */ @Test public void testGetLimitedString() { //TODO to be implemented } /** * Test method for {@link org.jajuk.util.UtilString#isChar(int)}. */ @Test public void testIsChar() { //TODO to be implemented } /** * Test method for {@link org.jajuk.util.UtilString#isXMLValid(java.lang.String)}. */ @Test public void testIsXMLValid() { //TODO to be implemented } /** * Test method for {@link org.jajuk.util.UtilString#padNumber(long, int)}. */ @Test public void testPadNumber() { //TODO to be implemented } /** * Test method for {@link org.jajuk.util.UtilString#parse(java.lang.String, java.lang.Class)}. */ @Test public void testParse() { //TODO to be implemented } /** * Test method for {@link org.jajuk.util.UtilString#fastLongParser(java.lang.String)}. */ @Test public void testFastLongParser() { //TODO to be implemented } /** * Test method for {@link org.jajuk.util.UtilString#fastBooleanParser(java.lang.String)}. */ @Test public void testFastBooleanParser() { //TODO to be implemented } /** * Test method for {@link org.jajuk.util.UtilString#rot13(java.lang.String)}. */ @Test public void testRot13() { //TODO to be implemented } /** * Test method for {@link org.jajuk.util.UtilString#matchesIgnoreCaseAndOrder(java.lang.String, java.lang.String)}. */ @Test public void testMatchesIgnoreCaseAndOrder() { //TODO to be implemented } /** * Test method for {@link org.jajuk.util.UtilString#encodeToUnicode(java.lang.String)}. */ @Test public void testEncodeToUnicode() { //TODO to be implemented } /** * Test method for {@link org.jajuk.util.UtilString#byteToHex(byte)}. */ @Test public void testByteToHex() { //TODO to be implemented } /** * Test method for {@link org.jajuk.util.UtilString#concat(java.lang.Object[])}. */ @Test public void testConcat() { //TODO to be implemented } /** * Test method for {@link org.jajuk.util.UtilString#getTextBetweenChars(java.lang.String, char, char)}. */ @Test public void testGetTextBetweenChars() { //TODO to be implemented } /** * Test method for {@link org.jajuk.util.UtilString#normalizeFilename(java.lang.String)}. */ @Test public void testNormalizeFilename() { // Regular string check String fileName = "foo.txt"; String normFileName = UtilString.normalizeFilename(fileName); assertTrue("foo.txt".equals(normFileName)); // Contains a Windows forbidden chars : ? fileName = "?-e.txt"; normFileName = UtilString.normalizeFilename(fileName); assertTrue("_-e.txt".equals(normFileName)); // Contains an accent fileName = '\u00E0' + "" + '\u00E9' + "!?-e.txt"; normFileName = UtilString.normalizeFilename(fileName); assertTrue("ae!_-e.txt".equals(normFileName)); } } jajuk-1.9.6.orig/src/test/java/org/jajuk/util/log/0000755000175000017500000000000011720500104021574 5ustar drazzibdrazzibjajuk-1.9.6.orig/src/test/java/org/jajuk/util/log/TestLog.java0000644000175000017500000002200511720500104024017 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.util.log; import java.util.List; import org.jajuk.JajukTestCase; import org.jajuk.util.Const; import org.jajuk.util.error.JajukException; /** * DOCUMENT_ME. */ public class TestLog extends JajukTestCase { /* * (non-Javadoc) * * @see org.jajuk.JajukTestCase#setUp() */ @Override protected void setUp() throws Exception { // make sure we have logging initialized for these tests Log.init(); super.setUp(); } /** * Test method for {@link org.jajuk.util.log.Log#getInstance()}. */ public void testGetInstance() { Log.init(); } /** * Test method for {@link org.jajuk.util.log.Log#debug(java.lang.String)}. */ public void testDebugString() { Log.debug("testlog1"); verifySpool("testlog1"); } /** * Test method for {@link org.jajuk.util.log.Log#debug(java.lang.Throwable)}. */ public void testDebugThrowable() { Log.debug(new Throwable("testthrowable2")); // this is anonymonized: verifySpool("testthrowable2"); verifySpool("***"); } /** * Test method for. * * {@link org.jajuk.util.log.Log#debug(java.lang.String, java.lang.Throwable)} * . */ public void testDebugStringThrowable() { Log.debug("testlog2", new Throwable("testthrowable2")); verifySpool("testlog2"); // this is anonymonized: verifySpool("testthrowable2"); verifySpool("***"); } /** * Test debug string throwable null. * DOCUMENT_ME */ public void testDebugStringThrowableNull() { Log.debug(null, new Throwable("testthrowable2")); // verifySpool("testlog2"); // this is anonymonized: verifySpool("testthrowable2"); verifySpool("***"); } /** * Test method for {@link org.jajuk.util.log.Log#info(java.lang.String)}. */ public void testInfo() { Log.info("testloginfo3"); verifySpool("testloginfo3"); } /** * Test method for {@link org.jajuk.util.log.Log#warn(java.lang.String)}. */ public void testWarnString() { Log.warn("testwarn4"); verifySpool("testwarn4"); } /** * Test method for. * * {@link org.jajuk.util.log.Log#warn(java.lang.String, java.lang.String)}. */ public void testWarnStringString() { Log.warn("warn5", "addinfo"); verifySpool("warn5"); verifySpool("addinfo"); } /** * Test method for. * * {@link org.jajuk.util.log.Log#warn(int, java.lang.String, java.lang.Throwable)} * . */ public void testWarnIntStringThrowable() { Log.warn(10, "warntext6", new Throwable("testthrowable")); verifySpool("warntext6"); // this is anonymonized: verifySpool("testthrowable2"); verifySpool("***"); } /** * Test warn int string throwable null. * DOCUMENT_ME */ public void testWarnIntStringThrowableNull() { Log.warn(10, null, new Throwable("testthrowable")); // this is anonymonized: verifySpool("testthrowable2"); verifySpool("***"); } /** * Test method for. * * {@link org.jajuk.util.log.Log#error(int, java.lang.String, java.lang.Throwable)} * . */ public void testErrorIntStringThrowable() { Log.error(30, "errortext7", new Throwable("errorthrowable")); verifySpool("errortext7"); // this is anonymonized: verifySpool("testthrowable2"); verifySpool("***"); } /** * Test method for {@link org.jajuk.util.log.Log#error(int)}. */ public void testErrorInt() { Log.error(31); verifySpool("31"); } /** * Test method for {@link org.jajuk.util.log.Log#error(java.lang.Throwable)}. */ public void testErrorThrowable() { Log.error(new Throwable("testerror8")); // this is anonymonized: verifySpool("testthrowable2"); verifySpool("***"); } /** * Test method for. * * {@link org.jajuk.util.log.Log#error(int, java.lang.Throwable)}. */ public void testErrorIntThrowable() { Log.error(32, new Throwable("testerror9")); verifySpool("32"); // this is anonymonized: verifySpool("testthrowable2"); verifySpool("***"); } /** * Test method for. * * {@link org.jajuk.util.log.Log#error(java.lang.String, org.jajuk.util.error.JajukException)} * . */ public void testErrorStringJajukException() { Log.error("teststring", new JajukException(33)); } /** * Test method for. * * {@link org.jajuk.util.log.Log#error(org.jajuk.util.error.JajukException)}. */ public void testErrorJajukException() { Log.error(new JajukException(34)); } /** * Test method for {@link org.jajuk.util.log.Log#fatal(java.lang.String)}. */ public void testFatal() { Log.fatal("testfataltext"); } /** * Test method for {@link org.jajuk.util.log.Log#getVerbosity()}. */ public void testGetVerbosity() { // set verbosity first as we can not rely on INFO being set because other // tests might have adjusted it somehow Log.setVerbosity(Log.INFO); assertEquals(Log.INFO, Log.getVerbosity()); Log.setVerbosity(Log.DEBUG); assertEquals(Log.DEBUG, Log.getVerbosity()); Log.setVerbosity(Log.INFO); assertEquals(Log.INFO, Log.getVerbosity()); Log.setVerbosity(Log.WARNING); assertEquals(Log.WARNING, Log.getVerbosity()); Log.setVerbosity(Log.ERROR); assertEquals(Log.ERROR, Log.getVerbosity()); Log.setVerbosity(Log.FATAL); assertEquals(Log.FATAL, Log.getVerbosity()); Log.setVerbosity(Log.INFO); // reset to info for other tests } /** * Test method for {@link org.jajuk.util.log.Log#setVerbosity(int)}. */ public void testSetVerbosity() { // tested above } /** * Test method for {@link org.jajuk.util.log.Log#stack(java.lang.Exception)}. */ public void testStack() { Log.stack(new Exception("teststacktraceexception")); } /** * Test method for {@link org.jajuk.util.log.Log#isDebugEnabled()}. */ public void testIsDebugEnabled() { Log.setVerbosity(Log.DEBUG); assertTrue(Log.isDebugEnabled()); Log.setVerbosity(Log.INFO); assertFalse(Log.isDebugEnabled()); } /** * Test method for {@link org.jajuk.util.log.Log#getSpool()}. */ public void testGetSpool() { // should return a list and not null assertNotNull(Log.getSpool()); // create enough spool to overflow for (int i = 0; i < Const.FEEDBACK_LINES + 10; i++) { Log.debug("Spooltest-" + i + '|'); } // should return the expected number of lines now assertEquals(Log.getSpool().toString(), Const.FEEDBACK_LINES, Log.getSpool().size()); // now the first ten should be moved out verifySpool("Spooltest-0|", false); verifySpool("Spooltest-9|", false); verifySpool("Spooltest-11|"); verifySpool("Spooltest-" + Integer.toString(Const.FEEDBACK_LINES + 9) + '|'); // more details tested in other methods } /** * Verify spool. * DOCUMENT_ME * * @param substring DOCUMENT_ME */ private void verifySpool(String substring) { verifySpool(substring, true); } /** * Verify spool. * DOCUMENT_ME * * @param substring DOCUMENT_ME * @param expected DOCUMENT_ME */ private void verifySpool(String substring, boolean expected) { List list = Log.getSpool(); for (String str : list) { if (str.contains(substring)) { // expected => return, not expected => fail if (expected) { return; } else { fail("Should not find string '" + substring + "' in spool: " + list.toString()); } } } // if we expected the string, but did not find it we need to fail here if (expected) { fail("List does not contain expected string '" + substring + "' in spool: " + list.toString()); } } /** * Test anonymization. * DOCUMENT_ME */ public void testAnonymization() { // things in {{...}} are replaced in the spool. Verify that this happens Log.info("this is {{sensitive}} data..."); verifySpool("this is"); verifySpool("sensitive", false); verifySpool("data..."); // replaced by "***" verifySpool("***"); } /** * Test anonymization player state. * DOCUMENT_ME */ public void testAnonymizationPlayerState() { // special replacement that is done to not show personal data in the spool Log.info("Player state changed: OPENING this is secret personal information"); verifySpool("Player"); verifySpool("OPENING"); verifySpool("secret", false); } } jajuk-1.9.6.orig/src/test/java/org/jajuk/util/TestFilter.java0000644000175000017500000000531011720500104023742 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.util; import java.util.ArrayList; import java.util.List; import org.jajuk.JajukTestCase; import org.jajuk.base.Item; /** * DOCUMENT_ME. */ public class TestFilter extends JajukTestCase { /** * Test method for. * * {@link org.jajuk.util.Filter#Filter(java.lang.String, java.lang.String, boolean, boolean)} * . */ public final void testFilter() { Filter filter = new Filter("test", "test", true, false); assertTrue(filter.isHuman()); assertFalse(filter.isExact()); filter = new Filter("test", "test", false, true); assertFalse(filter.isHuman()); assertTrue(filter.isExact()); } /** * Test method for {@link org.jajuk.util.Filter#getProperty()}. */ public final void testGetProperty() { Filter filter = new Filter("test1", "test2", true, false); assertEquals("test1", filter.getProperty()); } /** * Test method for {@link org.jajuk.util.Filter#getValue()}. */ public final void testGetValue() { Filter filter = new Filter("test1", "test2", true, false); assertEquals("test2", filter.getValue()); } /** * Test method for. * * {@link org.jajuk.util.Filter#filterItems(java.util.List, org.jajuk.util.Filter)} * . */ public final void testFilterItems() { // works with empty filter Filter.filterItems(null, null); // returns with empty expression Filter filter = new Filter("any", null, true, false); Filter.filterItems(null, filter); List list = new ArrayList(); // try to trigger a regex error filter = new Filter("any", "asdfas(sasdfsa", true, false); Filter.filterItems(list, filter); // works with useful filter filter = new Filter("any", "test", true, false); Filter.filterItems(list, filter); filter = new Filter("something", "test", true, false); Filter.filterItems(list, filter); // TODO: more sophisticated testing is missing here } } jajuk-1.9.6.orig/src/test/java/org/jajuk/util/TestUtilSystem.java0000644000175000017500000005664311720500104024656 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.util; import java.awt.HeadlessException; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.Random; import org.apache.commons.io.FileUtils; import org.apache.commons.lang.SystemUtils; import org.jajuk.JUnitHelpers; import org.jajuk.JajukTestCase; import org.jajuk.util.error.JajukException; /** * DOCUMENT_ME. */ public class TestUtilSystem extends JajukTestCase { /** DOCUMENT_ME. */ private File file1, file2; /* * (non-Javadoc) * * @see junit.framework.TestCase#setUp() */ @Override protected void setUp() throws Exception { file1 = File.createTempFile("test", ".jajuk"); file2 = File.createTempFile("test", ".jajuk"); super.setUp(); } /* * (non-Javadoc) * * @see junit.framework.TestCase#tearDown() */ @Override protected void tearDown() throws Exception { // just try to remove those and ignore errors as the file might not have // been created file1.delete(); file2.delete(); super.tearDown(); } /** * Test method for. * * {@link org.jajuk.util.UtilSystem#backupFile(java.io.File, int)}. */ public void testBackupFile() { // first test with no backup size set Conf.setProperty(Const.CONF_BACKUP_SIZE, "0"); UtilSystem.backupFile(file1, 1); // then set some backup size Conf.setProperty(Const.CONF_BACKUP_SIZE, "100"); UtilSystem.backupFile(file1, 1); // TODO: create a huge file and make sure it is truncated during backup } /** * Test method for. * * @throws Exception the exception * {@link org.jajuk.util.UtilSystem#copy(java.io.File, java.io.File)}. */ public void testCopyFileFile() throws Exception { FileUtils.writeStringToFile(file1, "this is some test data"); UtilSystem.copy(file1, file2); assertEquals("this is some test data", FileUtils.readFileToString(file2)); } /** * Test copy file exception. * DOCUMENT_ME * * @throws Exception the exception */ public void testCopyFileException() throws Exception { FileUtils.writeStringToFile(file1, "this is some test data"); assertTrue(file2.delete()); assertTrue(file2.mkdirs()); // should not be able to write if a directory // already exists try { UtilSystem.copy(file1, file2); fail("Should report exception"); } catch (IOException e) { // } } /** * Test copy file file empty. * DOCUMENT_ME * * @throws Exception the exception */ public void testCopyFileFileEmpty() throws Exception { FileUtils.writeStringToFile(file1, ""); UtilSystem.copy(file1, file2); assertEquals("", FileUtils.readFileToString(file2)); } /** * Test copy file file not exists. * DOCUMENT_ME * * @throws Exception the exception */ public void testCopyFileFileNotExists() throws Exception { assertTrue(file1.delete()); assertFalse(file1.exists()); try { UtilSystem.copy(file1, file2); fail("Should throw exception"); } catch (JajukException e) { assertEquals(9, e.getCode()); } } /** * Test method for. * * @throws Exception the exception * {@link org.jajuk.util.UtilSystem#copy(java.io.File, java.lang.String)}. */ public void testCopyFileString() throws Exception { FileUtils.writeStringToFile(file1, "this is some test data"); UtilSystem.copy(file1, "testfile"); // file is written into same directory as file1 here assertEquals("this is some test data", FileUtils.readFileToString(new File(new StringBuilder( file1.getParentFile().getAbsolutePath()).append('/').append("testfile").toString()))); } /** * Test copy file string empty. * DOCUMENT_ME * * @throws Exception the exception */ public void testCopyFileStringEmpty() throws Exception { FileUtils.writeStringToFile(file1, ""); UtilSystem.copy(file1, "testfile"); assertEquals("", FileUtils.readFileToString(file2)); } /** * Test copy file string not exists. * DOCUMENT_ME * * @throws Exception the exception */ public void testCopyFileStringNotExists() throws Exception { assertTrue(file1.delete()); assertFalse(file1.exists()); try { UtilSystem.copy(file1, "testfile"); fail("Should throw exception"); } catch (JajukException e) { assertEquals(9, e.getCode()); } } /** * Test method for. * * @throws Exception the exception * {@link org.jajuk.util.UtilSystem#copy(java.net.URL, java.lang.String)}. */ public void testCopyURLString() throws Exception { FileUtils.writeStringToFile(file1, "this is some test data"); UtilSystem.copy(file1.toURI().toURL(), file2.getAbsolutePath()); // file is written into same directory as file1 here // TODO: currently the copy(URL) methods adds a newline at the end, should // we change that?? assertEquals("this is some test data" + (SystemUtils.IS_OS_WINDOWS ? "\r" : "") + "\n", FileUtils.readFileToString(file2)); } /** * Test copy url string empty. * DOCUMENT_ME * * @throws Exception the exception */ public void testCopyURLStringEmpty() throws Exception { FileUtils.writeStringToFile(file1, ""); UtilSystem.copy(file1.toURI().toURL(), "testfile"); assertEquals("", FileUtils.readFileToString(file2)); } /** * Test copy url string not exists. * DOCUMENT_ME */ public void testCopyURLStringNotExists() { assertTrue(file1.delete()); assertFalse(file1.exists()); try { UtilSystem.copy(file1.toURI().toURL(), "testfile"); fail("Should throw exception"); } catch (IOException e) { // assertEquals(9, e.getCode()); } } /** * Test method for. * * @throws Exception the exception * {@link org.jajuk.util.UtilSystem#copyRecursively(java.io.File, java.io.File)} * . */ public void testCopyRecursivelySimple() throws Exception { FileUtils.writeStringToFile(file1, "this is some test data"); UtilSystem.copyRecursively(file1, file2); assertEquals("this is some test data", FileUtils.readFileToString(file2)); } /** * Test copy recursively. * DOCUMENT_ME * * @throws Exception the exception */ public void testCopyRecursively() throws Exception { assertTrue(file1.delete()); assertTrue(file1.mkdir()); assertTrue(file2.delete()); FileUtils.writeStringToFile(new File(file1.getAbsolutePath() + File.separator + "testfile"), "this is some test data"); UtilSystem.copyRecursively(file1, file2); assertEquals("this is some test data", FileUtils.readFileToString(new File(file2 .getAbsolutePath() + File.separator + "testfile"))); } /** * Test copy recursively cannot make dir. * DOCUMENT_ME * * @throws Exception the exception */ public void testCopyRecursivelyCannotMakeDir() throws Exception { assertTrue(file1.delete()); assertTrue(file1.mkdir()); FileUtils.writeStringToFile(new File(file1.getAbsolutePath() + File.separator + "testfile"), "this is some test data"); try { UtilSystem.copyRecursively(file1, file2); fail("should throw exception because there is a file where we want to create a directory!"); } catch (FileNotFoundException e) { } // assertEquals("", FileUtils.readFileToString(new // File(file2.getAbsolutePath() + File.separator // + "testfile"))); } /** * Test method for. * * @throws Exception the exception * {@link org.jajuk.util.UtilSystem#copyToDir(java.io.File, java.io.File)}. */ public void testCopyToDir() throws Exception { FileUtils.writeStringToFile(file1, "this is some test data"); assertTrue(file2.delete()); assertTrue(file2.mkdir()); UtilSystem.copyToDir(file1, file2); assertEquals("this is some test data", FileUtils.readFileToString(new File(file2 .getAbsolutePath() + File.separator + file1.getName()))); } /** * Test copy to dir exception. * DOCUMENT_ME * * @throws Exception the exception */ public void testCopyToDirException() throws Exception { FileUtils.writeStringToFile(file1, "this is some test data"); assertTrue(file1.delete()); try { UtilSystem.copyToDir(file1, file2); fail("Should throw exception"); } catch (JajukException e) { assertEquals(9, e.getCode()); } } /** * Test method for. * * @throws Exception the exception * {@link org.jajuk.util.UtilSystem#createEmptyFile(java.io.File)}. */ public void testCreateEmptyFile() throws Exception { assertTrue(file1.delete()); assertFalse(file1.exists()); UtilSystem.createEmptyFile(file1); assertEquals("", FileUtils.readFileToString(file1)); } /** * Test create empty file exception. * DOCUMENT_ME */ public void testCreateEmptyFileException() { assertTrue(file1.delete()); assertFalse(file1.exists()); assertTrue(file1.mkdir()); // test should fail if we try to create a file // when a directory already exists try { UtilSystem.createEmptyFile(file1); fail("Should report exception"); } catch (IOException e) { // } // still a directory now assertTrue(file1.exists()); assertTrue(file1.isDirectory()); } /** * Test method for {@link org.jajuk.util.UtilSystem#deleteDir(java.io.File)}. * * @throws Exception the exception */ public void testDeleteDir() throws Exception { assertTrue(file1.delete()); assertTrue(file1.mkdir()); FileUtils.writeStringToFile(new File(file1.getAbsolutePath() + File.separator + "testfile"), "this is some test data"); UtilSystem.deleteDir(file1); assertFalse(file1.exists()); } /** * Test delete dir file. * DOCUMENT_ME * * @throws Exception the exception */ public void testDeleteDirFile() throws Exception { UtilSystem.deleteDir(file1); assertFalse(file1.exists()); } /** * Test delete dir dir. * DOCUMENT_ME * * @throws Exception the exception */ public void testDeleteDirDir() throws Exception { assertTrue(file1.delete()); // create a directory inside a directory assertTrue(new File(file1.getAbsolutePath() + File.separator + "testdir").mkdirs()); FileUtils.writeStringToFile(new File(file1.getAbsolutePath() + File.separator + "testdir" + File.separator + "testfile"), "this is some test data"); UtilSystem.deleteDir(file1); assertFalse(file1.exists()); } /** * Test method for {@link org.jajuk.util.UtilSystem#deleteFile(java.io.File)}. * * @throws Exception the exception */ public void testDeleteFile() throws Exception { FileUtils.writeStringToFile(file1, "this is some test data"); UtilSystem.deleteFile(file1); assertFalse(file1.exists()); } /** * Test method for. * * {@link org.jajuk.util.UtilSystem#getExtension(java.io.File)}. */ public void testGetExtensionFile() { assertEquals("jajuk", UtilSystem.getExtension(file1)); } /** * Test get extension file none. * DOCUMENT_ME */ public void testGetExtensionFileNone() { assertEquals("", UtilSystem.getExtension("/tmp/testfile")); } /** * Test get extension file dot. * DOCUMENT_ME */ public void testGetExtensionFileDot() { // TODO: why do we return the full filename in this case? I.e. if there is a // "." as first character? assertEquals(".testfile", UtilSystem.getExtension(".testfile")); } /** * Test method for. * * {@link org.jajuk.util.UtilSystem#getExtension(java.lang.String)}. */ public void testGetExtensionString() { assertEquals("jajuk", UtilSystem.getExtension(file1.getAbsolutePath())); } /** * Test method for. * * @throws Exception the exception * {@link org.jajuk.util.UtilSystem#getFileChecksum(java.io.File)}. */ public void testGetFileChecksum() throws Exception { assertNotNull(UtilSystem.getFileChecksum(file1)); assertFalse(UtilSystem.getFileChecksum(file1).equals("")); FileUtils.writeStringToFile(file1, "this is some test data"); assertNotNull(UtilSystem.getFileChecksum(file1)); assertFalse(UtilSystem.getFileChecksum(file1).equals("")); } /** * Test get file checksum error. * DOCUMENT_ME */ public void testGetFileChecksumError() { try { UtilSystem.getFileChecksum(new File("notexistingfile.txt")); fail("Should throw exception"); } catch (JajukException e) { assertEquals(103, e.getCode()); } } /** * Test method for {@link org.jajuk.util.UtilSystem#getHostName()}. */ public void testGetHostName() { assertNotNull(UtilSystem.getHostName()); } /** * Test method for. * * {@link org.jajuk.util.UtilSystem#getJarLocation(java.lang.Class)}. */ public void testGetJarLocation() { // check upfront to see where it is failing... assertNotNull(JajukException.class); assertNotNull(JajukException.class.getProtectionDomain()); assertNotNull(JajukException.class.getProtectionDomain().getCodeSource()); assertNotNull(JajukException.class.getProtectionDomain().getCodeSource().getLocation()); assertNotNull(UtilSystem.getJarLocation(JajukException.class)); } /** * Test method for {@link org.jajuk.util.UtilSystem#getMPlayerOSXPath()}. */ public void testGetMPlayerOSXPath() { UtilSystem.getMPlayerOSXPath(); } /** * Test method for {@link org.jajuk.util.UtilSystem#getMPlayerWindowsPath()}. */ public void testGetMPlayerWindowsPath() { UtilSystem.getMPlayerWindowsPath(); } /** * Test method for. * * {@link org.jajuk.util.UtilSystem#getNormalizedFilename(java.lang.String)}. */ public void testGetNormalizedFilename() { // assertEquals(file1.getAbsolutePath(), // UtilSystem.getNormalizedFilename(file1.getAbsolutePath())); assertEquals("-tmp -test1----", UtilSystem.getNormalizedFilename("/tmp*|/te\"?st1<>\\:")); } /** * Test method for. * * {@link org.jajuk.util.UtilSystem#getOnlyFile(java.lang.String)}. */ public void testGetOnlyFile() { assertEquals("name.txt", UtilSystem.getOnlyFile("file:///tmp/some/name.txt")); } /** * Test method for. * * {@link org.jajuk.util.UtilSystem#getResource(java.lang.String)}. */ public void testGetResource() { assertNull(UtilSystem.getResource("unfoundresource")); assertNotNull(UtilSystem.getResource("icons/16x16/add_16x16.png")); } /** * Test method for. * * {@link org.jajuk.util.UtilSystem#isAncestor(java.io.File, java.io.File)}. */ public void testIsAncestor() { assertFalse(UtilSystem.isAncestor(file1, file2)); assertTrue(UtilSystem.isAncestor(new File("/tmp/"), new File("/tmp/test.txt"))); } /** * Test method for. * * {@link org.jajuk.util.UtilSystem#isDescendant(java.io.File, java.io.File)}. */ public void testIsDescendant() { assertFalse(UtilSystem.isDescendant(file2, file1)); assertTrue(UtilSystem.isDescendant(new File("/tmp/test.txt"), new File("/tmp/"))); } /** * Test method for {@link org.jajuk.util.UtilSystem#isUnderLinux()}. */ public void testIsUnderLinux() { assertEquals(SystemUtils.IS_OS_LINUX, UtilSystem.isUnderLinux()); } /** * Test method for {@link org.jajuk.util.UtilSystem#isUnderOSX()}. */ public void testIsUnderOSX() { assertEquals(SystemUtils.IS_OS_MAC_OSX, UtilSystem.isUnderOSX()); } /** * Test method for {@link org.jajuk.util.UtilSystem#isUnderWindows()}. */ public void testIsUnderWindows() { assertEquals(SystemUtils.IS_OS_WINDOWS, UtilSystem.isUnderWindows()); } /** * Test method for {@link org.jajuk.util.UtilSystem#isUnderWindows32bits()}. */ public void testIsUnderWindows32bits() { UtilSystem.isUnderWindows32bits(); // cannot check } /** * Test method for {@link org.jajuk.util.UtilSystem#isUnderWindows64bits()}. */ public void testIsUnderWindows64bits() { UtilSystem.isUnderWindows64bits(); // cannot check } /** * Test method for. * * {@link org.jajuk.util.UtilSystem#isValidFileName(java.io.File, java.lang.String)} * . */ public void testIsValidFileName() { // false whit invalid filenames assertFalse(UtilSystem.isValidFileName(null, null)); assertFalse(UtilSystem.isValidFileName(file1, null)); assertFalse(UtilSystem.isValidFileName(null, "test.txt")); // true with valid filenames assertTrue(UtilSystem.isValidFileName(new File("/tmp"), "testfile")); // already exists assertTrue(UtilSystem.isValidFileName(file1.getParentFile(), file1.getName())); // can be created assertTrue(file1.delete()); assertTrue(UtilSystem.isValidFileName(file1.getParentFile(), file1.getName())); // should not exist after doing the test assertFalse(file1.exists()); } /** * Test method for {@link org.jajuk.util.UtilSystem#needFullFC()}. */ public void testNeedFullFC() { UtilSystem.needFullFC(); // cannot check } /** * Test method for. * * @throws Exception the exception * {@link org.jajuk.util.UtilSystem#readFile(java.lang.String)}. */ public void testReadFile() throws Exception { FileUtils.writeStringToFile(file1, "this is some test data"); StringBuilder builder = UtilSystem.readFile(file1.getAbsolutePath()); assertEquals("this is some test data", builder.toString()); } /** * Test read file error. * DOCUMENT_ME */ public void testReadFileError() { try { UtilSystem.readFile("notexistingfile"); fail("Should throw exception"); } catch (JajukException e) { assertEquals(9, e.getCode()); assertTrue(e.getMessage(), e.getMessage().contains("notexistingfile")); // do // we // also // have // the // invalid // filename // in // the // error? } } /** * Test method for. * * @throws Exception the exception * {@link org.jajuk.util.UtilSystem#readJarFile(java.lang.String)}. */ public void testReadJarFile() throws Exception { try { StringBuilder builder = UtilSystem.readJarFile(UtilSystem .getJarLocation(JajukException.class).toString()); assertNotNull(builder); assertFalse(builder.toString().isEmpty()); } catch (NullPointerException e) { // TODO: we cannot run this test in eclipse as we do not have a Jajuk.jar // file available... } } /** * Test method for. * * {@link org.jajuk.util.UtilSystem#removeExtension(java.lang.String)}. */ public void testRemoveExtension() { assertNotNull(UtilSystem.removeExtension(file1.getAbsolutePath())); } /** * Test method for {@link org.jajuk.util.UtilSystem#getClassLoader()}. */ public void testGetClassLoader() { assertNotNull(UtilSystem.getClassLoader()); } /** * Test method for {@link org.jajuk.util.UtilSystem#getDirFilter()}. */ public void testGetDirFilter() { assertNotNull(UtilSystem.getDirFilter()); assertNotNull(UtilSystem.getDirFilter()); } /** * Test method for {@link org.jajuk.util.UtilSystem#getFileFilter()}. */ public void testGetFileFilter() { assertNotNull(UtilSystem.getFileFilter()); assertNotNull(UtilSystem.getFileFilter()); } /** * Test method for. * * @throws Exception the exception * {@link org.jajuk.util.UtilSystem#replaceInFile(java.io.File, java.lang.String, java.lang.String, java.lang.String)} * . */ public void testReplaceInFileNotReplaced() throws Exception { FileUtils.writeStringToFile(file1, "this is some test data"); assertFalse(UtilSystem.replaceInFile(file1, "notfound", "replaced", "UTF-8")); assertEquals("this is some test data", FileUtils.readFileToString(file1)); } /** * Test replace in file replaced. * DOCUMENT_ME * * @throws Exception the exception */ public void testReplaceInFileReplaced() throws Exception { FileUtils.writeStringToFile(file1, "this is some test data"); assertTrue(UtilSystem.replaceInFile(file1, "test", "replaced", "UTF-8")); assertEquals("this is some replaced data", FileUtils.readFileToString(file1)); } /** * Test method for {@link org.jajuk.util.UtilSystem#getRandom()}. */ public void testGetRandom() { Random rnd = UtilSystem.getRandom(); assertNotNull(rnd); } /** * Test method for. * * {@link org.jajuk.util.UtilSystem#openInExplorer(java.io.File)}. */ public void testOpenInExplorer() { try { UtilSystem.openInExplorer(file1.getParentFile()); } catch (HeadlessException e) { // on some servers we cannot initalize any ui and thus cannot test this } } /** * Test method for. * * {@link org.jajuk.util.UtilSystem#isRunning(java.lang.Process)}. */ public void testIsRunning() { assertTrue(UtilSystem.isRunning(new MockProcess(true))); assertFalse(UtilSystem.isRunning(new MockProcess(false))); } /** * Test method for. * * {@link org.jajuk.util.UtilSystem#getExitValue(java.lang.Process)}. */ public void testGetExitValue() { assertEquals(0, UtilSystem.getExitValue(new MockProcess(false))); assertEquals(-100, UtilSystem.getExitValue(new MockProcess(true))); } /** * DOCUMENT_ME. */ private static final class MockProcess extends Process { /** DOCUMENT_ME. */ boolean throwInExitValue; /** * Instantiates a new mock process. * * @param throwInWait DOCUMENT_ME */ public MockProcess(boolean throwInWait) { super(); this.throwInExitValue = throwInWait; } /* (non-Javadoc) * @see java.lang.Process#waitFor() */ @Override public int waitFor() throws InterruptedException { return 0; } /* (non-Javadoc) * @see java.lang.Process#getOutputStream() */ @Override public OutputStream getOutputStream() { return null; } /* (non-Javadoc) * @see java.lang.Process#getInputStream() */ @Override public InputStream getInputStream() { return null; } /* (non-Javadoc) * @see java.lang.Process#getErrorStream() */ @Override public InputStream getErrorStream() { return null; } /* (non-Javadoc) * @see java.lang.Process#exitValue() */ @Override public int exitValue() { if (throwInExitValue) { throw new IllegalThreadStateException("testexception"); } return 0; } /* (non-Javadoc) * @see java.lang.Process#destroy() */ @Override public void destroy() { } } // helper method to emma-coverage of the unused constructor /** * Test private constructor. * DOCUMENT_ME * * @throws Exception the exception */ public void testPrivateConstructor() throws Exception { // For EMMA code-coverage tests JUnitHelpers.executePrivateConstructor(UtilSystem.class); } } jajuk-1.9.6.orig/src/test/java/org/jajuk/util/error/0000755000175000017500000000000011720500104022144 5ustar drazzibdrazzibjajuk-1.9.6.orig/src/test/java/org/jajuk/util/error/TestTimeOutException.java0000644000175000017500000000257611720500104027126 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.util.error; import org.jajuk.JajukTestCase; /** * DOCUMENT_ME. */ public class TestTimeOutException extends JajukTestCase { /** * Test method for. * * {@link org.jajuk.util.error.TimeOutException#TimeOutException(int)}. */ public void testTimeOutExceptionInt() { new TimeOutException(11); } /** * Test method for. * * {@link org.jajuk.util.error.TimeOutException#TimeOutException(int, java.lang.Throwable)} * . */ public void testTimeOutExceptionIntThrowable() { new TimeOutException(24, new Throwable("TestException")); } } jajuk-1.9.6.orig/src/test/java/org/jajuk/util/error/TestCannotRenameException.java0000644000175000017500000000264311720500104030105 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.util.error; import org.jajuk.JajukTestCase; /** * DOCUMENT_ME. */ public class TestCannotRenameException extends JajukTestCase { /** * Test method for. * * {@link org.jajuk.util.error.CannotRenameException#CannotRenameException(int)} * . */ public void testCannotRenameExceptionInt() { new CannotRenameException(10); } /** * Test method for. * * {@link org.jajuk.util.error.CannotRenameException#CannotRenameException(int, java.lang.Throwable)} * . */ public void testCannotRenameExceptionIntThrowable() { new CannotRenameException(22, new Throwable()); } } jajuk-1.9.6.orig/src/test/java/org/jajuk/util/error/TestJajukException.java0000644000175000017500000000523211720500104026574 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.util.error; import org.jajuk.JajukTestCase; /** * DOCUMENT_ME. */ public class TestJajukException extends JajukTestCase { /** * Test method for. * * {@link org.jajuk.util.error.JajukException#JajukException(int)}. */ public void testJajukExceptionInt() { new JajukException(25); } /** * Test method for. * * {@link org.jajuk.util.error.JajukException#JajukException(int, java.lang.Throwable)} * . */ public void testJajukExceptionIntThrowable() { new JajukException(26, new Throwable("Testexception")); } /** * Test method for {@link org.jajuk.util.error.JajukException#getCode()}. */ public void testGetCode() { JajukException exc = new JajukException(27); assertEquals(27, exc.getCode()); } /** * Test method for. * * {@link org.jajuk.util.error.JajukException#JajukException(int, java.lang.String, java.lang.Throwable)} * . */ public void testJajukExceptionIntStringThrowable() { JajukException exc = new JajukException(28, "testexceptiontext", new Throwable("Testthrowable")); assertTrue(exc.getMessage(), exc.getMessage().contains("testexceptiontext")); } /** * Test jajuk exception int string throwable null. * DOCUMENT_ME */ public void testJajukExceptionIntStringThrowableNull() { new JajukException(28, null, new Throwable("Testthrowable")); } /** * Test method for. * * {@link org.jajuk.util.error.JajukException#JajukException(int, java.lang.String)} * . */ public void testJajukExceptionIntString() { JajukException exc = new JajukException(29, "testexceptiontext2"); assertTrue(exc.getMessage(), exc.getMessage().contains("testexceptiontext2")); } /** * Test jajuk exception int string null. * DOCUMENT_ME */ public void testJajukExceptionIntStringNull() { new JajukException(29, (String) null); } } jajuk-1.9.6.orig/src/test/java/org/jajuk/util/error/TestNoneAccessibleFileException.java0000644000175000017500000000275011720500104031207 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.util.error; import org.jajuk.JajukTestCase; /** * DOCUMENT_ME. */ public class TestNoneAccessibleFileException extends JajukTestCase { /** * Test method for. * * {@link org.jajuk.util.error.NoneAccessibleFileException#NoneAccessibleFileException(int)} * . */ public void testNoneAccessibleFileExceptionInt() { new NoneAccessibleFileException(101); } /** * Test method for. * * {@link org.jajuk.util.error.NoneAccessibleFileException#NoneAccessibleFileException(int, java.lang.Throwable)} * . */ public void testNoneAccessibleFileExceptionIntThrowable() { new NoneAccessibleFileException(23, new Throwable("testexception")); } } jajuk-1.9.6.orig/src/test/java/org/jajuk/util/TestUpgradeManager.java0000644000175000017500000000574011720500104025406 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.util; import org.jajuk.JajukTestCase; /** * DOCUMENT_ME. */ public class TestUpgradeManager extends JajukTestCase { /** DOCUMENT_ME. */ String v1 = "1.8.4"; /** DOCUMENT_ME. */ String v2 = "1.9.1"; /** DOCUMENT_ME. */ String v3 = "1.9.2RC3"; /** DOCUMENT_ME. */ String v4 = "1.8.5"; /** DOCUMENT_ME. */ String v5 = "1.8"; /** DOCUMENT_ME. */ String v6 = "1.9"; /** DOCUMENT_ME. */ String v7 = "1.9.2RC4"; /* * (non-Javadoc) * * @see junit.framework.TestCase#setUp() */ @Override protected void setUp() throws Exception { super.setUp(); } /** * Test method for. * * @throws Exception the exception * {@link org.jajuk.util.UpgradeManager#getNumberRelease(String)}. */ public void testGetNumberRelease() throws Exception { assertEquals(10804, UpgradeManager.getNumberRelease(v1)); assertEquals(10901, UpgradeManager.getNumberRelease(v2)); assertEquals(10902, UpgradeManager.getNumberRelease(v3)); assertEquals(10805, UpgradeManager.getNumberRelease(v4)); assertEquals(10800, UpgradeManager.getNumberRelease(v5)); assertEquals(10900, UpgradeManager.getNumberRelease(v6)); } /** * Test method for. * * @throws Exception the exception * {@link org.jajuk.util.UpgradeManager#isMajorMigration(String,String)}. */ public void testIsMajorMigration() throws Exception { assertEquals(true, UpgradeManager.isMajorMigration(v1, v2)); assertEquals(false, UpgradeManager.isMajorMigration(v1, v4)); assertEquals(false, UpgradeManager.isMajorMigration(v2, v3)); assertEquals(true, UpgradeManager.isMajorMigration(v5, v6)); assertEquals(false, UpgradeManager.isMajorMigration(v3, v7)); } /** * Test method for. * * @throws Exception the exception * {@link org.jajuk.util.UpgradeManager#isNewer(String,String)}. */ public void testIsNewer() throws Exception { assertEquals(true, UpgradeManager.isNewer(v1, v2)); assertEquals(true, UpgradeManager.isNewer(v1, v4)); assertEquals(true, UpgradeManager.isNewer(v2, v3)); assertEquals(false, UpgradeManager.isNewer(v2, v1)); assertEquals(true, UpgradeManager.isNewer(v5, v6)); } } jajuk-1.9.6.orig/src/test/java/org/jajuk/util/TestJajukFileFilter.java0000644000175000017500000001467011720500104025540 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.util; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import java.io.File; import org.jajuk.util.filters.AnyFileFilter; import org.junit.Test; /** * DOCUMENT_ME. */ public class TestJajukFileFilter { /** * Test method for. * * {@link org.jajuk.util.JajukFileFilter#JajukFileFilter(boolean, org.jajuk.util.JajukFileFilter[])} * . */ @Test public final void testJajukFileFilterBooleanJajukFileFilterArray() { new JajukFileFilter(true, new JajukFileFilter[] {}); } /** * Test method for. * * {@link org.jajuk.util.JajukFileFilter#JajukFileFilter(org.jajuk.util.JajukFileFilter[])} * . */ @Test public final void testJajukFileFilterJajukFileFilterArray() { new JajukFileFilter(new JajukFileFilter[] {}); } /** * Test method for. * * {@link org.jajuk.util.JajukFileFilter#JajukFileFilter(java.lang.String[])}. */ @Test public final void testJajukFileFilterStringArray() { new JajukFileFilter(new String[] {}); new JajukFileFilter((String[]) null); new JajukFileFilter(new String[] { "mp3", "ogg" }); } /** * Test method for {@link org.jajuk.util.JajukFileFilter#accept(java.io.File)} * . */ @Test public final void testAcceptFileExtension() { JajukFileFilter filter = new JajukFileFilter(new String[] { "mp3", "ogg" }); assertTrue(filter.accept(new File("test.mp3"))); assertFalse(filter.accept(new File("test.mp2"))); } /** * Test method for {@link org.jajuk.util.JajukFileFilter#accept(java.io.File)} * . */ @Test public final void testAcceptFileFilter() { JajukFileFilter filter = new JajukFileFilter(true, new JajukFileFilter[] { AnyFileFilter .getInstance() }); assertTrue(filter.accept(new File("test"))); } /** * Test method for {@link org.jajuk.util.JajukFileFilter#getDescription()}. */ @Test public final void testGetDescription() { JajukFileFilter filter = new JajukFileFilter(new String[] { "mp3", "ogg" }); assertTrue(filter.getDescription(), filter.getDescription().contains("mp3")); assertTrue(filter.getDescription(), filter.getDescription().contains("ogg")); JajukFileFilter filter2 = new JajukFileFilter(true, new JajukFileFilter[] { AnyFileFilter .getInstance() }); assertEquals("", filter2.getDescription()); } /** * Test method for {@link org.jajuk.util.JajukFileFilter#getExtensions()}. */ @Test public final void testGetExtensions() { JajukFileFilter filter = new JajukFileFilter(new String[] { "mp3", "ogg" }); assertEquals(2, filter.getExtensions().length); assertEquals("mp3", filter.getExtensions()[0]); assertEquals("ogg", filter.getExtensions()[1]); JajukFileFilter filter2 = new JajukFileFilter(true, new JajukFileFilter[] { AnyFileFilter .getInstance() }); assertEquals(0, filter2.getExtensions().length); } /** * Test method for {@link org.jajuk.util.JajukFileFilter#getFilters()}. */ @Test public final void testGetFilters() { JajukFileFilter filter = new JajukFileFilter(new String[] { "mp3", "ogg" }); assertEquals(0, filter.getFilters().length); JajukFileFilter filter2 = new JajukFileFilter(true, new JajukFileFilter[] { AnyFileFilter .getInstance() }); assertEquals(1, filter2.getFilters().length); } /** * Test method for. * * {@link org.jajuk.util.JajukFileFilter#isKnownExtension(java.io.File)}. */ @Test public final void testIsKnownExtension() { JajukFileFilter filter = new JajukFileFilter(new String[] { "mp3", "ogg" }); assertTrue(filter.isKnownExtension(new File("test.mp3"))); assertTrue(filter.isKnownExtension(new File("test.ogg"))); assertFalse(filter.isKnownExtension(new File("test.mp2"))); JajukFileFilter filter2 = new JajukFileFilter(true, new JajukFileFilter[] { AnyFileFilter .getInstance() }); assertFalse(filter2.isKnownExtension(new File("test.mp3"))); assertFalse(filter2.isKnownExtension(new File("test.ogg"))); assertFalse(filter2.isKnownExtension(new File("test.mp2"))); } /** * Test method for. * * {@link org.jajuk.util.JajukFileFilter#setAcceptDirectories(boolean)}. */ @Test public final void testSetAcceptDirectories() { { JajukFileFilter filter = new JajukFileFilter(new String[] { "mp3", "ogg" }); filter.setAcceptDirectories(true); assertTrue(filter.accept(new File(System.getProperty("java.io.tmpdir")))); filter.setAcceptDirectories(false); assertFalse(filter.accept(new File(System.getProperty("java.io.tmpdir")))); } { // ignored for Filter based matching JajukFileFilter filter2 = new JajukFileFilter(true, new JajukFileFilter[] { AnyFileFilter .getInstance() }); filter2.setAcceptDirectories(true); assertFalse(filter2.accept(new File(System.getProperty("java.io.tmpdir")))); filter2.setAcceptDirectories(false); assertFalse(filter2.accept(new File(System.getProperty("java.io.tmpdir")))); } } /** * Test method for {@link org.jajuk.util.JajukFileFilter#show(java.io.File)}. */ @Test public final void testShow() { { JajukFileFilter filter = new JajukFileFilter(new String[] { "mp3", "ogg" }); filter.setAcceptDirectories(true); assertTrue(filter.show(new File(System.getProperty("java.io.tmpdir")))); filter.setAcceptDirectories(false); assertFalse(filter.show(new File(System.getProperty("java.io.tmpdir")))); assertTrue(filter.show(new File("test.mp3"))); assertTrue(filter.show(new File("test.ogg"))); assertFalse(filter.show(new File("test.mp2"))); } } } jajuk-1.9.6.orig/src/test/java/org/jajuk/util/filters/0000755000175000017500000000000011720500104022463 5ustar drazzibdrazzibjajuk-1.9.6.orig/src/test/java/org/jajuk/util/filters/TestAnyFileFilter.java0000644000175000017500000000337611720500104026674 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.util.filters; import java.io.File; import org.jajuk.JajukTestCase; /** * DOCUMENT_ME. */ public class TestAnyFileFilter extends JajukTestCase { /** * Test method for. * * {@link org.jajuk.util.filters.AnyFileFilter#getDescription()}. */ public void testGetDescription() { AnyFileFilter filter = AnyFileFilter.getInstance(); assertEquals("*.*", filter.getDescription()); } /** * Test method for. * * {@link org.jajuk.util.filters.AnyFileFilter#isKnownExtension(java.io.File)} * . */ public void testIsKnownExtension() { AnyFileFilter filter = AnyFileFilter.getInstance(); assertTrue(filter.isKnownExtension(new File("anyfile.something"))); assertTrue(filter.isKnownExtension(new File("anyfilewithoutextension"))); } /** * Test method for {@link org.jajuk.util.filters.AnyFileFilter#getInstance()}. */ public void testGetInstance() { assertNotNull(AnyFileFilter.getInstance()); } } jajuk-1.9.6.orig/src/test/java/org/jajuk/util/filters/TestDirectoryFilter.java0000644000175000017500000000344211720500104027303 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.util.filters; import java.io.File; import org.apache.commons.lang.StringUtils; import org.jajuk.JajukTestCase; /** * DOCUMENT_ME. */ public class TestDirectoryFilter extends JajukTestCase { /** * Test method for. * * {@link org.jajuk.util.filters.DirectoryFilter#accept(java.io.File)}. */ public void testAcceptFile() { assertTrue(DirectoryFilter.getInstance().accept(new File(System.getProperty("java.io.tmpdir")))); assertFalse(DirectoryFilter.getInstance().accept(new File("notexisting"))); } /** * Test method for. * * {@link org.jajuk.util.filters.DirectoryFilter#getDescription()}. */ public void testGetDescription() { // contents is locale specific assertTrue(StringUtils.isNotBlank(DirectoryFilter.getInstance().getDescription())); } /** * Test method for. * * {@link org.jajuk.util.filters.DirectoryFilter#getInstance()}. */ public void testGetInstance() { assertNotNull(DirectoryFilter.getInstance()); } } jajuk-1.9.6.orig/src/test/java/org/jajuk/util/filters/TestGIFFilter.java0000644000175000017500000000253011720500104025741 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.util.filters; import java.io.File; import org.jajuk.JajukTestCase; /** * DOCUMENT_ME. */ public class TestGIFFilter extends JajukTestCase { /** * Test method for {@link org.jajuk.util.filters.GIFFilter#getInstance()}. */ public void testGetInstance() { assertNotNull(GIFFilter.getInstance()); } /** * Test accept. * DOCUMENT_ME */ public void testAccept() { assertTrue(GIFFilter.getInstance().accept(new File("test.gif"))); assertFalse(GIFFilter.getInstance().accept(new File("test.tst"))); } } jajuk-1.9.6.orig/src/test/java/org/jajuk/util/filters/TestHTMLFilter.java0000644000175000017500000000326511720500104026106 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.util.filters; import java.io.File; import org.jajuk.JajukTestCase; /** * DOCUMENT_ME. */ public class TestHTMLFilter extends JajukTestCase { /** * Test method for {@link org.jajuk.util.filters.HTMLFilter#getInstance()}. */ public void testGetInstance() { assertNotNull(HTMLFilter.getInstance()); } /** * Test accept. * DOCUMENT_ME */ public void testAccept() { assertTrue(HTMLFilter.getInstance().accept(new File("test.html"))); assertTrue(HTMLFilter.getInstance().accept(new File("test.HTML"))); // uppercase // if // copied // from // Windows assertTrue(HTMLFilter.getInstance().accept(new File("test.Html"))); // lower/upper // mixed // if // typed // manually assertTrue(HTMLFilter.getInstance().accept(new File("test.hTMl"))); // lower/upper // mixed // if // typed // manually } } jajuk-1.9.6.orig/src/test/java/org/jajuk/util/filters/TestAudioFilter.java0000644000175000017500000000622111720500104026376 0ustar drazzibdrazzib/* * Jajuk * Copyright (C) 2003-2011 The Jajuk Team * http://jajuk.info * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * $Revision$ */ package org.jajuk.util.filters; import java.io.File; import org.apache.commons.lang.StringUtils; import org.jajuk.JajukTestCase; import org.jajuk.base.TypeManager; import org.jajuk.services.startup.StartupCollectionService; /** * DOCUMENT_ME. */ public class TestAudioFilter extends JajukTestCase { /** * Test method for. * * {@link org.jajuk.util.filters.AudioFilter#accept(java.io.File)}. */ public void testAcceptFile() { StartupCollectionService.registerTypes(); // normal files assertFalse(AudioFilter.getInstance().accept(new File("test.tst"))); assertTrue(AudioFilter.getInstance().accept(new File("test.mp3"))); assertTrue(AudioFilter.getInstance().accept(new File("test.ogg"))); assertTrue(AudioFilter.getInstance().accept(new File("test.MP3"))); // files // copied // from // windows // to // linux // might // be // uppercase assertTrue(AudioFilter.getInstance().accept(new File("test.OGG"))); assertTrue(AudioFilter.getInstance().accept(new File("test.mP3"))); // manually // entered // filenames // might // be // lowercase/uppercase // mixed assertTrue(AudioFilter.getInstance().accept(new File("test.ogG"))); // directories, depends on the setting AudioFilter.getInstance().setAcceptDirectories(false); assertFalse(AudioFilter.getInstance().accept(new File(System.getProperty("java.io.tmpdir")))); AudioFilter.getInstance().setAcceptDirectories(true); assertTrue(AudioFilter.getInstance().accept(new File(System.getProperty("java.io.tmpdir")))); } /** * Test method for {@link org.jajuk.util.filters.AudioFilter#getDescription()} * . */ public void testGetDescription() { StartupCollectionService.registerTypes(); assertTrue(AudioFilter.getInstance().getDescription(), StringUtils.containsIgnoreCase( AudioFilter.getInstance().getDescription(), "mp3")); assertTrue(AudioFilter.getInstance().getDescription(), StringUtils.containsIgnoreCase( AudioFilter.getInstance().getDescription(), "ogg")); // try removing all types TypeManager.getInstance().clear(); assertEquals("", AudioFilter.getInstance().getDescription()); } /** * Test method for {@link org.jajuk.util.filters.AudioFilter#getInstance()}. */ public void testGetInstance() { assertNotNull(AudioFilter.getInstance()); } } jajuk-1.9.6.orig/src/scripts/0000755000175000017500000000000011720500104015732 5ustar drazzibdrazzibjajuk-1.9.6.orig/src/scripts/jajuk0000644000175000017500000001073711720500104016771 0ustar drazzibdrazzib#!/bin/bash ## Main starting script for Jajuk VERSION_REPLACED_BY_ANT ########################### ### CONFIGURATION START ### #to use your default java on your system use JAVA_BIN="java", or you can give the full path of java. JAVA_BIN="java" #JVM arguments used by Jajuk. It's important to notice that some of this tuning is useful only when using Java player (when mplayer is not available) # * -client : Use the client JVM, optimized for single user usage [Don't change this setting] # * -Xms : Initial Heap (total JVM reserved memory) size. We set it to a pretty large value because it requires resources to expand heap size and it causes a blanck when using java player. [it can be reduced to 25M by some users if required] # * -Xmx: Maximal Heap size. We set a large size because Out Of Memory errors make the application crash. In some rare cases, very large collection (>200Gb) users could increase this setting (see Performance section in the manual) [Change this setting only if you have very large collection, do not reduce it] # * -XX:MinHeapFreeRatio -XX:MaxHeapFreeRatio : fine running parameters that optimizes JVM to garbage collecting as rarely as possible (because a gc 'end of the world' causes an audio blanck). These values have been set by experience [keep these parameters as it] JAVA_OPTIONS="-client -Xms20M -Xmx2G -XX:MinHeapFreeRatio=5 -XX:MaxHeapFreeRatio=10" #Jajuk options JAJUK_OPTIONS="TEST_FLAG_REPLACED_BY_ANT" #Do you want this script to try to find and use an alternate java version installed on your system that will be more suitable for Jajuk? Use "true" or "false". FIND_OTHER_JAVA="true" ### CONFIGURATION END ### ######################### JAJUK_VERSION="VERSION_REPLACED_BY_ANT" PROGNAME=`basename $0` ## find java version in the default path JAVA_VER=$($JAVA_BIN -version 2>&1 | grep version | cut -d\" -f 2-2 | cut -c 1-3) find_java () { if [ "$JAVA_VER" = "1.6" ] ; then echo " Java version in the default path is: $JAVA_VER" elif [ "$FIND_OTHER_JAVA" = "true" ] ; then echo " Java version in the default path is: $JAVA_VER" echo " Java version in the default path may not be the best or compatible with Jajuk. Let's try other places in case a better version is present..." echo " To turn off this auto-detection funtion, edit $0 and set FIND_OTHER_JAVA to false" echo " Search for other java..." #Search for Java SUN 1.6 if [ -e /usr/lib/j2re1.6-sun/bin/java ] ; then JAVA_BIN="/usr/lib/j2re1.5-sun/bin/java" echo " j2re1.6-sun detected in $JAVA_BIN" elif [ -e /usr/lib/jvm/java-6-sun/jre/bin/java ] ; then JAVA_BIN="/usr/lib/jvm/java-6-sun/jre/bin/java" echo " j2re1.6-sun detected in $JAVA_BIN" fi else echo " Java version in the default path is: $JAVA_VER" echo " No Java compatible version detected, but let's still try to run it!" fi } ##Go in the right /bin directory #test if jajuk has been installed in default directory /usr/lib/jajuk/ via RPM/Deb package if [ "/usr/bin/jajuk" = "$0" ] && [ -e /usr/share/jajuk/bin/jajuk.jar ] ; then JAJUK_HOME="/usr/share/jajuk/bin" cd /usr/share/jajuk/bin else JAJUK_HOME=$(pwd)/`dirname "$0"`/bin cd "$JAJUK_HOME" fi ##Options if [ $# -gt 0 ]; then case $1 in -h|--help) cat < ...] Options: -h, --help This help -v, --version Report Jajuk, Java version and exit EOF exit 1 ;; -v|--version) echo "$PROGNAME ($JAJUK_HOME): $JAJUK_VERSION" echo "Jajuk options: $JAJUK_OPTIONS" find_java echo " Java bin: $JAVA_BIN" $JAVA_BIN -version echo " Java options: $JAVA_OPTIONS" exit 0 ;; esac fi ## Check 32- or 64-bit system if [ "`uname -m`" = "x86_64" ]; then echo Detected a 64-bit operating system, using the lib64 native library directory. ARCHLIB=lib64 RPMLIB=lib64 else ARCHLIB=lib32 RPMLIB=lib fi echo "$PROGNAME ($JAJUK_HOME): $JAJUK_VERSION" ## find installed java version find_java ##let's finally start Jajuk: echo " " echo $JAVA_BIN $JAVA_OPTIONS -Djava.library.path=/usr/lib/jni:/usr/lib:/usr/share/jajuk/$RPMLIB:$JAJUK_HOME/../lib/$ARCHLIB -jar jajuk.jar $JAJUK_OPTIONS $JAVA_BIN $JAVA_OPTIONS -Djava.library.path=/usr/lib/jni:/usr/lib:/usr/share/jajuk/$RPMLIB:"$JAJUK_HOME"/../lib/$ARCHLIB -jar jajuk.jar $JAJUK_OPTIONS jajuk-1.9.6.orig/src/scripts/build.xml0000644000175000017500000005733611720500104017571 0ustar drazzibdrazzib DATE_REPLACED_BY_ANT VERSION_REPLACED_BY_ANT VERSION_REPLACED_BY_ANT TEST_FLAG_REPLACED_BY_ANT TEST_FLAG_REPLACED_BY_ANT JNLP_VERSION_REPLACED_BY_ANT VERSION_REPLACED_BY_ANT TEST_FLAG_REPLACED_BY_ANT VERSION_REPLACED_BY_ANT TEST_FLAG_REPLACED_BY_ANT VERSION_REPLACED_BY_ANT VERSION_REPLACED_BY_ANT TEST_FLAG_REPLACED_BY_ANT jajuk-1.9.6.orig/src/legals/0000755000175000017500000000000011720500104015512 5ustar drazzibdrazzibjajuk-1.9.6.orig/src/legals/LICENSE-CREATIVE-COMMONS.txt0000644000175000017500000003462011720500104021653 0ustar drazzibdrazzibAttribution-ShareAlike 2.5 CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE LEGAL SERVICES. DISTRIBUTION OF THIS LICENSE DOES NOT CREATE AN ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES REGARDING THE INFORMATION PROVIDED, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM ITS USE. License THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS CREATIVE COMMONS PUBLIC LICENSE ("CCPL" OR "LICENSE"). THE WORK IS PROTECTED BY COPYRIGHT AND/OR OTHER APPLICABLE LAW. ANY USE OF THE WORK OTHER THAN AS AUTHORIZED UNDER THIS LICENSE OR COPYRIGHT LAW IS PROHIBITED. BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU ACCEPT AND AGREE TO BE BOUND BY THE TERMS OF THIS LICENSE. THE LICENSOR GRANTS YOU THE RIGHTS CONTAINED HERE IN CONSIDERATION OF YOUR ACCEPTANCE OF SUCH TERMS AND CONDITIONS. 1. Definitions 1. "Collective Work" means a work, such as a periodical issue, anthology or encyclopedia, in which the Work in its entirety in unmodified form, along with a number of other contributions, constituting separate and independent works in themselves, are assembled into a collective whole. A work that constitutes a Collective Work will not be considered a Derivative Work (as defined below) for the purposes of this License. 2. "Derivative Work" means a work based upon the Work or upon the Work and other pre-existing works, such as a translation, musical arrangement, dramatization, fictionalization, motion picture version, sound recording, art reproduction, abridgment, condensation, or any other form in which the Work may be recast, transformed, or adapted, except that a work that constitutes a Collective Work will not be considered a Derivative Work for the purpose of this License. For the avoidance of doubt, where the Work is a musical composition or sound recording, the synchronization of the Work in timed-relation with a moving image ("synching") will be considered a Derivative Work for the purpose of this License. 3. "Licensor" means the individual or entity that offers the Work under the terms of this License. 4. "Original Author" means the individual or entity who created the Work. 5. "Work" means the copyrightable work of authorship offered under the terms of this License. 6. "You" means an individual or entity exercising rights under this License who has not previously violated the terms of this License with respect to the Work, or who has received express permission from the Licensor to exercise rights under this License despite a previous violation. 7. "License Elements" means the following high-level license attributes as selected by Licensor and indicated in the title of this License: Attribution, ShareAlike. 2. Fair Use Rights. Nothing in this license is intended to reduce, limit, or restrict any rights arising from fair use, first sale or other limitations on the exclusive rights of the copyright owner under copyright law or other applicable laws. 3. License Grant. Subject to the terms and conditions of this License, Licensor hereby grants You a worldwide, royalty-free, non-exclusive, perpetual (for the duration of the applicable copyright) license to exercise the rights in the Work as stated below: 1. to reproduce the Work, to incorporate the Work into one or more Collective Works, and to reproduce the Work as incorporated in the Collective Works; 2. to create and reproduce Derivative Works; 3. to distribute copies or phonorecords of, display publicly, perform publicly, and perform publicly by means of a digital audio transmission the Work including as incorporated in Collective Works; 4. to distribute copies or phonorecords of, display publicly, perform publicly, and perform publicly by means of a digital audio transmission Derivative Works. 5. For the avoidance of doubt, where the work is a musical composition: 1. Performance Royalties Under Blanket Licenses. Licensor waives the exclusive right to collect, whether individually or via a performance rights society (e.g. ASCAP, BMI, SESAC), royalties for the public performance or public digital performance (e.g. webcast) of the Work. 2. Mechanical Rights and Statutory Royalties. Licensor waives the exclusive right to collect, whether individually or via a music rights society or designated agent (e.g. Harry Fox Agency), royalties for any phonorecord You create from the Work ("cover version") and distribute, subject to the compulsory license created by 17 USC Section 115 of the US Copyright Act (or the equivalent in other jurisdictions). 6. Webcasting Rights and Statutory Royalties. For the avoidance of doubt, where the Work is a sound recording, Licensor waives the exclusive right to collect, whether individually or via a performance-rights society (e.g. SoundExchange), royalties for the public digital performance (e.g. webcast) of the Work, subject to the compulsory license created by 17 USC Section 114 of the US Copyright Act (or the equivalent in other jurisdictions). The above rights may be exercised in all media and formats whether now known or hereafter devised. The above rights include the right to make such modifications as are technically necessary to exercise the rights in other media and formats. All rights not expressly granted by Licensor are hereby reserved. 4. Restrictions.The license granted in Section 3 above is expressly made subject to and limited by the following restrictions: 1. You may distribute, publicly display, publicly perform, or publicly digitally perform the Work only under the terms of this License, and You must include a copy of, or the Uniform Resource Identifier for, this License with every copy or phonorecord of the Work You distribute, publicly display, publicly perform, or publicly digitally perform. You may not offer or impose any terms on the Work that alter or restrict the terms of this License or the recipients' exercise of the rights granted hereunder. You may not sublicense the Work. You must keep intact all notices that refer to this License and to the disclaimer of warranties. You may not distribute, publicly display, publicly perform, or publicly digitally perform the Work with any technological measures that control access or use of the Work in a manner inconsistent with the terms of this License Agreement. The above applies to the Work as incorporated in a Collective Work, but this does not require the Collective Work apart from the Work itself to be made subject to the terms of this License. If You create a Collective Work, upon notice from any Licensor You must, to the extent practicable, remove from the Collective Work any credit as required by clause 4(c), as requested. If You create a Derivative Work, upon notice from any Licensor You must, to the extent practicable, remove from the Derivative Work any credit as required by clause 4(c), as requested. 2. You may distribute, publicly display, publicly perform, or publicly digitally perform a Derivative Work only under the terms of this License, a later version of this License with the same License Elements as this License, or a Creative Commons iCommons license that contains the same License Elements as this License (e.g. Attribution-ShareAlike 2.5 Japan). You must include a copy of, or the Uniform Resource Identifier for, this License or other license specified in the previous sentence with every copy or phonorecord of each Derivative Work You distribute, publicly display, publicly perform, or publicly digitally perform. You may not offer or impose any terms on the Derivative Works that alter or restrict the terms of this License or the recipients' exercise of the rights granted hereunder, and You must keep intact all notices that refer to this License and to the disclaimer of warranties. You may not distribute, publicly display, publicly perform, or publicly digitally perform the Derivative Work with any technological measures that control access or use of the Work in a manner inconsistent with the terms of this License Agreement. The above applies to the Derivative Work as incorporated in a Collective Work, but this does not require the Collective Work apart from the Derivative Work itself to be made subject to the terms of this License. 3. If you distribute, publicly display, publicly perform, or publicly digitally perform the Work or any Derivative Works or Collective Works, You must keep intact all copyright notices for the Work and provide, reasonable to the medium or means You are utilizing: (i) the name of the Original Author (or pseudonym, if applicable) if supplied, and/or (ii) if the Original Author and/or Licensor designate another party or parties (e.g. a sponsor institute, publishing entity, journal) for attribution in Licensor's copyright notice, terms of service or by other reasonable means, the name of such party or parties; the title of the Work if supplied; to the extent reasonably practicable, the Uniform Resource Identifier, if any, that Licensor specifies to be associated with the Work, unless such URI does not refer to the copyright notice or licensing information for the Work; and in the case of a Derivative Work, a credit identifying the use of the Work in the Derivative Work (e.g., "French translation of the Work by Original Author," or "Screenplay based on original Work by Original Author"). Such credit may be implemented in any reasonable manner; provided, however, that in the case of a Derivative Work or Collective Work, at a minimum such credit will appear where any other comparable authorship credit appears and in a manner at least as prominent as such other comparable authorship credit. 5. Representations, Warranties and Disclaimer UNLESS OTHERWISE AGREED TO BY THE PARTIES IN WRITING, LICENSOR OFFERS THE WORK AS-IS AND MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY KIND CONCERNING THE MATERIALS, EXPRESS, IMPLIED, STATUTORY OR OTHERWISE, INCLUDING, WITHOUT LIMITATION, WARRANTIES OF TITLE, MERCHANTIBILITY, FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT, OR THE ABSENCE OF LATENT OR OTHER DEFECTS, ACCURACY, OR THE PRESENCE OF ABSENCE OF ERRORS, WHETHER OR NOT DISCOVERABLE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF IMPLIED WARRANTIES, SO SUCH EXCLUSION MAY NOT APPLY TO YOU. 6. Limitation on Liability. EXCEPT TO THE EXTENT REQUIRED BY APPLICABLE LAW, IN NO EVENT WILL LICENSOR BE LIABLE TO YOU ON ANY LEGAL THEORY FOR ANY SPECIAL, INCIDENTAL, CONSEQUENTIAL, PUNITIVE OR EXEMPLARY DAMAGES ARISING OUT OF THIS LICENSE OR THE USE OF THE WORK, EVEN IF LICENSOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 7. Termination 1. This License and the rights granted hereunder will terminate automatically upon any breach by You of the terms of this License. Individuals or entities who have received Derivative Works or Collective Works from You under this License, however, will not have their licenses terminated provided such individuals or entities remain in full compliance with those licenses. Sections 1, 2, 5, 6, 7, and 8 will survive any termination of this License. 2. Subject to the above terms and conditions, the license granted here is perpetual (for the duration of the applicable copyright in the Work). Notwithstanding the above, Licensor reserves the right to release the Work under different license terms or to stop distributing the Work at any time; provided, however that any such election will not serve to withdraw this License (or any other license that has been, or is required to be, granted under the terms of this License), and this License will continue in full force and effect unless terminated as stated above. 8. Miscellaneous 1. Each time You distribute or publicly digitally perform the Work or a Collective Work, the Licensor offers to the recipient a license to the Work on the same terms and conditions as the license granted to You under this License. 2. Each time You distribute or publicly digitally perform a Derivative Work, Licensor offers to the recipient a license to the original Work on the same terms and conditions as the license granted to You under this License. 3. If any provision of this License is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this License, and without further action by the parties to this agreement, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable. 4. No term or provision of this License shall be deemed waived and no breach consented to unless such waiver or consent shall be in writing and signed by the party to be charged with such waiver or consent. 5. This License constitutes the entire agreement between the parties with respect to the Work licensed here. There are no understandings, agreements or representations with respect to the Work not specified here. Licensor shall not be bound by any additional provisions that may appear in any communication from You. This License may not be modified without the mutual written agreement of the Licensor and You. Creative Commons is not a party to this License, and makes no warranty whatsoever in connection with the Work. Creative Commons will not be liable to You or any party on any legal theory for any damages whatsoever, including without limitation any general, special, incidental or consequential damages arising in connection to this license. Notwithstanding the foregoing two (2) sentences, if Creative Commons has expressly identified itself as the Licensor hereunder, it shall have all rights and obligations of Licensor. Except for the limited purpose of indicating to the public that the Work is licensed under the CCPL, neither party will use the trademark "Creative Commons" or any related trademark or logo of Creative Commons without the prior written consent of Creative Commons. Any permitted use will be in compliance with Creative Commons' then-current trademark usage guidelines, as may be published on its website or otherwise made available upon request from time to time. Creative Commons may be contacted at http://creativecommons.org/. jajuk-1.9.6.orig/src/legals/DEPENDENCIES.txt0000644000175000017500000001041411720500104020101 0ustar drazzibdrazzibJajuk Dependencies ================== This list is an extract from http://jajuk.info/index.php/jajuk_dependencies NOTE FOR MAINTENERS : edit first the wiki page, then update this file. This is the list of API, frameworks or packaging tools (jars) included in this directory. We would like to thank their teams for making Jajuk possible. These third party softwares used by Jajuk come with their own licenses as listed out below. A copy of the following licenses is include in this directory. ------------------------------------------------------------------------------- GPL => LICENSE-GPL.txt LGPL => LICENSE-LGPL.txt BSD => LICENSE-BSD.txt Apache => LICENSE-Apache.txt Creative Commons => LICENSE-CREATIVE-COMMONS.txt CeCILL => LICENSE_CeCILL_V2-en.txt ------------------------------------------------------------------------------- --- Sound --- Project : Javalayer, BasicPlayer, Tritonus, mp3spi By : JavaZoom team Used for : MP3 sound engine URL : http://www.javazoom.net/javalayer/javalayer.html License : LGPL Project : Jogg, JOrbis, Vorbis, Vorbis SPI By : JavaZoom team Used for : Ogg Vorbis sound engine URL : http://www.javazoom.net License : LGPL Project : MPlayer By : MPlayer team Used for : Multi-format player. Mplayer is the default Jajuk player for all formats URL : http://www.mplayerhq.hu License : GPL --- Tags --- Project : JAudiotagger By : JAudiotagger team Used for : Java multi-format read / write tags library URL : http://www.jthink.net/jaudiotagger/index.jsp License : GLPL --- Look and feel --- Project : Substance By : Kirill Grouchnikov Used for : A cross-platform look & feel for Swing applications URL : https://substance.dev.java.net/ License : BSD --- GUI helpers --- Project : Jcommon By : Object Refinery Limited Used for : Common UI objects library URL : http://www.jfree.org/jcommon/ License : LGPL Project : JFreechart By : Object Refinery Limited Used for : Charts library URL : http://www.jfree.org/jfreechart/ License : LGPL Project : MigLayout By : MiG InfoCom AB Used for : Swing/SWT layout manager URL : http://www.miglayout.com License : BSD Project : SwingX By : Sun Microsystems Used for : Advanced Swing widgets like JXTable URL : https://swingx.dev.java.net License : LGPL Project : QDWizard By : QDWizard Team Used for : Swing Wizard API URL : http://qdwizard.sourceforge.net License : LGPL Project : VLDocking By : VLSolutions Used for : Docking framework URL : http://www.vlsolutions.com/en/products/docking/index.php License : CeCILL Project : JHlabs Filters By : JHLabs Used for : Images filters URL : http://www.jhlabs.com/ip/filters License : Apache 2.0 Project : Cobra By : Cobra team Used for : Web Browser library URL : http://html.xamjwg.org/cobra.jsp License : GPL Project : Animation By : JGoodies team Used for : Text animation API URL : http://www.jgoodies.com/freeware/animation/ License : LGPL --- Native/system integration --- Project : JIntellitype By : Meloware Used for : Intellitype keyboard support URL : http://melloware.com/products/jintellitype/ License : Apache 2.0 Project : D-Bus Java Bindings By : freedesktop.org Used for : D-Bus support URL : http://www.freedesktop.org/wiki/Software/DBusBindings License : Academic Free License version 2.1 or GNU Lesser/Library General Public License version 2 Project : Unix Sockets Library By : Matthew Johnson - dbus@matthew.ath.cx Used for : Support for Unix-sockets required for D-Bus support URL : http://www.matthew.ath.cx/projects/java/ License : LGPL version 2.1 --- Logging --- Project : Log4j By : Apache Jakarta Log4j team Used for : Java logging API URL : http://logging.apache.org/log4j/ License : Apache License Project : Commons Logging By : Apache Jakarta Logging team Used for : Common Logging facilities used by many Jakarta API URL : http://jakarta.apache.org/commons/logging/ License : Apache License --- Misc --- Project : Common-jukebox By : Common-jukebox team Used for : Various shared code between several jukebox projects URL : http://www.assembla.com/wiki/show/common-jukebox License : LGPL jajuk-1.9.6.orig/src/legals/LICENSE-LGPL.txt0000644000175000017500000006363711720500104020110 0ustar drazzibdrazzib GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 Free Software Foundation, Inc. 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish); that you receive source code or can get it if you want it; that you can change the software and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. , 1 April 1990 Ty Coon, President of Vice That's all there is to it! jajuk-1.9.6.orig/src/legals/LICENSE-BSD.txt0000644000175000017500000000273311720500104017750 0ustar drazzibdrazzibCopyright (c) The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. jajuk-1.9.6.orig/src/legals/DERIVATED.txt0000644000175000017500000001053611720500104017567 0ustar drazzibdrazzib================== The OFFICIAL list of API, frameworks or packaging tools Jajuk includes can be found on http://jajuk.info/index.php/jajuk_license_derivated NOTE FOR MAINTENERS : edit first the wiki page, then update this file. This file list external code source that Jajuk incorporated with or without changes. This code is located in the 'ext' Java package. ------------------------------------------------------- Swingx (various dates) https://swingx.dev.java.net/ The original codes are Copyright (C) 2006 Sun Microsystems, Inc. and are licensed under LGPL 2.1 license. Used for: Swingx workarounds (reported to Swingx team), modified 'JVM' class Files has been adapted to Jajuk by the Jajuk Team. Jajuk Copyright (C) 2007 The Jajuk Team ------------------------------------------------------- aTunes 1.6.0 http://www.atunes.org http://sourceforge.net/projects/atunes Used for: Lyrics search engine with fixes (reported to the atunes team) and Jajuk integration, adapted Proxy code, adapted Last.FM API. Files has been adapted to Jajuk by the Jajuk Team. Jajuk Copyright (C) 2007 The Jajuk Team The original codes are Copyright (C) 2006-2007 Alex Aranda (fleax) and are licensed under GPL 2.1 license. ------------------------------------------------------- DropDownButton No Legals information, Public domain code found at http://www.jroller.com/santhosh/date/20050528 Author: Santhosh kumar - santhosh@in.fiorano.com Used for : Drop down button Files has been adapted to Jajuk by the Jajuk Team. Jajuk Copyright (C) 2007 The Jajuk Team ------------------------------------------------------- FlowScrollPanel No Legals information, Public domain code found at: http://groups.google.fr/group/comp.lang.java.gui/browse_thread/thread/11403002a25da9a3/da4cea55cf283a52?q=%2BJscrollPane++%2Bflowlayout&rnum=2&hl=fr#da4cea55cf283a52 Author: Chris Long...@cs.berkeley.edu http://www.cs.berkeley.edu/~allanl Used for : Flow Scroll panel no provided in Swing API Files has been adapted to Jajuk by the Jajuk Team. Jajuk Copyright (C) 2007 The Jajuk Team ------------------------------------------------------- Part of Zeus API http://zeus-jscl.sourceforge.net/ The original codes are Copyright (C) 2004,2005 Gregory Kotsaftis gregkotsaftis@yahoo.com and are licensed under LGPL 2.1 license. Used for: Splash screen Files has been adapted to Jajuk by the Jajuk Team. Jajuk Copyright (C) 2007 The Jajuk Team ------------------------------------------------------- SliderMenuItem No Legals information, Public domain code found at: http://www.java2s.com/ExampleCode/Swing-JFC/AnexampleoftheJPopupMenuinaction.htm (the link is now broken) No author information Used for : adding a slider as a menu item Files has been adapted to Jajuk by the Jajuk Team. Jajuk Copyright (C) 2007 The Jajuk Team ------------------------------------------------------- Scrollable menus No Legals information, Public domain code found at: http://www.beginner-java-tutorial.com/scrollable-jpopupmenu.html author: balajihe Used for : adding scrollable behavior to menu items Files has been adapted to Jajuk by the Jajuk Team. Jajuk Copyright (C) 2007 The Jajuk Team ------------------------------------------------------- ProcessLauncher class LGPL code found at http://ydisanto.ftp-developpez.com/tutoriels/j2se/runtime/fichiers/ProcessLauncher.java authors: Fabio MARAZZATO, Yann D'ISANTO Used for : Executing external process ------------------------------------------------------- JXTrayIcon class Code modified from Alexander Potochkin's JXTray class at https://swinghelper.dev.java.net/source/browse/swinghelper/src/java/org/jdesktop/swinghelper/tray/JXTrayIcon.java?view=markup Copyright 2008 Sun Microsystems Used for : enhanced systray popup supporting swing widgets ------------------------------------------------------- MersenneTwister class OSI-compatible license provided in the MersenneTwister.java file. Copyright (c) 2003 by Sean Luke.
    * Portions copyright (c) 1993 by Michael Lecuyer.
    * All rights reserved.
    Used for : pseudo-random numbers generator ------------------------------------------------------- Util class (org.jajuk.util package) This class contains various code extracts found on the web, the URL is given in the method javadoc comment when it is the case. jajuk-1.9.6.orig/src/legals/AUTHORS.txt0000644000175000017500000000210411720500104017375 0ustar drazzibdrazzibJajuk authors sorted by number of commits Bertrand Florat Dominik Stadler Fsck222 Florian Strienz Varun Hiremath Gerhard Dietrichsteiner Josep Carles Collazos Erwan Richard Vitaliy Tamm Ronak Patel Sebastien Gringoire Eleftherios Spyromitros Laurent "haylem" Malvert Riccardo Capecchi Bart Cremers Antonis Thomas David Hadley Masiar Farahani Fabrice Dutron jajuk-1.9.6.orig/src/legals/LICENSE_CeCILL_V2-en.txt0000644000175000017500000005115511720500104021366 0ustar drazzibdrazzib CeCILL FREE SOFTWARE LICENSE AGREEMENT Notice This Agreement is a Free Software license agreement that is the result of discussions between its authors in order to ensure compliance with the two main principles guiding its drafting: * firstly, compliance with the principles governing the distribution of Free Software: access to source code, broad rights granted to users, * secondly, the election of a governing law, French law, with which it is conformant, both as regards the law of torts and intellectual property law, and the protection that it offers to both authors and holders of the economic rights over software. The authors of the CeCILL (for Ce[a] C[nrs] I[nria] L[ogiciel] L[ibre]) license are: Commissariat � l'Energie Atomique - CEA, a public scientific, technical and industrial research establishment, having its principal place of business at 25 rue Leblanc, immeuble Le Ponant D, 75015 Paris, France. Centre National de la Recherche Scientifique - CNRS, a public scientific and technological establishment, having its principal place of business at 3 rue Michel-Ange, 75794 Paris cedex 16, France. Institut National de Recherche en Informatique et en Automatique - INRIA, a public scientific and technological establishment, having its principal place of business at Domaine de Voluceau, Rocquencourt, BP 105, 78153 Le Chesnay cedex, France. Preamble The purpose of this Free Software license agreement is to grant users the right to modify and redistribute the software governed by this license within the framework of an open source distribution model. The exercising of these rights is conditional upon certain obligations for users so as to preserve this status for all subsequent redistributions. In consideration of access to the source code and the rights to copy, modify and redistribute granted by the license, users are provided only with a limited warranty and the software's author, the holder of the economic rights, and the successive licensors only have limited liability. In this respect, the risks associated with loading, using, modifying and/or developing or reproducing the software by the user are brought to the user's attention, given its Free Software status, which may make it complicated to use, with the result that its use is reserved for developers and experienced professionals having in-depth computer knowledge. Users are therefore encouraged to load and test the suitability of the software as regards their requirements in conditions enabling the security of their systems and/or data to be ensured and, more generally, to use and operate it in the same conditions of security. This Agreement may be freely reproduced and published, provided it is not altered, and that no provisions are either added or removed herefrom. This Agreement may apply to any or all software for which the holder of the economic rights decides to submit the use thereof to its provisions. Article 1 - DEFINITIONS For the purpose of this Agreement, when the following expressions commence with a capital letter, they shall have the following meaning: Agreement: means this license agreement, and its possible subsequent versions and annexes. Software: means the software in its Object Code and/or Source Code form and, where applicable, its documentation, "as is" when the Licensee accepts the Agreement. Initial Software: means the Software in its Source Code and possibly its Object Code form and, where applicable, its documentation, "as is" when it is first distributed under the terms and conditions of the Agreement. Modified Software: means the Software modified by at least one Contribution. Source Code: means all the Software's instructions and program lines to which access is required so as to modify the Software. Object Code: means the binary files originating from the compilation of the Source Code. Holder: means the holder(s) of the economic rights over the Initial Software. Licensee: means the Software user(s) having accepted the Agreement. Contributor: means a Licensee having made at least one Contribution. Licensor: means the Holder, or any other individual or legal entity, who distributes the Software under the Agreement. Contribution: means any or all modifications, corrections, translations, adaptations and/or new functions integrated into the Software by any or all Contributors, as well as any or all Internal Modules. Module: means a set of sources files including their documentation that enables supplementary functions or services in addition to those offered by the Software. External Module: means any or all Modules, not derived from the Software, so that this Module and the Software run in separate address spaces, with one calling the other when they are run. Internal Module: means any or all Module, connected to the Software so that they both execute in the same address space. GNU GPL: means the GNU General Public License version 2 or any subsequent version, as published by the Free Software Foundation Inc. Parties: mean both the Licensee and the Licensor. These expressions may be used both in singular and plural form. Article 2 - PURPOSE The purpose of the Agreement is the grant by the Licensor to the Licensee of a non-exclusive, transferable and worldwide license for the Software as set forth in Article 5 hereinafter for the whole term of the protection granted by the rights over said Software. Article 3 - ACCEPTANCE 3.1 The Licensee shall be deemed as having accepted the terms and conditions of this Agreement upon the occurrence of the first of the following events: * (i) loading the Software by any or all means, notably, by downloading from a remote server, or by loading from a physical medium; * (ii) the first time the Licensee exercises any of the rights granted hereunder. 3.2 One copy of the Agreement, containing a notice relating to the characteristics of the Software, to the limited warranty, and to the fact that its use is restricted to experienced users has been provided to the Licensee prior to its acceptance as set forth in Article 3.1 hereinabove, and the Licensee hereby acknowledges that it has read and understood it. Article 4 - EFFECTIVE DATE AND TERM 4.1 EFFECTIVE DATE The Agreement shall become effective on the date when it is accepted by the Licensee as set forth in Article 3.1. 4.2 TERM The Agreement shall remain in force for the entire legal term of protection of the economic rights over the Software. Article 5 - SCOPE OF RIGHTS GRANTED The Licensor hereby grants to the Licensee, who accepts, the following rights over the Software for any or all use, and for the term of the Agreement, on the basis of the terms and conditions set forth hereinafter. Besides, if the Licensor owns or comes to own one or more patents protecting all or part of the functions of the Software or of its components, the Licensor undertakes not to enforce the rights granted by these patents against successive Licensees using, exploiting or modifying the Software. If these patents are transferred, the Licensor undertakes to have the transferees subscribe to the obligations set forth in this paragraph. 5.1 RIGHT OF USE The Licensee is authorized to use the Software, without any limitation as to its fields of application, with it being hereinafter specified that this comprises: 1. permanent or temporary reproduction of all or part of the Software by any or all means and in any or all form. 2. loading, displaying, running, or storing the Software on any or all medium. 3. entitlement to observe, study or test its operation so as to determine the ideas and principles behind any or all constituent elements of said Software. This shall apply when the Licensee carries out any or all loading, displaying, running, transmission or storage operation as regards the Software, that it is entitled to carry out hereunder. 5.2 ENTITLEMENT TO MAKE CONTRIBUTIONS The right to make Contributions includes the right to translate, adapt, arrange, or make any or all modifications to the Software, and the right to reproduce the resulting software. The Licensee is authorized to make any or all Contributions to the Software provided that it includes an explicit notice that it is the author of said Contribution and indicates the date of the creation thereof. 5.3 RIGHT OF DISTRIBUTION In particular, the right of distribution includes the right to publish, transmit and communicate the Software to the general public on any or all medium, and by any or all means, and the right to market, either in consideration of a fee, or free of charge, one or more copies of the Software by any means. The Licensee is further authorized to distribute copies of the modified or unmodified Software to third parties according to the terms and conditions set forth hereinafter. 5.3.1 DISTRIBUTION OF SOFTWARE WITHOUT MODIFICATION The Licensee is authorized to distribute true copies of the Software in Source Code or Object Code form, provided that said distribution complies with all the provisions of the Agreement and is accompanied by: 1. a copy of the Agreement, 2. a notice relating to the limitation of both the Licensor's warranty and liability as set forth in Articles 8 and 9, and that, in the event that only the Object Code of the Software is redistributed, the Licensee allows future Licensees unhindered access to the full Source Code of the Software by indicating how to access it, it being understood that the additional cost of acquiring the Source Code shall not exceed the cost of transferring the data. 5.3.2 DISTRIBUTION OF MODIFIED SOFTWARE When the Licensee makes a Contribution to the Software, the terms and conditions for the distribution of the resulting Modified Software become subject to all the provisions of this Agreement. The Licensee is authorized to distribute the Modified Software, in source code or object code form, provided that said distribution complies with all the provisions of the Agreement and is accompanied by: 1. a copy of the Agreement, 2. a notice relating to the limitation of both the Licensor's warranty and liability as set forth in Articles 8 and 9, and that, in the event that only the object code of the Modified Software is redistributed, the Licensee allows future Licensees unhindered access to the full source code of the Modified Software by indicating how to access it, it being understood that the additional cost of acquiring the source code shall not exceed the cost of transferring the data. 5.3.3 DISTRIBUTION OF EXTERNAL MODULES When the Licensee has developed an External Module, the terms and conditions of this Agreement do not apply to said External Module, that may be distributed under a separate license agreement. 5.3.4 COMPATIBILITY WITH THE GNU GPL The Licensee can include a code that is subject to the provisions of one of the versions of the GNU GPL in the Modified or unmodified Software, and distribute that entire code under the terms of the same version of the GNU GPL. The Licensee can include the Modified or unmodified Software in a code that is subject to the provisions of one of the versions of the GNU GPL, and distribute that entire code under the terms of the same version of the GNU GPL. Article 6 - INTELLECTUAL PROPERTY 6.1 OVER THE INITIAL SOFTWARE The Holder owns the economic rights over the Initial Software. Any or all use of the Initial Software is subject to compliance with the terms and conditions under which the Holder has elected to distribute its work and no one shall be entitled to modify the terms and conditions for the distribution of said Initial Software. The Holder undertakes that the Initial Software will remain ruled at least by this Agreement, for the duration set forth in Article 4.2. 6.2 OVER THE CONTRIBUTIONS The Licensee who develops a Contribution is the owner of the intellectual property rights over this Contribution as defined by applicable law. 6.3 OVER THE EXTERNAL MODULES The Licensee who develops an External Module is the owner of the intellectual property rights over this External Module as defined by applicable law and is free to choose the type of agreement that shall govern its distribution. 6.4 JOINT PROVISIONS The Licensee expressly undertakes: 1. not to remove, or modify, in any manner, the intellectual property notices attached to the Software; 2. to reproduce said notices, in an identical manner, in the copies of the Software modified or not. The Licensee undertakes not to directly or indirectly infringe the intellectual property rights of the Holder and/or Contributors on the Software and to take, where applicable, vis-�-vis its staff, any and all measures required to ensure respect of said intellectual property rights of the Holder and/or Contributors. Article 7 - RELATED SERVICES 7.1 Under no circumstances shall the Agreement oblige the Licensor to provide technical assistance or maintenance services for the Software. However, the Licensor is entitled to offer this type of services. The terms and conditions of such technical assistance, and/or such maintenance, shall be set forth in a separate instrument. Only the Licensor offering said maintenance and/or technical assistance services shall incur liability therefor. 7.2 Similarly, any Licensor is entitled to offer to its licensees, under its sole responsibility, a warranty, that shall only be binding upon itself, for the redistribution of the Software and/or the Modified Software, under terms and conditions that it is free to decide. Said warranty, and the financial terms and conditions of its application, shall be subject of a separate instrument executed between the Licensor and the Licensee. Article 8 - LIABILITY 8.1 Subject to the provisions of Article 8.2, the Licensee shall be entitled to claim compensation for any direct loss it may have suffered from the Software as a result of a fault on the part of the relevant Licensor, subject to providing evidence thereof. 8.2 The Licensor's liability is limited to the commitments made under this Agreement and shall not be incurred as a result of in particular: (i) loss due the Licensee's total or partial failure to fulfill its obligations, (ii) direct or consequential loss that is suffered by the Licensee due to the use or performance of the Software, and (iii) more generally, any consequential loss. In particular the Parties expressly agree that any or all pecuniary or business loss (i.e. loss of data, loss of profits, operating loss, loss of customers or orders, opportunity cost, any disturbance to business activities) or any or all legal proceedings instituted against the Licensee by a third party, shall constitute consequential loss and shall not provide entitlement to any or all compensation from the Licensor. Article 9 - WARRANTY 9.1 The Licensee acknowledges that the scientific and technical state-of-the-art when the Software was distributed did not enable all possible uses to be tested and verified, nor for the presence of possible defects to be detected. In this respect, the Licensee's attention has been drawn to the risks associated with loading, using, modifying and/or developing and reproducing the Software which are reserved for experienced users. The Licensee shall be responsible for verifying, by any or all means, the suitability of the product for its requirements, its good working order, and for ensuring that it shall not cause damage to either persons or properties. 9.2 The Licensor hereby represents, in good faith, that it is entitled to grant all the rights over the Software (including in particular the rights set forth in Article 5). 9.3 The Licensee acknowledges that the Software is supplied "as is" by the Licensor without any other express or tacit warranty, other than that provided for in Article 9.2 and, in particular, without any warranty as to its commercial value, its secured, safe, innovative or relevant nature. Specifically, the Licensor does not warrant that the Software is free from any error, that it will operate without interruption, that it will be compatible with the Licensee's own equipment and software configuration, nor that it will meet the Licensee's requirements. 9.4 The Licensor does not either expressly or tacitly warrant that the Software does not infringe any third party intellectual property right relating to a patent, software or any other property right. Therefore, the Licensor disclaims any and all liability towards the Licensee arising out of any or all proceedings for infringement that may be instituted in respect of the use, modification and redistribution of the Software. Nevertheless, should such proceedings be instituted against the Licensee, the Licensor shall provide it with technical and legal assistance for its defense. Such technical and legal assistance shall be decided on a case-by-case basis between the relevant Licensor and the Licensee pursuant to a memorandum of understanding. The Licensor disclaims any and all liability as regards the Licensee's use of the name of the Software. No warranty is given as regards the existence of prior rights over the name of the Software or as regards the existence of a trademark. Article 10 - TERMINATION 10.1 In the event of a breach by the Licensee of its obligations hereunder, the Licensor may automatically terminate this Agreement thirty (30) days after notice has been sent to the Licensee and has remained ineffective. 10.2 A Licensee whose Agreement is terminated shall no longer be authorized to use, modify or distribute the Software. However, any licenses that it may have granted prior to termination of the Agreement shall remain valid subject to their having been granted in compliance with the terms and conditions hereof. Article 11 - MISCELLANEOUS 11.1 EXCUSABLE EVENTS Neither Party shall be liable for any or all delay, or failure to perform the Agreement, that may be attributable to an event of force majeure, an act of God or an outside cause, such as defective functioning or interruptions of the electricity or telecommunications networks, network paralysis following a virus attack, intervention by government authorities, natural disasters, water damage, earthquakes, fire, explosions, strikes and labor unrest, war, etc. 11.2 Any failure by either Party, on one or more occasions, to invoke one or more of the provisions hereof, shall under no circumstances be interpreted as being a waiver by the interested Party of its right to invoke said provision(s) subsequently. 11.3 The Agreement cancels and replaces any or all previous agreements, whether written or oral, between the Parties and having the same purpose, and constitutes the entirety of the agreement between said Parties concerning said purpose. No supplement or modification to the terms and conditions hereof shall be effective as between the Parties unless it is made in writing and signed by their duly authorized representatives. 11.4 In the event that one or more of the provisions hereof were to conflict with a current or future applicable act or legislative text, said act or legislative text shall prevail, and the Parties shall make the necessary amendments so as to comply with said act or legislative text. All other provisions shall remain effective. Similarly, invalidity of a provision of the Agreement, for any reason whatsoever, shall not cause the Agreement as a whole to be invalid. 11.5 LANGUAGE The Agreement is drafted in both French and English and both versions are deemed authentic. Article 12 - NEW VERSIONS OF THE AGREEMENT 12.1 Any person is authorized to duplicate and distribute copies of this Agreement. 12.2 So as to ensure coherence, the wording of this Agreement is protected and may only be modified by the authors of the License, who reserve the right to periodically publish updates or new versions of the Agreement, each with a separate number. These subsequent versions may address new issues encountered by Free Software. 12.3 Any Software distributed under a given version of the Agreement may only be subsequently distributed under the same version of the Agreement or a subsequent version, subject to the provisions of Article 5.3.4. Article 13 - GOVERNING LAW AND JURISDICTION 13.1 The Agreement is governed by French law. The Parties agree to endeavor to seek an amicable solution to any disagreements or disputes that may arise during the performance of the Agreement. 13.2 Failing an amicable solution within two (2) months as from their occurrence, and unless emergency proceedings are necessary, the disagreements or disputes shall be referred to the Paris Courts having jurisdiction, by the more diligent Party. Version 2.0 dated 2006-09-05. jajuk-1.9.6.orig/src/legals/LICENSE-GPL.txt0000644000175000017500000004310411720500104017757 0ustar drazzibdrazzib GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. jajuk-1.9.6.orig/src/legals/LICENSE-Apache.txt0000644000175000017500000002613511720500104020523 0ustar drazzibdrazzib Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. jajuk-1.9.6.orig/src/doc/0000755000175000017500000000000011720500104015010 5ustar drazzibdrazzibjajuk-1.9.6.orig/src/doc/README.html0000644000175000017500000000216011720500104016632 0ustar drazzibdrazzib Jajuk release notes

    Jajuk Release Notes

    Please have a look at these important notes

    Requirements

    • Java : JRE 1.6 and above. Can be downloaded for free if required.

    • Screen resolution : 1024x768 and above recommended

    • Minimum configuration : Intel Pentium 3, 600 Mhz, 256MB RAM and equivalents

    Legals

    Jajuk, Copyright 2003-2011 Jajuk team. License : GPL V2 (Free Software). See License provided with the program.

    FAQ

    Faq

    Issues/bugs

    Report bugs or wishes here

    Contact us

    Contact us and discussion Forum: here jajuk-1.9.6.orig/src/doc/specs.pdf0000644000175000017500000367317311720500104016644 0ustar drazzibdrazzib%PDF-1.4 % 1 0 obj << /Length 2 0 R /Filter /FlateDecode >> stream x[K$ /` H,Z$5cAXGJ.?+\<3]?_kp:~5\k8WswuQ@wJLpZmJ)>SQO E i௾)]_2czP 1B1, eUƨ*fbMvPMt߲7˿,*ǂ6o=/~o%3'MVeP1ƈ?Fd?}_!I}N˔>ۡ6xk߭e߉/dc9꭪}. e@]WF>RfqrhE_jV%{N eKJ/i]+8fzxH0vQMV35]ܹ074c~k#ìV֮j2PhכYgDI ay2<jƱHfh#-ی`dL9T5-xZJ0m>2WzT)nF$tA\m7]3.+h~4uk> -i (|\`Iv+-ҹ`ѩT]̸YfCșd?b&NP'ieOs ٷivfdmf^1n-]UM 2U}/ˍNE<>CQZH3ʉ^/ ]NTBhэկێoh5gez]M#- 9?̀}&kX㸆9qc7;o?u9Tk'FБ@/fw2{v5`$i'u86m|ӱص3bЀY5ힲYw.|]z+~dۖ6n0N#&⎍>il:AR(2Jqm֒5=ʦNܭ'wm"Ut}vsv``؈jHшboV貍jrCId S4Ƹ N<儵BaۤMmI g-AL^y=7%ޚdݓs7I\zkl3XA,fm3?˅Xg' K:sTyagv%/4Sl|(L/A/z=p>|U[q6d)Ά4HLqtEYuqR 60;Zfl[Z7,^uU鰉qSNwdt;S-o-#PEtUgn6+>'mƆf=&gKMmMINA=ć2ǧM&ө{ۄvr6 SѥF)"_pٔNHo|lBHSwӹ糊O*ʷr|<8 Z1+F:Fע脯- ZyVb3>h0cyG 3 lO̫IKk)$~%įc~ .#H&W*qED;^}Nci: HJD@%x&)24A _%&(M4I q J` J MPiT 0>`kp _)V((ז]_<AqS<E" HD+?+?  . pvp~H@ i!M Ȁ46h*4yb FGzM2KA\rI"&5J6CĘd"M[\MLImV<LBVEUZ܀+nFFMƩ\]?|J> stream x]ي,}Pφ)k C~?`0cy;J[i=UEv:RJGR(~ gzj)?uǟN}vo/ߟ5?CsnOyGs}п?cݏgzȯ(%GB?ԣׇXzv}"΍z]4gOCI/wF {Og"FWɇDfrQ/ eJ`U6N+F51^żf0U׽DU>< Zc!vS)vlMv^nQ*i&Қ3-2 j 3", z߹':#$q˻Ojj0nX$_#c$Do1ۤܶ߈aa|Sf= L5zW5FC5e`ElљOOjmθSBNfm US`UOC-p"OGW} wː+<߈銏6=%\"M>Eђ6W,> ^I"|azlXw. ?DM*@Jgdw[!ә*IXYJ㗶U>$j4#D'byE,)c5d]a&f^Ed+lhBU'Y=*QW{˃67C-Ǡ/QhXYE*¯t8mN pzI<; ֟x>* 0#M"um-fV!dTRUūUUPR>mEB TQM6q|ǭI[lX ׿كQa}ܖmmynye6:64rQ L?|>Ǹ[6Zq;:B +7ƭ.9YȻMm.R ɮ}47 τ HFÈva()rhںag\y{>ϥ&*QyYK,ϕT-ͥ` ^JBSt;M{FhbMË yqUxotᔷ H\ra9QעSkLuЍuj쀕K K(+9PC|0`(1h\X(A&f*3L0[Do]h\BS bZLPLۑ·nDҩCF-))1]C.Z_N< ¨ RU#q5Q&w\ Lx')up%(,,0* Y.\7:%J0q:.XXKyZ{4*_{1S[V _SD,{1p""[)Q<!k9Or"2+ y+K?1{:u^]7;<3f:XroH$QdEҔnReZ*Av+qjAho {*-$nMQ+W}g<~W<(\0?&$Y? s電o:G.`͐t]|ejٚ;hLk{55Z$U/̼U Vdve ZH~tOYG0SIf_vC)G7r? %|ː".p>4p z,%tPyhKmt *"l߰1YNPsvDTSTXNl Qܣ0dJ|w[F,1)-(r"Ӟ {s_!fqg?]#M1N.@)BlSZ~Xr jmx:5x97shb ШZD[CqpY=FG +**/|7P‘^^{;A2њ_i~T1X0;ؘ}V3m,JBsqJh'L q2h5΃XZv|,j1f(cKƟN`bendstream endobj 4 0 obj 3883 endobj 5 0 obj << /Length 6 0 R /Filter /FlateDecode >> stream xYɎ67s+,E vխbHJ!36W۫*&akt4OЍjw}P۟m~Ro'X>}.\]2vW3\q|jac- &(0L' lzF_ >>>} +vCQu @l,)?PtV-Ϙ\-e%j Bg}[ 캡 A*$p (3o}OnCw D<@>>U芕$qĠCIxA`OP(P߀+* ZD% ] P$xYAڡЧqe--{;Pa[W78v^ st o+X?F1\14E%p`.фxR-Sr3s13&NLv!B :izX|n٥&aE)|=q9u$YB`Vm0䅌unAPLD_8*mH@<7Gfsoٱu/9ıDMDd`j)m/ҽ r 7w8|&RֱH:܏(ꞌّB]])T_qW a9Xx{K˙eg^`cm $ }rzva۔^& S4 fg '&j:k!fGh 0K}Qm7}X7^̾yDr <6 @B >>P1BДfb>wᡃv"BTY%Yv%cBQZ{:>3 I}n[[ԉ0c ;@TPtq䚏_Χ%dY_zꋂqYZUUyrv#! Sq}G_+uJFH y Ĥ҆j}mX.),+ BB~l{0I¤-(.0ݜ \Z0qYQ`|LFf+QA\4i]<*n%ӍA1 /&=Ac#Cًt$=50Pr:dӦ :&=Fy7Du#lnr]ُ+vy>sBVɐRUv%2xѶ˗.}]ADntnu`{>endstream endobj 6 0 obj 1299 endobj 7 0 obj << /Length 8 0 R /Filter /FlateDecode >> stream xXM0 Ь%I Ka2@ ¶CHXN6 ,Acғޓ'G݀j՗~~?߹Uƨ7uwr :P0|R_olX~{#j״datQ_S8a) n.qƁ}j1!Y(V=[Ǫ}$;tJ@}'lAwq)?@qr H ;v']ϖaLMIz}M aaO؃'[w8)Qj^da$*ࣶɗNK6y!wpdFˢGZީ1Cwyf4Ԛ1+ќfJ̸%L !"vJ(4Hښ]leUi-  A藼Pu9r#Ҧ eTZ_q@]/u*#0Яӂl .;YNBً.Kkx$KB υ9%d2K)qdbd7cRB%#|-Z<c%B~o(OL\llSHIEInu[6V 3c/|6oݍ<"bx{e1N7xZa^mNϏ^_-6mendstream endobj 8 0 obj 1019 endobj 9 0 obj << /Type /XObject /Subtype /Image /Width 886 /Height 602 /BitsPerComponent 8 /ColorSpace /DeviceRGB /Filter /DCTDecode /Length 52732 >> stream JFIFC   %# , #&')*)-0-(0%()(C   (((((((((((((((((((((((((((((((((((((((((((((((((((Zv" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?B(PQKh4\v\CFa(4`.\CFa(4`.\CFa(4`.\CFa(4`.\CFa(4`.\CFa(4`.\CFa(4`.\CFa(4`.\CFa(4`.\CFa(4`.\CFa(4`.\CFa(4`.\CFa(4`.\CFa(4`.\CFa(4`.\CFa(4`.\CFa(4`.\CFa(4`.\CFa(4`.\CFa(4`.\CFa(4`.\CFa(4`.\CFa(4`.\CFa(4`.\CFa(4`.\CFa(4`.\CI@(k7ܢduvjBn螛ы\z?*Ok3L.$vH[SVw^ |+(Sٮ߀ן??ן??™毨_QG*;ٮ߀ן??ן??™毨_QG'f~^ 7^ g5}EXao~FLWQ毨?o~FLWQ/w]??3_QGTwk?uuy(WQk?uuy(Q;ٮ߀ן??ן??™毨_QG*;{5gQgS<y(Ox{5gQLWQ毨?Ȼ~^ 7^ g5}EXao~FLWQ毨?o~FLWQ/w]??3_QGTwk?uuy(WQk?uuy(Q;ٮ߀ן??ן??™毨_QG*;{5gQgS<y(Ox{5gQgS<y(o~FLWQ毨?=y?c(y?c)j<}b9o~Fo?3_Z<}bk?uuy(WQv1n15}Ej>Sv1n15}Eb>?x{5gQgS<y(O{f~^ 7^ g5}EXf~^ 7^ g1}EX=y?c(y?c)j<}b󿽇]??3_QGTw]??3_QGOv1n15}Ej>Sٮ߀ן??ן??™毨_QG*;ٮ߀ן??Œ gy(Ox{5gQgS<y(O{f~^ 7^ g5}EXf~^ 7^ g1}EX=y?c(y?c)j<}b󿽇]??3_QGTw]??3_QGOv1n15}Ej>Sٮ߀ן??ן??™毨_QG*;ٮ߀ן??ן??™毨_QG'f~^ Bo1c)j<}b9oP%Ή w00y/PYWivnORkըrm+Z348\EW8W=kM +k)DŽ?뽰.9_ SFlR[~o_E}I1??+ϛSW:</l}oY^glt{`F(}ey<Gdjy²G٣5|aGWh?= _1K[+|o$Gr<\&ywK%]rZ[H &#=RJըԕ웷{-kǒ7GOx]Ԣ<%s$qw1 H±9cId[k1+ƿ:K1stlJ…Ҷb%ȕ].I:vվy¼PßqpWźү>l}MN K724B(8#'Mn׊Z2N^} c~_7)=Gy²g#^}}eyΏ?Gdj7?:={#Wy²g5|j;FF 5FF 4n>n>`у@FF 4n>n>`у@FF 4n>n>`у@FF 4n>n>`у@FF 4n>n>`у@FF 4n>n>`у@FF 4n>n>`у@FF 4n>n>`у@FF 4n>n>`у@FF 4n>n>`у@FF 4n>KW,&-c qWph )E١49 u/M0%fiGN =1Qj~ާ .w;e}YA#;3ʬPlobLvS%ź(#tRӧKNP}ݏy7x;wgׯ}{8)iֶl'q;p0 銂BӬ-i7ý7wm<0h?orG.eZIo}=719N=ThZ\zOp8wBGF8|ћO׾t%f!= tk%,4빼WeV|ʌ08Z:iydK~b$\n2xPhWs3__'[G|zO߳Gͧn?٣^ϔ WǨ3__'fiۏioB!*?x? lvhݸF{ >PhWs3__'[G|z]sODrp sVmX7Ej_SBqg-O=G!*?w[#>Gdm?q~?{ >PhWs3__'[G|zO߳Gͧn?٧a p_x?  h/W{iۏhٴ4_B!*?x? lv?m?q~|Яg-O=G!*?w6ݸfO߳G(?+9 h/Qg-O=]ͧn?٣fa p_x?  h/W{iۏhٴ4oB!*?x? lv?m?q~|Яg-O=G!*?w6ݸfO߳G(?+9 h/Qg-O=]ͧn?٣fa p_x?  h/Wu&a<2g"^Z5R~giKWtP,»g h/Qg-O=^jPPfٴ4_B!*?x? lv?m?q~|Яg-O=G!*?w6ݸfO߳O^ϔ WǨ3__'fiۏi_B!*?x? lv?m?q~|Яg-O=G!)?wYߣEL"I89a(?+9 h/Qg-O=^u{mm"+(UVF!|HɩY Яg-O=G!*?w6ݸfO߳O^ϔ WǨ3__'fiۏhW8/CPhWs3__'[G|zO߳Gͧn?٧a p_x?  h/W{iۏhٴ4oB!*?x? lv?m?q~|Яg-O=G!*?w6ݸfO߳G(?+9 h/Qg-O=]ͧn?٣fa p_x?  h/W{iۏhٴ4oB!*?x? lv?m?q~|Яg-O=G!*?w6ݸfO߳G(?+9 h/Qg-O=]ͧn?٣fa p_x?  h/W{iۏhٴ4oB!*?x? lv?m?q~|Яg-O=G!)?w6ݸfO߳G(?+9 h/Qg-O=]ͧn?٣fa p_x?  h/W{iۏhٴ4oB!*?x? lv?m?q~/{ >PhWs3__'[G|zO߳Gͧn?٣^ϔ WǨ3__'fiۏhW8/CPhWs3__'[G|zO߳Gͧn?٣^ϔ WǨ3__'fiۏhW8/CPhWso:ΧfxmLF@;1.zפANBR4I1W'0>F+5raR;J(3 a#X8ֽcEk\yO hz6gz+kho+n74}oz *n=U?M\׺ɇĎWNf8$fJ<)ͬ _Q+z]?ȫg|ͣ~TGh<=F?*(hG ~TGhhG@Nx}I`23.?*J+=Izʖ6AQzʊ(=F?*(h&?*Z(=F?*(h&?*Z(6AQzʖM~TGhGh (ːdt޲4aj{[%Tb?܇C/6z+shaS=f ܨAzʍ~TQY6ARm򥢀 ~Tm6AQzʊ(=\VxQL p8}Q`E7qq:nFEuڍƋ)SwJ7j,>n4XQM}}QQ`3|K zӿ[^ f>VV09H`?кYB+l~?*}+/}E7qq1Swj7,>n>XQM}(}\N![k}q~ ;5IS5 ؙc\_-++ /G җX(QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE!@o?)7sJ(~%#^ 0`8u,E?.ŭ_XbcW/7-kr-kr6#|l*ST7/[2#8_ro Ǭҹ_ro ǬҿIoEWhQEQEQEQE/~+Ϳ>GGE7p"¾QII@ci_m~eiȾm|/Q_w:V]9[לp?ȨFVJ7)2('Gv!~/4Eqvi]K㏣ vQ}OaS+PSw((RnRnPSw((RnRnPSw((RnRnP2k 2Mr >}G 4OSg?/*<$G|p"4-—p"Sw((RnRnPxBR#vJj2?wd!_&: T_E]J;TJ{zoo_ҟ+_{zoo_ҎV_{zoo_ҎVJ{zoo_ҎV*(޿ j(޿ (޿ U}QJ9X}QJ9X)* QJ9X({zr'{zr,RT{zr,QUF(`OKUF(`X7F(`Xo_ҍQo_ҍQIPoo_ҍQEW޿=-W޿b޿bJ7G+zZJ7G+%AJ7G+'n(.QQW^6_ܞC&kIms}-EߋFnZ~/ǘ Ə9/ Ǽ`xO=T0 |;w-s @ý~mZݟI]ٳPǻ r:O=>Vӵ /[n.e, 8U]ǼCZ(TEc*sއ -#?/t?ʹ{ityUOȳ6x#+4(WtO Ge[n3)MI.n|U-_D]k@@4wKfx <>w} GQ]ǬUź+Y-M*ՎO Ҹ9g͞&mGSES<ۖ誔r˔V ,?S?3=@? u5fyu2ߥ atG(X66MEB 3S[ X9#/wxysi> ԧ#D<0v 1UH+/4g“i~&˕mDx$R+p<:Cb׼P: 7xĨOX%-m3TIB*̫d629gIִk%KkCQ{kn X #i37yRiw7×4(NW# GRžڞg ;Na5͞O>+ kW#Xnv ukr4gOI/ǗV=Ij"ujqS^o >X bGOǓn?1vz蚑ԵHa\n#T+ֿJ_a3E׵/A{Xnerٙ$eC7B:tTp:DYQH˘H"`B˃+u]oLP%Yͻː&pO ڼŚGBֶ7#fK2q"Uִu 2o:m\w`<046I7Y ?={z $oAGނ %Q締 |y**(_={z ,oAGނ %Q締 |y**(_={z ,oAK締h=#.^ä6i?^Ǥ6s=iLEWh.߇FoX~ɘ Ə8 ݬ? +\߁mVC]A2cv ʅ7VJwnU:j=et*xUصϳ ֭hIƠm#9Ol`ױǬ]8"4ԯƅ_iq1?uxSTsq?uxST~-Ϳ>Hݥ<Ф67ՋA%%J0:? lm]B9[g豅IΊ KRRՀP:(Eq%TWCM_))%TWCM_)*}?]~/ZZKIK@%-%-Q@ KIK@%-%-Q@ KIK@%-%-Q@u lPV8WM6oW3cr‰5ݬ/ ڹZ((ux?g'Wb:KL~EVXmZa &>h(KEEAG}Z*/0 <(QyQAE>0 ,T^ayQ`%>-}aX h(KEEAG}Z*/0 <)X h(KEEAG}Z*/0 <(QyQAE>0 vZ*/0 <(QyQAE>0 ,T^ayQ`%>-}aX h(KEEAG}Z*/0 <(&Sy^&Ims>&'d?fm\xٞ4[+4 xq{HrWA\VLOGaTq'˛l+ 쯡YgCFR9_r[|i}ݣ -$Y`2ki??ʦ/?OO*V֣8F8ub}?UxP.o_>Z*'_o͟?|B(xqijWYd_B|͘8R NmG ?*s$ MNmZW ZJZ`-'nx#x7OIܓ1~( LuO vL }' KIKH((( Ɲ7Y1\}uvk!,_-͟ o??s]\(RRPEq'b. gۥq~( LQ֭d0_x>Xo᠖讁QQ@QQ@QQ@QQ@QQ@QQ@QQ@QQ@QQ@QQ@QQ@QQ@QQ@QQ@QQ@QQ@QQ@QQ@QQ@QQ@QQ@QQ@QQ@QQ@QQ#7{^פ gm\x%M{V o+2Q^Ya\V䮆xV1=m,}QxW\smKV_In}\{YJu hZmvyC;-lVgz`vPi??ʲ%Z_>IkmcNHucڴn6q'WV?Քwn8E'įOtW7 5xY/w͞m:*Zf7k3%h٢ h?xH͚]kB *O*i ]`lFvv?LsS̯}@j/7ԔPQ@ j3IE.hϵ%4PڌQ@ 3IE.h%4PRQ@ 3IE.}%>ԔPQ@ j3IE.hϵ%4PڌQ@ 0M7%M{V o+|OzK'AWZe(¹߈*X?rWE\n9+SFOKm'KI_yCV1ˌgx3~]NQϭQ\Ǽ^iਗ਼vZ׋u+m\qm9UeWǼ[0V-u{ѩc?}~Z|3_?}~Z|3_. w͟7|(B(3kϊ:^!"hُmǔ%ɐN*Y03PtR'b ( ( ( ( ( ( ( ( ()7ǖ\?m[<&vOԿ띧Vu1 ۬O ۭXbL?`In 8PORJЮ­l㡷x&1cvFVf'huOe꺆m>?L{y~bNHq޼TֽIJޯEjO}}j&s gy$Xlݎ$W`z w_|A(--_YD mhX)۷)烃2+Z~"]iZʝ2]i#h<QcQ\KP4bF-˽&0+`vx-$u5_2\?\׻&8\?\׻&;5/I`μOk ѥ nQEt(((((((((((((((((((((((((Gu@5zOm똯HƗK9^դ6s?S-Es<)s]`]sT=+SFO"W5.[ҧLvHQԫR9T|9%zP4wGJ)3мcs:ƫyn]y@a00H5]0U%Cw5u+jt "0$O׆_ "2Sᮏßr_ w͟13{"eV<dS(cz/#j'#[n3©(خ+Rl9"y>\VN^jǮdQLQeXSy'A5.!ٿ_":ou^TtDEYNȨZXC(ȦQE~E(ȣ"EdS(?"eXQL2)Q`FE2,(ȦQE ݮjj_J+տOsv+?)+~c[ E(n+ßr_nhC+^*}m"^E'(ۻ5b ĩsI1Z?L'cݳvcqڗJlQw d{IeLn^@29{ԸZ 56wIңH㷃FR\9튳O[ú42m}V"VdkvV ս䁡u9d@B1_ǻ s:?;VQP5)[B̶pqNMtlFpj 򨻵'NQz\[j}?5sKs?׆?}ޯ7E6|mͺ(B(>*xxM|=RO&e?q޺_ xK5-ɸI ,' $a=sYrqcZ(QEr>&_ OHDU{j}SC/e//G:AEPEwrywV3SWO }լy4#h!$L](/gjQZhr07}ўfQX:_=WC4C4$o0')9Vu2ۓݢi^J 60q3_uu> mxAaaZPyveŔ3Js`RO`5`QESտOsv+?)V>Ǟ\/UnjsKm'>VlQE 81%ٿ[Tk#?|K5r][x}=+a#ک0q99WkWgğjgf1Ʋ!]ŦxWUK`R:+FVP>}f;I$M-߸=;}k5 sEwѝQ]B |M]ur>&_ u_+@\wW45: /ݧڍڝEt7iiQ@ }iPvj6juݦڝE7iiQ@ }}Pv6juݧڍE7iiQ@ h}Pvj6uݧڍڝE7iiQ@ }iPvj6juݦڝE7iiQ@ }}Pv6juݧڍE7iiQ@ h}Pvj6uݧڍڝE7iiRcⱍU9G憽Ims^,^&ImsfM`[+,+"vI\O뵿q=m,}QhZuPj0#(8ݟ¿()Vv}yCM m2ϐWⱨH0{w[S}+|v ad3:nA]Osqt/?5ȽzoiEǘQEqťh\mj&5,R$c98Ȯú;n~llp(6m(AGz(@߈״ :_OVA5gRuIiz2KHtRI!EPX^=M[Ry@y cu~SuE P 8I3GYsC:(T`8OăG/dJL=Ҭt*Z <1~?{W&f֥qsJp弽\Hc x=+9Q}JxW2Fjf* T;zA4k7ږ?uS*lP{׫QMQiq\'Z| x/mu E~ X #i3Gu!u-WT>xJӓLX uz8A OWZݩQ,fiq^o|?`EiN ((} a[Ǯ\oO+땗W>'^*&OifOiBؐ((((\߈״ s~#Ww^& uZ MOCkY$n]BWUl=#7Q'AU\f)O_23G? z__\J?_@]+Ok("<ҿdfJ(~ȏ't?ҿdfb>_r#_@]+Oht?XJ?a@]+Ok("<ҿdfJ(~ȏ't?ҿdfb>_r#_@]+Oht?XJ?_@]+Ok("<ҿdfJ(~ȏ't?ҿdfb>_r#?aDҿbfoJN6.Kdbwɸ\Usʔ{a:m0&?0&?zFQW>=/4c'P/(/(ޫX={_i_1i_13^_Q_QW{h<c'ҿc'P/(/(߫X={_i_13G7? O3^_Q_QW{h<ҿc'ҿc'P/(/ca@M+2?a@M+2 g?g?ՃGؾ0&?0&?zC(/(߫mǗcxW d4bW d5%dO~`y7? O3G7? O3^_Q_QW{h<ҿc'ҿc'P/%{~AoJfoJfCdOdO~`y7? O3G/? O3^_PR_ ?VmǗ\xSĺ-,-d4FQ@L޽NGs@5+[F*Ө`pfyn֍XOQEhlDN[뤮k7WG\j6>_owv,!Hۣ)*ޭ:n}WZ~  WMW\Hl-9\.=S})ɿշ֕kTƞG)/辟qt/?5ҋztOR_pg׫>O6xfǘ:J(05؄V?|3“n>mq&:-[x\~_~|٬ȍ/\覥7^}ZE%%P%x]{IzU_i?Vu/h*+tRGJZ$Z))(RQ@ E6<]|Mcf;g+E\+ U uӊu: Yv"sղX#~Q+}{OďdS$]_-X Z/IYYᔑ$dz%)ͦT~En(ⱺϐ&z/oLP/"d֯C7 <='vqu!?SP5 (9i?V5/h*o7'jƥ!\2+:RHQEQEQEQEQEQEQEQEQE^=dt ;*X0Ƕ\? EDIifONąyiY=Hֵ¶^;:ߍ|pSNdž,ǝݹپN>:T;^4z[skkoU$nݓJkWVTϬ[%wO)$|pw.[zTT$ xK摥qc#fGgN>0aaoy7")`189Ԍ_5HklugÚ汥5H،U*vH|+ iLfy~^V|ݷ޺ bկuu+~=ı,kEWO?^&h6}뷷Ntpe߷hk^;h4е-cW3" XOq]5m|Y1_+Kjj͖66̅dc*{Ys֑+{\^ Ԭ ( SОjJҼú^Cr~EWz[}:S΄8)IXN'?޺v> ?޺'Kk zg >E}u0}a),ARij H+~\|!y TXtf٧hku8r rkTZ۸0 <)V0 <)Q`0|LOV/'x=OխGFC\2+: _0 ebGQAL0 <)SayS(`AG}2,(QLQAL}a(>E0AG}2VMk ;+5uk?땇|+M0 ԿƯWBؑayW3CVt/;BHݣhc9 #ysV_V{뫨.|M,h~s&FQE Mڍƣxz\ww\M\.r+b%? Ims9&'AWm#-E\ďn?J#us{a3=z6Tu>{kKͳ&#p{VپCkVӬɧ{1u~So]5\[6'N?5Ƚzo_Q{מ`)a.дiF%PF' 98Zxɮk[c >Esr|lV5fM2\?h##w#jKY6a$αͮw4Sw 7zQM)r3@>&kA5kQO[i/j֣#45//BSsF]dQ{n):nF@QPn):nF@{ѸP.OMarҳ[wGOXq[Oҳ\zji?_WtWw ę#n;$N.4$"p2zY~Ն6kjڣۋEX"ݻhEsz7 N.\.^ӴƟ0H)([a$n#[֩ӼC}v'ۭ۲iP#1n>x?PV/f>KX~ʐ">1;1ZN]{VO`ח+Bszª4p,"AbwS) pvG~+kd AT  ~FJ4doQՁoI?[[i/iX#41Vꦓ o*|(@QEQEQEQEQEQEQEQEQEQEQEr7?BH_&p[ ɀy?TS7CFk0)ǡx4\L= ǡ>fh= 'LcQqmuu?܎IaoAy^zY3Yj6]ZL6X}ҴQBWeBJ.khR'xcIYR6w;10+t_i=x;DcӴ8R6/A*RpO_WķZ⸻)]fn5:޽zfcgIe4-۶P}t][ZUߤhIxW9K_Xt%#5ziiXgGmi (*G~<3i5dvLĂO$p1V1wvi?~t˿;xy7`WWבXv؛F tkvϊpZ^}vA9і*냱=1=]~Ψ%܍GGxßVU`G5=ؕg(J P@#hq1ZK^- d'?kMj-m7<1rеiǡx5k}ѼzWS7CFhz7CE}8op9?'km\p,? wOm똯s*_#ltQEzxW1'E ҈맮cOk67~և#y5niV >;fW6~LL{%'O5:ޫBKھZ]u?ikVj)CkE|Rbg1yAV_\|[}[WC~/^<( ( ( ( qEr8 ǝzK]hj%M\?`45?/BƟa>HQEQEQEQEQEQEQEQEQE{?*ŏF\,5u?ʱcQ=?K r2\zWx[QE0 ( ( (9V%Mo|Mw/j*|,h'AU6_*7 (Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@g1tXֿW_g#,n>n>Ey R>(}6~F)PAKS(>q(Q@}.L MSh>n>E;q2~)7AMP Je'jZ5e/k1^w_7Om똯{)dz n(\ >%ȡq_QtKBҘ?FkC<L7xպVM֡m>kk֌%Br##ؚNvM}ڍѫ&4>k hI|t֘$SOGo&eR|}[WEqƹ*MV?^Yy.MQME6u(Ea<_CF CTOzK?M rOХQME6u(ShQME6u(ShQME6e{I?ʱcQ=?K lbWiXkTTw54#|xʥ[H)SShQME6p+^&+פjm\[Om똫usp)QEQEQEQEQEQEQEQEQEQEQEߝJoNx4ĚH-{y?E}(%@ (Q@J(RP>H( AP%@ (Q@J(RP>H(P=X Wi? b#$ZzXO5z o+~f[+;¹(O_6SuKBҘ?FkCR0} (4`,QKh4Xуh E.`\CF%>CEJ)p} >R0} (4`,QKh4X3#>&?n>}O6`r#cr69ڧ#Q.]Kp;M+`Utyج=IϚ(Fg^fbs}RcSmk/g^fb/{K?TFg^fbG*56Ѷx/o(;JMm/{K6x/o((}RcSmk/g^fb/{K?TFg^fbG*56Ѷx/o(;JMm/{K6x/o((}RcSmk/o^fb/{K?TFo^fbG*56Ѷx/o(;JMm/{K6x/o((}Rb'f1\\i}I+;(\<^k9ؠWF/Z~Ea\'O)&ȡ?|LU͌G4o>Ե+E q FpAǶsV5%sZIJ̅$Fz Uj6QưkZm5!O5-cP6`^t%xS֥uIo ˎ5ַ5ۚbgNvVYvAvi\vAvq5Ƚzso-QEQEV?Kq!}flw-gcBִzzEwVLЂ-EUQE?/j|CU?7Q9W/`Կ%'uWCF(B(((((((((??ұ?垫\,5qr.+^wxպ}xժ[QE0 ( ( ( Gu@5X^(n^rI5洳b5Xԑ$W7,rs(2?¸#Y`pac_Qٿ1bgSj7j.3??Œ]ߘ ~FE`F.?qq˰ ??ŸQQebgQOh}1w?c(>n4Yvٿ1bfSj7j-1w?c(4n>[bfQO}h 7?ŸQQo F.o?qq@37?Œ]ߘ ~FE`F.o?qq@3??Œ] ~FEf.o1ڍƋy] 1w?~c)1bgS7j-1w?~c(>n>[bfQO}} 7?ŸѸQew?~c(>n4Yvٿ1bfSj7j-1w?c(4n>Yv]ߘ 1w?c)]f.o1ڍڋy] >7?ŸQ - 5Y|Cu]ʰu 8 3^aT3^fŭbcԨqQi (4[gͧ]MrO?*~և#pxժb0V+>; M~(?ֺ=;?ƹS,wJkI?ޯڸ3E՟?f(<(>#TO=Hn}˅%pA 's][hͨf9q+Em(AEP?ל0j_Us m9Jc`PdoGE%v .|kӏ}K{nWf;֣;.EUh٣[Uh٣[nWf;֎F,WgfF-nnWgfF-nQU_;<Z9\RU_;֏;9\QU_;֏;9\FU|hharKU|Zo8 U:Wm똮|h"[+,+"|gQWS\?*5HܓU~U~ϵA~PzJ(_+sZ~WKcdzj/W?f(<Т(;[ִ&ծ[twn 8SQxZWRw@]lEsIW‘ʊeaF++4QEQ@*N^S{U 7j_I`Iz1JZJQEQEQEQEQEQEQEQEQEI'-/KMnOa?][iZkT8k?ޫ5ZY(EPEPEPX*N^S_ ?oTXu5uR$xLuruCٽDE]:08jJSܻIU7J7JA({[{\\nrnnrrnnrrQzQZzQQJzQzQ%c ;u8tj|~NUgw 1="-byLV@i"tM#Ğ$Yh>1ҋj+Yi&ѮGW|/}j˩ h#5ktG3O<7v:׉5ٵF6ԛt7*387X} uxJ4jwGp f/0ݞk6;å}2ܤԅ'nek+.) 2תt#+9x>亵5a\mWnӊUĺz|NĐt .=vUv@v-aӓKew;ݼa\sw/.-ڴMmoۜyX8owßk %g!vX hōPgl<#'q \diIj a|k[%4GPT-aLĺNhvq-ciK6 VC^yIxoTե$3Em91*[%kf |R ,zD2nu=k'9;[R{5%T=(=+Opp tOpp Spp U=Ҏ@-=ҍŽ@.RUMҍҎ@.QT 7J9KTJ7 9IU7J7J9IUMҍ(_Eo_Ims~' rq.'AW}-EN>oҨWwݟE\Oњ$}NadTAiOj~>l-%/cR3?Һ[!浿,Z__ώͿ_ȟ4gڒ4f\QJ(sF}(%mUoի{VI`+&^SwW ƶ4f 3IE.h%4PRQ@ 3IE.}%>ԔPQ@ j3IE6a_XspڰH-5'V랗ƹq_ Cd0V3PYOj[\QJ)>ԔPQ@ j3IE/X*&[ l? ה[?\K[3 /h*cpC={z pk!(Tp@O締oAPnpY?ނ=Az΍~tY?ނ=Az7Qd{z <?:7QE(T=GE(Tp@O締oAPnpY?ނ=Az΍~tY?ނ 'vc 3\aQz΋ 'Uh-m㸎$veH]0IOZjvifpq2 SGwo%&+J L{XoٴM*"Exd5GX._h&/LIc$ܷcjH9OJͻ񍼞,i׶r/Fˋz`d5> /f?S'5Ej1m#R4m*Fr}ZWMg-?ޮk[}ciykT8ꚡ}>]+a E.O0]ҌJJ)vJ6JJ)p}(}(+տocxēU9QS`:t&3ӊ?`?&Ya{QڙEt?wP{QڙE?wP{QڙE?wP{QڙE?wP{QڙE?wP{QڙExmR-[ZŴ?a:Wߟa>sjNvqj)њ/*(m񀤀zqzjr"VF+Kt*T(Ln1}ʹf5|04.:Uh8gZV p^HoGg$ظE;}|W0F}o3ǵz햑Ise1$3H\1\ l\s5/qoɕpm88SD`o#{QڙEXFjenQ@FjenQ@FjenQ@FjenQ@Fje21D>&Ims' N&Ims{Ze(¹_&\ů]UrL_)5H5ߓS~OO_OsP:Rr!v[}>i\WMm\"EQEQEQEcQ:P7?פ 7?M Vg_A5fCwII>: (HQEQEQEQEQEQEQEQEQE??Ұn>\+5'V ?떛f1EDٶ}jzIlHQE(((1Jg_A5:V7?פ k|A?Kh}ν{\V  (&kBFhRf4QFi3@ E4QI\E-fE&is@f4Q3@QLFhRf4QFi3@ E4QI\E-fE&is@f4Q3@QLFh ?jG 9^դ6jSImsfMi袊 ~' 2ԟkKȖki$l2Hh{Jrt]9rKV~O\w^'ԭ"c}9;|,ʥp;v8ŷON+@-O_~G?J\0KooIM.7%qRO$89fYxIxFc!~}+NG-ªfƹb*Z(? zDGCO=^?a>j*"~#'?QpV'?j*"~#'?R8{ +Q:UDGCO=G"~$'c '|Y =W$MY]hki_&hݢ2,YۏP1bN cMx T2qzc W}UDGCO=G"~#'pV'?j*"~#'?QpV'?j*"~#'?QpV'?=>#4N)FKrF}jI b^$^!Ѯl+(S ?t, o^}UDGCO=G"~#'q{ +QV ? z'󇰟bg?Q`Ǩ8{ +QV ? z'󇰟b8X,^&/DICO=J ԵDu1[F@?;q3Q< Ґ 1YnUW[SKZ)"}D˨X2daL:x-cC7 2 aK+G9r?_5G sj'ǰ/@P-C|Z? g`z 0=+G9r?_5G sj/=-CT ?ZkƨOIaZ_C|Z?-CTma{A'cڴ-CT?ZkƨOj1+K9r?_5G sj/=/@P-C|Z? fRzV sj@P-X^{ 3qF=i?ZkƨQc;ғե9jů9r?_5G}{ \JQ9jůk a>n-CT?ZkƨOjLJQ9jůk a>nǵh?ZkƨQc7ҌAZ_C|Z?-CTma{A'ǵ&i?ZkƨQc7Rڴ-CT?ZkƨOaF@P-C|Z? fzRV sj@P-X^{ 3=&i?ZkƨQc;ŒAZ?C|Z?-CTma{A'ǰ@P-C|Z? g`z LJQ9jůk a>n=.@P-C|Z? g`zRc/A'P-C|Z? r-\hͤ\⽗Ies;jqF2yJsC]q1h00+%Sj+aY~&{]X֥axݶjZǶ#|2Xߺ04 Mլs f~o<{³ǚǡJs\bԝ}yG-4?CW>Y%_揲[5ix?!!dk|K7oooouNؑ$$?UW:m[qfH ~ ?*~#xJ{a.;\5OGaTq$R歿<|~'hy߭~M*.rsjkyd߭wKڱ$kyd߭wGa쑭ҏ<|~{~y߭ՇF??JoGX{$kyd߭oGa쑭ҏ<|~{~y߭ՇF??JwGX{$kyd߭wGa쑭ҏ<|~~y߭ՇF??JwGX{$kyd߭wGa쑭ҏ<|~{~y߭ՇF??JoGX{$kyd߭oGa쑭ҏ<|~{~y߭ՇF??JwGX{$kyd߭wGaxV|9gk/H$q-`Yy󻜍n5jZp]Zcv`]w.S8+g[>7\YShF3rHӾ+G¢3C34HdaUrTN@>}фFBY_߷nzmMy[KgWKW#(F꤆|U#b#~k:F+dmB+cg;(FҹRG_QY+!ƊQ` 5&[9#{k1auwoiDo~ڷT*$ֽ-l'+OnxsIբ6Fw7V"QգТفuܸN:8+ռA^^\\ߥEz30ݐ0:Z:S W d r Fso}~$ubRrj1γS45 V8KU@^&8|UoM5/ηc}~M299zEOI$#4zPiAg7ry1B ,3y4{ 4aԴJyvVy\$>5e pzg5SÞ8ƻ&FHZNi_w ss~cg{#i)6Zd]߻U9m>J[聯"Uv:gUxt7@v!09'`[xu, lA>f>}8¾ gyj_4XX,yePF=aT$,\c]iZ_o Ꚛi:];mE(+0՝wzm5}N;[([h#~Q+WM#^<5o7"llpt2ԒI1A?h##αx*Qھg~|;+vmuGu *} ~"|WA?><ڡUŰ8I?wo^^1F^XlzSso<|~y;kڳodo<|~y7h=5QҲ|o֏7ڰHG??JZ-^ד5H5j]V6z|X6vFQf;ѰfE;aa.6vFE\mލދ0)aqSz6z,hl>l>YN}} ѰfE;aa.6vFh ѰfE;a4l>YN}} aqSz6z,hl>ދ0)aqSCFE\mލfE;aa.6vh} Ѱzhl>l> N}} Ѱ4E;aah6vFF)hl>l>mލދ0)aqSz6z,hl>l>YN}} Ѱ,hl>l>YN} aqSz6CE\mލދ0)a.6vFE\mѰfE;aa4YN}} 6z,hl>l>0)aqSz6z,hl>l>YN}} }}( ~&izZJ^ۤ6cѵ Kv3LrH:Wms&Ggމj(Gk38V/3iα;.(_p{j?: ??Zh>Gڧ3iα;.V/3븢EZh?: ?(}38V/3iα;.(_p{j?: ??Zh>Gڧ3iα;.V/3븢QEZh?: ?(}38V/3iα;.(_p{j?: ??Zh>Gڧ3iα;.V/3븢QEZh?: ?(}38V/3iα;.(_p{j?: ??Zh>Gڧ3iα;.V/3븢QEZh?: ?(}38V/3iα;.(_p{j?: ??Zh>Gڧ3iα;.V/3븢EZh?: ?(}38V/3iα;.(_p{j?: ??Zh>Gڧ3iα;.V/3븢EZh?: ?(}38V/3iα;.(_p{j?: ??Zh>Gڧ3iα;.V/3븢EZh?: ?(}38V/3iα;.(_p{j?: ??Zh>Gڧ3iα;.V/3븢QEZh?: ?(}38V/3iα;.(_p{j?: ??Zh>Gڧ3iα;.V/3븢QEZh?: ?(}38V/3iα;.(_p{j?: ??Zh>Gڧ3iα;.V/3븢QEZh?: ?(}38V/3iα;.(_p{j?: ??Zh>Gڧ3iα;.V/3븢EZh?: ?(}38V/3iα;.(_p{j?: ??Zh>Gڧ3iα;.V/3븢EZh?: ?(}38V/3iα;.(_p{j?: ??Zh>Gڧ3iα;.V/3븢EZh?: ?(}38O%W ˗'ڮ)B(UP0-!+EXIVŠ($(((((((((((((((((((((((((((((((((((((((((((((((((((((((( endstream 10 0 obj << /Length 11 0 R /Filter /FlateDecode >> stream xZɊ97?y` IȬ9f۴0ʪ%!Uv{ƘA%/5?4?kOS۝Sh^h>\bW4/Y ںmeJEzUAPޮ||LAxոӦ,1y9W)tbP2AEרfx>.hI0fM]Ù@W_0 H۪eKpYn)HiCf9fllMX@7XC.zT"IȨg##Kʡ)[Xb. tڰ֌%1p+gmEzWŔϗ'TH"5cluž =i$i@u .>jR)m9G2t2*'xKrrvbUW$W*zc`Uvh'u:QCLtqߌ7}X1؂y(E5GZupsjbg(ӯS*aVBP hr|ГJo7dRg(/&IA[bw5(C,O3F $'h3#&h|}"O4*ii'pjZꀨ:{MxR"z逥$U<`!ps[} Zj.UfT([ķPVy  4yAjM/fY2 Fk\89*UÑ~"fzy{"c-{Y8>sm:򑣔o=?VMA}G ߉FV{-ZI/bvT_}p8ֹOkӭy*1WJu1^[AOMks_4}endstream endobj 11 0 obj 1716 endobj 12 0 obj << /Type /XObject /Subtype /Image /Width 884 /Height 584 /BitsPerComponent 8 /ColorSpace /DeviceRGB /Filter /DCTDecode /Length 51654 >> stream JFIFC   %# , #&')*)-0-(0%()(C   (((((((((((((((((((((((((((((((((((((((((((((((((((Ht" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?B(ݵ,\CF._/2eK.ӌ י1(`=M|NOh5n1n1:} >ן??ן??0t>C\FGOg:|CFcuuc?>1gQgQFуky?c(c?>1gQgQFуky?c(y?c(X#Oh5n1n1t{c4`7^ 7^ ?:=10} s???a} >ן??ן??0t>C\FGOg:|CFcuuc?>1gQgQFуky?c(y?c(X#Oh5n1n1t{c4`7^ 7^ ?:=10} s???a} >ן??ן??0t>C\FGOg:|CFcuuc?>1gQgQFуky?c(y?c(X#Oh5n1n1t{c4`7^ 7^ ?:=10} s???a} >ן??ן??0t>C\FGOg:|CFcu7??0t>C\FGOg:|CFcuuc?>1gQgQFуky?c(y?c(X#Oh5n1n1t{c4`7^ 7^ ?:=10} s???a} >ן??ן??0t>C\FGOg:|CFcuuc?>1gQgQFуky?c(y?c(X#Oh5fgQgQFуky?c(y?c(X#Oh5n1n1t{c4`7^ 7^ ?:=10} s???a} >ן??ן??0t>C\FGOg:|CFcuuc?>1gQgQFуky?c(y?c(X#Oi5ꚦO۷unDmKLk r:Z0R6z(\ (c[MᩇӜf+Wָ MŻ?uo~N>p4|y+;yŸ3&5}Egy7QCؚ>j< j< j< j< j< j< j< j< n>s0E?:ѸȽh?Q}h}had^?f>n>s0E?:ѸȽh?Q}h}had^?f>n>s0E?:ѸȽh?Q}h}had^?f>n>s0E?:ѸȽh?Q}h}had^?f>n>s0E?:ѸȽh?Q}h}had^?f>n>s0E?:ѸȽh?Q}h}had^?f>n>s0E?:ѸȏZ}'$»>"5qLIQφˁ?'6q5vtQE}EPC<#N!(<y7H w.-L,.O3 < 'q<7YJ6KK4(`уW WǨ3__'?Ռoej0hx?  h/Qc{/?p4`COs2ͧn?٣fm~Tm3,lv?m?q~U=Kzʏ̔r"&gU7lW { ~t4q+Gk)}V%f Lٴ5[ҭmvfZٴ4lvzʍ~T}^`eO߳Gͧn?٪GvAQz}m?q~6ݸfm=GfZٴ4lvzʍ~T}^`eO߳Gͧn?٪GvAQz}m?q~6ݸfhW9kfiۏj?*]~T}^`eO߳Gͧn?٪G=GfZٴ4lvzʓhW9e4]'Qc5> <Ve©LzW+rFkGq}RAwډ^5rx'8-ANI&2Q]YQxJpva?6ݸfO߳UARm>_6ݸfO߳UAQzʏ̳iۏhٴ5Wh.?*>Os2ͧn?٣fm~TG>_6ݸf:y$FiAW57`rhgU7lUgmVb*U_Mfn 贞t|puTR <ϸs6ݸfO߳UvARz}m?q~6ݸfm=GfZٴ4lvzʍ~T}^`eO߳Gͧn?٪GvAQz}m?q~6ݸfm=GfZٴ4lvzʓhW9kfiۏj?*6AQz}m?q~6ݸfm=GfZٴ4lvzʗhW9gfiۏj?*6AQz}m?q~6ݸfm=GfZٴ4lvzʗhW9gfiۏj?*]~T}^`eO߳Gͧn?٪G=GfYٴ4lvzʍ~T}^`eO߳Gͧn?٪GvAQz}m?q~6ݸfmhW9gfiۏj?*6AQz}m?q~6ݸfhW9kfiۏj?*6AQz}m?q~6ݸfhW9kfiۏj?*6AQz}m?q~6ݸfhW9kfiۏj?*6AQz}m?q~6ݸf=GfYٴ4lvzʓhW91#"7HEj+#ƯFt"' }t$P䓆p?QB582EWAERks;!!\+ EuF+>/@nЅ]JOU OQ_o㇡֞4QEQEQEQEs~,]m5V@ZoKVYjЖ=FOs?oUni p*\H( ( ( ( ( ( ( ( (?W'ZVMur~uo֞/ OQ]ii EV ( ( ( Ykoş뭾S.LG0̷kS&Ж-#A 0_=)V6ޙE2,z7 eXn(()Q`{ѸS(?ppQE~FLލ™E2, 7 eXn((=Q`QS(?ppQE~FL™E2, 7zeXn(=)Q`Q{(?ppQE~FLޙEo߶~t^ p`?<]?Fh (-i  7<3\ºCB[X ߔ<*׆IxNo^*TyC}}Wn4n>(}iQ`QSh;qqE[+:V:.4ևYwzBZ=ίHcoW76W+ y}}Tc7jmXn>n4(}}Q`ѸSh;qqEvFMƍڛEۏ6,!l8W#9^ fWo]5/AuDru%sW_Wrā}iV6ڍڛEۍ6,j7mXn>݌WA\ZЙ9mN7].Ot^gCJB?pvu4(ŢF@p"p"E7p?ȠF@p"p"E7p?ȠF@p"p"E7p?ȠF@p"p"E7p?ȠF@p"p"E7p?ȠF@p"p"E7p?ȠF@p"p"E7p?ȠF@p"p"E7p?ȠF@AoxġF<\G2!#QtQEyERks<3\º|4_J;?SE! rw <*׆ A:Ҿ끿_vsCh ( ( ( (9z? agCѮ3}-tGhzW6W*AmWkLh(Q@Q@Q@Q@Q@Q@Q@Q@t+?`߄?Jf rֱx_B+\;]:۠AEV# ( ( ( ]kqݿִ~4&c_?WM:rڛĪ+doyڭ+0{Uo1J<*9XhcyQEV_ҎV*cr,U(f?G 4Uo1J<(`YyQ?G+[_ҏ1J9XhcyQEV_ҎV*cr,U(f?G 4Uo1J<(`YyQ?G+[_ҏ1J9XhcyQEV_ҎV*cr,U(f?G 4Uo1J<(`YyQ?G+[_ҏ1J9XhcyQ߭kc tY FiEzEQ^AQE +q#W`: Snii՘] 'qUk I]SBg?O?oGp;1Җt/k(u XB#;٤Iϐ Hܼ+>#ZuVγim0(LN|g $` ?ƟW脮sktHc~$d/gG` ͶæEQ@ߋAd* +[~niжuz'pU:_2(((((((((\f!?5vr\f!?5j!uC3!# J<3!# Ju@+Q@Q@Q@s~/UW7PZ0"c뛟:RW7DžC-A5>1= ( KIK@%-%-Q@ KIK@%-%-Q@ KIK@%-%-Q@ KIK@%-%-Q@ KIK@%-%-Q@ KIK@%-%-Q@ KIK@%-%-Q@ KIK@%-%-Q@ KIK@+#ʇD'k_x*~_C5͏*]Q^9QE 07һF+'qWc_W&Mr6m#t5fV8Z??U 0:s,GoaT6?T  oU^s7 QLǎ?p?Ȩ?ppkU4 Ru$INԁYφSq-GsqhZ7uG#R?Ȥ?ȦQN?p?Ȩ`x*"M?qjxL?5l߹ҶO_ш4B?pvۅfW9ynRnS()w*:(?ȣpQEp"p"E.EGEn(nRnS(?p?Ȩ?p"™Ed#a 4 nWa'5i1[j9R_ 0:s,Goa]\??BZ ?ȣpQYXd()w*:(?ȣpQEp"Ao;0ZR^3 S9O:4v"v}n8H=>iKXW_޿dz2=!{z̏j2=E{z̏j2=޿dz2=޿d{Q(޿d{QE~(޿3#QE~(޿3#ڌQE~(޿3#ڌj,F)j,F)dz,F)d{Q`J7Ld{Q`J7L#Q`J7L#ڋQJfG#ڋQJfGQJfGXo_ҍS2=EXo_ҍS2=Xo_ҍS2=?{zoo_ҙ(?{zoo_ҙFG?{zoo_ҙFG{z̏QFG{z̏j2=Eam )_ -\y1t|6 /ǘ  β((Rٍny??B1\GTo6XG[}%Ρ%0(K+p;W4Wo" C)LW;ź+MH a\_&$~FX}FzWzr!,F P+hQچ6{Ԕg5!B'pT* }O<⇡EGQEpuMSHS3MiE0klI*:5Ɠso>" Isa_\%6Š(QEs/Ss ?4ƹM?V1f ?~hW'1*@((((((((lpo__ѫ45_?BZ/\U(aEPEPEP\tUL?֔!3?8{I(=<tY,LҢy(Vb,Uy(f締oAEh{z <YEVQ締e*ނ=`Yy(Qf"[oAGނ1h{z <Yf締oAE4Wxƕⶲ{솝 l$ony*O}| n-cU[^\[,Y:@޼H}rN9ixH *Z"qu4sX= q1qO2}=mmZK{iV" *Ã1+όt}?f #ۻ83OOJJ\:K%[oAGނ[oAGނ0,Uy(f締oAE4Uo={z ,EVQ締E*ނ=c,Uy([oAGނ1h{z <Y܋_F5rZ1QEQJ[1~C\GCqʺֿ&L h[[nӐ\r$:ZҊ;]Iʤ3QVG{!b~\Go0? TU:v'=M%} EP~Xij3?lKH F!o8< [^Ou!0#*n2IO jbˉ#o&q̤26{a3\w[xM@htQ:L\FnookIKIZZ(0|W²nePs /4-0t/aWj ~r݀RRTQE%-%-QE%-%-QE%-%-#}r:GVuO1ZOro?v';_qʻϠRRPEVAV`T\7a_ǖo2*ױX}wFCZ?a~4RQ]J(hJ(hJ(hJ(hJ(ǿ#x?)| "Ooֶp?Z;"" >k^5utt a|K/E_.vj ` [kZ+I_ayW.6קQU잪0ֺͼbZ\153ɣXŨ5Ԃ]x9kmI}uqaTwRgLP+b H>%0ı y<f5I%o+5{t)JnL0? TUZvũ0[<A__g_}4+Z(|#|/W:O&1R?qo JZJZ(0|U²ne|ެ?V_xz^ ~ڡtsWvIKIRERRPERRPEO1ZIt##Q?]kunO_NrRRRRPEVAVs+'ʇn&aߟ]7׿2ճbрݬ{MO?hlXX>EtؑayS(?>0 e}a)XQAL0 <)SayS(`AG}2,(QLQAL}a(>E0AG}2VayS(?>0 e}a)XQAL0 <)SayS(`AG}2,(QLQAL}a(>E0AG}2VayS(RS?|/9qZ_J+]"qZF(M(-xc>m"*|16]~L&}|AHtחaO,$cٛ"YO ''z]?f2I|o;`=k5I۵f99 7wF-M C ]ыSx_>"W~G|q;ZJZJc(+mnIKIL(_x*ȸUy#⬋Xw2:s.S:?+?Ct< hS -Q@ KIK@%-%-Q@ KIK@%-%-Q@ KIK@ 4,dz 'FK/ @ k}[EvrJZJZ%-%-Q@ KIK@s+W]s+WW >6Եd ˼Qk iڟx(l_6KE&hϵu-4RgڌI3@ E&h-4RfPI3@ E&}->RfIj3@ E&hϵ-4RgڌI3@ E&h-4RfPI3@ E&}->RfIj3@ E&hϵ-4STU»/._98!]¿g۟4eEWhQE)lƷ<["X/+=o$6FfZ uf|=]EbI+XJe!Nug7y?hLaNܜxbԾ?PX?1j_ uE~#ο٣fI|h٨FNX൅K,P+о%W]m+TXG*ڥ,cVg8eogO-u#M픝 ${{V)O?rh2q-|oioAe#"QV^E${o5dI/o5r1Pۢyt?FZ%㬉cu:3Wk;IݫJ%٣fQQG*_75{ZW.?sP/یgϵaM+usk Z`Zi ^$.ʼÜL\?Y 'j*.k62qZˡxL5KHs#yI[=*?\}di<,PIne gjNLگ Fm6nNgrW\M ; ;kϨ͛siG kȮ&7Q:ȬObVß:#V\45jOF~rEWQ!EPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPk]w.?wFGu ?\.iEWjQE)lƷkIN _OW]Z-Q@5m^HO.R|8'ޗVo#?~VǕn׌g>X,ږG,m_Eg_2LT|u|Vnv6ީ[Fn#GJ? xX,c׼O% =`R{{I';T^+9]3M= >)w# bMf+v4=(bxEm'_SB1_X?>Ý'HhOKqՖ~iiD]ڍivj6jJ)v6jNh}h(iiii]ڍivj6jJ)v6jNh}h(iiii]ڍivj6jJ)v6jNh}h(iiii]ڍivj6jJ)v6jNh}h(iiii]ڍ!D]W?Gr*vֺ-N}oGz?S;Z(S@)Kf5>#ugN5o_θdEt YrgA^Vs˴L  D `UڪUiC[c1qssv]Ez^mpU.mF6I\usWt=EtrrF9B/ȿެaY tuoK?ҮVMz)%*rU( {:O^aح"БҺ/d:ğ j7vZKsp8C d;63OUM+U}:Z+m]72~bumsL4j7`a1ln>{bž$Ѽ)kq՜ߖv! '*/kAuwXfm;MiLfO!O̠g=+Z\=C^9牯DEDfh GvuFloo亵&Ie@HAn@r~٤Z`, F$$s>tt~hr]["iF/u;RM6 jzφ|i\K%Ѯtmp FHzGknmǠ _i垥̷r̃Α||đJvz%PIsb[pzUM0^Ѽb 'bn݌1W[^q5ػ&肺&*|rF9B>kINt.#._MB68E៿k^뫍OAVWzE>P@t_gjP^wuU ]kkMn vyFsڶ(t >ծ:_x}ZO[{oS;ylg5gY'xM{>ȗ .B0~Rzhw/QThyErbxE]oZ(?-ԭY|;.籞8/.|*+Hw#cr:j/WH]Gq?EpӧxV[bI_23G? o.V-/.'4cW ?Z)?_@]+Oht?9XRcW _23Gר0rht?ҿdfQ`bI_23G? ^ŢҿdfJ>CE'? /.'4}z+OJ?_@]+OhF-/.'4cW ?Z)?_@]+Oht??9XRcW _23Gר0r1h7? /7? O3Gר0roJfoJfP`aE0&?0&?^Š?a@M+2?a@M+2>CcxW d4cxW d4}z+ (4h4hVQi_1i_1(c'ҿc'?9XQG7? O3G7? ^Š?a@M+2?a@M+2>CcxW _i_1(ҿc'ҿbfP`aE0&?0&?^Š?|a@M+2?a@M/2>C\}*ȱ7~y?KT'my6?L|Eg,Ir$؊ub˂hݢ+,(Rٍnxo?ײ"J9AWϵ#­oƝϫk:,N`X8ڨOA]5sw|?֚Mge>gVDL϶i<;?KmR5c(PFGNETe)h_RQbѶ:fToF`6ԆPAR2*(`-QTEPEP75˦zokJL#lqܭv+o??WIZBaEUQEQEQEVf?YxR{2?j뫑e W$NQEQ@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@kg ]=,Ĕ`hMOUO6xUS&mTQC(/)5;6K= 6K=Oa1%%?4fg݅q%dO3dOd!њ9v_Q_SFh}]_ 6K= ~hϻ 6K= 6K=Oa1%%?4fg݅q%dO3dOd!њ9v_Q_SFh}]_Q_SFh}_.l w+`ZW?kY 9 EdwV|>8]9}I:ҋzX,qQ^QJ[1 OAW76++gR~5w;$}(JZ(ow1^5VQE0(3[U՘?|ui>:ԥc*z=cvWI!EPREP=#>/æc-\Ψ\Ddj'U|{xJ]勭ՅLjmF@p ~V V>ݻd𭩴K\a\? }3ڹ _J|EmoQ[`FsӃmz2yϞ4m#N.ox:fʓBa@#`O'=|7PxwJnV"XbPf_|֕@Š(%-PIKE!kKK%mͥҒ ;3EtgU{G+X|(AIK^tn|QxVCXXRli|[\`[='>[ip=o^OhzLfn!oY]w|X*.0~ofFG2aS77Z9s!S7Z7 9szѸz̃}֎d}֍Ždons E3xp2E3pp0)ǭ9L(=hȦL=h(Adx 8MM{L'aE'6$wu՗a? ( (c[6+gGӬ>;TgR^9{iw{CrKKK1Y@{Zzɲ u=2$qqm>b]>hUkV,k7TwPͿJwY״mrS2+S~GgďQQyQA_ h(G^iRCs#mUZ;Ƶ5HQf ߆k#hZ|ڽݭݼk 6PqX4[̹[t[x}쁏jF6=V>0 谉h(QGf?h L) brR: ڱU,ح`jo0 $>0 vZ*/0 <(QyQAE>0 ,T^ayQ`%>-}aX h(KEEAG}Cұ4RVr{ TW)+68AV+g',>2Z4k|Sy^RlsנǽlyQATp9]{77χmFh+,̫K#cs3\jR <ڪ*z]xOYX|>%1"R0('诬Ioq >nǩxJ{[k1?i[$ o`fn}yϣ%P}'F.y>0 aX.fx[A搶6,ĻK,1;SlT^ayV6VB%oTU0 S?=~ȿ7}Zzoѭ]|o?SuQEŠ((((((((((( hXjg%~fFE}ƍƋ) ѸQpE3qqt>fFEn4n>\.Lhh]Qp) S77.Cn>n4\.cǃln'lW?e^"?e^"Z _Qh,.;!s'כx[:γd߈䲻aIь OtRyOvJ7V744ѴbX<7)GQ>: 4AoH>big^[gQK8C3::jy0XZ@mrZ/L#'8GJO[{2gZGjs] ]cחkioMZf27gW~4wqM[XH'eaA^})S?0V9uE%gZ1J[wsv!׵{[v+8'##8W;xt b:y_ӧ+s AFCsڪM;f&uxV-SNb/ :X9>T~:lt<; NRΡmm.#LbW[1x#ZmPf:ܱP=mǾ)4I4 [ksvr3=sRR=SW?.zoѭ]q ^.?kWa_/[[QYQEQEQEQEQEQEQEQEQEQEQE?wG%dk>L ŷ/2k?3񣠣Eyw8]QG0\J..R˵[S46ѴTdңㅥ¯dRԢH]4%Ԩ%)$ĺ1?5 Q;oi rAy^ܛ k&{>%ɝv@;XvaY:&j%\B|GRQЎ.ſ}Wi<9.E8f2`F~TkXZǯxׇ4{xzc7'ڴ*LPƤWr'="BTfIe7ôyj3q{o{3(|e.h1CKcR 2ea#q$E;ZV|6]Kfx\N TvJ[k&Mk/ogӠ {&ns,O9 |&-]EMrJ9hTQpvj\.Q&|V C5 {? cW5Q^QJ[1D8k+ww=+_c^"S_bϷ"Π`,~u(1ôg=zڸ]*[ :%rM)]águ֝zJ)}ůT).F>ͷJ_ K#i)}_V9(yפ_x=W|wH #4!ƒB\6h= C MQp>h= CQ .&= ǡ7AKQp6i7`qs[qmUc' Vψ<)io=+ :J}(}iy= g<7^>;8>ܳ9i{4h= CQ .&= ǡ7AKQpO[9?^|s1;X93Ztѭ^UC3+=@)Kf5;Azy؟tAzؿ˿m+To䪐 d8i)Fc*JOEmu1rQHIm?a^"T?TC|IAMQ@Q@Q@Q@OQ+0ǎV?fӿ*ԤmDz}IQZǴARQ!ES((((((((ҳ44?*Zҳt4?*Z ~;A~ ǕzE8ɭi(AEU(((*?\z;/._9뱮7gz|llQEfEPEPEPEPEPEPEPEPEPEPEP?O}LumxE|ҘLN?׃|k1.Q@WyE@ P(Q@PE@ P(Q@PE@ P(Q@PWJ+Go?G=PԆb]o ]g)ߡ߀QEQEo ǍzE#xפ_W}s{x^Ҧkf[Y^I Id{I,4KYXbTyb#y_xc<4A/|uXQE~xEPEru[]b&m~43O`"#kt= PEK@h (*j?YzwZzxVbǞ1W%Gcj= xHQE((((((((+;NFeӿgѿk68Sxi+v1zEݭi(QEb ( ( ( O[xR{|*r]q \nse_-[[QYQEQEQEQEQEQEQEQEQEQEQEßeQVN0%~cZ?Z'W1ͳiGUf ]m})vѶQK@FJҗmhh@> ]m})vѶ*ޮ䏷;UQ] _R|3E>^SC3+=@)Kf5AXv^Rf϶ N>&Xӭco b$d-%KmF5C:.0ms޺qs74'ft1*i&GQG ?"EGv^qE?TCv(O(~3523}sK~ ︞Qg[wm@w),3Ƿҽ>t{C (QESQT _ӿ*YQǦ1W%>-mIQRWR$(`QEQEQEQEQEQEQEQEϣ2֍gi3?&Z ;1zEݬ/ ;N8[? (AEPEPEPU5IuWPO'¡z} yuit ]ǰ7m..an%@?^sst:,CF??Œ] y1`0} sٿ1bgQO0: CF??Œ]ߘ >Ah5gQG<Ø0} >]ߘ 1w?c(s?F.oT}Ø0} >] 1w?~c(s?F.Tc4`w?~c(at>C\.ٿ1}S9уk??y1`0} sٿ1bfQO04u-u}*{+*He`\0KaI6ǥ7odmn?Z1w?c(+et|zԧ 9ݞ/{K6/o+??±á\Իн<_B7bfQGj]wo^fb/{Kw?c(p.;/i31FнtXٿ1bgQC}Zcg^fb,]ߘ 1w?~c(á\>K _ Q/i31].ٿ1aVv/o(7?Œ] ?WRs<_B7l _ WEF.ot?թv9ݾ/{K6x/o+7?:Իн|_B7bfQGj]wg^fb/{Kw?~c(p.;/i31FнtX1bgQC}Zcg^fb,]ߘ 1w?c(á\>Kv߼O)sȮ4HeI#f?$.j:uAnջ0]F|u6+]rL6Hé*p‹QEAQEo ;OH[ui+n^Q\O{ˉ _MK2Mَ)%q[Geg`b@ĒFI[ZTjJQzQ(Կ_v=(t@w|wXQE~xEPMWQtou 6`N2@Vo]xy 5xsFQlz$t{VGP<;l#]GQyo}GhI>k0Y'f(;cʯԁsJU9VöQE (?eEoZzSrWR۷PJPJ!ES((((((((O-hu'_c? 7M8[+v (AEPEPEPUuq*U?4+0:_4?ٖ>UyүxEoAo/ѸT{.Eea}j=7 ,3p"p"&FQX>n5EMڍڙIEqq ],j7p"‹&FL?Ȥ?ȢIѸT{.EGFEqqnRnQ`$h}=—p"ڍƣ?ȣpIQS7)7(n4n>KE~FQQQ`$}}X 77jp?Ȣ?qq((n>n>M,GRQ`Q{nX 7j7jfE&EMƍڣ)w(}j=7 ,z?}t r"$q\ߺr?SntQEyER{ nx?K4g+j|.?Wל_{izmGAKIJ:1 KO/Jg(G_>:<- /~_->Q_ QEQP]acqyv]m,vv]'Zcj1I9qN0;rv{QE@QEVH6hUҨZGd[տ*Ԩ#SOHQEQEQEQEQEQEQEQEQEVulj/}@kJf"Dωw)XįL>p+ VkO@QEX(((_ UR{V֡]_[4+\tV=CJ⦯O2槝w5r%h٨ih@KGQRQʀf;9Py4r%٣g(@MGEE |Zơi<;s{ԧ[Gb74~Κ} w>x^ڛb.`7ۉ8ݷ3zUZ ]hkFksZMk&Kx-#j1R;I\gR\߅u-&Ԛ dW&d'O@:;<Z5#MQ,-.$HHپMs,񵷇_.MPY[BQS1$0#'*jsGQ5+8.dɠHAY/GCKG*_;<ZTw4yTQʀgf/w?EIG*o;ڏu(kG_>:<- /.0|OQ$C _zgŏE3_ QF}bxD>E'cHh!FLjIs4gڧњ (ϵ r?"FQVJƵ4TUɈTvfSO?>ԉ (E4QFhϵQ3@gڌE>QFhQj3@fPuOP6羽Z ;- /nV'GJ4e+lZPfU(4f (ϵ3F}r?j 'ޔfu/(Z4a\%cJWMJgtL:ʖFU<y+~Q\zQUO={z 9BҍҪy(Q-nSoAGނPopp{z <r{TQ締.[(=*ނ=rFU<y( J7J締oAG(\QzUO={z 9BҰ> >/.SVނq `)`JI]H#Lu`^x[{}uHTȏ $=3kdԴ?_[h#(%TP0t>~3vn~'5nWΏs #IM6. GxQJ iZ[jny2[L s&ytM[ѴǺYeP0fH# 稬:džWC>ig+ yvFFp=+b鳚K5-lz« XY`CCSҿIHhkf𵡏0e cJ8G%Z6 +Ђ )AЌbTlM"VM^Y'e}?[GWN Qwcڣn:cֶu|/nt6kr'@GOխBRk}FݎLS$Ccegf RL7=W;g8zVuPXZ$PxM締a\zQUO={z |rFU<y( 7J締oAG(\zQUO={z 9BҍҪy(Q-nSoAGނPopp{z <r{TQ締.[(=*ނ=rFU<y( $ WS@2W#9xxt΁7}MJhnuQExơER{ nxGה_XF^QM~=4Y%(IJ:9҈<+ m#.,J#@cm(4WGQEQEQEQEEuSX*}k^QW-GcrO>{ҟ]()QEQEQEQEQEQEQEQEQ?"j:?a&|W8R@k¿?/Vѭi((QEQEQETW_u>-EuSI뾩)]񥮃N}2MW En]TMnjîiV]i&bȞ] #88m>(O>(OO:nO:Nbٌť8/TF.>|bXǾ]5_(1߇KcnS})VHݧҍҝE0FNQNQSQS>`S>m>(>m>(O>(NzUq7 O@*3{D\2G6! V7?׬ҟ„>`S7iiQ@ iQ@ }(Q@ }*+;=Eq#=`U?5nxLjSnOr>"Z)(EZ)(Z)(Z)(Z)(Z)( (92Wt?L 4 K0x[±*Uc{Ey4}9s5' s-0\Ko [ed0N22:RQKd)6;ۍ:[);"Rj>?WaEG=yy)Q^)QE[Ƒdc{WؿK՟mGA@(Gjd__ֿ=(A9^)<1 }+cE~_#峿Cn(Џ((((GV%{U҈nGV%{U҈ԥ7-ԭIQZ!ES((((((((_8o%__8o%s⿄ʎ? JX[u_+n=Š(QEQEQE܏j+I҇1VKqj8?OҶW|/Վ[cړҺ\z \{PsIv4fjLJnisK)q@ &i`z Lњ\J\{ fisN?ŒA@ ǰf4AI@ L(њv&=74`z 0=(;—PsFi杁(4{ \A@ `zRcڀ\RzPsIv=ǰ`zRcڀ\RzPsIv=ǰǵRڀ+](?wu޹{#{WOEOϯ?S;Z(S@)7eqc5ܳ9і'$nO8<(1?o5NѯԜ!q" 涍?kBzժS]Fa/:mƩGCUKdk|hQx}O~3;N5Z>68p8FjFeol]m-̢,FWR=:gKdk|vaUQ^F3F 0d'?9`ǨO0dyG-4ؾ}s?Q`ǫ%_揲[5h[}xK2KPhl\} H?Pk]=ga]Z1xnUNpro>o<bdqZyeS>nDZS6/GosA}yG-5v/O-_h?~EKA_MKdk|b/?i9EKA_9 o<?_em>39 ?/4?]7-4}yG݋ͧ/4?G"%/%_揲[5h[}ٴ"%/[Ŀtdk|Kv/6s[Ŀx>o' sj@P-myG-4xߋ}O@P-C|Z%_揲[5hZ]?}O@P-C|Z%_揲[5hZ]C|Z?-CUKdk|~,?1?-CT?Zkƫo>o' sj@P-myG-4xߋ}OA'P-C|Z%_揲[5hZ]C|Z?-CUKdk|~,?1?-CT?Zkƫo>ooo' sj@P-myG-4xߋu>0/u =c⑆]H4l,1(x5(|+w% K!c+-jf5eFJ*5R/s^(lŠ(-xjoaWa p> m0!<x~7?$>PI>x?<|~yMx?<|~y4|hǡ;x(M?CYx(GbhTyƳQҏlǡ<|~y4|cG= gy=CQG??J={Gx?<|~y4|hǡ;x(M?CYx(GbhTyƳQҏlǡ<|~y4|cG= gy=CQG??J={G?י|b5#²k+EhȈ9`v9im|GFsBO${T5֨TRͫ+Mv1|N/K~aY;;]B3>S5I.BmnHa#3W0 p=/e_Oq붛hkhǡ3;/5X.QK2q Vu]JR娚~c#5x>x?<|~y~ǡ<|~y4|cG= gy=CQG??J={Gx?<|~y4|hǡ;x(M?CYx(GbhTyƳQҏlǡ<|~y4|cG= gy=CQG??J={Gx?<|~y(Pb㮗od?lT4\"ζ(>|(RٍnxWmkEt>w\׆yAkVZ>ڗ>oGZ+ů;j]^wGZ( o֏;Qv-y߭oUh,ZZ{sIfKɣ,00+`;Na4uͭ[MYގ߃ɫ*hwUv cF2*FlUH8@Ƕ+(p [׭MfS~K N+(;o!jĺфmztӤů7jvibם~V.ů;j]^oGZ( o֏7Qv-y߭wUh,Z}Z蓏|-91»O'>nGFz4?S?NΊ(>t(<'kzz pAmx#Dծ互 e;X<}5 Ecw]|M~Rzo'} t4_?gq Ecw]e/fs{?: ??ZhQ?0S}}iα;.V/3Tj?CF]'+M~ut´XGW~/?a7Ѱ?Zh?: ??}9ލ޺OV/3iα;.F_plY>l>OV/3iα;.W~/?a7ѰI Ecw]4_?gq)>޺OV/3iα;.F_plNoaa5´XG+M~ut5fs{t4_?gq Ecw]_هh}iα;.V/3Tj?z6z?Zh?: ??}9ލ޺OV/3iα;.F_plNoaa?: ??ZhQ?0S}}iα;.V/3Tj?z6z?Zh?: ??}9ލ޺OV/3iα;.F_plNoaa?: ??Zh)>l>´XG+M~ut5fs{t4_?gq Ecw]_هF]'+M~ut´XGW~/?a7ѰI Ecw]4_?gq)>l>´XG+M~ut5fs{a?: ??ZhQ?0S}} t4_?gq Ecw]_هF]'+M~ut´XGW~/?a76z?Zh?: ??}9ލI Ecw]4_?gq)>l>´XG+M~ut}9ލI Ecw]4_?gq)>l>´XG+M~ut5fs{a?: ??ZhQ?0S}} t4_?gq Ecw]_هF]'+M~ut´XGW~/?a76z?Zh?: ??}9ލ޺OV/3iα;.F_plNoaa?: ??ZhQ?0S}}iα;.V/3Tj?z6z?Zh?: ??}9ލ޺OV/3iα;.F_plNoaa?: ??ZhQ?0S}}iα;.V/3Tj?z6z?Zh?: ?_هF]'+M~ut´XGW~/?a7ѰI Ecw]4_?gq)>l>´XG+M~ut5fs{t4_?gq Ecw]_هh}iα;.V/3Tj?z6C]'+M~ut´XGW~/?a7ѰI Ecw]4_?gq)>޺OV/3iα;.F_plNb1#sֺgwZA]Htei\= ´$ўͨO"7Vr]AGmi$ +ɲieҔ+c%$4QE}Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@ endstream 13 0 obj << /Length 14 0 R /Filter /FlateDecode >> stream x+T0P53T034 (U!\K!( E\N!\&@iSK=c}7#C#4#g;,^.W@,L p3 X>#>3b)9 Z+endstream endobj 14 0 obj 112 endobj 15 0 obj << /Length 16 0 R /Filter /FlateDecode >> stream xVۊ1 }\$cBf@ޠ-'cɎ=3;9sU>CG.߯?շO~w~7\;w^uZ]~Uhzu!tG8M&ɂ--aαHBQg8ԡ e#^|9N%@7nt$Yѳ)JL`G.)v(C31rg$NI;{U BZk:fH @"ٺ,X 's0<q*&gpNb)["/t5C%sV0YulZ2 n u*n5#͒+w8U6 ';ȳsWrk˥Yr2~Ȱ > +;/6,g6aܚq$x$*o݈Eex g ZbΤ-9f5k6ÛߎV="&jE3O3V4w++s_jz}0FGs~twqUّ8rPe5EM`G4Q~tO\sBendstream endobj 16 0 obj 642 endobj 17 0 obj << /Type /XObject /Subtype /Image /Width 878 /Height 586 /BitsPerComponent 8 /ColorSpace /DeviceRGB /Filter /DCTDecode /Length 41927 >> stream JFIFC   %# , #&')*)-0-(0%()(C   (((((((((((((((((((((((((((((((((((((((((((((((((((Jn" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?B*y,Uzεzt#Qœrݠ8)qhܴ5Ӣ?-?q~ܸۖf\'AZiYܸۖfO\߳G~ _4O\߳G.?٣W ?}VtVg.?٣r>WM:+3riˏhUgˏhܴ4j?SNܴ4nZr?pj)EfnZr?-?q~ڸOӢ?-?q~ܸۖf\'AZiYܸۖfO\߳G~ _4O\߳G.?٣W ?}VtVg.?٣r>WM:+3riˏhUiˏhܴ4j?SNܴ4nZr?pj)EfnZr?-?q~ڸOӢ?-?q~ܸۖf\'AZiYܸۖfO\߳G~ _4O\߳G.?٣W ?}VtVg.?٣r>WM:+3riˏhUiˏhܴ4j?SNܴ4nZr?pj)EfnYr?,q~ڸOӢ?-?q~ܸۖf\'AZiYܸۖfO\߳G~ _4O\߳G.?٣W ?}VtVg.?٣r>WM:+3riˏhUiˏhܴ4j?SNܴ4nZr?pj)EfnZr?-?q~ڸOӢ?-?q~ܸۖf\'AZiYܸۖfO\߳G~ _4O\߳G.?٣W ?}VtVg.?٣r>WM:+3riˏhUiˏhܴ4j?SNܴ4nZr?pj)EfnZr?-?q~ڸOӢ?-?q~ܸۖf\'AZiYܸۖfO\߳G~ _4O\߳G.?٣W ?}VtVg.?٣r>WM:+3riˏhUiˏhܴ4j?SNܴ4nZr?pj)EfnYrOO\߳G~ o5(O\߳G.?٣W ?}VtVg.?٣r>WM:+3riˏhUiˏj7C*"\CXJS +kwt"]Rg;N.+ T|J:1u))qWO3udv8bf:Q7|Gs8~s{Q7e?(G{D͗8裏7s{Q{6\?*yGAs8~s{Q7e?(G{D/f˜tQESڏ9~͗8裏7s{Q{6\?*yGAs8~s{Q7e?(G{D͗8裏7s{Q{6\?*yGAs8~s{Q7e?(G{D͗8裏7s{Q{6\?*yGAs8~s{Q7e?(G{D͗8裏7s{Q{6\?*yGAs8~s{Q7e?(G#.qGOoj<{6\?*yGClEtU?9ڏhٲqToj=f˜tQESڏ9=.qGOoj{yzxԍ%czZFo^Jx>۔0\K?fyw)о *G}J=Dj}}GU_ҏ8{Fh_CQ?e>чFT}}Y~q(GaȍO/BʲQ_ҏh٣S *>о8y0hBʏ//>q(9?h_CV_}Jч"5>о *G}J=fO/BʲQ_ҏh٣S *>о8y0FT}}Y~q(Gaѩ?h_CV_}Jq(=5>о *G}J=fO/BʲQ_ҏhÑh_CQ?e>чFT}}Y~q(Gaѩ?h_CV_}JÂs]pÚM^^kkos_ޥ{\u騎XP Gl֔'k)::[LPԞ|7jV_Юmjf?36ÿzGe, iV2ܦƸs9o()s5=ֲm^߈n5ݭٸ 12O^'E$u1[ +*923O\5h*ݧۮOԉ+M> hνIF c8??ӏ|F\IePdR|w t(xy_k..Fvq\Νm^/: 8&_G ;K)#o^Q%tIJ*w-V)*_{>_<uzcN$`8>h_CWFyѝ>h_CQ?e>ч"5>о *G}J=fO/BʲQ_ҏh٣S *>о8y0FT}}Y~q(Gaѩ?h_CV_}Jq(=5>о *G}J=fO/BʲQ_ҏhÑh_CQ?e>чFT}}Y~q(Gaѩ?h_CV_}Jо8y0hBʏ//>q(=5>о *G}J=Dj}}GU_ҏ8{Fh_CQ?e>чFT}}Y~q(GaȍO/BʲQ_ҏh٣S *>о8y0hBʳuCذ~i7ӟa2W)9}lz\ 1נWR>Cizx7&dm-[!=;TFpUkjS"ve3jgоzVX&zZ`G4GkKƿ?q~ѩEeGkKƏH iJdjQY?*?=Z_G4}R?=;RA֙Q?*?aԢ#5TG$z hp{X25(H i A/>_ѩEeGkLƏH iJdjQY?*?=ZgG4}R?=;RA֗Q?*?aV_$z hA֗QTkF A/?#5TG+#ú5(H i A/>_ѩEeGoKƏH iJѩEeGkKƏH iJѩEeGkKƏH iJѩEeGkLƏH iJѩEeGkKƏH iJѩEeGkKƏH iJѩEeGkLƏH iJѩEeGoKƏH JѩEeGkKƏH JѩEeGoLƏH iJѩEeGoKƏH JѩEeGkKƏH JѩEeGoLƏH iJѩEeGkKƏH iJdjQY?*?=Z_G4}R?=;RA֙Q?*?aԢ#5TG$z hp{X25(H i A/>_ѩEeGkLƏH iJdjQY?*?=ZgG4}R?=;RA֗Q?*?aV_$z hA֗QTkF A/?#5TG+#ú5(H i A/>_ѩEeGkLƏH JѩEeGkKƏH iJѩEeGkKƏH iJѩEeGkLƏH iJѩEeGkKƏH iJѩEeGkKƏH iJѩEeGkLƏH iJѩEeGoKƏH JѩEeGkKƏH JѩEeGoLƏH iJѩEeGoKƏH JѩEeGkKƏH JѩEeGoLƏH iJѩEeGkKƏH iJdjQY?*?=Z_G4}R?=;RA֙Q?*?aԨoFmGkKƕ HH]oL-\'ӷĎGK**HE$q]܉".*P#;3"Uˠᅧ+4)V]’XT"S،!sK=!WhӃg ž UV *:_O6}bk쓋+b>tB_nfϬ_ٶXdc?gV?$,tNHnh\IAI)A Yl,6}bhʹXZ6 C`ޮ'ɀX'dSs5?m?/O] 1w?c(sٶGm|V.o1}O9_O6}bk+??Œ]ߘ >m|i>5F.SsW6}bhʹX??9i>4fϬ_ebgQGÜʹX?m?/沱w?~c(~ajfϬ_ٶYX1bgQ?05m?/O] 1w?c(sٶGm|V.o1}O9_O6}bk+??Œ] >m|i>5F.oSsW6}bhʹX7?9i>4fϬ_ebfQGÜʹX?m?/沱w?~c(~ajfϬ_ٶYXٿ1bfQ?05m?/O]ߘ 1w?~c(sٶGm|V.oٿ1}O9_O6}bk+??Œ] >m|i>5??9i>4fϬ_ebgP~ajfϬٶYX1bgQ?05m?/O_Y4IFRpAU$FrQq9$ZO6}bkOI#rNvz??‡ajfϬ_ٶYXٿ1bgRsٶGm|V.ٿ1}O9_O6}bk+??Œ] >m|i>5F.SsW6}bhʹX7?9i>4fϬ_ebgQGÜʹX?m?/沱w?c(~ajfϬ_ٶYX1bgQ?05m?/O]ߘ 1w?c(sٶGm|V.ٿ1}O9_O6}bk+??Œ] >m|i>5F.SsW6}bhʹX7?9i>4fϬ_ebfQGÜʹX?m?/沱w?~c(~ajfϬ_ٶYXٿ1bfQ?05m?/O]ߘ 1w?~c(sٶGe|V.o1}O9_O6}bk( F.SsW6}bhʹX GÜʹX?m?/沱w?c(~ajfϬ_ٶY@]ߘ 1w?c(sٶGm|V.]ߘ >m|i>5F.SsW6}bhʹX??9i>4fϬ_ebgVn}iGy#)8!Q;&b@E:9ɩXLKb:j-H8I4_3^^ni%fKOtQE|?v*u XW>Nv^Iu[mf }v%QYQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEYEhx<xVxu]+>TSR5 ֥eS` (QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEV?n?kGB{^+k7y]_WK^^/4^m L#T7S:~S:̊3Q_3s\nƧq>ZummoѲ)A3]nFki?ƿr>A2=Edz2=EGELQFGI(X 2=E&G#TtQ`$dz,QQE#Q*:(dz2=EGELQFGI(X 2=E&G#TtQ`$dz,QQE#Q*:(dz2=EGELQFGI(X 2=E&G#TtQ`1[QeA~?QO3+GHߏ|_оG?εk+? ju>&(Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@cxA![5iOB{WY\?^A+F+GSWW&=⟡ (W̝\%/s¸J_XmCvOc!3]q?_'5O>AŠ((((((((((((((((((((((_ 顿~չa 覭Qu7|0I#ϩuXdSflQEf0((((((((((((((((((((((((O4+n襯Gpq"'F_ź|E!)F7%N够Wjq:M]_>ǽشQEfEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP';?%{ os w-[>fGǯ±<- [5Ƈn*,J7 eXn(()Q`zQS(?ppQE~FLҍ™E2, 7 eXn(()Q`QS(?ppQE~FL™E2, 7 eXn(=()Q`QS(?ppQE~FL™E2, Q٭? ®2ٗA+F+[Fo ԫʋJ6S=◡')wkz|E!FƸ/#xYկSj:\OO _+Xn<Y?&XJͯr>%}hɨQQѸaQQѓEq& '֍֋&Z,T{4XdTy>n>XDTy4d`$}hɢ$q$ɣ'֋%FM%O%M>X (Z2h(}h}h(hIEGѓEIEGFEIEGFOJ*=֌,3# os w-[)'1$׉1$- [gAkӜn2Nw-U)( (Q-Th 誔r˔UJ( trtUJJ9B*rtU:Z9*%rR9B*-rRPrErN@nIG(\ETPnKG \ET.\QG(\ES.[RQ.QU(.[-7^4G}3CKAWۦ ]xد;yIoCjj#\?S*~r:)iu<_^xZi-W(m| FR_sNFW?'T 5xG\фh}A7\O\E7J{c.e̺oFt\F!묟>W?b>((((((((((((((((((((((? ¹ ??CWG?\Ӓ4{GF>Vc`nJZJZ JZJZ( JZJZ( JZJZ( JZJZ( JZJZ( JZJZ( JZJZ( JZJZ( 7OZ֬4*3CMGj>Ez1_őv g|xszFY#FF5|w|r:.kȼ#Eյ/j'ۧycY!, \e$89X>WT FgF3iˠq1)1DDUT ++S]`\?or9I_4v%gAD\=I~zqGŽ7w5ry4r%٣g(@MGEE |Z9zGaK[Ֆeok:M3$ g GA <'*ץ75v+ǻW¿&7Du۴~ע.;=C,*R&Z\. dt ;\?o_>fyK2<@$j)rkcܰ?cn7}a?봟˰W`a?봟ϨJÏv-Q@((((((( 4Gy9NoϱJlv_'z'}A>zMjV_SZ(4RA(A ( (A(A ( (A(A ( (A(A ( (=+/_cUһ~贮YG`.?F{xq_580=:KHt}+t i\h.2)r@;'^Thԭ.Zj'8Y37q\A5hzl .*rFyOZ|OWP5fwhv!uƮ~W]뼿1_>?D|[ݎ(RRPERRPERRPERRPERRPERRPERRPEW=I^=ĭ JT>NJ֥e{W+]}'Yϴv1+)kb]k-ՏZtX7q\A5W%?Xh+&K]뼿1_>i_7jA_WCEU 4TG(*P-QUh 4TG(*P-QUh 4TG(*P-QUh 4TG(*P-QUh 4TG(*P-QUh 4TG(*P-QUh 4TG(*P-QUh ({}Es0Q_%z+aēI^>mBJhy+3G4bI|y**(_={z ,oAGނ %Q締 |y**(_={z ,oAGނ %Q締 |y**(_={z ,W փu_,7$* Ϊ0 ίdAiQsX8jLu>:dtk_/?oywf9Xϙ7gѤ>b+FV)|j 4kTIr` ܊8!IFS\x'LoڵM?YMZHazwWNHI  < ۮnU~{z _c/{o?1Ҽ Ӵ4\^Xe`+G[4j" gv+2<)X}꽬^`={z x~I}n{˨㻒V؆y[H8rzO qmi,v L]YK9=rxe[&%s<y+˵(qu;nV]Y,.bdFcsa~[Ț^kں V !0۽Ƣl <y**+[!(TTQd{z <Y/ނ=EE@K締oAQQE(TTQd{z <Y/ނ=EE@K締oAQQE(TTQd{z /duGX6n/ڿc'J+?őv n?kױW?q^C_2KJjsYz֪mO3G J3d|# gtL 6I^inf|9 s|[^mTWz"L",Q#8*y/?]/F]Tj1rW2: Qe; wF5uàGNycW\: |C݋EU (A(A ( (A(A ( (A(A ( (A( =ibK["{Es a%GmQSG4:Gy^HfE4Q@hP3EfE4Q@hP3EfE4Q@^*Э|Ki7VRմ>mфMa31]m>Xwg)w}>m3OW{3ʺe1쑞G5w7WLquw/4Fs{E5N)!hUfE4Q@hP3EfE4Q@hP3EfE:Co¯U_<𡁻?RWy\߿tQ{_5,WI#%~eFK_!?{GpKR}F}']}>Kkkg,e zr|u 5ZJ=Ԅ>&wUx_4mNY:Q5qAZM&q-)%'LxFu l?%o֮tGQGKv;qq%%%%%%%%%%%%%%%%%%%%%~Z?o =nyn>GZY}֋0'hG?`OEAZ<Z,}֋0'hG?`OEAZ<Z,}֋0'hG?`OEAZ<Z,}֋0'hG?`OEAZ<Z,}֋0'hG?`OEAZ<Z,}֋0'hG?`OEAZ<Z,}֋0'hG?`OEAZ<Z,joQo\}qsQGIc_N_T4iin }]KbGL}(}))>fF@QPn4n>)>fF@ѸPn>n4)>fF@Qn>n>)>fF@QPn4n>)>fF@ѸPn>n4)>fF@Qn>n>ǓVԉ#t k&:U\1_3,MW# u޽^Oo8ۯU_2Cdtk3 ӵmNX0':}a$98 fqW^M/ jWMukw4~Ll}1_)WZ%hqU'C4mJY- :Q5G =k#gMXM6~KIwB.ǒIv3qUGA5b\az}Z]W%_֮tXkWF: >InŠ(QEQEQEQEQEQE3x7^!Lv6pZɧU 60@'>^!d:mׯ"{KK*FNI9dI:VR L"Xcm ̧hVφMx)do$P`=;n}'˼WqxTyj r'/ÇĚNꖒh֤!PJ:Udr?Ai|/Y[=iaߓ~={]|B𵞩&ur_qz5O"?l8ȵ|["2$.<>1Qh۟8ϥi)N[BGUk^ SNk fи ǽfh;γvڛwwMpkj^c#5;#3(*cj|+jk/jps$ >1 8~+S]Mc,mZ;mp&T'׏N+t/ 4IjI(ܑgr=v'r-iiC+Afy./yOAoFoG6ycӜgjrwr=J8un6xEg_71Vp2G c/jSeA/أ2 F:F>ךkVL?8~,N9%c1'nt ^,v:3E!{Mi~CmRŏ ש֔QZQEQEQEQEQEQEGX6f=lՌqU'lGEDUUZ]KbECL4RRA4PE!4RRA4PE!4RRA4PE!4RRA4PE!4RRA4PE!4RRA4PE!4RRA4PE!4RRA4PE!5[RF=Wѱy>??Lu &: Oeo]u޽Y`U_2ChtW-WMuK}h}a'c50+Zj 0W:Kv.hV њ(4f(3Fh њ(4f(3Fh њ(4f(,3EX4f(3Fh њ(4f(3Fh њ(4f(fq1e'_ [Rdz2=El!hdzZ)2=ELQFG#Q(hdzZ)2=ELQFG#Q(hdzZ)2=ELQFG#Q(hdzZ)2=ELQFG#Q(hdzZ)2=ELQFG#Q(hdzǛ.B6ұzH^gJ=VU{Z]KbB(EPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPUWW>Lj??DU5 "*OeoQ={_>JF]+8>e~y޳⫝7kڍ?[M!̊|][׊Jj+rLa،/{^׬ j kj]Oisk M_oG-Š( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( (*?{ [y=cc \ꊉb1l=Ae§!ES((((((((((((((((((((((((/moپo|*KDU5 _gYz`o^I9}_>J)w{G_EFzn?5^v 1}s 'g| NE)B7gGX>%kA5:dMV,iskN濢p> [ɥɭEGFMIE3&&$ɥɠQѓ@QLɤɠ (irhTy4dS2i2hJ*<\}M4%̚L&&EGFMIE3&&$ɥɠQѓ@QLɤɠ (irhTy4dS2i2hJ*<\S'uPe[RVO7rbw*&GZP>HRQLZ)(Z)(Z)(Z)(Z)(Z)(Z)(Z)(Z)(Z)(Z)(Z)(omL ߅_/IA>W$*OeoI9}_>J&+8>e~\KFo,Nm,Z؃~XpG5Waq UUJ>5R<Z/y׬ ְKw'i2m;>su=;>su7|bPhQ@E(4QE(4PA@Q@E(4QE(4PA@Q@E(4QE(4PA@Q@E(4[RF=%?կMZڗz7YQBɉ>Ե59H)SS)e(S)e(S)e(S)e(S)e(S)e(S)e(S)e(SC}hk_~xxkϾ߈LU5;xD'CW҉+x>e~sYFoMC I7ha~RAZu8խ5gnۋ E%`p,G<#8l x:Svog=%Ms#H-ci±]H8>޵|M7%Mip}5 `Vg%M>z6/_W?9l&_W_=j0>[h%"IE.hQ@ E%Z3IE-PJ(h%RQ@ )(4PIE.hQ@ E%Z3IE-PJ(h%_P.?'Bթǫ^wiڬ|&{-J+ ٕxdw<[Qo*%OGjsY#TՌsjrH)ۖʽ?B5(_Usܵm_W?noKYܵm_W?n_Usz_̂Ԡ_j*tnZ϶7G,J+/r}\?-WU2 3PYۖk>ڿ ?oKYܵm_W?n_UsEenZ϶7Gj*t{z_̂4V_j*tnZ϶7G,J enZ϶7Gj*t/AfjQYۖk>ڿ ?oKYܵm_W?n_UsA_Usܵm_W?noKYV_j*tnZ϶7G,CEenZ϶7Gj*t{z_̂Ԡ_j*tnZ϶7Kdfk>ڿ ۖh_Usܵm_W?noKYܵm_W?n_Us{ẑԢ-WUr}\~ޗ 5 k>ڿ ۖA_Usܵm_W?noKYV_j*tnZ϶7Odf-WUr}\^ޟ 5(5k>ڿ ۖ2 3Rܵm_W?n_Usj; _UsmfHm_y<컁Ħ(u2 3U~#1W ]FXBqpL⻚Jl !^D=uQ (OݣQWhR5xkHtWQ ͍a$d989| =\Di+R4Βu>vߙ _ϝ“pp4{8(]?G?Fh(pP_m}~g(= B_ϝϝ“pp4{8(]?KRng ~u>vߙ OϝѸz=?.}~g(}~g)7 7CG}|3o;o&h(pP_m}~g(= B>u>vߙ >u>vߙ 7 7CG}|3}|3ng }~g(}~g(= B>u>vߙ >u>vߙ 7 7CG}|3}|3ng }~g)~u>vߙ MѸz=?.\~g)~u>vߙ Mv/?I?3ng ~u>vߙ >u>vߙ MѸz=?.\~g)~u>vߙ Mv/?I?3ng ~u>vߙ Oc<3nvo;o/?IQz=?._m[L0cOZnY͂0UӣNRZ:k'M\_P+AB4N+G/!yWW _BJ$hCF{QՕJگ\7菄(ܐ(((((((((((((((((((((zEqeJ?%Z=^鄋W(W5}4vlqw?ε fG:ɮze"J? qq? *<7,"O£hɢIGQ4n4XdM'GQ4d`$7,2OŠ&Ƌ2hQT{'EGFEIQT{4X (*=ƍƋ ɣq$(*=ƌ,~FEIQQѸa~~FMJ? qq$(hh? ? q&%GѸa~Ty4n4XDGѓE£hh? Qikd75t׼˿1^?tW]\gâHf_Wg^V+4^"9o )I?+}a)Cݣ3? JS֒;>+%9[uj/k hU.G[U˿(S_8oG-ؔQEnHQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE^=TS=#AWoپi oQ2Z>Vbxi5毡KPDT~jʏ5}Sf2J*?5} jʋ0$WTyhJ*?5}G (4y*,_CQ毡 (?jʋ0$W毡J*?5}G0$WTy*,_CG (?j,_CQ毡J*?5} jʋ0$WTyhJ*?5}G (4y*,_CQ毡 (?jʋ0$W毡J*?5}G0$WTy*,_CG (?j,_CQ毡J1iZ~jʲ _( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( (!fmz<Z?"+ofAHk}Jy{}Ev[5j+n[\h}kGrFTK濯G([}}'(FU<(_w->n5O~krڍڪyRyҎP.n4n>S_ҏ5J9GrFTK濯G([}}'(FU<(_w*xĺGR\7$&sjװf4MJc-(靌#wKDD~/xV[6-- 9Q뻌 *?1v IqdaYCZ`v9h.x&VPڍd_̦+;9UܒD#y`%SC*2Ay7~04HKt_}8t(9]suzNF\mkL<[#v9|o#翠5[w7W&:XZ=̖r=vqGy#V改XXڍƼ#:nx;[KǧED 8>_dz֭8`Z]NʼÜL)UQWhb}}ȯ|oj>KjqY0L Y3ZVZ/^Ejϰ4(c [M4n>S_ҏ5Jה.[}j)|({T__ߥ\h}krڍƩҗ_ҎQ\QUO5JO5QƍڪyQ濯G([}j)|({T__ߥ\h}krڲB 8VewNpXc1c,Hk΅c0YX3eW$7wnjFhT+ܥM:T=7VJA*O Y[_8/o]j~!Z fHcX n)rOs].FMҋwc^4˛X-|Wx4+i0!pANN3Lo6ڭ'4;PkTF267\Ѹ{>bcj y󶻶ͻ_[5:ڄB;3gc=}Spp5jJ,UmލުY=EۇpY=EۇY=Eۇ(=EV= (=EV== (=EV==wQF*h=wQF*FhwQF*FEzlRjd}hg뽮_sD]|'7^'o%}2WW(?|[A (E(4Ph(4PhE (E(4Ph(4PhE (E(4Ph(4PhE (E(4Ph; 57G޷.?7ְd}5ֹ1[bMPُckQ(mhm6Ѷ (F(mhm6Ѷ (F(mhm6Ѷ (F(mhm6Ѷ (F(mhm6Ѷ (F(mhm6Ѷ (F*vM_i07>߈xkϾ?DBgYz`y[IV1r#0A潂|C JaH+ΡS~Uc6+X5b9ճ`7Gշ*u ]@# ? _??zZGm[Ϯ7PjlvztK4r@pXQ 3;]iliK ҚO\l.h;{qkJDIڿ zg~G~GCL?jgk>ڿ ۖצiϝiϝ4?6ۖk>ڿ zg~G~GCL?jgk>ڿ ۖצiϝiϝ4?6ۖk>ڿ zg~G~GCL?jgk>ڿ ۖצiϝiϝ4?6ۖk>ڿ zg~G~GCL?jgk>ڿ ۖצiϝiϝ4?6ۖk>ڿ zg~G~GCL?jgk>ڿ ۖצiϝwm0ͨyj*tnZ϶7^w>v߯Qw>v߯QڇnZ϶7Gj*uwmwm0ͨyj*tnZ϶7^w>v߯Qw>v߯QڇnZ϶7Gj*uwmwm0ͨyj*tnZ϶7^w>v߯Qw>v߯QڇnZ϶7Gj*uwmwm0ͨyj*tnZ϶7^w>v߯Qw>v߯QڇnZ϶7Gj*uwmwm0ͨyj*tnZ϶7^w>v߯Qw>v߯QڇnZ϶7Gj*uwmwm0ͨyj*tnZ϶7^w>v߯Qw>v߯QڇnZ϶7Gj*uwm'~GCL?jik>ڿ ۖצiϝiϝ4?6ۖk>ڿ zg~G~GCL?jgk>ڿ ۖצiϝiϝ4?6ۖҶi$LWO.g)^w>v߯U[gcqR|eA-&5Un[cwy{n{qO*L⻚j0vbX5vxt9MWO%Ss/3L+dQpFx~RorK7xy?jz^Fz4y={&hog<=47ѿ޳oFjɚYoF7Gd o7Gѣڇfz7ѣhC3C?hh왡ލh4{PLFz4y={&hog<=ލh4{PLFz4y={&hog<=ލh4{PLFz4y={&hog<=47ѿ޳oFjɚYoF7Gd o7Gѣڇfz7ѣhC3C?hh왡ލk'ľ'Ҽ3`[[4 [N0yRJ0WlR*:mn \״5-*e>Lrld݆*x`P{U4xҔNFzC V]0ZꚍJi;F3cQ]Gѫ8IY=it47ѿ޳oF{&hog<=47ѿ޳T+MFeqo>f܁47'hmo-SZ/%8FmҶvW|CIICC?hi{Q&hog<=47ѿ޳oFjɚYoF7Gdhog<=47ѿ޳oFjɚYoF7Gd o7Gѣڇfz7ѣhC3C?hh왡ލh4{PLFz4y={&hog<=47ѿ޳oFjɚYoF7Gd o7Gѣڇfz7ѣhC3C?hh왡ލh4{PLFz4y={&hog<=47ѿ޳oFjɚYoF7Gd Ou`sV|dL'Q:ѱtIe/Eu|2m˩"qkѲl?Cq+^gcӏJx>۔ lhojF_ϣFQڍҎvC{QQڎvCz >՛QQÑ_hoAGVnj7J9rK GVnFj9r#K (C{VnFG;Di}hoAY}(aʍ/7hoAYϥaȍ/7 Yϥϥ9}fy*4}f>o"4ނ7f>o>sFQڍҎvC{QQڎvCz >՛QQÑ_hoAGVnj7J9rK GVnFj9r#K (C{VnFG;Di}hoAY}(aʍ/7hoAYϥaȍ/7 Yϥϥ9ټ qΝq_i6c?&og#sǽt`ׄZօW05oWҾx t)[ Be:2'n30} \KxEb^W}X oPsh :&w ț|ՋpTZZZٿnV鑟>S/3n[siӷa}^^0uGƾe/Fx?c6B8yHy? ~ Ū&FD azsmp?>ݿf~^ן8zKel>1t4ӽRJ:k^jW6#lCGP;ZmUKx? ;U{Y d`}pzc#SŦ\>&BeT́v\#浯)$F zoza(N`:g8r&5evkVN޾}5&oU]γɶD3D]mU|OWX:&ob5[wA?v/=wi$::;8O;al.p0|[ Ǫ^^xs_H\dʹiܖr>ku[iTi}v)j8ևsPI!44HdVeV`wN*ޣúu6zv2Gf#XLGcw^&_xvDkMy*$b; >&ѿ#_}g1ySX"*KWӥַ'Z˯:ϴ7 Yϥϥ|=Di}hoAY}(cFڏ7ҍsFQҍҎvCz >ނwQQÕ_hoj>ނwJ7QÑ_hoAGڳwJ7J9r#K (Cz FG;Ti}Cz }(G;Di}hoj}(}(aȍ/7 +7ϥ9Q +7y9}7yy"4ނ7o>sFڏ7ҍsFQҍҎvCz >ނwQQÕ_hoj>ނwJ7QÑ_hoAGڳwJ7J9r#K (Cz FG;Ti}Cz }(G;Di}hoj}(}(aȍ/7nBL;SwUmEhfHN)#Xrui$A=.k|[ O4BIFuK?3%{myg|9隥:trHđgVWen$ ?pqXu*3, U[SIʠY>3: ok?qר1?*?T?V?;Ful>CQʠαB}[3Эvv\waOʏUuѝc]cbPbT~3Эvv+kշ>}z?Ac]cgX[Xظ?? +kշ: oh϶^PgX[X?V?o;G.;}'G*: ohαB}[?qר1?*?T?V?o;Fuul>CQʠαB}[3ЭVv\waOʏUuuѝcmcbPbT~3ЭVv+kտ>}z"T~3ЫVv*շ>}z?AcmcgXWXؘ?? *շ: oh϶^PgXWX?U?o;G&;}'G*: ohαB}[?1ר1?*?T?V?;Fuul>CQʠαB}[3ЫVvLwaOʏUuuѝcmcbcPbT~3ЫVv*տ>}z?AcmcgXWXؘ?? *տ: oh϶^PgX[X?U?;G.;}'G*: ohαB}[?qר1?*?T?U?;Ful>CQʠαB}[3ЫVv\waOʏUuѝcmcbPbT~3ЫVv+kݿ>}z?AcmcgXWXظ?? +kտ: mh϶^PgXWX?V?;G.;}'G*: mhαB}[?qר1?*?T?V?;Ful>CQʠαB}[3ЭVv\waOʏUuѝcmcbcPdOʏUuuѝc]cbcPbT~3ЭVv*տ>}z?Ac]cgX[Xؘ?? *տ: mh϶^PgX[X?U?;G&;}'G*: mhαB}[?1ר1?*?T?V?;Fuul>CQʠαB}[3ЭVvLwaOʏUuuѝc]cbcPbT~3ЭVv*շ>}z?Ac]cgX[Xؘ?? *շ: mh϶^ȟ? +kݿ: mh϶^PgXWX?V?;G.;}'G*: mhαB}[?qר1?*w[7: oiOP[W OO؞:#Q>"h?UU|6ѯt+$Ho&'@{k )RœI+YIlQEbQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE endstream 18 0 obj << /Length 19 0 R /Filter /FlateDecode >> stream xVۊ0}PH%X q.Dž@? ےckɉS ^3V |_'\{tnMU t<38nK쏟1z4ҁWG(_j4Tb V0D5U3fhѲn,B+{0ưj)߱,M`^gYiҩ5(ADDkz)=8^kcFj ;$X >9Ia<ں\—IBlQ(n>!G(נ@qO$8.a#< q:]:P)o1ۆ{CiOiqDiƄk}UU-yU-~Ma>{B龬vϯWچvsPVG(%JUa 4j3ئ.ѷ`#xq8RGyp5n$7vW2/^Rɥ; nzbCqq|EdR?y 4N6]-8y!GNwZ?r)"#5?Aendstream endobj 19 0 obj 592 endobj 20 0 obj << /Type /XObject /Subtype /Image /Width 886 /Height 584 /BitsPerComponent 8 /ColorSpace /DeviceRGB /Filter /DCTDecode /Length 38307 >> stream JFIFC   %# , #&')*)-0-(0%()(C   (((((((((((((((((((((((((((((((((((((((((((((((((((Hv" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?B2qEet;bb6#XYתҕG\֜={-4JpFaI=pQ9f~o<ԒRYtbxG}yG-4:Ⱦ}BΟσ{} o(B[5h%_/>O=|/W1Kdk|E!?_Уσ{} >o<GWPsB>+%_揲[5hX"t|/Q=sdk|K__x}BΟσ{} o(B[5h%_/>O=|/W1Kdk|E!?_Уσ{} >o<?:Ⱦ;?yx\-4}yGWPsB>+%_揲[5hX"t|/Q=sdk|K__x}BΟσ{} o(B[5h%_/>O=|/W1Kdk|E!?_Уσ{} >o<?:Ⱦ;?yx\-4}yGWPsB>+%_揲[5hX"t|/Q=sdk|K__x}BΟσ{} o(B[5h%_/>O=|/W1Kdk|E!?_Уσ{} >o<?:Ⱦ;?yx\-4}yGWPsB>+%_揲[5hX"t|/Q=sdk|K__x}BΟσ{} o(B[5h%_/>O=|/W1Kdk|E!?_Уσ{} >o<?:Ⱦ;?yx\-4}yGWPsB>+%_揲[5hX"t|/Q=sdk|K__x}BΟσ{} o(B[5h%_/>O=|/W1Kdk|E!?_Уσ{} >o<?:Ⱦ;?yx\-4}yGWPsB>+%_揲[5hX"t|/Q=sdk|K__x}BΟσ{} o(B[5h%_/>O=|/W1K܌yk|E!Q$F>40q^]y4v! zt/ď zFj5(atE!X^7m?VkvVXFJǫj/'ΉTrykOr\|շҿ.NUcgOx5ҏ<|~^؟bhTyƳQҏlǡ<|~y4|cG= gy=CQG??J={Gx?<|~y4|hǡ;x(M?CYx(GbhTyƳQҏlǡ<|~y4|cG= gy=CQG??J={Gx4yƳWz|4WQ5S䵁N7m"Oڇ5yrHA]CGkЬUQ6[M^%I,VDC2lj|/jmk0tkFpљT~ShK6I^zzϟhǡgW>]:0J7Ff`{E -ч\ŲyVO ew(ZQ564;x?<|~y4|hǡ;x(M?CYx(GbhTyƳQҏlǡ<|~y4|cG= gy=CQG??J={Gx?<|~y4|hǡ;x(M?Yx(Gbs$>R?ʽSJMpWx%M{ o+WUU~ȋtQE}ys?<%p齰Ɉ릮[aDŽ'A1W65_5h>4FWgku~]e*j s6^}knua,Rc!)lWGg ŒJG]yJJN?\IZ*|HUx'SW9ء_c %92 'ԌWQPG`Uo)Sgj ~r#mh'G=ogo,Ej1zGK߁9QkƑxƲBy}5HHXbH-zP"~n:]}TU9vm%Q(ūKw8+j5{uZ@DK`W%ͷn"mnEYcV3=uV5s(Ԣ%{駕SHg{kh}ZEyWgM^wGZ( o֏;Qv-y߭oUh,ZZOҺl#G*++ "OAú.咗cmWiqU޺;Eol>´XG+M~ut5fs{t4_?gq Fcw]_ه}}iα;.V/35fs{t4_?gq Ecw]_هF]'+M~ut´XGW~/?a7ѰI Ecw]4_?gq)>l>´XG+M~ut5fs{?: ??ZhQ?0S}}iα;.V/3Tj?CF]'+M~ut´XGW~/?a7Ѱ?Zh?: ??}9ލ޺OV/3iα;.F_plNoa4l>´XG+M~ut5fs{t4_?gq Fcw]/F_plNoa4l>´XG+M~ut5fs{?: ??ZhQ?0S}}iα;.V/3Tj?CF]'+M~ut´XGW~/?a7Ѱ?Zh?: ??}9ލ޺OV/3iα;.F_plNoaa?: ??ZhQ?0S}}iα;.V/3Tj?z6z?Zh?: ??}9ލ޺OV/3iα;.F_plNoaa?: ??ZhQ?0S}}iα;.V73Tj?F]'+M~ut´XOQ?0S}}iα;.V/3Tj?z6z?Zh?: ??}9ލ޺OV/3iα;.F_plNoaa?: ??ZhQ?0S}} t4_?gq Ecw]_هF]'+M~ut´XGW~/?a76z?Zh?: ??}9ލI Ecw]4_?gq)>l>´XG+M~ut5fs{a?: ??ZhQ?0S}}iα;.V735fs{a?: ??ZhQ?0S}} t4_?gq Ecw]_هF]'+M~ut´XGW~/?a76z?Zh?: ??}9ލI Ecw]4_?gq)>l>´XG+M~ut5fs{t4_?gq Ecw]_هF]'+M~ut´XGW~/?a7ѰI Ecw]4_?gq)>l>´XG+M~ut}8Ocѵ Kv3LrH:WmsZ|<-o\M>u,OW`B+|J^;2M+XZ(* ۨdF2q߰=cEk\ʲBu#MЂHd &(SwA7t?V|3\\3۞$K}>~g*+vi *pMWT 4mTaKg<7sg~$~u%4Fv G\j%t>YBKյy98ѭ ;?GA}^߳Wcw›Ecw›Ecw›Ecw›Ecw›Ecw›Ecw›Ecw›Ecw›Ecw›Ecw›Ecw›Ecw›Ecw›Ecw›Ecw›Ecw›Ecw›EwA}N}Shð]ӽh?iϴ m{8(]Ӿh?iϴ m{8(]ӽh?iϴ m{8v w;?Mg w;?Mg w;?Mg w;?Mg w;?Mg w;?Mg w;?Mg w;?Mg w;?Mg w;?Mg w;?Mg w;?Mg w;?Mg w;?Mg w;?Mg w;?Mg w;?Mg w;?Mg w;?Mg w;?Mg w;?Mgv;N}Q{>G)Qv;N}Q{>G)Qv;N}Q}>G)Q.iϴ ?6=?.iϴ ?6=?.iϴ }-`){8(]PK *stnݯLLF\U8EWPV?_X-~cW/7-Cm'oއ6WT 5j7 &9M?=?J|)Cs{/S=f ?Uo3Ϳ>FQ_ByEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPKIK@N![k SZQ0:+,+D]c?X3rZ*F_Cυ4[5o[E[bJ#iW-]0\/j%t'-+W/Q+z]+_7x>d? +42}'ѓE>d? ('ޏ€ SFO~dѓh('ތz? ? 2}M>QPFO z2}((4dG@O>Š2}'ѓE>d? ('ޏ€ SFO~dѓh('ތz? ? 2}M>QPFO z2}((4dG@O>Š2}'ѓE>d? ('ޏ€ SFO~dѓh('ތz? ? 2}M>QPFO z2}((4dG@O>Š2}'ѓE>d? ('ޏ€ SFO~dѓh('ތz? ? 2}M>QPFO z2}((4dG@O>Š2}81פl$$ν*<pVYé=Q^YaX3rbbxE˟ы\y_ hz{MK߯ͨ: =etŴl8_ro Ǭҹ{V;q_ 16 ~+#(𢾈CŠ? ? ((Š? ? ((Š? ? ((Š? ? ((Š? ? ((Š? ? ((Š? ? ((Š? ? ((Š? ? ((Š? ? ((Š? ? ((Š? ? ((Š? ? ((Š? ? ((Š? ? ((Š? ? ((3ğץXǔ? ?7r?ץi=VYéf(,Oȹs_1kn'?UWm똬38袊o"խdžnߋFq?#|7K/t?ʪN߅|k:tpIulb(wJrcŽ FykkNmgbz}1=J<(S<(fyQ'JLO_ҋ0E3O_ҏ1=Jv`>gbz}1=J<(S<(fyQ'JLO_ҋ0E3O_ҏ1=Jv`>gbz}1=J<(S<(fyQ'JLO_ҋ0E3O_ҏ1=Jv`>gbz}1=J<(S<(fyQ'JLO_ҋ0E3O_ҏ1=Jv`>gbz}1=J<(S<(fyQ'JLO_ҋ0E3O_ҏ1=Jv`>gbz}1=J<(S<(fyQ'JLO_ҋ0E3O_ҏ1=Jv`>gbz}1=J<(S<(fyQ'JLO_ҋ0E3O_ҏ1=Jv`>gbz}1=J<(wLL)ف?'W_ b ?*+AW6cQ^YVX~X:bjW&aS/7>|-oVP{[hn0 0p@?ex[TV~_MPOOvZ}vZ}aGu\9r=dt*PJŦ8?uxS\sqXS[gf$oQEǚQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQ@woz o+K41\Y*n(,+_,]J߮{+\H?rW&?֧ŏ8 ^#:ܾf?oxzqgsGOZ1Լ7'1][i0[JIcoM{zUF5鼶4o ϟ+3W/OO$a8?uxS\rkE]7?~-Ϳ>GCEWhQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEP:);P_^6po׬i? b/\ tQEyes>ZA}"tG%rcݪz?Xޭ߭ USs./A98 r'?7 ;{yo4mM7]srI!z]{IU׎NIS۵֦4'))u8eŸzŸzL#+O4(((((((((((((((((((((((((((((((((((((((((((((((();Rv/q\A5Om똯'G}\MzƓ o+2%S-Es?·?W;E[JTGDRչk_zId~X}kDV}vZGD\(iLM?R'Q;G;/\y??ʪo&8O t%b|̟O tU/ȻϙͿ>F(޿6#J7M J7M J7M J7M J7M J7M J7M J7M J7M J7M J7M J7M J7M J7M J7M J7M J7M J7M J7M J7M J7M J7M J7M J7M J7M J7M J7M J7M J7M J7M J7M J7M J7M J7M J7M J7M J7M J7M J7M J7M J7M J7M J7M J7M J7M J7M J7M J7M J :;Qd%|o׭i? bݿ^6/i(¹߈*X?rWE\<)s]`\j6>5_(l|ꚋs"%=Πgؒ'֦rbhx)I#q!}΢f}d̬yG4h\+M\1K&"bg2mMz{UKL)6ɟx2]f]tk0G>hnDg3?}~Z|3_c^<6؎Q87E6|m7hw}M4un:nj7{Q`E7wڍXQMFj,wSw{Qڋ)Eun:nj7{Q`E7wڍXQMFj,wSw{Qڋ)Eun:nj7{Q`E7wڍXQMFj,wSw{Qڋ)Eun:nj7{Q`E7wڍXQMFj,wSw{Qڋ)Eun:nj7{Q`E7wڍXQMFj,wSw{Qڋ)Eun:nj7{Q`E7wڍXQMFj,wSw{Qڋ)Eu7wOݿ^6/d8wMz o+̾ɤ tQEyesT=+s?Grݪz?XܗӾ{m"2OY\L¬>: EWOfϫ>H9.뭵2K+mFkVq*EYwnk^+6iB{cx^w57 .7ףO&W6b}?5sKs>^9%zP|y6袊 ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( (9/}ׯi? bzA5Om똯/3&tQEyes<'so㮎)krݪz?XLUD&fXQ\y{ZbB + 觵ZտƴuF ӹWԊO饖N_ R?YZ= fZk:]VW)E:=@9roM55Wo11r@<x+*.>cڹEۈ+I3E՟)3{O_ғO_Ҫ_[y5=CGTP-yRE[SSQ5=CGTP-yRE[SSQ5=CGTP-yRE[SSQ5=CGTP-yRE[SSQ5=CGTP-yRE[SSQ5=CGTP-yRE[SSQ5=CGTP-yRE[SSQ5=CGTP-yRξvFp!\MAAૹF{裕ay(ٌ5=JO5=J5ehW/a6uK{O&R#x +~N-0ط槯hSxkl`%9}; gwOjm4y//SoO_ғO_ҪO ~jz5=JEZSS5R9@槯I槯Uh ~jz5=JEZSS5R9@槯I槯Uh ~jz5=JEZSS5R9@槯I槯Uh ~jz5=JEZSS5R9@槯I槯Uh ~jz5=JEZSS5R9@槯I槯Uh ~jz5=JEZSS5R9@槯I槯Uh ~jz5=JEZSS5R9@槯I槯Uh ~jz5=CU(=()7ok41^9Ow'k1^FgMi袊 "ȧs]|uW5E;m\wOGaTpz/xO|</ڼpnmSkN)WU-{;c(×]wP0Z!$-6&oM5F H7v]WYϜ}7̱(};H Cئ]n EU'ƹEۈ+I3E՟33N(<(( ( (((((( ( (((((( ( (((((( ( (Ek6wY<.jeHl4t 4?aV5;txP:p+g+$xXdRA\+ćv|6gJƭ7'xcLa%]cWXT P*r9YQ A?EK}Zg >rc=SGӵM%8ee c c1̷Om XΙm< \JNzUφ~䚞rr3]-[|ĉw89kxZ-晥V9|u%ᎀ5-=yǭϦuL:IP@$`uV]-̺6^%IDԥ4Q|=0Iy5Ž懧 E}A]䓌g$š&w%ԏ;uWl@BO溔D#UTQUvM+aqEQGQEQGPEq@Q@qEQGQEQGPEq@Q@qEQGQEQGPEq@Q@qEQGQEQzQf9i?^Ǥ6i?^Ǥ63=iLEWh|FJ륮k7WG\j6X?էY/z'E7')o)OT۵ݮ},96zΗ{rZ}袝]ȫo?%#7HU !''$ voQ4ՙ4f|J[C_Et:/?ޯ3E՟+3N(<(((((((((((((((((((((((((((((((((((((((((((((((((7A5Om똯7A5Om똯3&tQEyf\o?뽷Z~#ȣq_Qrz?ڇcETVd$_|ƭ:[$ʱEwvڪdO@+I]5ZmܗVuRg|V&x:EX&9HW`0][P䞕*jU+^4%hls?޺TW7s~So]H"ϓͿEA7S_]c'}MOEA7SEq4n>=h}Mz* Ѹ,Tq4X 7SFhPn>`'}MOEA7SEq4n>=h}Mz* Ѹ,Tq4X 7SFhPn>`'}MOEA7SEq4n>=h}Mz* Ѹ,Tq4X 7SFhPn>`'}MOEA7SEq4n>=h}Mz* Ѹ,Tq4X 7SFhPn>`'}MOEA7SEq4n>=h}Mz* Ѹ,Tq4X 7SFhPn>`'}MOEA7SEq4n>=h}Mz* Ѹ,Tq4X 7SFhPn>`'}MaxU{IM'AWx=}'AWZe(¹(ůG]5s??Q_(=mCG__V9xE)i__W)>Yhca!7F.T}ҽU5t Z *$鏽OҺqؘk{X^<nyY]Cs_6?__pg׫>S6xe(((((((((((((((((((((((((((((((((((((((((((((((((( ǭzI}'AWx=oO׳? b\x-E|IB-:"|ZDu͍wh>|DTou_k ˉNK !򢅉-˓<1h; q^㟭5kMS/ftewſMtZQӏsmUm]5Ƚz3_]}(})(>JkӾkn zgfZ+0(((((((((((((((((((((((((((((((((((((((((((((((((Gu@5zOm똯Gu@5zOm똯32Q^Ya\&?*~&ȡ7}YTUϋG~Uc$zW>&}v C*QG/]t_+~.^>76x"Q_^yEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP'הim\xהim\xٟJe(@Wo՟E]UrO*~և#pv?rOAf0$j~>; A~^(?ҺK'#m8etCO rٷ(J9Z)9J9Z)9J9Z)9J9Z)9J9Z)9J9Z)9J9Z)9J9Z)9J9Z)9J9Z)9J9Z)9J9Z)9J9Z)9J9Z)9J9Z)9J9Z)9J(_ ?o״? b_C$?b@5Om똯3iLEWhN>oҨWwݟE\Oњ$}NӤT I?ީLeR?JJ^R3?Һk>\ηAY\_|vmDQE}yQ@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@製c@yM}'AWx@yM}'AWQ4[+4 ~'țp}.msuUO2-*~֏#pAS6~OO_>; -Bkc&_o  Z!v[}>WȺ>>;6yd(No:n6Ө8m:n6Sm:n6Өo:n6Ө8m:n6Sm:n6Өo:n6Ө8m:n6Sm:n6Өo:n6Ө8m:n6Sm:n6Өo:n6Ө8m:n6Sm:n6Өo:n6Ө8m:n6Sm:n6Өo:n6Ө8m:n6Sm:n6Өo:n6Ө8m:n6Sm:n6Өo:cxcDQfm\x׋פ em\xٟZe(¹_&\ů]Us?ay(cxgeQ9؀:T43J." ꭔʞlNE'̮ cV6FJ@xF>>8֥B]̎S\rWm]5ߓ\έ1c )Ȍ챱>WMmþ{S_ώZxbz)vJ6J]ҍҕJ)vJ6J.QKQS(}(})\ii%OO(}(}((}(})R>m>QKQPQKQS(}(})\iiiiQKQR E.F@ E.FLiip]ҍҋR>m>\iiQKQR E.FEJ)vJ6J`%OO+R>m>\iiQKQR E.FEJ)vJ6JJ)vJ6JJ)vJ6J`%OO+R>m>R>m>J)vJ6JW(}(}((}(})R>m>QKQPQKQS(}(})\ii%OO(}(})R>m>QKQQp]ҍҘ IڝQP/פ em\xѓDCygrHWmsM`Z+,)5/#E$^<=tGV]f5<=Bw4cZFKSj"j(L=\**9&kOmLOE| B՟Q?Z ?*^_q?UvӼ1cs>𴯘WN[GWCEtU?G_"^"} Lj?>WOEtUXQsxo~WOEtQc>G!?xttQE;T{"} Lj?>WOEtQc>G!?xttQE;T{"} Lj?>WOEtQc>G! .xo~WOEtQc>G!?xttQE;4{"} Lj?>WOEtQc>G!?xttQE;T{"} Lj?>WOEtQcR?xxo~Qu+?(XR?xxo~Qu+?(X/Qsxo~Qu+?(XR?xxo~Qu+?(XQ?xxo~Qu+?(XR?x_rD<7? 9]?qGŎ`1u(CG,wԨ9D<7? 9G"}8b0}JcC!裏?,wԨ9D<7? 9G"}8b0}JcC!裏?,wԨ9D<7? 9G"}8b0G!<6|x_r~?(*= '^:,'dl/ne+{ocCTEU\a6黎+-$mb(5dlzlscu&+< +zψG?x#l?cO² x~_.)2:l}}_*Y*|柜yYh_CQ??lO4ojBʏ/M?9ڳ>о *={Ooj<ϴ/Bʏlڏ93 *>о4ojBʏ/M?9ڳ>о *={Ooj<ϴ/Bʏlڏ93 *>о4ojBʏ/M?9ڳ>о *={Ooj<ϴ/Bʏlڏ93 *>о4ojBʏ/M?9ڳ>о *={Ooj<ϴ/Bʏlڏ93 *>о4ojBʏ/M?9ڳ>о *={Ooj<ϴ/Bʏlڏ93 *>о4ojBʏ/M?9ڼo||lnk;A3ڽޣ .R 6b=<1^¹x;[[nsI&լߥJکkV7W[_ZMu&HcY*G&Ɨ:ýsRt,kym^Ph;sW;Nž ) oożq<8\i'5< 9JvKMNqKgs{Q7yΟ[;/xr}o_ʶ):4F+Ze玵]gE7>qy?Il$M1a8'VT{iuk^ەOGGoAor{B]=ovGr#bJ3\ sT!oyci 5'ƱĥAS摂Xtv5Kjw^Қv~s{Q7qo|3ak$!ʰ.0><-!5]z-#QuvڄWFX1NP㑑Dpwim)ʚzwy^'^:\:jN>F3] %x{j hwbR1!HpU)PN$ݥMɌ$ڞ7s{W/F4yQo$18S$cq!֝д}NX˜m gvO$ w-}մ[AӵCojeԬtSN٤ 28 kBʹksQ$54M?9ڳ>о *M?9ڳ>о *={Ooj<ϴ/Bʏlڏ93 *>о4ojBʏ/M?9ڳ>о *={Ooj<ϴ/Bʏlڏ93 *>о4ojBʏ/M?9ڳ>о *={Ooj<ϴ/Bʏlڏ93 *>о4ojBʏ/M?9ڳ>о *={Ooj<ϴ/Bʏlڏ93 *>о4ojBʏ/M?9ڳ>о *={Ooj<ϴ/Bʏlڏ93 *>о4ojBʏ/M?9ڳ>о *={ IJ{3g'Wi_ bsįtw?cm\}w ?Os}9n(q**.Q7}Jq*(y>CEo8yhM_ҏ8 \ Q_ҡ7}Jq*(y>CEo8yhM_ҏ8 \ Q_ҡ7}Jq*(y>CE k?yo4ǕZQ4j6s9Oi~8fqKiy7)߲"9>a7MSQIrΰKoX㴍Q-flڍ˽O(s uP' isr% (yg.to>^_MQY!4۵fRH p2Ns+W}城l&YnYG{m{N[8={@oo& h`Pcq*(y>CEo8yhM_ҏ8 \ Q_ҡ7}Jq*(y>CEo8yhM_ҏ8 \ Q_ҡ7}Jq*(y>CEo8yhM_ҔJs(co[C'AWxcL[S'AWp~(袊 cqN 8khX?*HT{|WC@T*2qicx}N1*}[b*OH i׶OkhQϫ :}keT[;=}?#5TG$z k/?SS?#5TG$z k/?Q?mOOA֗Q?*?gγh?/Fa?> stream xVۊ0}7Ph$Y,x@ޠ-dI#{0X39$7@B ? >?nB<\ H H N ޿|'9&P!"4d[PI!B9=TAx(\$SĜo$W["~°oU˕Ȫu󓡋tFaBaTA2ciu-Eԝ%3{ +Hi&|b,k/V12ł[|2 bwe!-.zɪd22Z,% OwS< ]vkt<5U7h웘r&UqfVcV 猧J Ϋ?*1CU74 qKX4 ZlzI,Cif3:>yK*<6taĦ@45 H=4j9 gbgUakm4nĽV{q p" +ITyYWA7RpKʿendstream endobj 22 0 obj 540 endobj 23 0 obj << /Type /XObject /Subtype /Image /Width 878 /Height 598 /BitsPerComponent 8 /ColorSpace /DeviceRGB /Filter /DCTDecode /Length 38128 >> stream JFIFC   %# , #&')*)-0-(0%()(C   (((((((((((((((((((((((((((((((((((((((((((((((((((Vn" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?B)p} 2ĢуhXJ)p} >уhXJ)p} >уhXJ)p} >уhXJ)p} >уhXJ)p} >уhXJ)p} >уhXJ)p} >уhXJ)p} >уhXJ)p} >уhXJ)p} >уhXJ)p} >уhXJ)p} >уhXJ)p} >уhXJ)p} >уhXJ)p} >уhXJ)p} >уhXJ)p} >уhXJ)p} >уhXJ)p} >уhXJ)p} >уhXJ)p} >уhXJ)p} >уhXJ)p} >уhXJ)p} >уhXJ)p} >уhXJ)p} >уhXJ(QC2}I:tRPGiձ5RwDZ+(6MXbɨo/Prk[FLWQ毨?k?uuy(Q;ٮ߀ן??ן??™毨_QG*;{5gQgS<y(Ox{5gQgS<y(o~FLWQ毨?=7??™毨_QG'f~^ 7^ g1}EX=y?c(y?c)j<}b󿽇]??3_QGTw]??3_QGOv1n15}Ej>Sٮ߀ן??ן??™毨_QG*;ٮ߀ן??ן??™毨_QG'f~^ 7^ g5}EXao~FLWQ毨?o~FLWQ/w]??3_QGTwk?uuy(W֏O?uuy(Q;ٮ߀ן??ן??™毨_QG*;{5gQgS<y(Ox{5gQgS<y(o~FLWQ毨?=y?c(y?c)j<}b=y?c(y?c)j<}bk?uuy(WQv1n15}Ej>Sv1n15}Eb>?x{5gQgS<y(O{f~^ 7^ g5}EX9o~FLWQ/w]??3_QGTwk?uuy(WQk?uuy(Q;ٮ߀ן??ן??™毨_QG*;{5gQgS<y(Ox{5gQgS<y(o~FLWQ毨?=y?c(y?c)j<}b=y?c(y?c)j<}bk?uuy(WQvgQgS<y(Ox{5gQgS<y(o~FLWQ毨?=y?c(y?c)j<}b=y?c(y?c)j<}bk?uuy(WQv1n15}Ej>Sv1n15}Eb>?x{5gQgS<y(O{f~^ 7^ g5}EXf~yYj$9!_1}Eq# BSdOQ,UhJ2֝(JQGPÀ4[L;rzfOZ=kM +ěb>"xJpZ+NH|/\D_ϠU5uok+lyξc5|aG++lZ={#W:<= 6vϨjR e'Qܟ} ĺΥ+1&ˈ㹍HpW88<+կ"Ӿ.wz;k.KKyDPg*@]G,qI: `߀Mz)RPrW{tϛ(}ü1+ƿ:K1stlJ…ҫ7 sn.XGU@9YrsS鮫O#'Zh7Q gšViY#K㺓!cEu I'1m=Dw9LkI ̱O$ ʦ!6ӛ˕ǭo|)^|ٺTSndgdi PpW'֬UgwMn O{(}żok -#OMsL7# 0+lnVse}#訳B@FlPII8*YgV&bv^,,}?Sro7Z7Z0h=}h}h ֍֌0h}h}h ֍֌0h}h}h ֍֌0h}h}h ֍֌0h}h}h ֍֌0h}h}h ֍֌0h}h}h ֍֌0h}h}h ֍֌0h}h}h ֍֌0h}h}h ֍֌0h}h}h ֍֌0hYk6Mi[Eun;$>4/h t68ne8,N8t4`ք8ͨЇN|jsZ7-}{C%˝CVP@'+ZI;u1Lꤠ!H9㧷0i]wk鶻 R)]iZq3n#f w)m[]F]ɸ 8\T/3W$wgizh4a|;ˢi֒[OxMas|֖ 5_Y{^q _K[OIvH;HNFRSNϚvUgʜ/F RTTݖڽ 4o]=6S'ۢ~pPvHdxSD MX% x>0h&6&ն׹R nF+yme3:!8@zphn>`уYΤKnEYFF 5 ֍֌0h}h}h ֍֌0h}h}h ֍֌0h}h}h ֍֌0h}h}h ֍֌0h}h}h ֍֌0h}h}h ֍֌0h}h}h ֍֌0h}h}h ֍֌0h}h}h ֍֌0h}h}h ֍֌0hCI zZKo4}QQ>U{^ o*Tm\[VĽʚoiuNz{pA:݄q`OY@'zSF0TQOaTiy*3^v>8)5_ΜPhWs3__'[G|zO߳Gͧn?٣^ϔ WǨ3__'fiˏhW8/CPhWs3__'[G|zO߳Gͧn?٣^ϔ WǨ3__'fiۏhW8/CPhWs3__'[G|zO߳Gͧn?٣^ϔ WǨ3__'fiۏhW8/CPhWs3__'[G|zO߳Gͧn?٣^ϔ WǨ3__'fiˏhW8/CPhWs3__'[G|zO߳Gͧn?٣^ϔ WǨ3__'fiۏhW8/CPhWs3__'[G|zO߳Gͧn?٣^ϔ OǨ3__'fiۏhW8/CPhWs3__'[G|zO߳Gͧn?٣^ϔ WǨ3__'fg_Ӗ@$!oB7!*?x? 3]Cn*z*+1d\*a^ԐhWs OǨ3__'fiۏj7A_ [G|zCPhWs3__'[G|zO߳Gͧn?٣^ϔ WǨ3__'fiۏhW8/CPhWs3__'[G|zO߳Gͧn?٥a p_x?  h/W{iۏhٴ47A_ [G|zC_i=Ek\ׅo/gK=GE_Mrs0#0WUDŽ4_Q+(T:: sk>B6AV?o~ϖAzʍ~TQY6ARm򥢀 ~Tm6AQzʊ(=Izʖ6ARm򥢀hGh=F?*Z(6ARM~Tm򥢀hGh=Kzʊ(6AR6ARm򥢀 ~TmM~TG ~TGhh&?*Z(6AQzʖ6ARm򥢀h.?*(=F?*Z(=IzʖM~Tm򥢀 ~Tm6ARm򥢀 ~Tm6AQzʊ(=Izʖ6AQzʊ(6AQzʖM~Tm򥢀h.?*(=F?*Z(6AQzʖM~TGh.?*(hs^+Om7SZ+_Mfn 贞t|puW9 -7%HeSo~TGm=KEG=EGvAQEG6AR@?*M~TPmh-m=KE&?*]~TQ@ zʍ~TPzʸc.6xn_vL h S^ o_Tֹ Ǵ!]' _1k\Džn|*^"~V{M)y75_T 5iq\WWB9Ya9+(T:: Ǭ![6?ehn>e)gaQ`E7qq:nFEuڍƋ)SwJ7j,>n4XQM}}QQ`E7qq:nFEuҍڋ)Swj7j,>n>XQM}hQQ`E7qq:nFEuڍڋ)Swj7,>n>XQM}(}Q`E7qq:nFEuڍƋ)SwJ7j,>n4XQM}}QQ`E7qq:nFEuҍڋYk}o?}kCI=ޟBZ[?rt@Ж}!eO?90^ѸV6)Swj7j,>n>XQM}hQQ`E7qq:nFEuڍڋ)ֿ+sv{/f>9f=61) RjbE˯1k{M.]}cы\o|/C?=^nQEǬJo?_MqVsj%v3ꂷΛ?tz]+vaPQEŠ((((((((((((((((((((((((((((((((((((z]֏Ƅ̻Xq-u:Gm^ k?ou.QEŠ(((((((((Ro]q$ζ%aP*z<pT͌Oȹu1kKUݦty5W9">/t[ od-—p"Sw((RnRnPSw((RnRnPSw((RnRnPSw((RnRnPSw((RnRnPSw((RnRnPSw((RnRnPSw((RnRnPSw((RnRnPSw((RnRnPSw((RnRnPSw((RnRnPTEW;X{iwW' -#FT}P:Ǽ*k{]򮆿d*(((((((((((((((((((((((((((((((((((((+߮җ&c\& +?;su'pPu/EŠ(((((((((q^'?U+'q?ʵ=7Jmsni_ bϽ͌/ȵu_5k{] u~:bjWoS_ ĺbV{f%F'܏Nmկe苭hf}s,v'Ǫfkh W$Gj׮*XJWwFùMВ=aڑcwq1?uY#eEJig_t5xSTn#y&UJ*9GrNPnIG(\ETPnKG(\ET.\QG(\ES.[RQ.QU(.[-U)( (Q-Th 誔r˔UJ( trtUJJ9B*rtU:Z9B*%rR9B*-rRPrErNPnIG(\ETPnKG(\ET.\QG(\ES.[RQ.QU(.[-U)( (Q-;0ZՅPti ? ~CJ4OA>A6_i]> ~^7SbE.QܷES.[RQ.QU(.[-U)( (Q-Th 誔r˔UJ( ]P+/~\O򫦭q341Vꦓ o*|_R u"Ԯ3z2K+\xkڶdDY ʁ?ylm *Z_VP4$cP60k`zNwWP{zUڱmwq1?uG#*>L<)oƷk Ÿ{kvj!h JZJZ( JZJZ( JZJZ( JZJZ( JZJZ( JZJZ( JZJZ( JZJZ( JZJZ( JZJZ( JZJZ( JZJZ(W·k {*3&A6_i]> ~1s /4El?J|7ܻEPRRIKI@ EPRRIKI@ EPRRIKI@ EP:KEq%Up&z o*Tm\[{>* M}FRt1te=Er_Í?OtA5,3_[T\@ pMvWKV\`(FNǴ\2 >V*/?OO~h"R1: o??s]~=ϑBE JZJZ( JZJZ( JZJZ( JZJZ( JZJZ( JZJZ( JZJZ( JZJZ( JZJZ( JZJZ( JZJZ( JZJZ(txT?Uq3&U2:tBN}+Uy#Ct< E?osB((((+;wpGo>+G}\M\vbgi? bM'AUǹxEkJ<+_Džn9+m^?ޣ2k>ZM ^ռM(ge8pZLL~gdxKD4}=vƝsǵyTqJ |M,34ƥ{IU/Ovoy8 5ӑ;4EVL<'owͶ)x:ٯ>AQyQf2JZf7,٣f0%٣f0$h٢ i*?7q(?'WdZm\[Om똫uoss"uG%q>U/|@V >(yA tVG|9~<9 XNjs.0Fzg8x*f=u]J$1j1[NUrGUWCJӧSu$mKy??ʸ=t*O_ֆ3|3_n<3_nogDžQH((((((((((((((((((((((((((((((((((((WG}?V}S']tmoJO2%KE!GRJ@?a^ҵhu9cUVKwԮ 0l$qꨯ*8:pvL%J|jGt[\Q HO vwC\[O׆/S DE`sKm ?"e(ȦQE~E(ȣ"EdS(?"eXQL2)Q`FE2,(ȦQE~E(ȣ"EdS(?"eXQL2)Q`FE2,(ȦQE~E(ȣ"EdS(?"eXQL2)Q`FE2,(ȦQE~E(ȣ"EdS(?"eXQL2)Q`FE2,(ȦQE~E(ȣ"EdS(?"1dS(l!dS(?"eXQL2)Q`FE2,(ȦQE~E(ȣ"EdS(<|NGr]]r>&_ 6U41V^9 EKoҸ}ޮ?G\7H .p>n|SO՟C on֟s5y;&:h$~5j~<;C=[P7V7VLF?z-.5.퉐Uz~Gͨj-ơvf[|J88'&0Q'7ZZ=zU)vSwj}?5]w5p^ݤt~[uϹ/շ_3り(EPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPX#[u?ЌaM'&_ 'AU6_079)kpZ/x{E;o ET.*<}?V}O7i\-fx3T51FpAǶ6~94˟k>CΟlkb Z#Ơm#޼l.\]g5h靖Tf[S}+t\vۈ+S}+t\vۈ+?cK1whx֝fhx֝~>,(((((((((((((((((ZW7f+j8'oUɵ Ro"͍pcWؼ/!g߶M3~) n/Ɲ|߱ɍ:9Uy[V PjpXX]moK+'j$^#zihk|={-<^ʩ rORwS _XV r2{t»M{XiA֧3ԵMWK}!Eouy54B #2Bey-ƺFjsn-ݭ%~rzsnNEQ@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@fkZuO' tua+ al??a_-QEt((+"ĚMψt(/[t%c ~6}^CiWM hi:*OfgkkcRB59//XWpvȀڻ1>SYSC]Vzq63c00E^:Cov~ic;A89qNkƕKJ}^+Xb1VpȧUFMIh$zOKN`c/Γ "~w;OTŧ0\4LK sE8Ouo vKM,3x,ff‘UsG{ LwK~_y]۱3 mC]{_]CCXRY2ULf p{UP>,B*ry󮮒Wo_ _:qҶQ/AM_Qv8+9xBMS뺖>w%I7v*I4A-COg݋˫IDqy]vvAqhuPM\߈״ i?S?=Imsni? b=΃"w"wOLz΃SRPna@#Rv=¢bM'4|+;dL\(@oSV/`Ul~d-#S؎Ƽú^Cr~EWx(Rug+4վǥ95#g+$OMu OҹkқzR9/ya|xև}gi?_Wuc(QN?>0 eXQAL>E+0 <)Q`AG}2`?>0 e(QE}a)0 <)R>EayS((QJ?>0 eXQAL>E+0 <)Q`AG}2`?>0 e(QE}a)0 <)R>EayS((QJ?>0 eXQAL>E+0 <)Q`AG}2`?>0 e(QE}a)0 <)R>EayS((QJ?>&]:|R{g?>:ݳbрݬE[υ_*E0 <)WMAG}2,(QLQAL}a(>E0AG}2VayS(?>0 e}a)XW=b~x{CެǵzI Om똫uSImsnYns??Q_(JR$҈"|>Y?K>us{a3=z-NP3d?}"b9 :5jՄf-ߩN1ms|OҹkқzپCrGuJmR8/y5zi'N?5wp#cnuހE7ppQM=(Sw 7zu€E7ppQM(=Sw 7 uލ€E7ppQM((Swz7 uހE7ppQM=(Sw 7zu€E7ppQM(=Sw 7 uލ€E7ppQM((Swz7 uހE7ppQM=(Sw 7zu€E7ppQM(=Sw 7 uލ€E7ppQM((Swz7 uQԧnKV9?<4/(-?k 9ӿԿ*ܵ?sa~ʑ5ލºE7ppQM((Swz7 uހE7ppQM=(Sw 7zu€E7ppV$Modf$ȡq_Qy5P_(KV>,4}?So?񕴳cbg%c-t eH(B(((((((((GoI[r8ǝzK =Imsni? bʽcWkןiF(O_6Sy5|YX~.QexPq5FL2!F9Q0}TxoC{M>Ym?k0F88 |5|tMKz+7f\|}[WNt/}VAVp)zٗJ7\Zoxպ;:mu(ShQME6u(ShQME6u(ShQME6u(ShQME6u(ShQME6u(ShQME6u(ShQME6u(ShQME6u(ShQME6uS?'­UMGR)=DUkb/ySm[ǼA\_ME6$u(ShQME6u(ShQME6u(èǕzKܬ?dž^Ʒ=Imsni? bʽ__ͯ^}zĿ'_)NV>,,}?SrD𾝣kf%En;bI$+!Z#(Ksؔ#&[}\}Z[WPt/}VAV)zYMVU4ouv>,(`QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQESQT U5I1NSҘj= _ӿ*ڶx eH(B(((((((((OzKܬ?dž^Ʒ=Imsni? bʽ[gͧ\5LBҘտƾ?O~WujZ#8f`9+|k}Wdc^j\Bb?xj:o %d)"7F?cN-ųKml$6 9_@m 8yS\[m݈9ROCok?ֺ}G>>Jk^/R3/y5nq5jx[QE0 ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ݧ­U]C\ O`2M7SJbo+/*۷PJ/Օ"J( ( ( ( ( ( ( ( ( ( Gu@5X^(n^r'AU6_*:[gͧ\5M>oҘI?ޯ>&b(=ok?ֺOҹ}S,wJk8kF4CtzwZ 'fx[QE0 ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( VG&/*۷PJă}4vߪTUo?sa~ʐ( ( ( ( ( ( ( ( ( ( Gu@5X~)+ϥ=Imsni? bʽ΃"|gQWc$z߉'_VUpV?rOOɾX+hC[UһJOC[UһJ/_?y-ݓU~Ul|XQE((((((((((((((((((((((((((((((((((((*܏UR{oMVҨvB}+ FQVW6~+(((((((((O'T)[u7j*|,:Ӥ6U41V^AN>oҨYUN>oҨ'|YXz~d×?E%/c\6Xav5aYi^ Ɨpf:[!걚ZSW+cϵ 3IE.h%4PRQ@ 3IE.}%>ԔPQ@ j3IE.hϵ%4PڌQ@ 3IE.h%4PRQ@ 3IE.}%>ԔPQ@ j3IE.hϵ%4PڌQ@ 3IE.h%4PRQ@ 3IE.}%>ԔPQ@ j3IE.hϵ%4PڌQ@ rMQ]}{k:hoVҨv +?zgE[Ǻ}+ VT$ϵ4gڒ\њJ(sFi(4f\QJ(sF}(>f_±|T?M9M٬V)QS`=Imsni? bʽ΃"|gQW iO"tW1W j1Oɾ zKr}ZWQNkc>ǎeW_1ZST6`ﺧ}+BQKFLiҀ]ҍҀ\J6JJ)vJ0}((}(}((iiҀ]ҍҀ\J6JJ)vJ0}((}(}((iiҀ]ҍҀ\J6JJ)vJ0}((}(}((iiҀ]ҍҀ\J6JJ)vJ0}((}(}((iiҀ]ҍҀ\J6JJ)vJ0}((}(}((iiҀ]ҍҀ\J6JJ)vJ0}((}(}((i}jmҢS>bY?*܃=Xc1id U\O)p}(}+(}(iiҍҀ]ҌJJ)vJ6JJ)p}(}((}(iiҍҀW M[ lV7I5_@5>}'AU6_*:W?k1W ms?D˟Ҙ}kOɾ zEW/rWm]@~i\W?1I o'֧VQL((((((((((((((((((((((((((((((((((((RWr?=İ}#jQn[Zð}#jQn[Z|/Օ"J( ( ( ( ( ( ( ( ( ( qұY =W$Ml㎕'j*|,h]'AU6_*79_> '.#K{I/"YCe#Ww^'ԭ"c}=Yv $C\Y' -_h?~NYϞCEM9 ?/4?G'؆osA-_h?~'󇰟b*oEKA_9 ?0}h/4?G"%/8{ ![Ŀxc '؆osA-_h?~O 7"%/[Ŀ/'󇰟b*oEKA_9 ?0}h/4?G"%/8{ ![Ŀxc '؆osA-_h?~'󇰟b*oEKA_9 ?0}h/4?G"%/8{ ![Ŀxc *v![Ŀxc *v![Ŀxc '؆osA-_h?~'󇰟b*oEKA_9 Oa>4TxosA0}h/4?G"%/8{ ![Ŀxc '؆osA-_h?~'󇰟b*oEKA_9 ?0}h/4?G"%/8{ ![Ŀxc '؆osA-_h?~'󇰟b*oEKA_9 ?0}h/4/?G"%/8{ ![Ŀxc '؆osA-_h?~'󇰩؆osA-_h?~'󇰟b*oEKA_9 ?0}h/4?G"%/8{ ![Ŀxc '؆osA-_h?~'󇰟b*oEKA_9 ?0}h/4?G"%/8{ !>UEKA_ҷ|E,~Tz6e\} J?Phy{9?릫/Oz@Z1xnC9?x0?x7~X^"G"-{C)؛φ0ЋR*Tg؆osA-_h?~?0Ob*oEKA_9 ?0§b*oEKA_9 ?0§b*oEKA_9 ?0}h/4?G"%/8{ ![ĿxpCEM9 ?/4?Kc '؆osA-_h?~'󇰟b*oEKA_9 ?0}h/4?G"%/8{ !+şO"%/A_T#յ{ mCۘvb]=@iK6I8Wc3Zz o*2K^;(5w2\mPGlֹ}Suk( ]ѫ\fģǚn#X+o՞]s%_揲[5ix?'W,}yG-4ooooj#xJ{a>؟5R툋YB6Λx+'hZoj[#[x+'h}Z=do<|~y;h=5QҲ|o֏;ڰHG??JZs.obF"&;[fslRdm+$uuhf]n3\ |'$vumf,.]4r{Rj |cxj/ ..lo{"  nq)%)k]Z^|)SJ>;o/o,Z8n ,ܰ.)]|S?xsKxPc[cG:W'Q㩚52r@0Rȱ$$fA?h##\IH)=VI4:$R}1'۸c#cړTz֚#.$14|MܞL{Ѐ;GK MszNi_w ss~cg{#`ͨӺw洛tϰ9ܭקgc|9wAq*izY:y^9E0HLI>wZmĿ Mkzֱk$~{}r@fo @j=$јRPH`=]5pthq\iuZyv%;6߇G^"]mf@hcݍ~\cF𾩩c%ӶRϢ ygyj_4XX,yePF=+& [o,>Dِu%2J`iԳwwQ鶾[oq{uGk6tiqZF9Br099bxwWEm@*T`EpԒI1A?h##Ώ2'ǛT*XI'Jz1o̢ky5.zw??JwGX{$kyd߭wGa쑭ҏ<|~~y߭ՇF??JwGX{$kyd߭wGa쑭ҏ<|~{~y߭ՇF??JoGX{$kyd߭oGa쑭ҏ<|~{~y߭ՇF??JwGX{$kyd߭wGa쑭ҏ<|~~y߭ՇF??JwGX{$kyd߭wGa쑭ҹ/>d~?;ڹ/C֌$Lim\[Om똫uvGŽ[aDŽ'A1W#w.E5{*$+]_ ʼnXzAqQN}}jhl>l>YN}} ѰfE;aa.6vFE\mލދ0)aqSz6z,hl>l>YN}} ѰfE;a4l>YN}} aqSz6z,hl>ދ0).6vFE\mލfE;aa.6vh} Ѱ,hl>l>+mѰ4E;aaPmލޖ)=CASz6z=mލލCASz6zZhl>l>YN}} ѰfE;aa.6vFE\mލދ0)a.6vFh ѰfE;a4l>YN}} aqSz6z,hl>l>0)aqSCFE\mލfE;aa.6vh} ѰfE;aa.6vFE\mލދ0a?PoKIO8ksacѵ 43 = WN?mgYF{F o*UҸm똫U$FTWVV PEq?4 d jx~=ʊ҅O\Q]?: ??Zh}{j?: ??Zh>Gڧ3iα;.V/3븢EZh?: ?(}38V/3iα;.(_p{j?: ??Zh>Gڧ3iα;.V/3븢QEZh?: ?(}38V/3iα;.(_p{j?: ??Zh>Gڧ3iα;.V/3븢QEZh?: ?(}38V/3iα;.(_p{j?: ??Zh>Gڧ3iα;.V/3븢QEZh?: ?(}38V/3iα;.(_p{j?: ??Zh>Gڧ3iα;.V/3븢EZh?: ?(}38V/3iα;.(_p{j?: ??Zh>Gڧ3iα;.V/3븢EZh?: ?(}38V/3iα;.(_p{j?: ??Zh>Gڧ3iα;.V/3븢EZh?: ?(}38V/3iα;.(_p{j?: ??Zh>Gڧ3iα;.V/3븢EZh?: ?(}38V/3iα;.(_p{j?: ??Zh>Gڧ3iα;.V/3븢QEZh?: ?(}38V/3iα;.(_p{j?: ??Zh>Gڧ3iα;.V/3븢QEZh?: ?(}38V/3iα;.(_p{j?: ??Zh>Gڧ3iα;.V/3븢EZh?: ?(}38V/3iα;.(_p{j?: ??Zh>Gڧ3iα;.V/3븢EZh?: ?(}38V/3iα;.(_p{j?: ??Zh>Gڧ3iα;.V/3븢EZh?: ?(}38V73{O%W ˗'ڮ)h:z6"(E ((((((((((((((((((((((((((((((((((((((((((((((((((((((( endstream 24 0 obj << /Length 25 0 R /Filter /FlateDecode >> stream x\Y~o@heY! p?D9XU*7.ےJ~|\Ww]!;?~o_vxi~~tuzO}~=G7=yדwG|OSLJ·pϯ?z)u4 2K=< Gw]JEO`+䑶z OnZ!\90n:f:Bye4Eʸ(598g3=[`>Oy-zO'Zk3lד!fy( .R/҅GD۶(YoB"np0ju Qh$v&.SPN 䀀V5M\Roh]Pi/>y1Ld2'Ꭿ®|P-2?l6yiR0s}2,NH6o=`:p{e@r^5Y+ J&.-g$| @2mmU5bkT)]5\2MC 3:+ᱦ)zrݰEIniz6yBKڋAZDh(1#q(N%Aa'XR0M@|yвC6sWv< `VFz(rkFddLKm%()$T!6 MKcZt>L(~sTYtFJس'_GimS/Jk6P 9;PЁe'LLaZpzUFҲŐmL|"ڰpϔJ<0Ԓ5F <̪B7 a5TSº=XVJ@z ]J+# ; 5s-e>yXvEq_f9u ȼ`MwA(]YE&=_ETr RۘɁۻpVvEZϳ?zj؞G*_#^nlRϯҁ*5I8,g6Ř,>j1³!N uԄX`HүVKV_*6q_ ڃAv˚R:ў"HXp,N>W' 0#; LU5}'M%ڰUQ_]T eu NuP$͋SCm976|rik.~%1.g !3vPlK|cok1ОB> XJ!mNfĐx߸eq茲1S?BaYRI@*z1pH(O`wDwJo@@)ZDt)IfP͌}_1.V)DjFГү#(."h6arWh"JH723^cac2- )")T{.OwH0j2Aš+ ]Ȓ+i>ؕ{t @N (bH=CLVH}^ۖZ#ZEҟu(>ѵ5LAqFz*{҄~qi9 1؎r;1vG˴qIP0S%')zBHj0mJҐÍXj{#ΌT}kWT`5(g jW)qsPlG>2L8|Ge#/JSt%d˷dW<6=Iw" $6@Q.Sit0--#1&Q.s8_Avܮ}z!w p#6Wupam϶.\<;.¡6BR~KfCf#'?DaOמFh2=>JD&hE7J?9XfAբ7}GFXBS5BNȊj Hϰ;gF@' ~>,d(@EV^TD/9l4em[TkRoO`gY1 ~.N~:΢1kw&U#åizeV";wH%nX]{*CԌ_a8ܥɚ&66{Z5(rm(vb>&1e'v1MK`_>6 B|vMmz[fDͩW]RuhӯH06 DiͱJ?@qG: 4{n0MiFゖĆ3O6Ji ̐&ߦ"=8§9#Z"X>|-g~Biucr+47rmK'ދteTՊ 5 q}$4Cdӻdam sX ӹ>4W8߮|(uA&˞V,}NhΎ8}ߐ}{#QrT23lbufƤDf@F>RVv_h/]yE9 3#8WSξI1a^Plݘ6F_~M. lZ{\!g(O.ᰎ|7cAۆ޴cfΦ)13o8bZ=Ĭs#*@9P oJ"u YhiFF9*8AئVJ5fY6ea㼾\K[WOì1Oݷn()I~.3`|U/ᅦ-Loendstream endobj 25 0 obj 3088 endobj 26 0 obj << /Type /XObject /Subtype /Image /Width 914 /Height 124 /BitsPerComponent 8 /ColorSpace /DeviceRGB /Filter /DCTDecode /Length 18289 >> stream JFIFC   %# , #&')*)-0-(0%()(C   (((((((((((((((((((((((((((((((((((((((((((((((((((|" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?/z~8!wv<6I>u__oxP]iZ"i_БsqI$#<vWEhRD2'?uCo V%_^?PUBy 㑅#ZƵOZRw`ƹ Jc,+I 6Ew=^-. aE .@(<0pyz֞kT n-7u\H:e1,nZmo7mio}g-3C6AWzdv޹3s]ΥmI7ɢj 5h%#v20et3 :\څ&vnX,^&Vm19{z'(y4/\x]5l0>_$(jnj iZ͍ĭmmL4lu1G=i_KPV,/uKk+8Oq*2@$u( Z^E="aXgYdE++)?kK݂׍r,TYZ&Vm+W7՝1-N³T`;U95[)v2o,}5LTxaAf:T[6Չ 5" GּwMҵIi|/̞$u-6hyHm>3ݖ!޶8h> |<\-c[ʩm\esЗ&/T/, uʬXuR:7.OmָMG_4"gUKKۘQ %RrŮ<>5=rW2iZS<%vj#M;/Q xZuM?S6n`lφy2rzAbJ㱝 M,C4RKn&D`LlT0 ;ݣ=L4nV*HGb1\>'b@Ӵ{o78opapF1\koY<ڃ~&etBe($]zԶ noUr{ ܐ;_* |Km~i i=/1HbF?152U׼a?>i\+g ͤ21SsAM\;_U4mZXRCtю]f|jcHQU/ڏ/ځةQU/ڏ/ڀO~Y,TG@XQU/ڏ/ڀS~_/@XQU/ړ>__[|j?/ڏ/ڮy~Ԟ_bGVjs|cx:O|?j^is%&3CAdEi#_z m,jҸXϥbxZ7a_K.ge 򑑂r б_?GޱBƧmBG wo cBɍ:ӎ8O|?j^iS%&3CA$%i#_z m,jpC],u7&Ó$4K?Mxb->y4xQ9s5?k?X-WKմ;Pγq]aAjcBtӵ;eѶ*TAOoXcS~cO.0vRH`X̗7$NۥbN!rx8u65}{5ķ2: wFO˜sGޱBƧmz \V*>AyO cd 91b?t~{ 4p[c0ݑ ?XoXcS~Ķ^,i$kx$v)gb[%d008O|?j^iS%&3CAd%i#_z m,jpMFeD"[H2>Z;GygҰ5?k?XcGKmt%*9gْWi'3t㊡q-GҦWH˶|έw0zcб_?GֱBƧm ^c_iK[s+y8yv&u odOʋص{QUoԣru( |j'~T]>__V\J>/RسQ{Uoԣru(>__UlQ=,Z򽪯dOʏ蟕abחGU~'~T}OD j'~Tů/ڏ+ڪODlS jbyVڿ?j???f.cs__ҏ1}JQWGه1/GQQ瘾bGڏGcs__ҏ1}JQWGه1/GQQ瘾bڿ?j??91}J<+G_ʏf7<(?ʏʏf7<(ְQanyQ/Xj??jhT{0/GaxT}xT{0%ҋ UVbg2Pv"&zF Z\,fF9&@,UI8>&0*`<~濳=Z$mͽ#P6E©;N<=u;@/CJiYS+3@ȡ:E-kVO?P?m5ٵ+RǦ?ƬV){m<54_U-پkXPNg gIo.7 %iH 3~,??_ ql,Sգɝ#+eqܤâ')c s^?2.UՊae ۃ1DGZďfcd1RIwBI55 xῊuӁ `IQxĎcuAjHvNOBe1 :p'&WBOx;~մ5;u_&o>ޮUH 'oM5&h+"AA'XĺύH{X- $ǖ?P0sҚ _hj$S"89'N M1N_4+t{k$-"hߛWYD.; oK2r`["RHTP2I$;3jzJW+:\!q:-O5O3B22I[huD_Sok)--د]R$m_R=wIk,#Dg<}GZ~2n-M6 aglg8=}J;m!xP:9L;(U9 *:QwC6iP)oʖ/iK_àR0Ԛm5HKV+x,vi\]lm5Kj RX(5;TO*AʑBmJ|,y!$1G9.GSӛUyK,Sd'%[&A%}pMGk`&2[@#'B:ٲO 7idt; (((((((((((pC+xOcs X]#HVi-}*EcQEcfƢ+,6hj(X٢cfƢ+,6hj(X٢cfƢ+,6hj(X٢cfƢ+,6jެ( Q@̟ !Jjoj֠PK"+0{{ ;#_M7J -II#`V85'7/=փ3dRqTea8Ǹ?^xK7(y/O'Ǹ?^xK7(y/O9 {1+焿_?WMd 9ÐǸ?^xK7(y/O9 {1+焿_?WMd 9ÐǸ?^xK7(y/O9 {1+焿_?WMd 9ÐǸ?^xK7(y/O9 {1+焿_?WMd 9ÐǸ?^xK7(y/O9 {1+焿_?WMd 9ÐǸ?^xK7(y/O9\A!]1_5NBc0'>j][Cwm5qMo2E `qy/O焿_?Žp/5zEV6 }}O$II5k$%R+-Ẓ59)E8ǯ>^xK7+WG摣î"('!kQEdCE )kZ|!"`o\ljr"Ӣcv)-ƺz45Hn^ًC:(lda# 5WGxšx(H NX1PV*uA#'? "%z'wcb"Դӥ<_x: Nٜ XjO0~ηQ,\ B`˳^}qgҪa91Ihѩ8lHബ3<5GgrYQ.JѭR6j?2OrO$I8jkit5<f2'hCg.}c]axsðq1k,6YL+vhh9iC/W򹖺B=Mdj:ƁAn.͒sՓkRz3MT^4Q?_/RFn,chx]VW-&؏k4w2(`܈ӆdgy1;)ٽ D6vv nv'@N( _0ͯ"cwۓ=I/`ȺXm_0ͯ}ezv"cd]ì6bK '4/E :k(ȺXmmy2q#HbuȺXm_0ͯb0qOXX,cd]ì6b싯uVד'4y2u#@_0ͯ"cTM'ݢbd]ì6b싯uVDTAa4,}?4XZ_0ͯ"cє40qEdd]ì6b싯uV싯uQuC|֢uC|?.a?_1I}ͧO,K#}w$ q"('h 0085@?_0ͯ"cEc'"cd]ì6bZE@XȺXm_0ͯj('"cd]ì6b,dd]ì6b싯uV싯uQuC|֢uC|?.a?_1ZP2.a?_1GE :k+ZOE :k(ȺXmkQ@XȺXm_0ͯj( ?_0ͯ"cEc'"cz6QDE* ڢ9KXx/ o%ر*>PrI8kMt{"KQ)ߧ:Fֵdd]ì6b싯uVr(WY,xleH|$A U9;"g8^FE :k(ȺXmV//k o*|LrgJgzߤ՝jȺXm_0ͯz|k%ݽlpi~l5+D1m p_0ͯ"cE!ȺXm_0ͯj( ?_0ͯ"cEc'"cd]ì6b,dd]ì6b싯uV싯uQuC|֢uC|?.a?_1ZP2.a?_1GE :k+ZOE :k(ȺXmkQ@XȺXm_0ͯj( ?_0ͯ"cEc'"cd]ì6b,dd]ì6b싯uV싯uQuC|֢uC|?.a?_1ZP2.a?_1GE :k+ZOE :k+F#k\Yon{U_nR@Q@W]Dx)|!@?֬W+4kW Tw&[ZM& }sChdtI# Il:U#۬[χ|L[`>&Ѕ~tkΡWaqr{"HP3_fŁ + RSp)7bdm!)K{G!ʜGk\L }@܁k̼"Z xJy k-W{I z^p~s 襱$r;Tlg8U"Y4w-9?5~)Ԥ t}6Stnç 6Hǧqb#no}.vz^4n>Oev.LuzזCxvU[iv#:egnsWw NH'#VlDq4Hlr0t+#~|M6ҨZ|M6ҨS֢(8s`?Z.ݼi݇5wMs se(Sgd~DExQHSi]-K٭VI \3O1eT??ֳ<eg?/*^#iʖƻ|A#r.>RIMkA=\VM'JKuebݧ1㌘ g| Z]YϢGoXͷPYDq琠9ʩ4-,{6 [!o o.9IA!A~})ܸ8s`?pz(t2c%!y$NI$k;zPl&9ZrYu+19$$";ƚm2𥮗q:,~OU*jH,y^$Q%j=9Q7vPdIuϣI_NY-.2DLD<14-TKNr ^zD#[0|~0ׇ4۳(ISKF[@2{clc^:&zXFqy?…Ed H,{5k5pxCZ xmine(F u5%xn$mY>[XVb)]r.xP54WfC$ǔ u*S{j[{=Ķak,1k~ktlv(UEAfijJt`AE)6:څwyc47!UUӺcOi7u$Ietfg\Rp:4MV,( AW|vi:ai+_ =yh3GWE47 9:l{?F :?Q ÿ0^?)s3 ]'+t 'a6?*PgK=?\,OãlU<;CTr3:M'(¹XG?bxwcft=?F :?Q ÿ0G(s3'+t 'a6?*PgI?OW7 ÿ0G,OãlU΍¢bGr*(m[dvC` Qu Z5YR3$jivtQEIFL7ѶY3ߧ:Fֵdx6>yXEIs :^o37G{G4KsBmll? mNT,oYn#1te#q }-9\:\1 <=<;Uf*hxy*d_i>1xKurƶU,1'W&FݹSM1Kn01;`@ 0Ec_lu=ўQSK?FZ|m#܄QV_ulFX$=7&'+$}짱Hf|ĒBO@q"ןJ|>o>֮e] [V5z咗j<j6cvMXCл;!Z֮k8-h.oiڐnu u+[$w\@ w#'5 eA={?rk0r5M|^SܞVgcz Mv!@Y+^iIEsm,z*-lzvzo\]cos;{fDd`UCCwe%ecJԴ;PG{i1T- >e =O@t^_IT'%Y6p#8:3\jq[jWƾʪ(z aRG7N0z=FU/PR֭zKE!+F%AQ8]> >-că th…5NRs45oEZbU *+epdR {+BGE@ʊ ‚NG|SY˥hIyeprI,I2Ap:z Av>y6I&XjnQoxQ&Eo 5;]DӤ,n`w *+ п2>xZHt->92- #x +2Ȋ GZwTxFhtW]1ıtU}WJ{oVאĮM]Xp@=>X[Gi&vC*"I8`dO5 _/ G+ п2W9gG#YT[ى *Ə#F?+\EQ tITWVV PEKwe%ec%X*đEp74?niSzy>XX9~Q㌜`ocVڕq ={9Ủg-߅"m5}:o^>=,7nV'7LJM'm;ˌQ@de =+͏|+[C]]j~a6YbUPU'u_<%BkNgtEފS |Q5WN`r~ dUE-.(@:һ`vxkDY5m&UM3I; kkcJx`vFx5|'trYMcXs$%>hvħ~¼ o'Q _/ N밹YS3EsMEe٤Cf#Qu%;(Z}MwngB!T΃)5*LʠCc8}F֖8rOq'5iX`0?FN$|V^*s[!Mn%2r98s[/ 7 gAM?r2'x%!k)"t2P= WS6jE5ቷ pc+ETa@TU*FQEd[A_W5kUM*f3ͻY3ɏ~=@c\x[3I5ƅK,]ff'$G$Eato-7Mht+k8YXԶp>n>o1]K3mn^4f'$мzYi,*I$I95fĢؚg|όhR3;L??4(;L??4(;L??4(;L(??4(;L?_M3|`kB?M3|`kF?B8#XF*J((:[i[vwA?qL;IQoZ4Q@> stream x\Y$~P2.>e/ؒh-V/8*#2*wFYXvj*8jt|7?vSח/ϯz}9}z}!?ooSt~;MwrMo a|snmu1J|NoCOfvy!s;ǻ?6l#<7xd'BwkO/W xpC wcbcugw.4g>^;]h\ WnY"xx<2H": 5^ao'P `?c&aEً+{0|{'EP(U.p/$=܆Wxw,)#?F%2 g"@ğr%Q$a3잌d4K,}L0 "8aNX*۬^|]4-=r+RS!#_@$ 퇵sL0 s|BN[ )$TX"e4W[ZҊ5=([<}!?_WM̐ЍC͵%{DB՜j{/xBw.PvqC<.- J&5In]j:.R/ Hj"AA ܳd~0.!Ø3`\+[F}k&aWrie!^94:3 UNXuw,se 3~Qy9Idkd fB}9,IMY;u$ݰiÃC 'zZ.$"?TOPP}U=0.;/w'y[4,I\D>YJfZ2j%R^$8#sLU(WL-&0x2a2gV/k?#{WBCPgcj%ka:곂Ai-(iHdxX/ٚLϯ/}ӿ~V1TP9B6j;F ʴT))ac4,\5T˕`!Ds?Q6e&+5ѐ޶L}+DpW٧˞EiC jٽ42A?:,U>^YRo)Uªz,y'(B4Q[]/@IYHP qj-QO$ AD&pg5-9Mp[FlKΪm+9 zg AA5{pLM5}4vz(#KhÌf곙) 3('N[4C {nGGd7GZ:UfU 68ksԅ٪QI8äJO@dFpDFm&$ɀy#2h ŚU$QX7ֱZ[oܨ0,0+0>i yV k[~'huZȵ'˘ɽ'Ua WEgfL}{#vغᄡo -s0^1vf3b"3'xBXFT=}ɽ4½5[ >]p^!L!YJ4_بe=r񚲩OLU2(ދLH~%[)p}й8>COސKP5ElX41d#V"DÞJac-F\YKƱ`1FZ)s V ]iV ki4/ɂ9I'}2_FVn AeCJniNTƸB_ʀ @ QRU[H9zg`/Q2)O?_Z1PtEU߉qe)TiԤJ~`45\87y\zfO`׼r5 .FlW#xXm$sؤIʾf֏_t 6Nx%q|M׊~9:XTBQ M3GY ' b72z!>FrQW,c[ R!}$}ey],gns/1S&k gjX]@^W#LJ=g;`!a4kAKzlo3Pg}6l'ֿ1B-Z "ro-NA[8ʘI-o7Od~Of&h9]Ĵ,ö*FYRS秄-Mhߡ_o|1Db3ue`}ݗ<[?uq Oq}t_0{endstream endobj 28 0 obj 2842 endobj 29 0 obj << /Type /XObject /Subtype /Image /Width 914 /Height 124 /BitsPerComponent 8 /ColorSpace /DeviceRGB /Filter /DCTDecode /Length 24817 >> stream JFIFC   %# , #&')*)-0-(0%()(C   (((((((((((((((((((((((((((((((((((((((((((((((((((|" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?/z~8!wv<6I>u__oxP]iZ"i_БsqI$#<vWEhRD2'?uCo V%_^?PUBy 㑅#ZƵOZRw`ƹ Jc,+I 6Ew=^-. aE .@(<0pyz֞kT n-7u\H:e1,nZmo7mio}g-3C6AWzdv޹3s]ΥmI7ɢj 5h%#v20et3 :\څ&vnX,^&Vm19{z'(y4/\x]5l0>_$(jnj iZ͍ĭmmL4lu1G=i_KPV,/uKk+8Oq*2@$u( Z^E="aXgYdE++)?kK݂׍r,TYZ&Vm+W7՝1-N³T`;U95[)v2o,}5LTxaAf:T[6Չ 5" GּwMҵIi|/̞$u-6hyHm>3ݖ!޶8h> |<\-c[ʩm\esЗ&/T/, uʬXuR:7.OmָMG_4"gUKKۘQ %RrŮ<>5=rW2iZS<%vj#M;/Q xZuM?S6n`lφy2rzAbJ㱝 M,C4RKn&D`LlT0 ;ݣ=L4nV*HGb1\>'b@Ӵ{o78opapF1\koY<ڃ~&etBe($]zԶ noUr{ ܐ;_* |Km~i i=/1HbF?152U׼a?>i\+g ͤ21SsAM\;_U4mZXRCtю]f|jcHQU/ڏ/ځةQU/ڏ/ڀO~Y,TG@XQU/ڏ/ڀS~_/@XQU/ړ>__[|j?/ڏ/ڮy~Ԟ_bGVjXO kPZP~7"G<;nz_I]1]["F\Ơqcu?6f%3[-3*f\Ts=8W~ ^>n/Lu$ep ?= Ptܢi|ܒG>YOxKFL6qk yBd~R20NT5?k?Xh\hw:<7,pP891PzqIB >x$&ha#䄹8$pkoXcS~cO.3B5c륎0FrsԒcF{Rl^Eٯ& 6Ո/Rz oXcS~cO.4t&Hm vF$II$I$ht]V[_%}Ȳ! ȧ#wޱBƧmz s0vڶyjywp+7R2# AChVΖvl6ӰJU`@ "m,jб_?E_ ]i, Y$btY؄.O?FЦOr9GA.Yhsh?XoXcS~]'>5/4)ܓ l "4ŒUïdFKrvcf;69z m,jqؖeؼP$Po29YZE,KdCIB >xd$&ha 섹8$pkoXcS~cO. Ѽ h^XY̳BKw4AGrH@ҺO,VޱBƧmz \,hzMCG,ܸ[2J#$fcTQћz4=Η5Iaqq%ԑ;1̯!NXFL`S?5?k?XbKyK[Vi Fw- Hwr+p=A K>$5-J9"+Fm*}+oXcS~cO.+-͸(8R4UT`(/ڰ5?kݖ:Z]ŀRmO.F1h/+ڏ+ڪODlS j'~T]^WWUlUm7ZMJ OuƱg𷅵-jNGDWӄIB 莗+xǞM}{P;㴏^A 綿wf),#w oXzޭ}jZu%i:@W_e#,2;  `FHLaiAcyW}JOG~i_Z6>x[;IꭆS3ȭ?/ھ3 KK4v4g 9J`d#q|?_!1 jꎊU=7A\J:|M|Du<+]Ҭb#uXOm8Æ;Tl+bVV"MSWg_Z;wWU,)/5;{;Hk4\X2H2SK=̐CJ^Id;Q bN$c⯎{ei;D1g$o ''@2,oY>XveVx|:$n?z{eGy]ZI[Ȳ#`p >Q4{~MlGG \4IgUX#0b03?W/%g) o#T)չiq>򽪝x nWR2H< /R>wZ3ş/ڏ/ڪODlQv-y~y^Wz'GdOʋkm?*>'~T]^__UlQ=,Z򽪯dOʏ蟕abחGU~'~T}OD jg?w~̶74S914`?|+񮻩%-s_@"K8s`kziv=N̮v+#$N8U2YKUTM+v{NdzQ_EPEPEPEPEPEPEPEPEPEPEPEPEPU+Yڇz3袊e>C\;+C/ ̕aI9RG<*1Io?~\ծ#+-k6??-_Kۦ**I=f |! x{JY^XV4-b) nu?]i,&𓟕w\ #q1𶶯# -$,$;q|T0F0,˿y.ZeƧZXXJCໝU8$BG?|S+KPM{R)9dܘrџ ˁXWھ*.ifXB`7Ss__ҏ1}JQWGf瘾bڏGڏG byVڿ?j??91}J<+G_ʏf瘾bڏGڏG byXjhT}xT{07<(?ʏ*=\__Ұ*>*=\_ZWGGه1/GaxT}Q瘾bQQ愗J. <0U[\6yۺΛy\>fgn3E`\_cPeZOx?Ƹ~6ռ! ;Ծ#4?@˹AFHNG7\IkNpKpU$$ ĚpnB;WhZ6$@ F|c8dZC)dN(|!"`oY>C@uZ · G)ڬ"i5^ u}FY4WOxih4Ev:?𭧍<-w7%8@r 0k/xk o~Z_X)l" HVc~:sFITMۛn:ۜmOX~ x-mdƅpI.~2x#Z|⦑}sKTxg*'@ %K3I6$ƲCL˻LȻ3Aa$HK? _+ lԬT=).EU"[t((] lsR>m;XE:R菪+c^{'~x Hɡda,RyTcxKƿ/|7N'~jږI0P$i"s6Fbi|xJS$O"U_᫼=XVKXsGĞ Ѭ|S]x{"/<ZL)0HnۑMs#R}vX./k ȓP)=8?CJԼ"w ,`Kpn>qm7B`e$h 83=I "Yvr#qkK;gp:w 2Sԭ,,cnH!p]*GZ {;=CO)14SE# :^'H& ԌyR®ff;̣LdxWZk&<'I$@IS|~oޖa(; ݽZ/ޅ7N_4+t{$RIq WRH̭b{ }H[E lѿ7‹\Gi#}]a%#*oPpwU@<Ύd~W49u_j];ũCs""@{gҼ➅a:F;Mck*lRGu$U:|4eN?^tw ܦF2zs"mMl/GS[Զy |3eH7aXz41j4wdݛnս|+|E-OtAx>""kBK-XF1r:deXuPYG2y5^2UOoiZ\XAuuiW,dv-ޮͅ'`I(4Xomo%㺕B<0T䀫נ_+]-$;`RGCe'ൊILHK3B(I _xDُT/aNy~}#>¾[cV[V/ܻLֶ9AϦ.6I(m^@BqWឡi(_j4>>2裁<`pxm88Cp%irO4>%V u$zZU0Lܰ;i%}pMkSЌ ff:<7ߖɧ.fGdvQEbhQEQEQEQEQEQEQEQEQEQEJeo–H;UKr=2BPV5 E 4V5X,lXQ`EcQEE 4V5X,lXQ`EcQEE 4V5X,lXQ`EcQEE 4V5X,lmCJYP (>CZՓo?~\խ@#ơDVa.vG2;*n$2A[JA/ΒFC+[; ܼZ$rm,}I5q(nicQqX<%B¼ o'S'Ǹ?^xK7(y/O9 {1+焿_?WMd 9ÐǸ?^xK7(y/O9 {1+焿_?WMd 9ÐǸ?^xK7(y/O9 {1+焿_?WMd 9ÐǸ?^xK7(y/O9 {1+焿_?WMd 9ÐǸ?^xK7(y/O9 {1+焿_?WMd 9ÐǸ?^xK7(y/O9\A!]1_5NBc0'>j][Cwm5qMo2E `qy/O焿_?Žp/5zEV6 }}O$II5k$%R+-Ẓ59)E8ǯ>^xK7+WG摣î"('!kQEdCE )kZ|!"`o\׈%hgACa},w/ȕ1RJ'Ng~O/;fr.a?Q.JѭR6j?2OrO$I8jkit5<f2'hCg.}c]axsðq1k,6YL+vh~mUתT9{f٘bO5W76K{s4aVMIFH85PYx G@|~I6'em5xmGs/ ȉX8aFycCnmWUgPs_?LkA CgnaWaжbqd HY> jǐ 3 Uv*H#WME=y2jMFK Npx{ᏋEAhZ\XϻːvS9xfl:}%_9Wj\W>𮻣x{$y/Khc-彸m0g5d]ì6b!/5kviBcYn!\21܇F+_~6ox5./e7/BMǪH/|_\J8-NzOoюnw%fu?_0ͯy?=Fr<ɍ@-GlBmIZYɂ:*Y H߈oǞ)7wet( I33ө$I$| k)JR!֪O[|KUPGS#S%qI5U;nmĺJH쌮d2#ιz.Sg$$rǫ*1 {mDŽSoayu;V`I0v? \{x<4mn~]ሕ5c싯uQuC|*{Z;v2?.a?_1UgӭZZ؈2' Y*nI% ޷'ia*싯uQuC|֬𾥭..#c nbg'WNMB W9Hm]7k<ڂ 1Epv15QIxw eĬ`PSO5:׍T74ږLIv==(ğ uG~פ1i; 6KBxċz8_L GYIvv;w'-t-A%FMpFUFTFy.a?_1_| ̳ȚEˈo1!J`d 1.:ҾS?%b;2?j* Ɲ-xU$}U b`u&_m#Q{HK}HCMcod59\`hoǶҕ%`b?h(; Pʝ2C-wn~qIkc V4厩iTWVzjeR|c Vx֭iRqYD'"e\c ã dm|-Hsk\]캚!~ڞr%/$vLosF#xYKXh~s^9gtQs(ꕽWկ-yvGx;N^Aid]ì6b싯uVFS H|]#"cd]ì6b,dd]ì6b싯uV싯uQuC|O m:ydYK뼙$g[@;@UQǹzȺXm_0ͯj( ?_0ͯ"c^ƕ_h˼ʟRCu$:$l`}׮,fU}] ͑9 싯uQuC|n.%Oj9r#5UHUj|]Ѯ57bFIl~9rH0?Gu|dD]GϦ.a?_1GE :k*{oiRyQ$ɂ7#(e88# XqqvgQuC|?.a?_1ZR ?_0ͯ"cEc'"cd]ì6b,dd]ì6b싯uV싯uQuC|֢uC|?.a?_1ZP2.a?_1GE :k+ZOE :k*898mV(PUP0Er6:^%Ki%cU |2Lq֚E얣hSOujȺXm_0ͯj/|QYi-ʐj1I!JAު0rvDq싯uQuC|_^XeT0x́N~q+]/@E]m 2#w˹p8ngi6pE)1vz(5=>f1Fq*=*M. #S_Έdhnle`Xdq_jkojW0ܸF;gQi-FٖE{&!A _mRT\W[O/֝>ȺXm_0ͯ/S{ xyuElhq&cSE+uI+_]Ы[5P2.a?_1GE :k+Z.OE :k(ȺXmkQ@XȺXm_0ͯj( ?_0ͯ"cEc'"cd]ì6b,dd]ì6b싯uV싯uQuC|֢uC|?.a?_1ZP2.a?_1GE :k+ZOE :k(ȺXmkQ@XȺXm_0ͯj( ?_0ͯ"cEc'"cd]ì6b,dd]ì6b싯uV싯uQuC|֢uC|ѴH业9`۞Wۀ:TPEPߴlE{XXD;wH(=aHS|𕶯\x^t]˸ʻ%S n#{?* (ƚ傰X*TC_˓I=fm_څņqŭf ĸYPW8$5V⥚]N 1F7r,0;3M}5O i~ 3c%mâ,Yձ$"$8aX& 7薺ä2Oڑ]j{-\[6?69 c)'> ̟:7pY}uܘ Į22XeG#_W~D")M ;5k`4(ϛCt(y|-juY(9iԪnGxß%Ӵk ^?گ.Axug1nk h&)&qgbp$չk&:=kl!cT*-C39Q+Kk'$^L+\6"J6=L^8zΜ%udoO6?UkVO6?Ujss> HV@#$sϢ|qwT: ]B-?R\ɣzIKEnJd= d:׿K|w{h_$CP[nep"Tǯ<>\WW:U.`ɤ$]v%|0x_ HCKe$h83=I xgS/(2z=Oɞ|y]X,n5=J?6TB$umqʕ \x=[PB%6 sctf\FJ x}Sb!@<.kh#i-4g]]G K#r>`A۹RZ\c 'SW&ǝ1NP6a dW3FMo+Z[3)poK{6,G="Qf[| XaW-K;-k..Vhӧ\wx'ᗊDiwE(d8͍qU!s9M;kxeu ,1Xd)8`T>vaS ЩJeRr"ImM\V:|WK ny<,hF QeBx)嘙);ZەRW<uψ<߂CL䍸-翴0XPN]ˎ{f5+ 6e"цƁev1 N/1$%9W8*23.d8jm}~Ϊ*8x'7ttkZ (hgv N'[P(DruFqטjGkjui 0`I yhθr@* (I _/F|9[ 2(?4mE܌S[ Ys7kYZk/%%jz_tŦkayUEY3ۂq }#xJTzE+3B9>[8s> z2èy(ye F*ذ{ʠtMœ488y;}?!sHb*RAJɤ'wmSM|#w:iVaUJ35|xf|jdPTX<ʩ)0#%y2HO7ω.%[I&QGnr+_>.We_ 28Ag$WPUe$$Wa3 "8WZjkӦl{lv-?Zf6Cg."$vo۞ b:Z*Cu kkGi M'0fPݒ8/@O,SIZ T.## )rWD<gm f2YsYfo9*a(U%RIEkm7+6cξ ^_ݍWRAw{)ʓtKCN+t{Ėiֱ[Oam~,$F.p|ҽ^zZImwmdoy Y\@;r +iS\˻sqqp3 U=r[1Ό[=_Kz=M+? |N𦹦xR.n4m>IQC*83׌ÚޡmUdE6Kdo#+c"`3g2Nû{mbn;NO,||Hd6@j麭&8-In~( p.~q``g9z]zJ2RCZ8nhyf3 R!&gjw!&1agöĒB;G +t1_-QPPQEo?~\խY>CZ xmine(F u5%xn$mY>[XVb)]r.x^nȍacqr҂M"Bʘ`C<]!|oAh˫]MBӴKg<^٬Nw:c-w4xvȃ r9Z};5 oHI&;/&+Tc}S Zpk1Rj˕%{[s_seˋφRCq!x U$G9<_¼xLmGޑ}@Tʜi ÿ0_)թKrm}U6lo. :?Q ÿ0^)|v|g'+t 'a6?*PgI?OW7 ÿ0G,OãlUΗg'(¹XG?bxwcft?OQs_<;CT :?Q6|g bxwct 9ѸTRX(TEMl85xstz]>>:_Ʋ 9VWrpzdMY 6Ί((ɟF?6ֵ&]Z֠ :`5O'D= Y"0ZOC u\uY~=-z,aHc1e$OEI5qpGSII٭5=4ȕQ)\-;~Z^{{4Z,K$nU.G_9@l@O_2|(mSWfڬR#I>dq!$PvMXL]PKy%đ\gdA4 xAZ_5MqrUi]ݷ3񝣪c75ƫgqk쪮`*?Al'V=,T9*- b*MA]ʶz%ZնoX4iuh?evĨ8 "'-7ʷMCE-̑er{Q?4=y6I&Xj+ GkBo_MF𾏳StM:H2;Xh'pP@"¼ o'SdBNC,qG1<~9EwsQfSUHS[N#cBW z렆;x8P" Z~m}Vrx>"jK>;M>3QI$}ɬWMd ?^xK7*3uLjxEE{xnNJF#u8ǯ>n?qW6ǢFOPOV4i1^ol:(VHl `z*[)++vq*,NV$B+ѾAsJġ duxLfFl"Ԯ#}UQG-ʮdO+9o.i})*n[ # 8 c*# ϧ+"Y t'Kʗ%ORIj[Lj62Voi38Hn-xIܱ @?5-,7w+xVzޛYEusGΓڶb(22v^f>֭.5?0oK,D*EQ*ҺWMd x3úlk "OE k`l4(ugZ]GQȀ)u2=Av0+#Z։ȲjMܪ0$f$feasm~ iVְ/ھ>4/nZ)kw6{8d!ؔvֺoWMd ?^xK7).eO ύ5u+fWV|GzISZ7 V+IkadnW5im8cPc:{[Ԫ\A3* lvI$f1 5 #$/Wھu2{d)mIJ3N[ s eA={?rAl)SDĶդ8~$QfR$ t1XxM[Q16p}u(*(ʊQEHŠ( !JjYyyc&y1oǾ3Vk x~i&дelH޶h /C5B14O94{(x)2:+~NTfi=?σXuܰ; 2I>kr N<ЬK#I$:I y!B8ぎcqujǵ SFw&>04biZ4WYόؚg|֍όؚg|Vόؚg|֍ϔؚg|֍ό/&>05EgbiG&>05EgbiWm!i%QE-;;&l^B7( Z5mPӚymKs4'+Ob3^3w:iw~\mG2>G+tP<|OoS2۵}0t\1k袀3}Jք#X5|$^qp3AQ^4{HѴ m-q1RA*Jq=jQZ{YVAEVc ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( (? endstream 30 0 obj << /Length 31 0 R /Filter /FlateDecode >> stream x[YF~_g}̄<:YH@tkT[Ҭ°iU]_U~nL֜lY?1}~MmC۝w5/?7ﮮyؼw4/=>\ޜF͋noڴ>~ބۃ'ܞt'koBh<{2 hB J$Daq ߲ 6O_DN=,^5& A5kS- O|A րGCdݹ D^ kig((iiPT՛X"C;R3٬/kAU$uA\{%5džk$v΁_m-0MuxVxwX[~+pm \݁51@jMܧvjuU0Zf)"U0R*jF<J{@*U:JАSAZᮨkC!]2ۆJ.GUҫtYϘsfHRUZ* }YWswHk>1RDwvWXȮPQ`h~֮x0C0vإ&˜J1|z#!4J*!^TFVÐ9M͵ ~3]CmؙcYXA/ @V@`gvo6q_Tܗ̐/by"|IUrp t!3u)pIm(D%ՠ5&XUs}RiSa 3nD~QTegUӧLJ-Zw6ko7?T{QC/ba3@3↮ɼk*ޛc ?*Umm)5خ-wKg\eRAcHp Eҕ24l24RŭPqEWWi=笅ٌ~hP iu]Q9ƃwPQq3aj.C :U_P?TJgd{LYAr|.;ue$#6XQR8"ιW2o'#fȍM"7>Ę" 홥Mpgw4$M$GN4:>ZMd-"(`}q[*vQ "(!J v4,!ɿV;DWv%D ^elC 4 N YZ(%EXS\bZΆZ)BkS;JE<,e?,Kͱ(2O%M/X{tFs6B2" Ȅpr %+x5]y/iyrWO؅F(gY"[6NX圐P";R!,򢈘V0HF3CK.;UQ6|Xw\XbsYYRl`*Н"OY s N[,#`ѹ;Xw%c*FNTzy .~w\]+pP8 7) H@k`6vHCnd%OП0CІW5i)#9|V0[bfbv/2gXoGEj>{tMQj:.E y!Bl"+_j}~a x3,Zr^ҧt_NpےD")mږgѵ;e&ItuJ^e(WD],Cll^v &gŽ.i/0Un Il.dL}um.uOu!d@7(;j_zK 4Q55j ZQU|u03M0UԿ +ѨB|jUuBxVwtEU-|.?˷-r q:tS+84W WkȾ: _e 5&5];te9Z7DcZ/bM qcuN{mvECcDim'o`!ϗD8tWi}ɻg37 Rendstream endobj 31 0 obj 2011 endobj 32 0 obj << /Type /XObject /Subtype /Image /Width 474 /Height 324 /BitsPerComponent 8 /ColorSpace /DeviceRGB /Filter /DCTDecode /Length 11833 >> stream JFIFC   %# , #&')*)-0-(0%()(C   (((((((((((((((((((((((((((((((((((((((((((((((((((D" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?B(PQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEHg r3@O?Gމ| e1yQO?Gމ| e1yQO?Gމ| e1yQO?Gމ| e1yQO?Gމ| e1yQO?Gމ| e1yQO?Gމ| e1yQO?Gމ| e1yQO?Gމ| e1yQO?Gމ| e1yQO?Gމ| e1yQO?Gމ| e1yQO?Gމ| e1yQO?XI)<$Y@ۙƤORhZ((?Է)K?2(+|ok0|7h"NE.6$6@=`:*AhZv=R,@*X2E]đp㨬WY%D{F xehd${cJѠQEQEQEQEQYjKR_[v@RG16x:Ѡ.QEQEQT'-촧&6Oe\~4QEQEQEQEQEQEQEQEQEQEQEQEQEQEtEl7MEPEPO[iրEPW<;OX++wqrpM7 k힗ZM˩]E}$H*t˶SQi\GvG\_ĤѵjV+ԬeQt觺VMiِ,kT+~E +~E V$oq5ÿ \\.k$9;TOrMxoM Ƚ;5ŕ@"?+o^F?~"†UM#΍v^xmćv2`|**c˼Eg ֻGѵ{7$(w~dFͧ{p`Nsxږc lK2Y[0dS¶{+s+~E +~E =nysiKsv#%y߈߈.SM8R -oWlo)AX=4m6G,-!H"^UW+?]}bQ2=nc.dެ@A9ueZmvpG5ērIfc׹8t-QEQEQEQEQEQEQEQEQEQEQEQEQEV7MX 7A?ZQ@Q@<oSxZeQ@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@cx+D k[5tElEQESxZe<oQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEV7MX 7A?ZQ@Q@<oSxZeQ@Q@Q@Q@Q@Q@Q@Q@Q@s>3χldu✦c痆JWc[xⳈ$yHTLqpq|<T~~] s"`8֯.ZP0[n}/mCx:k[d`d- z ӒE|2ӀvꭆR 6ɩ‹yg PeȪ|k/eks,&r;Lg H@8* kp |m}}4ZF+MmYS?,QS[칧Ef}TgVzj,P4Ϸj,QS[S[>ݪгO=@\Ӣ>ݪгO=G۵OuoiǨ tVg۵OuoiǨvBέm?sNvBέm?n?Yտ.iYn?Yտڧ ::+3ڧ :}TgVzEf}TgVzj,P4Ϸj,QS[^kF.ozyn1F3X((("n^赭WxAր6h()K?2?Է(ż_lCkM 4a9GmW%#iCHehIdFWtGxb/ikhI bEl"9vIT@'Qkqvi_g-FϰU=_\q3v]qC8]Fm!I]xt=_[Ey5Gɡh-u[MPdi`Wirx^}&ysiKy%SB8,b1ݏIhTDwȪ8v8 כGԡĺp1<6NMf+ i'54kwa FX5[ǵ /i6/SgG[K缳&xDQFSmr;B5uMKzkڮtRG(۴AyjRNTsA>kim}5亇ź$q}@n" n>8 Y6I$IfY`Р\1pmJTMv?MW[|VTB{jPOs0Re] 'x2Sԭ,,cnH!p]*GZ-~x(#WK)#PI0G oOR^'61km ≠Q ^d8Z/1imݗW,GҖ+s((((((((((_>5+g (Q@Q@cx+D k[5tElEQESxZe<oQERNdҬ #X8*(=sBiֱi/f;i$yWG9yn9}Ϩi$eD,RkImRxtK_\EG$qEy-~hTM%)U^6V p883ZN%V̒YG4P;LUeei2XIJ)dkb8ޘ"mr8eRpĈv/0=gxOg?-~רq*>vbT8ḯֺKwdCAO9w_%ղM:Kh T)BWƝGosWp9]+;=BoYi&o d*܅]F1ӌKoVZ56mvVO1ϒV6rN[v6z5Ec6Cn&fKK&Ye R~sz xGGMޟ ȟ1i! Q#Q鎕ET4]V[_%`Ȳ! ȧV袀 7xFJj{iQ9p4S9ETg=(}ԅbO,\}U??z?zrgQgP.QTL>L*ۿ=Gۿ=@XESw3Ǩw3Ǩ (nnbO,\}U??z?zCJYb@q^QEQEQEV7MX 7A?ZQ@Q@<oSxZeQ@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@cx+D k[5tElEQESxZe<oQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEV7MX 7A?ZQ@Q@<oSxZeQ@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@cx+D k[5tElEQESxZe<oQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEV7MX 7A?ZQ@Q@<oSxZeQ@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@cx+D k[5tElEQESxZe<oQEQEQEQEQEQESuM?H[ZݟYnX 3N=Tb(+Z&piΙ:!V RN2@ϸJ% AJŠ(((((([EPEPEPEPEPEPEPEPEPEPEPEPX 7A?Zcx+D k@4QEQE֙O[hQEQEQEQEQEr?Nisk/[ťN[̶h^ܤH r:q_LUesK$W i.qJ nct;xk:vo}< =^~l uzV/3=~~a YOCZ?f?fW+cv֏ه >?P3} >~?Qau€h5a|Qa|P3} !6y-.V6(wSm?xj=+埌mCY|%|M-ul̺eaYL˴Nj/.-et˩#6*&!OHյ[-:)- p ="ۃr>"U1XGͫF=J3~iXVǙj7,oq;@kz}xvKxgM l ".QT6;ǵTa8J6z7z|cޢ?Eh{xjS4iI$݌JK1$Nk1c?_T${BcƏ?#5rf?~Gh (f??Gُ *꽴&@F?Zs6)Kh(0((((((oțׄ-kf"n^赠 ( ( xRL-( ( ( ( (9Ox6IG ei7mU3K)vpH?O8)e.bn##9Y8J5~\__2Cx…B즵4}ZIyOm#cɱY;C0G5)'cϾxfz.hū&c׃D5x]-ψHKiuc"ZE'++HC -_Vw=DeATȬEm}\KwZ[΍xp,Kqד!5gC{7Mm.CdI.'V *|AV8 gŕ;Ibvuð  a~\j@4Vzhh_^wjG3y7~tY[XZGv8@9*ǂ(+'p=S2oCͼ\J9"C+*A_Q=K5Ht4Y``Щ?rV/_B[h.m$C/味vk]vZş. x8$\I㹯qvBoIsݻvo"')У<+5P4$(v6q踨l$7WԝlП݀z1oizm[\eOb AA[6򤌱i`vI&0q#=+u://{#l@72Z4DmȰ4j@ "m[kk:/I"y˄]w385xVu'NXK$GOYfV T6uZf:uԸ[qm89;f:?&ԓLO _W|Z[mI7W;?qGXJkwP 邘K|ぃ{OjT3ZXpSI5q{ԩo#}N.ona慾*IB|*c ȧ=r@gx_ Mc2ۘ@Wgx'P,gp$NPyZZs&>Gwq(WȒ/,.Gۉ'}:ޫXn_nXL3\9^m6a+V]4zt&IxJJȸvTQEdhQEQEQEQEQEQEtEl7MEPEPO[iրEPEPEPEPEPUu=>SkkxI pUFrG5j%]G]EWȔO_w  _os(z uQp eA=?rAl'W[E  _os(z uQp eA=?rAl'W[E &&uu]>Uӡ |~ [‘DQF(2`HpE-&E׵->xKuXeHǢ#fgGιCf)݊??pιCf( #g\S{_3G#:,Cs O8jkk9Fu5?43=.䇆1x?aўc<7w Yl?:V]$(EPEPEPEPEPEPX 7A?Zcx+D k@4QEQE֙U5 #EM.r~ =-X.jQ}B-lX.jQ}B-lX.jQ}B-lX.jQ}B-lX.jQ}B-lX.jQ}B-lX.jQ}B-lX.jQ}B-lX.jQ}B-lX.jQ}B-lX.jQ}B-lX.jQ}B-lX.jQ}B-lX.jQ}B-lX.jQ}B-lX.jQ}B-lX.jQ}B-lX.jQ}B-lX.jQ}B-lX.jQ}B-lX.jQ}B-lX.jQ}B-lX.jQ}B-lX.jQ}B-lX.jQ}B-lX.jQ}B-l7Ml_й_=Sx^k i6I HbrT"4袊(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((( endstream 33 0 obj << /Length 34 0 R /Filter /FlateDecode >> stream x[ۊG }_g%U_zn!NqOu2%UOaaLE:::R4y^aZ~Kt/c24ߛw'l}М|~jӗ'!` 4DçP44/Ʈwj$ZڴC2rL`O/{$|ytU@#m~"x;7]>ᘶЦtX񺲌ڽcr3lÁ ˜Sނ@ bCbQڡ  qٴ'U!PÌ ߃V}n O(gt22}aAgFGz3>*hc_Ġ/.qP!;=}Li% Јj^/,eqEKؔzNʡa 6%{r~ X#rޒ[!g.Pl 6SY0y\5 8SR+=gJrڃ&ãXB.aY-}>Dt_VHdNց&N:6۰#A <W4&0,0J8WgVʈ2,SŞ^[5 lW)%k @CZgc+QXFjmM*)ADm:rd=<1Ӫ=V " 4GpWݎq{dPw5C+pg@z[]N2{L6E(uPGtLzw!#UB=+Sα_J :HkҢM -% lϽʾ=Mq9&xE>, SvVH+֯0R,W&('sU%d>l1\#Qt$tOIl9@`y>'F;bQ€Zf2L> ֦5mZ1*9U4Z8kAIU E*ܓq:*t~d#ֿ+:w+SP{Ғd.ki'9/!ouak\%&è!Q( ׁu[;yUe\K]sUR*r+"з4 9<qd]r;|br4cЕ1B6Vm]BBުTIôq 05 B/bAl[O|Ӣ\> stream JFIFC   %# , #&')*)-0-(0%()(C   (((((((((((((((((((((((((((((((((((((((((((((((((((4" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?B(PQEI*$GPtS?tyGS?tyGS?tyGS?tyGS?tyGS?tyGS?tyGS?tyGS?tyGS?tyGS?tyGS?tyGS?tyGS?tyGS?tyGS?tyGS?tyGS?tyGS?tyGS?tyGS?tyGS?tyGS?tyGS?tyGS?tyGS?tyGS?u3.ry?oҩhf(((ݓ)Q@ ((?-/4$mOʖR`c3^2$virxn^=.;EUC.NZ> їNP:,'%b7)H@f![8<+;)5QeᄶG-V)MAd#S(zյ+F9}NԒtXdf@v<Hc.9*7/#GY>`x{jfqrLhl??/AiNk6i5 K`|YT2+7Y״ bmoUӖRDf!g2?:kq ݼw4(d6 BA:v[#IoubsCA.i;ša`DW Ee!t)uW+srHS*z>I=\iRjrjY z|PqڬZeƫa.?'P((s~ կy&jZ\q{r`Yۆ$2nG#A5kWLvn[X$rmD9#q"(WP褐7Wyuo ]Msw} {,JrI5+У+FimYEԯ fDVOs-Œʯ( Xq=]KG^YW#Rѵtc0y7[N(р:Wi (w4¾g >d?MSU/6γFIQ$ cf Aq]{X]b_5pG,ŊZ_nFII,t8f{H1F/o!N['Z%wEnJ[D7sI$Nrs5o?Q !h}|;,3so/hZ~}qEu%Jfr[pـ:VtwMd}'O5+B᠑-x&6H%0gyc,Ŏ @M (w41%c6+Cݛ[oi ̻d܌|yeXiix_E*nuo:KfXJnPm}|;?_x3&+&c2.׵[˙lRм/10JgP|4=#Y|WMwq;Yi+-HiqxyY`M/Rɓw.j]WW{_|vMNligfHIۻ8#]. cתq\̱w/}GQF.[X~h_s2Rh̑;N2h¶P.K_^5PO.:rm.T+e#ZBr4Wx[q{uhdJdbIyt-GfI6:{unVC5ܒ9lJ***pF @9cq2o;]ì-Bpl0$ mόcu)|1J)N1p(ޕ_;msgzQ+G[֎@(ޕG \ޔoJkz.lJ7c}hkz6wұ޴}h ;ҍXmoZ>޴r͝Pα ׯJkz f- A-WsY`.rO9'ҹX3#ԤO(tiYaifWs2@+O n_\w}sz2X*q6B(v% Ēq"C{3ftזN, jc-ݩzOx[O9oS ((((o *ҩkf% J ( ( ( |vOSE2( yWؙ1ܹv Ď5 մqyWpOo =~UU( u1l)$[=I[+h&F0=W-6Tk=Nͱ H:eH"@uQ#kiQܛ8`q] P+mݽ' ȤRHq ( ( (9Nl&Yqin*2{g`3jC, ;N}qqr "Vd}'rX'UjV%? _/ G+ п2>qr y/O焿_?Žp71( _/ G+ п2mKqX<%B¼ o'QB?^xK7(y/O9 {L{y/O焿_?Žp71ФǸOWMd ?^xK7(CsŒ+焿_?WMd 9ÐǸr'V0X('N?Uy/O焿_?Žp4 y.UX4 *_ MZk_D^' *+ п2<%Bs!kit,I=O`r{4X<EpfKtWf7lY4[e^*~ WFDPRQ(aEPEPEPXT{RcxKASK@4QEQEQEQLdweQ@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@cxKASK[5/O_U-lEQEQESE2ݓ(QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE/O_U-l7?TEPEPEPO|vOQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEV7?TXT{RQ@Q@Q@>?'S)?EPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPXT{RcxKASK@4QEQEQEQLdweQ@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@cxKASK[5/O_U-lEQEQESE2ݓ(QEQEQEQEQEQEU}BNQ,oE41d>O]b_uC&rd'(tU}>QN\E7) >W;N.aER((((|Eh  +b j M*ݍJ*i\i7[Kk2ʁTq*Ap*@((((((((((+_ Z٬o *ҩhf(((ݓ)Q@ (((((&Ye"C$U bxI+ ǐMu_[$iQjYL9$(E>:]C)G#Gڑʌ2 :/YKy?"]_[/NRSH%rzskm#G89!EҾ 3XM&B ݸ91;҄b")]?;X '566F/5n2/fԅc[>Jy5fm4m5uek-MF"oQb{>7fm4m5~ssO"IR ȩ<ghc3ii?%CjE,35ITu>q &}Whj̤x¶V7_Kpov8ݜ%X| Z;CQvrZYfsǹby&#KhCku;]ep#ح~Z)y {UU,]MǙKl\jΥǟiMinnJr0*SnQ`A"WσmcEv=cqgR:v2H&=%_^Kqg?ָ G0qJkVJ|} >~? >? ﹝h5a|Qa|P3} >~? >? v֏هHm8~{eW( >Ϩ$gو$ qV#Ձ;QHaEPEPEPEPEPXT{RcxKASK@4QEQEQEQLdweQ@Q@Q@Q@Q@Q@-]9izγ9ot3{D[G,>DpY2rTw7x_,ͥ]Zc5܎8|Qm5u{[U-q5v(@z65EݭܓA(a{<_gF"z5?^v>uCsT֭5_Y=l2ܠ.X6S+np ܿAQ˞=/ZhUmNTn]MсVOJs\־i[["dsc_OGQ$e R~g•Z?jif(-y ȭ^k(O5i5cZ𖍭^%{FkkmB԰<Oyn7)hsxP5[5[_ Y]\F>ռy{dnR'7"F$XhZm[KuͬvGf˔\ S{V~KXL1f,>H^ (a$rO | HuNi4-KS!Xҡ wDÓ]5? y`J{vs6%x U>*Tw jNA]Z4÷cv* 4O -1i! Q#Q鎔w۽U+ST|)$0Naduxbh|i-[4rb~+幬vЫ @`ғ RqxBOO\vR2K7m݃ yL A#Y^b J6H]X+SL3CYյx&{Qq['4o 6ulkvM:4J1 71)a>xIsK k7kUHP%m)@?2T W!pU&yNPQ@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@ endstream 36 0 obj << /Length 37 0 R /Filter /FlateDecode >> stream xY[8 ~B/I e!3@ vۅr=]r2^P[>I$Wc{{Ӂ˿}*o_͗w5-~?/ԛ膓3/Wg _Ü}n pG|?|}şҲb+ Ox.<().+9{=::^P6;q;ZvJWh͏aG`S@:T Աθ"f`Hggw,E6X,&tAWUhR!7m ǥt0ncJosUo`9J.lm,lȦG}x<  3Ad 3 mpn\_a:.=b#0Jq(LiDZ]#mâfŚ);MlE`FtR3Ƴ:_l ڕ,(C;Wɰw=ErׯX 1 va1c:@qeMobX7?pz된w*s{Tj/vˀ:%"]ByPqsNFf(l.>bpUD9Ԙ p?90:Jm7[)B7C΄ ($t 0rH fE=gNP!BJ0U%V[Xyܧ~F`E*J^ "]E*>'mR#.9j'JyܸUYj@ʯܐÜ  `5?{+sޡQ\-[hK]>q^lQ\1_O-SCݝ%~D5:pLx@o)UxBkE~wnfK|r 'O`bRpF X -mu > stream JFIFC   %# , #&')*)-0-(0%()(C   ((((((((((((((((((((((((((((((((((((((((((((((((((((" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?BAbx?2oT[z)POQ巪bE?oT[z)POQ巪bE?oT[z)POQ巪bE?oT[z)POQ巪bE?oT[z)POQ巪bE?oT[z)POQ巪bE?oT[z)POQ巪bE?oT[z)POQ巪bE?oT[z)POQ巪bE?oT[z)POQ巪bE?oT[z)POQ巪bE?oT[z)POQ巪bE?oT[z)POQ巪bE?oTWmqi+ 傜~_J?r?F\Q@>)GQEQEQ^ykW@;&y#M0P n70 `W }s$>:Ķb<4;-ؑ&#{Q=Ҋ/#iZfη鰑# wU Xpy8xRӾ xD4VyR`oh4Ǖ0cWQPM$ۼ˷|dmBk?M̷z6ldD${(mZX%'@0PEr7-aYhZ{ Y#KH2pzu$UwZ/V;lmc5`P@\Sx{ֺƯue-Y"+LH)Fee# zsO LCGվK4څ1 bſxY q4<=5g>c|mG:m,rnQހ:+Cz~qZLj[BkNAeB8<xOX5K3Y>%w9a 0zu$3Bi>$Qm-h'DfAܠo66I,H/-"G]ʜ9`HJ$sNstwk3iK}n4JrN 9\.&|/m+P'TP9cOY4%pl*AhZv=R@*X2ErOĭ:]ҵ:Z*7"E+Tr2lpM OJ5j:WJԇyGsiڗ FJ5a}5 ۶7%K0z\Ff>dމs?|3]KRs^]#,nFCUy8uvC| OtE'b5qY|FW#J*Vzm>ykOh3M]GQjXP$H6Mh=%ֱjZV,,iXOͼ.ɯnỵ緙 rE*GR0U4[[kmQo5 `(#|#_|}]ñ6k[7ˀ# gk'I񍇂j֭u}F]R5HRJ9(elӵ{Gc]Oi:-K|:g[@_gZAyonm<ͲBcГ>n. y[?!9'vCľ ÿâֶ_6y1^E Ʈiwuvgd #lINj*ԦѼ/v\XOs R02y_oyMei׮k/7G.&Iix]<=}=od:2Tr {_AmGV:rK]JgY@@TdsׁWT1t`RwC)')5Gf/!6Xb6L*99ʷA -XZ#1JXd2{gtJ9GfW+^%aJףsG8]Vه >?Wms:0:Gه uau+GfW( Vه >?P3}{_.gQZ?fW(0:@\΢~?S h/94Vه l!(wlP D 0PwjNER(kOOї5X֟9ji.hf(|?xP((]/Ρ/,ef+o Lh5/:h4f%Wj~!t OWӬXF2w=3xGO>յ#|d-Ð w.F}Cuo  #2 mz3js.agkw}i֗jiD(q=;kx)$~54;I4kL|4NN~)>Y}ǂ~5kxH(tU !:\W5<%h?Ə\Opֶf&I7)R1#C>/K=JIKq:d2Cq5k;xzxԴutF"XIH+?v[Q[[&-E]p>{{Zi?~k:kZ6 Ԡi!Qcd4z}*eiq#@*LLOd{7CS[Zq 2l994L@!XWKԢc~$hC76SF~Y<]W]B+aQp>̧sEJoC,>{oL*yvrqVkŷ #3paBevCyex;O qZߦER((go\G]DMH܌ y&wzHԓmݜaz#Ѥ%,Q_ 2f;=H;``O ʫ5 na^8WJw!^Kk L@Y[8D{ڼgG:ؿOwl~c+-n gHdGdd P9&? ԰4nonu r?v\SqKG3um8jI(boSÍu⻿ÛM:# "A6#'19}U5hzMz=٬- Ϸs<$嘞Oz3xb.m~]8F}}Mcі/scki~־dʂ5-G* ?k_SI5F[ގT6>־kk-FO.l}}Mk_SXoz2r4l_SX>eAsckk6}C8b5[ްs9{ohxޟgaM*+i${.Db׊;|ekV:/l㙬Ͷxp"0z09/z^vjǪhS]LETQEi#^2kG-S-?elES]™Ot eQ@Q@Q@a6~0慩qь۲+ꣷLQEQE?i$;D1 3J 89Plqʊآ(((((uP@ ownf9ɵЩ=H& //CZV!,4;>W3gǨ4SOIW̲J{Ӓj(QEQEQEQEQEQEQEQEQEQEQE+]o MߘӮvo "l1RI88ܻH`q7:МWƹMZtė2,` X '>XTVWvќؚVkn.k\$1fv'%}V,L a1Ⱦ+z J>ѧewEQ\Λƻhn()s@ >e88g8(o>,,BM 0Y  }<%cfk9_^YO.Vwa9Rz*DQ=5o]ܚ-/zj6%M[rɨ禭k9G"Z_տmw(\-/zj6%M[rɨ禭k9G"Z_տmw(\-/zj6%M[rɨ禭k9G"Z_տmw(\-/zj6%M[rɨ禭k9G"Z_տmw(\s–`vUwvI>hQEQEV5ZxZ˚٬kOOї4EPOt e>(QEɥYcI)<hc"9,NHe#)7n`3!xd# ;^A~3!A0QXͨaܩJܿ? _jj&4xuR0Y@28z#uKm+L/!{[b"c 8it}OMʹ'Mw#ppFAyOk,~ [N $)pVkY[y܂<֟=wQ?P<g}l_73j}O\JOɽd y2h @ 2Ht^ =jB)VQ=e }c z]V_,; ]ƫ o:@ rďx=3H J( ( ( ( (#*xe%WLy6iMS ܶO?2k~$xI收ژxW%lsnͷ'nB; .VSKG?stNj<%ԼIw~$1B`pp1sY5 xI5-\yuccxQB@3[ZCyqPлA(Qz˴d—]? ~Ξ-V%-wcnC*A=+ķv/tbIR3"$9 9+𝟈t.l5-6G{K7U-̬0 Һ(`8}?ᾛi]OWĶk}=m`Hx|FOԵ]6KKHĒ.0nFS@'h#NgYwSѤ{kA73pv Az֞5naj[Z(1/;]1/ ع͝žf3@+R((((((H[xٔh#eHϨ>XP+4V5X,lXQ`EcQEE 4V5X,lXQ`EcQEE 4V5X,lXQ`5|(aEPEPX֟9ji.kf?r?F\Q@>)GQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEV5ZxZ˚٬kOOї4EPOt e>(QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEi#^2kG-S-?elES]™Ot eQ@Q@Q@Q@Q@Q@|Fx#ԟmNB[: NW !8G HnAhq;6i9udz׷~>ҍ?wB6}EExh+W-L]ːr[81.q_b&hmXTG$l]He#9W;-'0q]=bIEW AEPEPEPEPEW/m49.--c$X2@f Ԋvo='exK)!"!*2 e<` ˗ ko|ȝHgW:O!pWд˛}*Z<#t'ty-.qrq ?/̿0$|g90q|yӴ{W(VLꨢ((((((((((?r?F\cZׅ ( |?xS)@ (((((Pwzr#hm H|,QjW PKH-#%XRbT>}5ӃtI6)>2ֵ[sUԵk._|V=80wz7=[Tu<5ms}KogqwQ)87u7ޕcu+[[YKopp@\繯ٳE\/ 5tT_JR6vHZY0a # ҟnuǝql{_2@d6T*9W kAk}5i8XR+<7/A\ü1F=+ fFh=vﱥ/r'4y2q#W?ex\7gηuok"2y\TE&!=bo&O7hd~Fto^N4Kit#U:6E&yB/)Wz|aN;s2q#G'5hݾ2]Ek3[*2_T+Sʃ B(y2q#G'5ʃ M*2 M1PF)kqo $+Z+ϛj? \lX(>cn> ާ*PYMz%eqkkRxEy 6Aނ%:|ѸЊ焴^T^7ֱYKvddAL)=FGDdFͫ+ߥޛ>eKΣL/ l5lE +6dfX~EMg&bp&_h#|m u^D.<]%K}=Ͷ2&E1 ǁWUy6.Y1rOF먪Gr.⸴'C,gr: Ry2q#\7aFO+Z]wk5WG$dH b K+8. 3[OXdAD6Lo_~TyPq?*溥h- ,}h37.vc>տ dѿ:/S-X4+q$dF2pAv6E?[Wciuoϲymݹ+-ψ[7mJgV{an$xby t9>h^k:G۝H1 ;d|sַ2E$79HR y1_|Hд}J{;i׺if0fX~eh\Hpv?铴/<]r?rW`g<~f&7zƭQݻ_]]_{…τ? ;=q9'qfr331\ɼ<5kMo}}j[utܰ@$Y/;}2.X[cԼi F'G5gSO؉m&kyau;x.q_:xđ عծpP;Kk=aY GZ.%_:妳 ^v4Q<cEa j:*i󋫋q`<ݝƜ}xY5[sFME(<1BrئmAό&|O/kwN,r2($cLuxW4k$ o.t#JBFQ'QRtmqj(~䃚'}]wkZG"O-.mQo0Lom8*l>'"?~~#ew7Kuf38T%I Fp\׹}^e, փ6IHi!̛/~co4ojbliRnIO7|߈7+To5c\"sһvT-^[ eޢ* ( ( ( ( ( ƴT Os[5i#^26h)L?2((((((5ng>4gYϴ_[*gYϴ_V GuE|պ(uE|g>5n xmƉF*Z(EV{ WbocԕgYϴ_[*gYϴ_V GuE|պ(uE|g>5ng>4gYϴ_[*>E@j`tQ@Q@Q@Q@Q@Q@Q@cZׅƴT Os@4QEGSeVhcrY{FG#ڀEccǫ߻_3G= z4Eccǫ߻_3G= z4Eccǫ߻_3G= z4Eccǫ߻_3G= z4Eccǫ߻_3G= z4Eccǫ߻_3G= z4Eccǫ߻_3G= z4Eccǫ߻_3G= z4Eccǫ߻_3G= z4Eccǫ߻_3G= z4Eccǫ߻_3G= z4Eccǫ߻_3G= z4Eccǫ߻_3G= z4Eccǫ߻_3G= z4Eccǫ߻_3G= z4Eccǫ߻_3G= z4Eccǫ߻_3G= z4Eccǫ߻_3G= z4Eccǫ߻_3G= z4Eccǫ߻_3G= z4Eccǫ߻_3G= z4Eccǫ߻_3G= z4Eccǫ߻_3G= z4Eccǫ߻_3G= z4Eccǫ߻_3G= z4Eccǫ߻_3G= z4X֟9ji.hǾVvfcysw5kڨ\"7\Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@ endstream 38 0 obj << /Type /XObject /Subtype /Image /Width 968 /Height 162 /BitsPerComponent 8 /ColorSpace /DeviceRGB /Filter /DCTDecode /Length 17539 >> stream JFIFC   %# , #&')*)-0-(0%()(C   (((((((((((((((((((((((((((((((((((((((((((((((((((" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?B(PQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQESwgɦEz'=?L~G(ؿ?#(z'=?L~G(ؿ?#(z'=?L~G(ؿ?#(z'=?L~G(ؿ?#(z'=?L~G(ؿ?#(z'=?L~G(ؿ?#(z'=?L*\$q$P{n uaԊ~G+ia*z'=?L~G(ؿ?#(z'=?L~G(ؿ?#(z'=?L~G(ؿ?#(z'=?L~G(ؿ?#(z'«j7vu\LDA>HF,@URI%j7xZFJ =?FQ@ؿ?#l_蟑 e=?FQ@ؿ?#l_蟑 e=?FQ@ؿ?#l_蟑 e=?FQ@ؿ?#l_蟑 e=?FQ@ؿ?#l_蟑 e=?FQ@ؿ?#l_蟑 e=?FQ@ؿ?#l_蟑 e=?FQ@ؿ?#l_蟑 e=?Um:Ѯn" ʟ$o#f *$`5d<-?#cQPbDS(_蟑 6/O2~bDS(_蟑 6/O2~bDS(_蟑 6/O2~bDS(_蟑 6/O2~bDS(_蟑 6/O2~bDS(_蟑 6/O2~bDS(_蟑 6/O2~bDS(_蟑 6/O2~bDS(_蟑 6/O2~𪗷qZOew16#wl!HWßK=lESE2ݓ(ݵ^ctE\ RO\f PtW5m,'YZYK8GeiF@)}Ut/]3DwHꋐcpHiaYS7_3Yk@1z"z7a=:jOv+::+m>[I7\jcr9#8iO\=ܰipaǚK$d([:r[tV X3#\`ǒH'1[H-[gUGb 8<&OTUY>&OTTEPEPEPEz}VUI<͛pbqo]8svkXv.}}Z [bF@<>nӣP\c|7n?^}W5 Qqc"% xϩjWz)[˰xmuD\g*røwy^ɕޢ}FX--K.;颒%u?0sC\F $O ֒ R6 e瓑MٰngSEEj'X]&OTUY>&OTTEPEPEPEPTy1Ms3% g$z:񫕗$Y_ΐ #8[k;BkJI9Yw-26k(̫p@s1>U֑YLjq^?b_]Ii(h@ `<׍i+;L#K"d$~իsMuM=ՎВ)˨ص c6֐JTXQifmLH~ |ՏHg/XIkm*s0gTZQv5i$jɓ=5R\[*Ce\eϰ$`kOF6f!FBGZWj2Cj̛l')3ǩ zSTiYF: knYhlO8FX>m1*#Wq gA%=I:#g $esHW$ s:3=WdXkmr|QNw&1L Y&Y-$ZO(S)dHU!9ⲮR8ID\FPyq+ l{Y6 v[=%pqϾ*PW:4hE2 qp=xON>mc6Lv&X}#=k0=d:i!"~'>i\J)T_f88:qo\;3^\+yŲeITĜwױy<`-dwW+:]ڽk:ɀAݞyatm\)+,F3~*kR#⢴-QEdQEQEQEQEQEWßK=l6!_,EPO|vOT^!MLd:=A*z)Ӻv^A{7$I20uOİq$ arz-4nF!QB6B0 kU/gȾz m~D~Lf ^!_cPռ7 h:5KyDK`qb&YN[EtUGR6yjs|IM6nORM[֗kypXK TclQD$۾*ӓnfd5Ry̻%%nr򻴛 *KNA'9tSWx6pO ܢ]4dV? úQN j>s8;d9浨K7Zm%}H|-KhJݪ,wi6T$NsӞ5,m"bL̕nNyf$OELlT'p+2((( Ǎl*֬Ǎl*֠(n-5w,>Ty8!3y**7t4d hiL9}1R KKyl;[&2qҢM>vd6 fϿX ̆7*rNF2ryNNKٮ,/V>*I Ñ~E?o?)WđNI9#isҢǒ5Eǹv劕#9? آ4.vd 2\-ɹ`9`zԮ.͊8c9U)J96QEfHQEVO6?UkVO6?UkQEQEQEU]B+e.oHk#t?BGV8mxJn<Ț&qp9Iow6K}{pm1FT yZ+Om>sp.m`O&+i|VFiwS%h1=z}\I;ܕ&Sn]\fVIS1< sKyv/#J:FcoÎlOV40,o4Ln< Db7"d Wj̼dzJԢ$I^33FБU#Рx.'7H#J?)bp vE5VqVLVFYAq{&OTTKT<-G ZgXTBz+ вMk[^?z٠CoYO&4m )ܿf(  вMh/S uP9 e?ѷ_,r,r|%B7/oYO&5@X6Kn_3F вMkm )ܿfe?_Ec/S |%B7/!_,r6Kn_3]}CoYO&5|?,1ȾBȡ}:4l*>dV>_?_(?E΁@ "ihϪN$HydND84atm?U) &wt(?FthUn43Itvm* n.Z,vq(КնnkY˕[Όm˦̣z8:|9_Q@>?'S)?^'v7u8 _Sb1Z5+raǹQ@3N|0|](}d dC g-|3;>xjo`xWKDw98ye7zc&z.7H2j #4%KIRnqұEg ֻGѵ{7$(w~dFͧ{p`Nsv-8w 9΍w1?jn< q5zeqorOlizG=~U =rm?C״!ŎiXO%Ѭᑇy ͟"?CKN;`i X|̅p :׸RL \'zb^nl^-[H!$$6pWGt CfdevILw4I+C{cqNǐsq׸W+2;=V[ֵyl}/FHY`sm,qZ#I]M+8n|ĺ>پ%$Ck r6m8EۃsD5Q&CլXԄpr pbsE,"@$`ޔQ@Š(((( Ǎl*֬Ǎl*֠:e񯁵R&`=ͥfr͍8-5mC^u]M{+{/^tq)Ђ<=zUx;G檗=IPppXF; 3T𦓪ZX%%f(^;) i>vwsLV'^#sj֖Fg|&Tzd y^2>8ռemjZKZۼ;9>֕߄;I{̆Ky#r:p[$5{D,tM=,q>7ff9ffbK1'$I,yT26̈8G)V=dϫqJ񮤐ͫR8Qg8~Lǣ&U|&/;(T$u9Iɪ'--BXx.oeӮ.~ٖ [n*|H*j< oQ7J !.(!U$ \HM@%_C4>k어6! p=oSRŐhٶwh1Z_fP3#$ i7 C,2ťqE72豐P  o .[/Gt9g$Yr)'8qM C]'Z{;_C8aicq/;BrmB$Ϯ#cAPƋms+)ywv|@Rn}:SN-^l"X " }x7Bׯ ֧dNшdh%͌g FEZOT4Z~&=V! Pܼc@ni|M6ҨN(Qc*+3ia*k[5WßK=l0((((((((2/H"xJ{Xa $k;E7ȢҟY H-mі09v.\{o:ZjV׶AhnbYUVzyil +ImQ⌀@*`w4sÚ3kLj95h5V ٝqyK{Z4KOh&ha;d C+dmlcfOhioCm7m8}M2:-]_)n'#'e5yt.P浺#9wc"4NN:e%YN eє^N1x㮾Ҵ?68 iWF8lm--"!8a@(P8ojx[hG"<^p<<`@Qs3~=fs^,td{ql\ȭ(r빔h FKq^7~Ч̒K. ;9,ĮI'$[Vmw s̆9"C#*A-g=e}Hi,{yv#CrȭǍl*(@pY^&OTT1%ea|9_ekM641I"z!E'ba2gԏZoP1S?TyR7S?TyR7S?TyR7S?TyR7S?TyR7S?TyR7S?TyR7S?TyR7~uʓyD!G|e-u?>$b-s_H\nʞ2+GŚ-ƿ%{29'Ȁ4rH;1u%4鍧k =r .c^+ 緶"u _my5g4vpK,407H噰8XpѼI6xK{X[o$FHq>o$t].i3̫uj%au,0J9/sx;C&I5YlB ]M m$dF 1G1iQDDP@SlJ' KBi^-SV4?R_F=lZo={~O>m[ZϚ8mM|c vP1L=~Z1B;b !$H9>öbjz{S:7"=:N0k "嵬,!&;N3C? #ah-1Goy5 $D )8Oo6 m2;\ڴ2!WRKoWb@ϰø]=jzީ>mܲ-g3&B'! 3=:wmڶj] IcԒOzg즹.9-'9O3hH*G2ׁ ;Giji }Kzͨ\Nof$r[ɥkynSw"halqr'o*fψMCpJSX,; #%0$9zn+ӭo/2K)nwM?,0r9thAu#E;`廹~:{W}NR :ುS<2<'hϠ:7ZZIga!n,b%޻=F$i Qq%Ôn?(8Cx3@LEdtH+uX`)-|'c`}[Ű}:e;+%-`rx|9_ck@ZQ@Ÿݓ)e۴ڍ彤MWUKu$'ƀ'* h2? +{IƏJ=A'#٢* h2? +{IƏJ=A'#٢* h2? +{IƏJ=A'#٢* h2? +{IƏJ=A'#٢* h2? +{IƏJ=A'#٢* h2? +{IƏJ=A'#٢* h2?<-?#cQVsz"&?. 3.T{g{տJ=A'#٢* h2? +{IƏJ=A'#٢* h2? +{IƏJ=A'#٢* h2? +{IƏJ=A'#٢* h2? +{IƏJ=A'#٬Ǎl*g%^Q5 pwm9{ݎt^S|PPTIӼ?u W=dG%^nyGd%^x{OG4=͓z?Xx{OG4Ui?'Ώ6OaUi? W=d@l:> stream xZ۪6}?pυҖmY08yz>fV}(tGǒm}|L9n!GO?oֿzox:a쮿w\|݇]~;|ۼ9 : }f2u?~ۂ;ۊ9ٜh9\WFHt|U5xNw1|vK]Lz89'B[dҰ65Vv 8Oݔh_2h5ْFķVbn 0&KFGt$9jg'JEoP3kE0:udCyY gJbXŮPЗT 9et5hB";+& N2~2>BkYM9bbm|-xx۾Z(IcxQDjX+_l bgb͛*71?CًK#igϳ1:2AUYX.P.Y˫u c„\vV17YNl< ƈyJ]F5$ii /puzb =CHO[)$X21=2}.ꛚ!yOޮl]^# 5qcMSlm P 꺀Q| IzK ÌCX@XE'z)2-?]>b9<:r֙?[GGί<ZȔ.r 2:pL[(g@m2Fr{^d VpI\ǍK-+}"QWXTm ̭D&4:2娞Ti|r@&G g ?U ښ* }(H^ ;/~Ozw~kGѲ60\0zhhLWf8[Sxڻ`@V`6r:5^Ugf9 { }gm[Ș#qrke{:S@kJN,bGm.Խ3E+âL(v"!p'?M \s8hf7$&?~2xx QsbNsӕG\%9OT5-4fRUQ?lj $̶60Ѝ%f iɛn 7hM7̷g(SKSK"?꒹E9aaEY_uP>*L#UP-/(d\惜yi{jmEQWljMBvHR{T?T_?7s %_)%endstream endobj 41 0 obj 1639 endobj 42 0 obj << /Length 43 0 R /Filter /FlateDecode >> stream xYۊ#7}7^hMB$̾]VI6CvvF#rTf`g:{?.߿a`>_ߎv`0/W0.|g{ѼyTe9:؋ܨM\11/=F6s= x xpSZ>wNltIcY\HUvA8axG`h^-Lqid+C">F2)nJ8#x1>4̫iş2fp] Fq~7kStnQE-ǟJE)xGۉ! D:?D$IR{WsseqE# >|πuBjvq%$ѶQd\ADYrr 6-.rKΐ(l%vVE'(R$]Rlʞj>O\QH}9o._p:4xfxiшӱP[A,-뚯P+X ws0e">8);]v8P%HKS-v*^-r݉PUᢊAfEJ/R]4fV0pCeB `C\yd#+muGCkgB'cf%W(8CizU! vRK1(KbkDL#\m`F˝#á AIfӰd}89:qr2d9ogGaqg+2Ïⴗ5tz5*sQJ3⚯sٷjNPi Sr‾4U|DHyE)fkcPzi]ВwEd">7 jU`+2e3A{]?fF*$ 9!뺶ldEqG,k[0:3j9Ke:?rg,۱)4gDdxʉmÌq;+_zFtkMOP }*n23&"4a5O

    7s}%>_v kf,qnendstream endobj 43 0 obj 1419 endobj 44 0 obj << /Type /XObject /Subtype /Image /Width 588 /Height 628 /BitsPerComponent 8 /ColorSpace /DeviceRGB /Filter /DCTDecode /Length 37109 >> stream JFIFC   %# , #&')*)-0-(0%()(C   (((((((((((((((((((((((((((((((((((((((((((((((((((tL" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?B(PQEQU ]:KF KH{8',@?t|> M #MݓgU]F;: Is{yH \81QH(pF#l})h((UR?JJ)YJ}i(((+“AzJ( ( ( >R`9qI@Q@Q@S~T( ( ( ((@QEQEQEQEQEQEQEQEQEQEQEQE7ZZ$#YpdbzIJ^bkt5,7@I ҔT|mK7;<8ӢwK b1gT7P(|-7n"aZ\FrJ̤k7kKd-sn,a$Jy$mX'BEE1wޯ׫gn|-VKƹ=4r`7e[2 I?xdޘamCynHVCnq'nO IⷸK;׍3!,cCM1ڡd|]yq4zp *+ȥ*D$onqf3Xx|>ki((MvQTۧSG>cz'(?RiVqVvcH8`vGEPIŒo^ j}ZK)(xpcEz2K]RaI[80jOxAނ%Bx#}+Zx3,SO_8e/񟅭5XI`%NJ /1w쭯XhgZix7"(gnqھ1?~W`Th=B)oD:FLF?ZO/ Fk̶-4?~֯ea"FF8T$X񗍼y/\u>"0@b78$״~Sʶ~YdI%Ӽae$t$lۏ?|W?Ɨ.|#OSW7d{J]tvG^NS佑\<=}=od:2Tr }i/l9f,LCǚ@ )ݵ|*>?Ot+z 'X_tGD)]tUV HC QTA]qT8(wWwQ&&9F}71;%&8'j=> ON7qIYCc ifIe_7.)ՙnY26v8]Gè_~tWö>q6m$JYĤI|et0ytoԍ_1y?f]i<)U$;Sm4e6@jȪ1 `nK/оcz'+~ V^Msv}L,')$ CIž9ccTz N]6ֺoDcz')eŦfzeŽݫlL8 ™%qȌrs+U/މ| S@+|`1iޭ;n]k[de3 Ƽe]0-i[h|Ko;UQ@P`8}#>qv6\I<'ŵ!B4qTU^]wIW]Tմgn򇶴fᕹcL]QV ǥyo[2j"dt :e\[X!$/W@@G.vԊOk#~Jj] m.GO#嘞gڡeY{%OiۙYi'mWȟ<q/_)d.F愀LG@%[]i? b+y`9 rE"WR0U8 ף2 t:Ec;:Z_x[7VA%E>U2`q\f>7SPG=ԭ3G r{E2H ᯂ{K; ]1$TdPYv:,lbdCn,T{aGr$,)gQqNzugLI @-YYO:{&^> :>Э-dzO7TށDz Ɲ y*82 G|F#̷rxʳ1%'p@t+2? iɦ]_ܘ)|r+?]ӼQ#J`R!5mkX<->JK%UucS,Z¤. c|k5inψtNWR^]%t7oҰVڸ= "/ïju]iwˆ9bB(Dp0&^)kj| ;_ [#mx;.HTrY<ddLn8'8asS9,cH;2'Q}[zl׭iqv*$pGw*}ӕS .ҵmSR;pbw9aڻVQS xK7uY'M$bY:}Ս~mO+Jd晤6I7tt=ޑG'ee.!"F2pr F4M;LFG+U.mn<_tMW& gm,yC!Qu!d +mFieCuÌ_`^4玃km{]kӡ*|F|MoPYF(2n嶇 4233$(?@"οx)}՞3u4SZYY"sh2(s8=_u_ BZoQnv&wPٔX!_ks>4~==*K%s4.g)l4` FmB/yiZv]}XQ%Ǥ|4t;MBmc\y]Q.)@ ) 8W;~&\'ef?&#ॗ&Wc Y?iA%AQC2>F,9$_񋕰ԥܱ+-u:YΝlOxZOm똫uEPEPEPEPEPEPEPEP7MX 7A?ZQE>SL7`-,-k#su?Ҁ$lԴXx2?ι3k:^?}w8^{ !h+ zyyӰL=ԟ^Чvz? ez<? ez|\?)k:ͧ{PRyz #$syysFF Hbo'_G_G(!]SvYP_*H:`dg*OI?S[V?GG?GUF$ן)=սc/#c/#Õ]cӼ3*4"$'dq}Etӎ$*sׁO7_~7_~ƒFq$-/^ a7r%>Sq[^n@2=]|`F_G;0z]leniwg?4̇t OG=V}M2Xa ?#iI"O?c |D-ER,?Hqkm)uHȡD3G$૏xcANmْV渿scuc |G?h?/#sdxF=Ow[mbR 3eU8+l:f躌mO7_~2kMCM//l$l&xhTTʬU{<Pxo kWAc/#c/#RhM&sС5Hy}{=|o?]?GG?GG3T`.𞽸,mq1Uw67ЍBTah U^{֏?GG?GII#ZIKsg$ڬ=6)6 Fx8##9? ez<? ezIg-js]az[w^=XOS9V fMm6Zޣ m|5ܹ.e6Uq _G_G'宽-6־ ᷅qڪ `T{#ջc/#c/#Õo~&R`d%ʖfHu@q]dyք#Rc [YaBN,\ŷ4HCRӮ6eX۸*w8=h1)Zǟ菎 OR5s&oRhI-7Uj-F;c[‘ں>_GzR1eѿ:/*[ P/m4RRcUpWsm'h$]/?h?/#ӒUF Ft#PS[MR}5x|4yuMPVAZQiXԭ/TK BéWH>t_Gi5v~MJi3k'|aii76s /mt˨-sGn CZ̎SܿoYYʮrBqSҽ:t_Kg\n đx_Xφ+M'NѶLgvf,Y)|IZzu͆msy--,J ȫx$]vu0Cki(?ThiVPF x|4y%VO?GG?G@\֢|? ez<? ezc/#c/#57_~7_~Edyj+'_G_G.kQY>n@2=n@2=sZu1u1 WxAֶk'HxSE%IlQ"y+Z ( |v?SM2(((((((((((((((((((((((((((((((((( oțׄ-kf"n^赭()}O4( (o'[[YpJĥN);!JJ*욊jw%[~bG^kϲj %!z]+FK=կx;:+׼^ٴB%g ,6j/[/ŤL-(dcbe9:?ps\ݎڊlnF*}E:އQE((((6V,{ymn+ T,nb2yr}4jV: 6{my  Ry~un ( ( ( ( ( ( ( ( * ۻkgSLcweQ@w5|,lƩҏe5ͶAtZ)Q/#Qk2GX9k*3s = pc˾7BBZyV1Bs})  GW!V-\]Զ^nc'C`Mz1xLa/ԗ--N9-T=j-Jug,* Wo *ǠI?ZԵ[R9+'V+xK*sUaR]_ڮ'QS!bR0QT)8 :ytv;+NGR6xQspQpAEg*i$\#3q׀zW =D-=L?㣈**Ş# kZ4'1j9?f^_R*q]Р ((( #iE,@q+ƏiwxyeK{ sUdV ų ~~t> MXGzd+uQ"G%|B4F]wzGik$'GːNA5imy嬚u畇U 8O=(ݰ,QLntY5έϧZVF݄Wg)-M7]|UoCGaF$E05kӏn[x3, s] <em> iWwE-((**F8,xvӴN>.%=`zS{—Z+kBWwӚHt/i?|E MEvmPVcݰ&{pmMdmxGִ.--dKu+ZXkԁaJs ?,gt8괟 ]ݲLʇ|6;'"v!3ڱqh-I];_ ^!՛ضvӌ+r)뵁l \ιҜ-l˞9OMhQ\5+)Wݪ{_4WӜ@S] QEQEQEQEQEQEQEQEQEQEcx+D k[5tElEPO4|v?W;㋳m9Ye [ G|~W C2Lb#qqɣ+$(sM&!eE'P+6p9!.v;N>^] xYA5nΏq~;R>d֮UK Zo;Œ^}oohT'Pմ/u] RXˤExs2eQۊIa_;Bks=-[⎌'$o&{ ;/7`2B pAl}Aq~Ix ((usֽ"ࣉA i#4xCRHN .kJHzE{lP.` BZ1b3دc}W~wa] jiip%Dq=Nvn<ס;m Xx|E?o\3vG q ddH&z=Gyε ];Z6<7gGN .+LBXyN5mS1Jr>آqאX"YP8V+O ( (0> x ĤpFs :Zaodx4˓\,]Xi"%XAd4ϙ7(8c<ǽjhך,HNGִclW.N-gXti`;_v?~y⥆ŲzrBkCaRJW:\(!ԒtDL<+wgQ7X[6RT,`|?t2zh,"D*"Ffr`eII&QG5vvzwDm3:qxdۢ8DZσ24 ߌ uiwl|joRיV<ҟ<wQEdXQEQEQEQE2Zկ{w 0{T2zTS?xȝe ʇ#c`ֺ 8TXs'ltkӼ^ˀϏƸx[;`x=*ao % ӌXJe6Zg/+[9r\{TZLT3|ؑ{`01¼?ڐcNJ]Y d\ =>jΣN_xRúAw2nAG~S@ jP[T-OLV58MUg֞&N7Gz0KnoCFֽkCT܅v׿t?MӴSO:YZ/ۺr{XDwV8Iϊ8Ҫnv>G5T4خ#OJ<5⹴9#A\[iP5yZwEjeO#Kg\'8Fq[1󮚴VeqG>Gianc|c89WJnl.Z7 3ʞ5?$c JW>r֔>rקALȑ%,QU!s+>T9^:tt),"HiFNR͏|^_:<|0yd_C3SPf`8 CĚ|W]f$ vpJpGLԲ D9/\g-n="tˣ!-,ʥ[8;p3]*UpuՓgVxj+a ?oe1W_Ge5`= ¾PsTi]u9ej-U/[&j1fČq0e..Ԭ+\R%Z[V5O2Ozlu;;P S9\L9kK>CpIaŴ\x@:|h +"OG[R(dMᑲEːOsմt .+G/fS4hn2gp0ָ_^ZFy0{|?| ƺC#e S1ǫUg`4Wo X5OLƣ @\g= |e_si7iխ)Uv pzs((((>CLJ$C S*;SEš3emm#v4MuI OJY)pw<\%Z`|\ ;~# \.x@s_* Km$J=r}Q% 8s[0kVUIk {[g}CL9_W|$,hẕ>X.7 5 })|Zel~LElN8,[[jt{VO3S4R-!A}ץY2kjJO塇rVjv]P--gcyv'PGWğ2|MacqďWM#XKd\5n2u ̽ϫl kUE^k:xKX"b TS~brۺsQEQEQEQEQEQEQEQEQEcx+D k[5tElEPO4|v?QEHֹcm>n2D@q_~pJ$Lx :BˢG ˴g?(8'w-͖Ʋz[s^=jzQSiACG4Pw ct pFӎ^īY̠ 0:ׯ>)Sme[.TRfBx(;H P~^ygB&]Ѫ) Byt;؏*7VQ2I䞵x6&;M"V$MU @P>*tVϟ_*= 7seٿ p9  ͸5q CYAU>^iPȾS0i-u1g*ÏUF5(1zbFI³WJJo%sFcH~*eEtx7N8 zi|?{+ Z"h-;qN:`/;]bUHOr#qH}٦YDB7R@_1fRIR`po%-1[[k1(DE `=1RQExxQEQEM)5L4Qj(A"$Q-"xvxMn?v>:" z^E;_6HDzwzT¥PV 5BHn#uaR?t׶w}korrhÀ}+>vgiRj:,˼=:0E"_}x3:>çkq#c.X?EE*LG4*s,{}yW!$'du {NGxL"g{SLM{ំ5ye:[) M:^S?U5jKyxs_耥2wjmP>|:ɮT ިrGF\xg$Z 0KpfEicok(ZD&7ʌ_jwo\R5OOnOܭZq 0wt/מڀϚD& -܏xs4`Xß-2a$NzwoQ08vIxEYQ|"Оz/ ͼ/Kݶ5TtQݘQԞ³{5s?ko j0KUK1@$^s{fKSqxqA*9$0P4QEQEQEQEQEQEQEQEQEcx+D k[5tElEPO4|v?QESԵ; *8dliD5ypXh Q[<-̪EwU 1r=jj+kOXsat~g(p~]Ƿ֊֍yП=7fDƢ咺>5. -kza >llOMywk2/,ċ# 1#%wt*K/ma+iO+ZkšViw<2/|GA@_iַu%i;&ǏwG9@jw~>дnMa10fc 0]õCx]m+Zԍ۸lD~L3Y*-MC0&۶{>7Ƨ䲖9|ﴘ㻙 2ݼFNyO4pJױk4-ze>7BdD&fYgsk.?&׵~mBqƊ9OA׋A!n)o#}"[`.PԱ,TֲIPfz U-[ż%2}ۇuZ<;_^]YJ&!7sC fDG xGEE mu-HVhK3C@}OYK]Mk,rH 5~ KHv 4槠QEV? :{x.x9UkbuY v.-Mk[`2%̒ɔ`w b.%4}G%āKR_p#$gHx"6&t c}w)=aؑީOڮa{40sngVwo;>diЙ^h^ CZHۑ.YUO  Ciyh @1T  Xu].M{Fc>YAJX޽5/s^8 >d׵Z}0\y׌`.&7Cx!ۻ im[X"R"[;n>)codVgnc0"_.2ڸT tZW꺽;V&ӯ|e]9V ^\ȼor ռ[5vM m-W3%G9=>477k%G/#g'qr@9[USҬ/n S-źHKGBmjxo~xkW6.pR눮S_mo)#0v 8tO Xx*×J.m~mnKdyX˖b}ڏ08 ķ'u]0cIfِNyFx(s[/<7-U4#jrY-rP\:F$f#IM27{N,V]kcwoy8 s. F -CZ}7:u} ʶq\nrNtv'֭u BvU; XdhwcI'N܂Jl鑻MF&=ͦs-.{;ݴLU%a vN i:rlƴh\mGMnLc8VQ=ƝZLw-fcCnF(N9W'ZЇO|EY}&H/!Hʭo :^2hXP/^+= [m^LVv_vrhiɯhSԛ .K2&H ')O-~p\q9aob4? Wg< sj)O)}EPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP7MX 7A?ZQE>SLcweQ@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@ 7A?Zcx+D k[4QESM2'ݏhQEQEQEQEQEQEQEQEQEQEQEQER;*)g`I'S!)0u( ((((((((*彔FK%?1u4в唸Km⶧N.$$I湍WYD`Gz|aiZI>H%FcG V+=Oź<$<&bLSE\<kDÞ-KMr7o38rR\w@QEbPQEQEQEQEQEQEQEQEQEtEl7M@Q@>O)}EPLT6V $.zR~n =ҵ-e&Ri/-!a9Uh4nDwZ[uЏj6PXd`N=+XUiS kBE9c)\lU a;M*ìZ!+9&"IX}b_j̮T8Oֳr/lFl--R<4WqA+&ua$*:0>J#5O}QEAEPEPEPEPE#0PK5a,6}Ic4قf (Mc\kZJnG =ϵZB ]0{֮+{HD6$1S ݿ5mڃ#Wt ~ᑶ@?yf)(|f*sҜ[l1 jZi %?4g޵+e7uue,9ykĦ^3iE=Ӕ-V:(QEQEQEQEQEQTgԢF)ic?@ֺCm]ֱޯ@+kr{uoּkrMz9f\ɎS$t潲MRIC OՔz -w&_PlOr]X2 GHa%>Ưׁ~̎lg͹HHz g=+k; {Kct1*F#"mø2Ϡú1K5}z`6O5hnt  Hb VAҌ4)+Ͽg ͤj94i<Ď]H$OݯV_٫ߪgY4wAET ((((((((WxAֶk_&?Z٠('ݏi>S@ (1NʕQMkCkcl7('X mt3?СJ^=sӊ>zi/S6㩪*n#V$ao]]v =IBE7Q c:JuMb .maN?=ķ%,)WtWaҵxi7~mtk-8{[6e෰=+lZjVαUq];3Q^=zקJ9bsɻݗCn5+W0]6H{dC@kAg CʍPc*5ޝL钘gȦKXT }[S;K#[,)LEGdU1u{{*Q"Q-4:&}@UfRXsxB"3RWG~<>-{PX gWЕ"MDkRw4 m)W?1ʌ R'`rQG{$סjE'#]s-0_Z#v8 vU44r}=<{rG!2k>= ο.X>;Ig :DXrۍ4gc>4)V\]LΜ GerlTa{~KHuȬ+pfTq6ъQ_"kFGb? J$𺽼xOb=;SEBMRIB s+H|w8IO>s7( @ZΨ`MPk[m~Kcc"n`]v٘mum5p,?~U FJ z}$ ٳy4NMt6Z!TOvs\f# ,OGZ? ‘JN/o#a}kză?)oX^2?s~-IVp$BDQ-fg:_XԼI$+wAgv^wqzJ>ΛgC袊((((*q}b4{?4g㿵eG6S*j@bcRAeei*f)TvdrjI\$@hR_YTJ:/'?Rx(ﴩTJr7pk[E+Z%σCl4Zx#UM]5|5乹aӎ+ɼ_+lxz ae(M*q? |mq #YXqt*3 qx[2zSWL$Vر\_ 5`GY$H/Ik^ou>-4N4[xa$pxx}tܲxJ?YO`N^X=v<g8U|m+{looq)awҽڼGZw ((((((((( oțׄ-kf"n^赭()}O4(E|7 CjSf/|{x ~%0VXy dyx__俎 Rqێ3/_U^o &M1̫Qӗ2&J韅a;Ftt~|je'e_܏Cvt]z9b ;Cnp}ju?yuUZzVt}dGWëǹ2A5.-VQF+JS#"@=++LlD q\ ÍvKCNwvNz=\g^-i>kKS X9%swbu?#ZxMf!7/^O=}+^03$u eck utXK,Պnz|#kMݧZ4kʏnP|'9ԂJWz1Zm^xz]kZ&D2 86*@9= {~TL7ڴH }@~UK _:A/%z LuO5a~T9װ1F} ;ZWDqֳ,6*׆R(13ڼ~>{?IC`뭥(\Җ Kw^>h@T^0 ݾja3kWyFl\g?0qAVvs}MM]\Pe? 'tgx#HPkfѳ)8qgڽ]'IJDSwِJ譾7.Dq|ŵjbtVe m:-;Wz*'VSݍ$(QEQEQEQEQE i>.fa%vцp}FMoQM6@d{Ú?->ˡPn-%'={ ֢op (Q@Q@Q@Q@Q@Q@Q@珼%iO{4dCqxdd^=5 5;U& {ytR̻C_BQW '>\B8T [*n]ڂG8`.bR]A*:+x*/_Qr#|2پg4\ v1FXn`BN8}h^[]M$#Y@7Vzַ*Mԗ3)+QPEPEPEPEPEPEPEPEPEP7MX 7A?ZQE>SLcwea_+[H!rdz$ ܮG0Ykl짿.-4TYII#%״Zua5mDLwIYIiŚ֖xYNʯye}mHd.H xɬ^*t]%ld̔U"Dp曯xw}id`$W|[Fk2,BPrqdOs^neVx.H'IzP=ҡ1E$5v GҪ\|5;)te|Mm 7Q(GtʱʀߗEG{mqm4t()|T ur/x~]&mV-sJ}2 -a H9moBoZ{]GiȬ渚EڀpȪxvƺƙ}$`s*>m +o Fg'K8w. g^8Z^ervƟ)8.(9W-F-mF. {D]1Q9]_6zLjS{:k/(/5W 1XB>tHLٮ,jʮ7lRKF1 Iw4]97O=@eWrx6Zviai֯lK4!D'' \x[M-SIna„_7q c]*(Š((kyB>sx ]. 2X"9 ֥o`;/j7Z__*cc mI.#vOj7V:aˎT6h;-ěy|ѡКEqi٣ $lGp#c[^$յ"ċ[Zirq$<'.Bq9Lwyzf5$=ޛPFVA01TWO.e]jw1΍y},r&x!a`y{Q·څ֭-P4y?$sBPnu{[kkhb0e@DEPXNpz[iI#+SdjJEq_u-U^mYny6v<W6hz65qcd/5#C_v E y" E%VR)u)5*jdtK! #5wÞu{'6vڀuKu)fSWxM3SԮ E{H@bΠ9ڻ0qx[-t3V{5($`BZGPdpq?4)Ե{m |5: (7ʕUH SLcweQ@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@ 7A?Zcx+D k[4QESM2'ݏhQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEcx+D k[5tElEPO4|v?QEQEQXW~)Ey$ảA֖ꖂQ$D#> EP ((((((((((((((((((((((((((((((_&?Z٬oțׄ-kf ( |v?SM2(k{y;:Pxj4F0.R:0Cji<&K8\}9]oķ_ iC]lTy*MUC5NNOq 5Q imNSvڕ.$=+F9mk^(?+ aьZiN}#]Eigo;OnbRzEZD,a;|.'/xQ=5Qjv<;^MM;z+BXxǟKCcKSv?:uğtҠydmB B~-EF>ͯѲJJnsť ~ >Qi5Mf5eLyDiqszVғ0JETQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEtEl7M@Q@>O)}EP73 2X xcZr yBsA+ckqKuErzxv|Y"#!o#e#麺?狴o GQSVX# ҽ a,MNsR{~᫯kkhV]G:2Y9VA?+4DR&l/!zg /LHYFp:;j/`[pm|v ;NUl*+o`P^%{Rr$DAsƓVQE((((((((((((((((((((((((((WxAֶk_&?Z٠('ݏi>S@ (.'ŽjS-Ẕ̌\)\6>4UFN:Ke<=[żϚI9lp8+M)QE>1zZPfw;@~cOxRmZ+-j7i'$ O?x=WU-]5'J;sqW^y'4G+`$~CB䜕澬 D4{(,c$q.,}kFQEŠ(((((((((((((((((((((((((( oțׄ-kf"n^赭()}O4( +g-?o,PrEI i@2ZYH(vZvlMLѴ CӬ?h6Zu%ż,lnB7bg9M;+}o5Hƕ,[?1y*9 ԂkEqaM>EeLEibDHJQsCV[xwLw Ed/g󀸞E`1 ]u^édq,7kc*E) nR3OEfms=[=V> (^ /r0Xv~+V׵RUKxĊr w@#{7 )(EPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP7MX 7A?ZQE>SLcweQ@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@ 7A?Zcx+D k[4QESM2'ݏhQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEcx+D k[5tElEPO4|v?QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEtEl7M@Q@>O)}EPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP7MX 7A?ZQE>SLcweQ@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@ 7A?Zcx+D k[4QESM2'ݏhQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEcx+D k[5tElEPO4|v?QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEtEl7M@Q@>O+>5Wӭ#_)nQs'#@V7%^x{OG4EcUi? W=d@4V7%^x{OG4EcUi? W=d@4V7%^x{OG4EcUi? W=d@4V7%^x{OG4EcUi? W=d@4V7%^x{OG4EcUi? W=d@4V7%^x{OG4EcUi? W=d@4V7%^x{OG4EcUi? W=d@4V7%^x{OG4EcUi? W=d@4V7%^x{OG4EcUi? W=d@4V7%^x{OG4EcUi? W=d@4V7%^x{OG4EcUi? W=d@4V7%^x{OG4EcUi? W=d@4V7%^x{OG4EcUi? W=d@4V7%^x{OG4EcUi? W=d@4V7%^x{OG4EcUi? W=d@4V7%^x{OG4EcUi? W=d@4V7%^x{OG4EcUi? W=d@MX 7A?ZQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE endstream 45 0 obj << /Length 46 0 R /Filter /FlateDecode >> stream xZۊ8}s`;,m v7c``?`7 ,d?XLY:Uk~s;}HqCӏuytxy~nlw94>4/_Onvߛ2?}@\vMuڸi|wMGS(%:kc̒] -IڤXÞvG[)%M~j48V!b{t7""9ɃK.ٝ$kh$6W(}&ДG9%-l])I;;4˾ H~J'zFk7V^Z9%+R @b:du_'Bb  VL:ѥ{v拴뇽hQsp3wh8r2Ry}>KԔ!-iGepeun+كBqNN^Ĕ\^h,[voP9{5Ty{0XwN%U?䪃~IlZWKx/R+G=#O)eV!D!+K2H85vܡq[k3)ҪTL^W"/󷩐#U#/akr%Tc_vF-j$Ɓa(=>m, qd/.q€*ޞ>sU͘/3MO)yrπt0|k~VІ#Iίi2 h^]QET4P3PR}V?,BGu8ǂ%%e4b[6 &15TikP3͵ :5ENS$/YR0G\=E*'eKFcnͺig tqP)1獞TPP+HI\5Fa)2n(cq @ET(O:3A a SC# A<nRN$bGN|T,,pPwGҬ(*~"LA_j.)(t(E eJir*.=8汬ىr(+ b!!$?׆/}"[uWf 8x] EP5>U4 hbvWu 9(|U/O!h$xEC8s!b8N`-=x?k\UoѥꍼJQ]z9v^/%S=~Ylnю*lˬUFИu8aY C(fwk|3"'0uq//F~Rvlb7k0Ad[JC LLTo( q?w05+lCU a3~!ЍnOztqqJk]FCs/?>㘼aG_4_?,'N]{]?i>=_s9~(endstream endobj 46 0 obj 1665 endobj 47 0 obj << /Type /XObject /Subtype /Image /Width 660 /Height 480 /BitsPerComponent 8 /ColorSpace /DeviceRGB /Filter /DCTDecode /Length 20509 >> stream JFIFC   %# , #&')*)-0-(0%()(C   (((((((((((((((((((((((((((((((((((((((((((((((((((" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?B(PQN 1RR7S?TyR7S?TyR7S?TyR7S?TyR7S?TyR7S?TyR7S?TyR7S?TyR7S?TyR7S?TyR7S?TyR7S?TyR7S?TyR7S?TyR7S?TyR7S?TyR7S?TyR7S?TyR7S?TyR7S?TyR7S?TyR7S?TyR7S?TyR7S?TyR7S?TyR7S?TyR7S?TyR7S?TyR7S?TyR7S?TyR7S?TyR7S?TyR7S?TyR7S?TyR7S?TyR7S?TyR7S?TyR7S?U-9!eMBIz(h((|v?SM2 ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( o/*kſ *٢(((}O4((((((((((s/xZ^"fUiT @ÿJݢCǠjZg}#jM+۱09#ֽ*QEV {Yvv8ɠ 4VwuChӌۏoOA829EhEPEPEp xXtfk8YmjљpvݜAy ( +wtk^#/"ЮrӢuđۨEutQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEV7TUX-TeQPQ@Q@Q@4|v?PEPEPEPEPEPEPEPEPEP^aKLUP)l$|<VdkRXpr@+Q$1n_ tlߵw [/b|/Okdž}l#TfX31@ óKkn4Y"&>o>+z)Տ%xWn-3=+çύKx 0ny>`A'$E'ZX=e ~5d;&=Q!,HdSuxݿ*)Kcz~Ŭ:[u[ɛt1+ .?(L?0ImZmiqFch_"g2aNxrs:澪Xš?fkϓ>g{5k ;.-cz֣>LcXuF:fV>^aiߍouGU巌6fvCp:jm|ac}0ծo՚ }Fs2N1䌜'}m,|chwu;74e$eQUbT1@$dgËx^Wm.I$sv0$]6;QH(((((((((((((((((([ ?Jo/*6h((|v?SM2 ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( o/*kſ *٢(((}O4(((((((((((((((((((((((((((((((((((((+ſ *٬o*Ҩf(((cwe>O(((uyR 9uIwDd  Ʊ<:Xjkua ʲg х"N{`Q^MGֵk:J]&4KuѯC.D(Hr1 ԾΡgkof&Msivb[YIvsh>%ՎYiS֠ӭ*cYbKmEp1Wu]o_]O?ٺKEӠ3$8+!2ndrH˜=ҊoTמUݧ['VQ7$G9+GZ]LVk) NA#:+Ϥgj&kzp[Y'V9d;d!߁SHY6~NZ |Eֹ|-gnqg@߼A=ӏO* $1X]snx$dg#OO*LollF)}qn2s&F0G$zml=gT4_귶Vۂy2ibM[&V?|;z@:G|[OZw^UE2tKL ̒FPn|8 '9I?S|%x&O.0 l#t<`uU& ԭmcVxmUȫ*SLcweQEQEbxu >{=zFCxVK[Qu]Ha[U4$ 8PNs] N1i1gkzݦr΂NFPBsZyK/n?-!p]$~ u6k潽PE(G8%h|qKaLl5SUaUG71$s )Z( óiw}ZԀƑ^Dp['^`׬uwyE͜Ơeh1qs׌h@XuXΠ\")1H 1J5zqzRM5͛Yх,p@c $tPgEny~qk #`HGR3o=0]]\["<(%J%F$f( Xtm]OPԤ׮ qXu[[ܡ)bLE&sv])jo[j-<=-: "F' G@ |%'CV<~,X5EyP3/k٧P<3ٌxێ{ߋh$׆ھ~%ޕu<u >uEQo|)lK|Udk)gfVCàb<|DԼeTξHAnzmKCtӼ w)VJ7e_69vFE\`(܃qV|1A,ujmbZù  ]>N@:5|nf{wgHD HPOaڮi4zMJmL*# /V=OO`<.o6]v]Ig+9)0+wſ ?6&KO*KȚ2q絢kx[:H55bp$cȪNT3&/xv x?I#y.ߋ?oQ@O| Z,tFQ<}K`n {8AgFW5uyi#H[Ĩ - ӊ(@r |>fti'K]*@*1kѾ W#^(dڠddO!v(#=zQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEA__Ul7TTEPEPEPM2'ݏiQEQEQY Ѭn^V## 5%^lXx{OG4Ui? W=dG%^lXx{OG4Ui? W=dG%^lXx{OG4Ui? W=dG%^lXx{OG4Ui? W=dG%^lXx{OG4Ui? W=dG%^lXx{OG4Ui? W=dG%^lXx{OG4Ui? W=dG%^lXx{OG4Ui? W=dG%^lXx{OG4Ui? W=dG%^lXx{OG4Ui? W=dG%^lXx{OG4Ui? W=dG%^lXx{OG4Ui? W=dG%^lXx{OG4Ui? W=dG%^lXx{OG4Ui? W=dG%^lXx{OG4Ui? W=dG%^lXx{OG55\>v ;6N9< Ӣ(((o*Ҩf[ ?J ( ( ('ݏi>SL(( mB#X+f I`(((((((((((((((((((((((((((((()}#L2((([ ?Jo/*6h((|v?SM2 ( (1 I` Yf_5a4a4N8f?֠QOFc_jef?֠QOFc_jef?֠QOFc_jef?֠QOFc_jef?֠QOFc_jef?֠QOFc_jef?֠QOFc_jef?֠QOFc_jef?֠QOFc_jef?֠QOFc_jef?֠QOFc_jef?֠QOFc_jef?֠QOFc_jef?֠QOFc_jef?֠QOFc_jef?֠SFԡrU[8#PtQEQEQEA__Ul7TTEPEPEPM2'ݏiQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEV7TUX-TeQPQ@Q@Q@4|v?PEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPX-TeQVcxAPE@4QEQEQE>O)}@Q@Q@ϊi_WѬ58h̩q^4)$RF2ՋV_hb’<9q׷-M*\񾍥1wz6 {1GP{[Xԡj1MsM).MQ$dHԖC2źr0VT7`dasI jz촑}kORËm.Xon3KӹuY1vrCYgFӶWa\hڥm4Es=o;④r{V«wO^΁.uWUcҀ}ºO?Vze֖Hc[S$>1/iݨ0񞑤sCaaX0A_}c+0]| };Lů{KMM䱷HBO2ܘU'C '#+`rH4M QnGEQK3H4u3^;¿> x(~69_>f8ݝ{RiDG]YMi">buq<a}O`^g[ȡ:;݈A\)9;0NH>IuE6[cfIh֦  p2˽0s7ƏqbQa6z#Þ&U։f7wr]L#6sɉX_-Z%ha7 B5L;-3ݏx.);PH4M QnGEQK3H6[F?ѾG͛~]W>nW?7"س?j97oBMkR$HoY J*s&r{iם_hO_ +iNr_N=06V\^f& Lӻd1.܃orc&UeCAqp-P(I!vw9d @+'Sx۟>.7}] |=1mjʹ/Eg8-(X)gblmlU9PH##K^=/ & n&?v|%w}3RxoÐxĶ{!n"8s}qv\&z/___[E;ɑ'U Ճ/+?a{y_;>bԦI]wMΉsw"OQn 8PI`8ώ:6-jjEF,Hˇpz[>#4 r-t}lY``:wg]JU_O ik n ǂ(c u&4zΗ_Hu4j֦m[S/g-!# 9^_wV:?,<'/6Cu`-rPPrU7(C ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( o/*kſ *٢(((}O4(((((((((((((((((((((((((((((((((((((+ſ *٬o*Ҩf(((cwe>O(((wֶwfUypE'-jegF+oTbB^P&(/6xǾG 73QܱSPEPEVlޥedbVo@XѢ(((({+g%Y㈸ u n\ۇ:IYdDi[dap=N8$(n`kY7QW{>5Q@VsyoVWٰKY9p~V}+F ( ( (?ռƛms3Ȯ3Fubv ((5'N5;[ o @((((((((((((((o*Ҩf[ ?J ( ( ('ݏi>SL((5/j܁ͽKf>}FGz<]up,?±X mo!{˃@a{ׯͧZͪZ2Eh)7$(\c891Q8jѠ5}F;׫G|K,UC);z8;ؗNT|VmPx|sN>tC:zf76,-?Lp̏CM9%rہtsJleU&In w!Wkqӌ;oVZ56mvVO1ϒV6rN[v6z .gc_. ~%խŴjf 0AOzڽuZ&hZ a)#x P A#aSx[Gօԭ mKx"gB$Car1Kx_Hiy,\Iq#ʹdsMOiSe&E+C} '9Z4}s\צ)Z[CH̪ۆ[?6Nq+ ݅I&3CA$E/b:H4:/&%ڊ0I$;bkw6tYx-I9eTy|O;בߍ][.kWZk;x E  nxcIIc UwNFpp*[/V2geOFJqBƇ''shM 4=޽啺L nvhX77wKm[_K.]cf>  .zOn#]"`eɷA˕@6y%X-k{s,-坉o`9iZ鶖:ż[%Mrۉ5O*(34=%'s5oh'[A,H]<w/#gb5j71>։ *p: Fqa]5t 2K9-6mj]K ]b0rU$9wo<0O쫔]0ArsZ5*?A' lI8mr<ª qG\2îE5{[bu_YxbtmIl}{w"h6Q>`1i#c m%W"[" s+14h-NvMtsx!"KLx9rF:nu-u17ANCK +/z&ak?ے&O=ӸیvΆZ4$hJ.]Vdׯn,9DiVrY DKy3Ox&xVYGw-C#[J}k01kkD¹p<6zը5%U=:HܗF~ʒFsxxEޝ"ׯ=ŭ 9MV;ˋkXk[Y8`#)Cűx#](/.%%Bܭ'N e}PqϤYxJN{;(:}2Uc\g&499<{wK}P:}bvfdx d&<7j#1!m1Xӵ%x"?2{4`;H 6@DY#dUсVVW9x@ѯӭ&K}Bɞ(r 3N Qi'ڕݬo}?.8&XyKJ2گkOܬpg’s"[V9'pPy5v/Q}˵ٯeb߯97pv"QlkUn|7c?v6ܚ%öi%L8PJ=}TQ= E, "FpI3C/wZ[[tV12'ZEjfht}5XTBIVnpn\EgzՖo[GWzF$6F4~f9%vCqD[2ňQ r}M%4;dHZ9H摙E`IvG8+;q׉k]i/eɨ k*2@qTT6jZs41(Q@09iX[FG^A,&dti˱Yks/.b d~dA`~z CIKnoqO<hqߘdsc4k7hױZy%L.&*Qݎ0ӭo/2K)nwM?,0r9>^'oǂE=ĩ 5t)%1$_hZ6AM:}Y}IOyReNpnP0(QEQEQEQEQEQEQEQEQEQEQEQEV7TUX-TeQPQ@Q@Q@4|v?PEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPX-TeQVcxAPE@4QEQEQE>O)}@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@cxAPE[5A__UlEQEQE>SLcweQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEA__Ul7TTEPEPEPM2'ݏiQEQEQEQEQEQEQEQEQEQE.@ E.F@ E.F@ E.F@ E.F@ E.I@Q@>C@ E.QKh4R0} %>C@ EPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPX-TeQVcxAPE@4QEQEQE>O)}@Q@Q@Q@Q@Q@Q@Q@Q@Q@ O*E-U"ZhfkyZ& 7䦡o.qϭ\UzOޓ?Gޓ?U~?Q֗#^JzOJzOs^5bIx4,q={}\?<)O 6y2OO$$ng0z.V%'Ə%'ƼC_PK}&F8$ye#-YݏV?u}VzUyb[D(dOѯ4 A=jǩ has"KifY]pךKpV[;C>ʆèiis7pWp8 W+y'Cqgqf?f?pZfZW@mH}o,F BUF ԼQad܋[ 98v q'gَهGه\_ [MJ 2ohR2r09YEa|Qa|W;xDmo!Ito-1! D+sӊ#"gԴ6{-&xD$6TgMWzf;ه Ǽc7d.8.̐FՔ\|dߒۓ}QTYȧUM+AU(((((((((((((((+ſ *٬o*Ҩf(((cwe>O(((((((((('OZN(ګiեXjhgw+ֹEzyY/03ΙFR=9Ϩ*DG޵kwUM] n]6f4+6Y(Vd4R#GYTڹKMolö́in#̊G  PzQ"⬅* 89k 6L}O悺8 ]cLlljNm^;VP[#=}x_L-C&UfV0IK--ÏAd 6WPC JVU’ ~(ҵMKTu [g$oAv IʮPܐu[M?1 7E4<SI\pCgA oG$HF8we چn<8W;~;L|-C&[Mz޷vKx񋕰ԤݱHj_L|-C&c.^iyyZ1R۝dO V1V궘4uaVk`(((((((((((((((o*Ҩf[ ?J ( ( ('ݏi>SL(((((((((7ihiSiSiSiS*}:((dW3U/@?/?tPO?:}jS:}hγhETγhrXZKx-Y ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( o/*kſ *٢(((}O4(((((((((((((((((((((((((((((((((((((+ſ *٬o*Ҩf(((cwe>O((((((((((((((((((((((((((((((((((((((o*Ҩf[ ?J ( ( ('ݏi>SL((((((((((((((((((((((((((((((((((((([ ?Jo/*6h((|v?SM2 ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( o/*kſ *٢(((}Yk2\gCn<=re֠?)O?@4V7CAM'> i?-SIl~O dEc}?['!?lXg4?)O?@4V7CAM'> i?-SIl~O dEc}?['!?lXg4?)O?@4V7CAM'> i?-SIl~O dEc}?['!?lXg4?)O?@4V7CAM'> i?-SIl~O dEc}?['!?lXg4?)O?@4V7CAM'> i?-SIl~O dEc}?['!?lXg4?)O?@4V7CAM'> i?-SIl~O dEc}?['!?lXg4?)O?@4V7CAM'> i?-SIl~O dEc}?['!?lXg4?)O?@4V7CAM'> i?-SIl~O dEc}?['!?lXg4?)O?@4V7CAM'> i?-SIl~O dEc}?['!?lXg4?)O?@4V7CAM'> i?-cxAPEGCAM'Kou=<ۥ3`Ȳ t4QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE endstream 48 0 obj << /Length 49 0 R /Filter /FlateDecode >> stream xW͊@ s^Xإm}[(MߙL<B">}#/ =TRM}S4~^o7aJ:|U)$uxVڿSۍÓGVЏO~F &%2Q+g,DǠ-0GYRxY)+TY>_ T3}Qw_?էI  = 1͊>M遰a/h*>MFa#2iR8fVs)8v /86 jWHjC&p$^E~.9?j87N. ? `vxN nб*f_!ўͣ$'xES Y+pp- Xڒt XX&ܼ,5IVIWjgj0x" -Qdj) 2!|*+-z#"tg8+I؁mjrH$|#Zf๝`KYf`b= K5Z 2qk܁EwEFdDTK$/1$CujNVamX[  :TiUE-U$lŰ.V4;K٠` ĚTկ-sוU Vv9]HN :"yny]w2\lµE5l'IlŹl u8fY ~35SONz z)E`CI:œMK i v ,ۡš/ѹ:'O혈a{O"] ](}/x85f=RтV'#?endstream endobj 49 0 obj 814 endobj 50 0 obj << /Type /XObject /Subtype /Image /Width 692 /Height 482 /BitsPerComponent 8 /ColorSpace /DeviceRGB /Filter /DCTDecode /Length 34190 >> stream JFIFC   %# , #&')*)-0-(0%()(C   (((((((((((((((((((((((((((((((((((((((((((((((((((" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?B(PQEQR#]8S|?t)l:̖1,9R*ppGpFj|oj_|1O_h4hnouho(fr'?'Tohf \ya= G_;4.1 z׳#g xJduCyZx*4|Eiۛnnc'nw%W>׼AxÖZ׉kwowYؒ 3 O7{oZJ B~e 6{HW=>,GS^!}B^-I ',%@gޥ>!]<7mbit,܄&s).=?w4_4_>We*1R^Xַkoj4__6jw0E,䋈rb;A˗~#|NWm Pk7]7*0: m?&G>^1QjkR`Xc #'Z>-|5M-t{/Z#NB[۪T`p$󊛁=ϊ4k_xr{Mj<6.v[8?SڋO~)>ex<D!H;?}x}|˭zj^"&{˝B;ky eb~2W]~"׭_?_)~uPEPEPEPEPEPEPEPEPEPT5LVZӬ uq"ẃ 0  5~Ѵ CW.O--]fxoCI5M$AkT,+V6O.m:M0S my֘(Jm'}ۡoPN֕w7lZucqĪn! KӴll_;R6ʁjx_Eѹt-*m#zi:,mɊ% EfXh=T[* |pWnqZ~N\\5фDdcܜ'@xhiٟho_Eyqg[t-'[Z5C[t/08(%7hisͪ1 ! Sd"j &2j.^ZFEA$slQ@Z,V1,  q[F4}H4]'OӼ_3ZTP"{G|/+7ۍ8*̞ѥHou;[!{+Nm| +Knmt`rH\"_[:]\N%{HQ$dEd_cA-m-M.B[E5n((Ut}2 Z}V:=Ntx(E³q*OaW <5[ꍩjLKe$;O}G{tu9C$Gle F:(iV1ivVqgd,qI' IEQEQEQEQEQEQEQEQEQEQEQEQEQEQEV6!_,X|9_Q@Q@Q@Q@Q@W e>_?_)QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEV6!_,X|9_Q@Q@Q@Q@Q@W e>_?_)QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEV6!_,X|9_Q@Q@Q@Q@Q@W e>_?_)QEQE|I})LoFEtN V(>}6JhN\+MՌ9$m*6$b%`SM/Xеmë%p~S}Y/Վ֩$ۈlmŲzLN6t{]W ;K].U4w)~( 6A85jZد?o}-o~<[6qVq .T7`jR\iqZ0͏4Yv؜odYxS]m_B|K:D,pE|`ocg#!t nWѼws(Kh eOk$w{c @1p9ƭZ{w}LmmdkoӴ . pO=)x6/WV^R-m`/"P$$I ȭݽ퟊5mSN6$h0?!|-V\j%욬wS!ωP6|yVpy:Ejs0O6V@Uf'SE@˟ugⵦXiGxw3#LMɐeKp;ڰ}ԷωXQiّ"S6BpDǩ'="-c,Wm":xIPd'%QsQt/Ɯy淕#87TV~-uK]+LTuaop$+Q3 ۽T Zg<{}Egp Ee6rKoT {ΕU᭄2/5} 5O hxNӮYѡwWj>w(?!9m[q Uy$@we*Tc3jZDQV۸]Derf$<1YkV;ž\(-̑91je =D*?#6us`fm!gW2ZVbwI qџx],?klv}*Iv;zη.H#oi;Ά=r0Pg|J49l?,ڱIfxi#V۴/TS ֭|a{Kko۵ޗ/vVQcȢ&ģ3i>QGXO6xN'殃K~kh?nRfy[`g?7玸t or:M6 =gԬ#ԑuMAl!|bKxPGrG+xrWP!Q"6xeʜ00{ot=:ZV\TMgCuC-*A,F]^o{mz`"$RxB]6=H#;42Fg ΣhT9w㱬6uy 0Fp!rzp '+~;{{OqiȬ 5Q= {q% Vx.wP@80GZ/3,YG𝦵ei>)~K$`\2 j/?"~OX7`Jb/ˀzsڻv]YӭZci+ (c'I9瑌KOjs{ O7:{M"d,F3c޲'Q=߈ǏF,ߐ_q~1Zt;( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ׿+%k^?z٢(((((!L2 ( ( *X6u^YZUf S4[M-ƑY ,L"/QEQECms3Ȯ3Fubv (*n`Yxs"8&6*p{{QET/s]Elķ2kvsj6zi:ʁ*HU(k2I,@f'$Um7P,.,ϗ=">  GVh((((((((((((((((m{BYf sIg ( ( ( ( (/|xS((({=w+mF,2 2p8F>jS$Zw3OVooӱ,7r#;0fH<]-_Wif,`)Hcv׍p3aO4KUY˳M3`y=Np:P jpZﵝ3׆/|IR{$>rM^8_66o%iI"p,aojZhbay"cI^lH P:bK6}>i%kc-m<~Gaz({h$86]3K#x fEi BϔX3~ n6~^1\Ź״xvEZzxGw32 <\du=^:XGv$?o^kE;i k>1y;3Kr2]cTQ:zmau8t++\"0ȰՎIMgcԼR7Č-ءyTG#cyʦ7)R8NIkxK~G5MkY6Y8q8ú[躆ֹs34#%F3* Z[ZJ}w4WSBxXGaUF< 3U3B{{YԄ)fѝSY @] @nVO> fmيMѷE$]~Ɖ>4V3I^]r0UvePF`,|Yڭ}^]KrdA.ef rxmGN:}/P*g$-W$coxRҬ/nG)#*s ~ EQ@'iFI\Qp;sdO[,u=Kq=me9VVR # >[ xW:^V8vjO84ίKovnX,0T'0bI-Z.swqȷqWq,*b{st^4n-&H 0r".Qx$p &rzOO&ST@`yc%j6Z5Sj:k 36E8ԍeqm&wQw='s9'=Tv{b-.,InFII#GgwI)%ۡqӊkmFӾ?x[@ZԵ-Im 0[,Hѳ Hve7↸a-"֓NwyE0)8|Ǣ\i&cq'*<;H6bF*mzfpI..r8f $6`j]> ^:~.v%`II%RCHkA1s'5 :u2x=x'x^G2TFM:=Z}M"Gm$1;*88>²o|^Ck5Mss,R$!YH(bGck{="SU_.k`kH"ݩxPk\̺}6x\xF i!:~F?h0L9% <IB8 ~e{gjY(v#2d HIAwO,Ha֏̰ ABr s֮h|vZtMdFrI$Y$I4!7CWw bFy`yrrow5濴5x'O購SLV#^+ӭcէ,_MvI33 s+7|ca;/ZE0H׏PћB<J>#^Q.-jIBcFv"Y@}똸=B;}a5r6/!YJ9}߭}kMŷ&fws1i;G k"ᇃEi49bppGSD]?_/Ɵq_[6m{iorL`v[a\|y{/-FOӜL k1'RtmY~a}o4)&H{6crG;FN3Iυ~ P{|^Y%;(Zü#;Yr)ucGgD ("URx#'rM4>$񭮺.m%PALȌ,v9ħ#|>ዯYhC,ֳ;̮(ݗ$0x##g>xW^sI[;c0tocqQ=žҼ5. 8?<*{p =koxkiW7j l9BǨ*Ëx(GLҮd{n$uibvMrqJt Z.ZDV:mde*Tb69'MU.,}R{-)}!P3æ / ை6ߤ>%F̖O66Pq5뷟 |{hˤ;=-4,ś~ '#8*׆=5Y|'Agq~Ji<Cl\ߡV];m_8tKg޲ -0$#d'LsƷ:-K1BmUcQ $,03c3ܿ|9yk-wŽ d?Zڎf/+, ʌy9?"Q/>%S@𶣧X>%N4 3,$Ub6%I'>u} O[THn@Y%n`Vbx'K#U5=.YYʲ(@a'a]6 (aEPEPEPEPEPEPEPEPEPEPEPEPEPX|9_ck@4QEQEQEQEQE>_?_)~uPEPEPE6I(IR4:k/I.\<F_Μvq@QEQP v_?_)~uPEPEPt׼/w=Y0ȡxYUYR޹ wJim'IkiiAB`"!:]k\vlVS̉t@ <hwck3]"kOPVm񝸠7Gf~?/eU/{[`qcoj^)_ xFUnPREo<#Sg'$~"K_+{$dhJ=FN+M;i k>1y;3Kr2]c}k01kkD¹p<6z;DӴqel"ZCbf Cc`qs8 j麿5ˮ}Icգ6ip#pB114xVu> 9FY ep nzx{K5|DY's<08t-zjvM$FX|$$ dr}h x:֤,VHi}ZEl.F995RDTQ:gi]YVv1-B$9'4m=n`*@A=붶meZCkGek%ch$Gagzԗzy6-ݜs6nBL*OygaO:ǃ"Ե95yqKۘ@*ozNYX~Ѫnkt8#sersUߴr>fl5~tG̷"Kst/'OMBUr`ʲUWk:q$8Un|7c_ywg("hr#uW8ebET*t+SK yV^H1F)]Usג@㖃k˥X;YGqA`qn[4]2 aʎIqdGnIx1¦ŭ#_öyyI|A]2!x?B9 K AзYG!AI+ |=9[SL⋟iۙO+ʑǕ>^0kxgMLJl{hk,$'X$`c|*_u-WEP̳ X8flct-ww~xU.k waۆ1(R7nc~X?e [Ry_b#WM)W>_1\.iw.5+PcdY(]i(N Fs6$z`~R)V<~4DV~|!FO߻$yT+aU@ONp8 ־'[C$h_Ik_ |!ê\owFBCecg@~}o6oݿwǵ oS)QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEV6!_,X|9_Q@Q@Q@Q@Q@W e>_?_)QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEV6!_,X|9_Q@Q@Q@Q@Q@W e>_?_)QEQEQ\VPҰ-v}nd23UE|=@' ٢t(W? +_I8E|=@' ٢t(W? +_I8E|=@' ٢t(W? +_I8E|=@' ٢t(W? +_I8E|=@' ٢t(W? +_I8E|=@' ٢t(W? +_I8E|=@' ٢t(W? +_I8E|=@' ٢t(W? +_I8E|=@' ٢t(W? +_I8E|=@' ٢t(W? +_I8E|=@' ٢t(W? +_I8E|=@' ٢t(W? +_I8E|=@' ٢t(W? +_I8E|=@' ٢t(W? +_I8E|=@' ٢t(W? +_I8E|=@' ٢t*k/ hP^A4.ȮV PQ@Q@Q@ck[5WßK=lEQEQEQEQE~uSB@Q@Q@֟9ji.kf?r?F\QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEGS]€EPEPEPX|9_ck@4QEQEQEQEQE>_?_)~uPEPEPH,U5<[H{1ߋ؏|Pш^E?y|Pш^E?y|Pш^E?y|Pш^E?y|Pш^E?y|Pш^E?y|Pш^E?y|Pш^E?y|Pш^E?y|Pш^E?y|Pш^E?y|Pш^E?y|Pш^E?y|Pш^E?y|Pш^E?y|PӐƮ~^ ( ( ( ׿+%k^?z٢(((((!L2 ( ( +cdu`}cn^fi5rŨ n|Ij6z%֭7Zni(6^jLJnKQ<kTco5 1-d#\D<!Č3.ǡQ^S|Eoxk<,F ѯ,bIbPDN&U7]?%X'_+w ؤ, 5$5b)cS~;\LѬ-B|7$<^5al4}7RŧeVo-6cXN>RY-Aa]}{-\zy8 7jmv' +=vOC:|s :&ݙ,9 =M-Ǻ.^ H4V9[37O>RN$$OB\.Vm; |G/TRd {\oMúNmJmT,ab(s˜P a\+|_ikm^Kl.4mggʯ#'}Uf&s|s ý쎊~-Þӵ9,9D.#W3HޙSxSѼ3}j7B` 9m9;p:ڢJ$ocjVe5G,f0T׊")]Łʨ\<(<ib="Xmm͵r#x=ҳlrW&oEXjz&.4;)nt%Udx|Am)f{m/U"Bd9`@{EU~4nu%^nӳ~vq3VSvߍ3@ E|@ -X[ha +0#o$e|;}m+rb]6 `k<=oHmF$jʹdd#eϋ;}V{{+nFʱ.Xml9Ox^o[k#Mu[vKm?U{tv`cWS dmM%5M#Ó`oRm)qW2d} N9@x3ėzqgcx塒 xm vqՓ|A;WΨT 9!rX[mQu_iӛQIΒm y%N3G呂R R+V\uC4jm9fbήJar~SJao4MSVMfim&)&݊AS1g4mGSO[ՌfHC"(b'OjѴmZ Ŏuwi)`34<2qέw—זk {Ju3ebq!1w_x|ꫧ9Zg-317g[i7ulZX\:#\ޭjw -% 1c n+=IMxHN42^.mg4= ;FH ҳ4-'&4.,n0#y l_#p FwyxcRׯ9j~ֳxf GVno lf M9I/+k&OM Ol]M,݊@wd8*'<w.O^gUέN._Nkؒw2W*Eh:k;&N6FvF r` ''W/tCڟ.CF@ d23 Nsڸ}|^Ѵ=2 j-8R%_Vx\3߈>$o x%.RUӴ˅&4v}W 6AW~3xKQuf[X 6gRO#֠=(((((((((((((( sIg׿+%6h((((|xS)!L((_3v;g5Z^6Y_-Ck:Ji8?Zah6u{|x.Qrϭ7M]}L˟(O[ܤa ;NG=9EP/E&u+->'mSJ#&_@:+]!Mm _k(sh/nmT3PY$ U.dڊkZci9[w7YyP|A.u}u?G`x~lP6h$ |Ak3K-nRVORq@tVnnayso{2H֧]JŬ`[f1g!rml,RF:+./jIū~rV(Hp9%J{.K{uDт-# ʩ?%^ / ыKprC\IxrjqiV-8tx'uA']f;ֲx]6`TI*n>~z|=DfUcH~ۻ滚(z [C'У𶣯躕XeQU88h е=*jZ6q{ a3&`pЅ0J(*Ǒj>Gý%KèM.dofTI+٢xcT?mE<ūHvɧ$1!`w"ad;Ny;FazOoi:nRzu?iQNcʴY<Iv6۽2ac8̊Gˇ*2z1_*GV5 2M0Z[]iD@Z? ~+D vx 6X(2جP22Txp E'/7jCZbYO1-̈́vێ4R{ GKxn;[]Cqqo5 Sp9^]Mgh56&qΛ)nHUVMd.Iqs+ب4XuŤjHmEw@fFɜ+.< O ONoyuNTH:(zFǞz Gay'h."2F ޘ?u-F`𞧧][Gy[Gؘ_?_)QEQEQ^_[C")]Łʨ\<(<6h^/ GIf[q1|H2z+cϤj>4++kdߪr4- ;V';{ŅQiWSis2oV`KgGq˰‘(5뚶?9Yo*wtDTFRI1$089x^+!veY=帺 o?&FTK iEsmqpp{75&}X^i[-.x01g(9w= (RN&h$rDpSn aAl5__vQI'["Wegϗ2r'x[4 ;˭"3y7;mcdg,Q^ku<;&rr lY` FKNޱͩr5K9sGs,yKY#kÃbǥQ^yl|N$7\t@$/-7~*[KY3Χ0<'+&W;#i؞mn5?MдHͶkwqu=Y$$bA+#-lx]joQULc 0%clt *\}ޫ S_t .-yc,ɵUv1'$9?>"M vxRѴk[TdR\|0OS I7c(55 ^iַݭDZnnh&9br /(t۫Y%Ar,̹W p$wLw/RH:~5x;—:l^@\5O;<  9aWQ&c6k/Ut#K'|2;j+`ok IIME/Zd"xcR1#F4NJd|C<~[e]wh1K+Á2@_-]1{}\O2:[I*C=K˯|beӟKMQC-dH6pn)#n_ܚfjWZ]"4[VkX=wG"3#2! dnqN̏DM_:4i,yK$dB 1)0rEuFy-Σپӟ+vo9i ;M~7ct|@ -X[ha +0#o$e>ao]~nV[پET1 H6AV⟊o<9vxny^a鷷ǨՃ&(((((((((((( sIg׿+%6h((((|xS)!L(( & zWw\=jVV#=x-Km[!u&$WGfc,4e2s<ui~mJZ<# *Sߌ s'n-]bU;& AӴ7`KxR E ;Z4PG?^[PPQtF8ZH#'dѥxONt¶oqoy7y{;2Z0sޣW3& oO[;"qtR9N_~>+]^3=壄- AR8d ٢9o FN{WU'7u".ax.@\h7O)Tg1VXR IVt9K8OUn4ӣ1, ,g;Ac&x+Kilgc笢O3s6Rktu=2v:"Z,_d 6Knь#x UM:Ư^"5ܨ [NU8;/x=,55{oY ?EI DQƼ=4belwZqeAZmzfqakpy2](\ebNA(,s.5; _V.IY)ens-ׂvK: 6eyde}n#5Q@nrF഍IKHRS$EU)zVz_l#à:=f]Voydc9յu5GJcnl`@<22pFMtR #Ҽ'iw:Lf[N<=yg-9VoQv2x_XZ[v8eܻ;p0d8Ul\ >V Xxqkn0Z̧1@d(N|l ߡY6Q.n.HLYPB RF#5^/QXKjQ߼D$WJswjS]ݽ|#6ɺB1TTSu}J{ tsu,fH a0 TUsWaE0}]h!H1Hr6njrlt#qql.ax|g,[ݘg U( Eڊ'=Mbv~/IqQ#۲0H#շE8o|1u Z5 #; &ñUC;:F1S+=RURԵͨjwt\ |۰QBEPEPEPEPEPEPEPEPEPEPEPEPX|9_ck@4QEQEQEQEQE>_?_)~uPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPX|9_ck@4QEQEQEQEQE>_?_)~uPEPEPEPEPEPEPEPEPEPKj9d&28lw[ 4݊>CZ?f?f? h5a|Qa|P3} >~? >? v֏هM;n_.P4Tj8YZՆŠ(Ki8ۢMX'[*PW4݈} >~?Qa|R >CZ?f?f?s;уkG__.g`0} h|+m_.gJ5A,8S*sȦՁ;QHaEPEPEPEPEPEPEPEPEPEPEPEPEPEPX|9_ck@4QEQEQEQEQE>_?_)~uPEPEPEPEPEPEPEPEPEP~'Я"O[˒~~-m:~wDbI:%}T}UAG}>TMxēh}zYV0UWs8Sk7sxevm>!{Yd;cܮKH,1CM>Q҄GR/9[jJB23`ܒ8jɼ}{Zm&[]{s-R<"Fp]Pb1 \>!_Y=mmw{BE 2D.'9%P 1ڠgAe\ȒN 4($3'J:o|G@(C$߻mvX\m*x@W=2lҺhd*Z2G*J 8$qO >*FO'_8 <(C^E+ުuLWT?WuQ=ˆETS֤{?)|=9y'3ŏWYLUtR⫁:MSVLnd1PY+ԼwYé@34먦yUH2 @>Mz=gCtV y-eԩǾ r^4ң^;N(B^Ė1OT!z|ch3ZRɿt}$e4e^ȪOX]Cm6OkQZr@Ȣ4mvGN3XŁ5Bѹ\vh:u={-D+=Ϙ3=7=x&Wvw3xBC΢axv۴Q3sj #i[CDՅeo/)Hd;p[}rc'#yծhPVY Y+$WGG-_ŚXj+tP򥸈FG ~xeNkjm%Х%C}ek4v1KF\e]0H+7u?xxvm6kRYQ$v7K UU~Nz}W*&.JMzAXf+Z}La(((((((((((((((m{BYf sIg ( ( ( ( (/|xS((((((((((2Xi}I rkž\`brcHC0>Wj85 NۦRnr[M?1 7E5gYϴ_OC2h dѿ:/:}hγh9Ð?1 7E4co4okγh?/p9L|-C&9?3Ts2h dѿ:/:}hγh|9L|-C&[M/?\9 dѿ:/ ɣt_]uE|g>4s!co4oiG|-.UgYϴ_G8 zƗ6?2V/IbxzO Ec}? e'!^)?l@hI(GO1[4P7?2V/IbxzO Ec}? e'!^)?l@hI(GO1[4P7?2V/IbxzO Ec}? e'!^)?l@hI(GO1[4P7?2V/IbxzO Ec}? e'!^)?l@hI(GO1[4P7?2V/IbxzO Ec}? e'!^)?l@hI(GO1[4P7?2V/IbxzO Ec}? e'!^)?l@hI(GO1[4P7?2V/IbxzO Ec}? e'!^)?l@hI(GO1[4P7?2V/IbxzO Ec}? e'!^)?l@hI(GO1[4P7?2V/IbxzO Ec}? e' fS彴.vhVl$`bQ@sQ@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@ endstream 51 0 obj << /Length 52 0 R /Filter /FlateDecode >> stream xYۊ$7 }ZK! B$̾.]r/-Y#քC@g?N~o~鍾}{y~j4o6˗7/aIԇh5EքܰfMan"$^Id.`;E6-KѪ;i,E&.COCfYv/KQqt`Xa}<T ڸpȬÖOַrvJ@b0(y)X,s!H9&lQ$]noK39WJsÞ\FL E6 63jJ6C8E^S3Cji=D=J#Z)߬ЋI;fJJ =ӫJ6:|s\:stct 趮tSRfu)J+هBY&hXiPC+w rT: Չ-99`A7Jߏt?KA7K>?M ~4 ]P`ߟ|c|U*37h}>,\y؎ Ci}i'k=MO˺R#0p\ƚ|{h#tjXm !>nijm!/x]x9f!G3=oK&fq]'t7f۽<$3 8.%v3 e:c 1֟zg^0Jre|yi駡4NԹrw>H\ZT|_O;Qendstream endobj 52 0 obj 1455 endobj 53 0 obj << /Type /XObject /Subtype /Image /Width 918 /Height 690 /BitsPerComponent 8 /ColorSpace /DeviceRGB /Filter /DCTDecode /Length 64660 >> stream JFIFC   %# , #&')*)-0-(0%()(C   (((((((((((((((((((((((((((((((((((((((((((((((((((" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?B)蠩f$@gP)|@ ^G)|@ ^G)|@ ^G)|@ ^G)|@ ^G)|@ ^G)|@ ^G)|@ ^G)|@ ^G)|@ ^G)|@ ^G)|@ ^G)|@ ^G)|@ ^G)|@ ^G)|@ ^G)|@ ^G)|@ ^G)|@ ^G)|@ ^G)|@ ^G)|@ ^G)|@ ^G)|@ ^G)|@ ^G)|@ ^G)|@ ^G)|@ ^G*}X_~Wڭݻn gv?Է)K?2(((((((((((((((((((((((((((((((((((((((((((((((((((((((( oțׄ-h_&?Z(f?Է)K?2((+ St,OWc|G"d2WM,KUo--Ko*ȇ@U]RJ/5 <;H^i6؈N<Eeg^|O[jڴT[&TʑZQEQEQEQEfϮV徍>kqF dA,#&4+~.vqom9ހ9'x][H<{ݠ((((((((((((((((((((((((((((((((((((((((((((( oțׄ-h_&?Z(f?Է)K?2((y4]/^ik֚QH]Ba F}} ^i/V-C%;H:m@ "v) ȠE_9oG0iflbdeyXW,!xmKP6P[i f9V=r{߀h J}F%2 p[ g8&5 'S%H#$*}OҎ]7J% @r7*9u$;oWZ&"߆ź0bl6RXG88^0N}o,$ly&qɿysǵV-~<)Izl5$.'|H!B.1BQ?#[!k5'=%Xpc:c^AZƳ;Kn>"00Gp{R7? K ݥΟ`%Ēq@\cAjDŽ~igm[]f٬}R&*YUv*Z?_5ִk]ftBcɔ6@&Cp:g}C^OZmݬw76-A(A}+:׉jF8 =~Rz>ia ofB"=Au:Ik%oGC6*v;IK ~ݤH̆XܤG#ۊ?Alf׼KY:jz[vb)0; Xc; .Vnx\ѭh:~et; [$]3m#8-RZ+¾7> Ƭ..42$LdFj7/ zci:<:cY$d;H;Hz83'[f]f@.I]bNFN8-[/ /5:˻ .v~d*xx(#_S n?w?.eCnFγp\8᧊|R|KjYWkh3Wbn9^ ?AueXAjѶr9''''5wN&Fӧ-'Mvq`T 3C }c2.}E~v5̷R4IdbNKy$s_o xTWJޯ.*mE%ԛNu;m./._oHxP n`[{x$r)VFH<bWYKս]iCŻwNּ_ZG5~GVYU"QM;[kG~̾?CVKM>Ydwd(0 Xsc*O>O5į =DY**ة _?*׌4*Jj;pn:T#G'֗Oʏ"/柕|s7ʓyho"iQC<.fR7T#Z^D_?*<~T*OʓykKȇyGOʀI<4yR7iy4!i|o'I<5E<ȋy@\oyJȇy@*Ode+I 5k)Dd M+1E"-"((((((((((((((((((((((((((((((((((( oțׄ-h_&?Z(f?Է)K?2((3+h^[84/'XmկudӮ 6d6zWQ[YuSZnyk#zIq /5 _V8C*xF('j#F$Z. -leV074@$ 6$lI?wu@pl5%Te%!x 61'tmZQ5m[D`cO=RDpTq\𭞥jW=oa][ip6]'.%;ua g5|C /V}OТ9ft.0dVUEw$Կ}^|: i/#FX|+ bg\9=*η]G[سu=ThE|h%C)N23֛|q{ÍoOskmayQ.7e~FIUC{kYMe9mh۱VR``ڴ&>]jO>;j-p~f9T1^^uGhaoeb.xA=}i/0gK$5HV9mB(m9O2kvw{xf0%v"e#|S6=lp!AqTJ/A$xxdt "T@I h4k^!ޠeҷXvEV[@##9+̴x൏+b4{Y@O|w AֽS_~`.y3rEq \[ BcsF]"kQ l\:ψ|W>=ִ f;]+:]* I%In\(@I'vHGH!'[KKE ̥Q(۔o,MY_:F%@f@rՑW#8XoX֭/ 3FP(\` F5YOJחEj~Xk4m Jҥ4"M?E;t@2+o3r>bx㈴sdeu$鄗4R2 pJfxg]"i"F9#iy|#,ȁc/8"N=k@'ll'?*L3i"D.L!Ȭ/QEU=/A^+ $6-<=O jW"V}@ŨI,Oo;$ %Aˌ5^jn,.u %Y㜼0T*^W m=i!ǎ/m5m3B|Guho&g`fiJFa2pI U#Ƕ<9^i8`JdBʺh=r8Oú$_Nwu"ʅ)e=^ ԥмs-ͣx [ @b2F<sӊ"C. oXLQƤribE 0v@'ƐA+L_6 m2Jlr3_:k^Ҵ@#ZXEk9# @zp4?iWў{.dkM)=MfdѓEXcfO>XꗠM'_$Y5'Kuu4)j4ŪI$lk.3C\Ҭ&LR6K ~ `#f+#?#_?GؼiA+h~x9˧A-L+sңa.kGwy7+{ľ.̭ ZNK2㙝Ar9f~ϤrTX-َPK*$asg+%=+VN?'ؼjtpbtƿgoi[xO_y&UMV@-C$` 'U@Z,- 'w;)5Ɵ?_/^4vWG/G@|~x: QG3Tqbt?#_?]s0G/G@|~x: QG3Tqbt?#_?]s0G>ش6 a=:^4vRaʎ+5Q&$7p0FM \e]NfWoۼObI 8V7%izZZ[>kZIq,5,C `jWICƟ&m,W͸!-T. mxt_H 3Xy]X^F|Ҁ7ᏋWMw'"j@hHƃEEq5=|JFG4Wk# FͷqfU}b)ǸG(n9I]<[J]-r$WNs5'y>xD+deˍRAo:uPkϾN.q^r-fIq}Tl`I1SW xÞ-P<z+ FM^k`HAP8:WpƒQM8kn*룽G,$#/4JO*T6C)8 uu6>>ӣ7L7tjT0gu[hy?gWov<՚( ѢJ%a".w=Ej[v׷W]Dʹawlz Ef`hأG<^6^iƉkpZΙcD*v(SТ*uj-;k;`r"c@~K{̷ѫRvp'r3VhLՍs&vOUl1  oEλv]]`P7|r3ٗkL䢯#|uHV|Ogad"FuR$eD<n *j|73׌;{fȚ4銒r!x$7~8ŵNKJLoC#,I'TvksŬCq#6*0#A5raU<%x/IAVY5;|eYpWE=󯜾|V>%ο%J9`p3g|O;eG=+αv5~tyD&,5~tyD&,5~tyD&,5~tyD&,5~tyD&,5~tyD&,5~tyD&,5~tyD&,5~uRնm`qQ@X(QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEcx+D kE 7A?Z@4֙O[hQEQEW|JE߇85+]>j&;+m!FM6Rpz}O.U5 XM.kK,9#p20bFӰ\+̵ϋ66Χز6!vuY,#-sm֖Sr 'fHRI{LIz|Zv;+>"x;=$iW:ZC$ڃ<"n$Av+b;oj~/::j1G53%bpGK\?|4,쵍JW+9%ْ&ݧ8̣nN*?E>{2 Bnڂ_[m(\08ʐ Pz5 ?n-{+y<ؘI8>0j [}Vy22y0r6*p2I\.zZ^?ou=*Y>uyO.%l9ӍӚ_6+jZ叉p:vV1{{˭shW6(^Hm?9’8=3R2WKLK <.TMÆ늵@|9RTk^;׵l?S<@Ozt'/F.VL h$~[h'צ@ki(wo3!QեJU߈[`.>y4v Mnd-.&>D|s3y׃|PXVuhn42 r\?Z'Un iv+\ oZy qn+ Zy+QOlsKp6WƲT0`8KL ~V>x^OxH҄uMx/^W#dg5 >NXT$6§fDQ=5o]ߢ0?禭k9G"Z_տmw+~KK iV(-/zj6%M[r DQ=5o]ߢ0?禭k9G"Z_տmw+~KK iV(-/zj6%M[r DQ=5o]ߢ0?禭k9S&o@ZɞI8;:g}Ml=GY?ҁQLaEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP7MQtEO[iրEPEH=)nu2ίKHnF@7I# 1*Q vR߇5C~l$΍Pme`=<5k!5OͧGmHn-4!DHKF M|1.wiOg[9TIC 9Kmy0 |L PN2rsgSЦymR,hڬQd#КݯJtVkҝG+wɵFe%\,Ҝ'_^{oI 2xaKMBI"d@H">S{g5QRǟuh7Z,KV 9\<"tVY I49,Ȁ.3nk_$FgZZu:&T: R {b|9?Z )dzӴ 'E! gDأq8gk(hS7iw-#KpXX(< =5V[xB}FC$+\G&G~pn >E;,sUNj$"]_KР9$ԦE (<VƬ/Nx4n5 g;7㝻sE *biT0CO|f]v9yZ+ ~|c3]Qk(u#@cPkvҝYҒ7fi=g\ʺ*SCadcʒik\"3:̤2F+z:+fj{k_X^ZG%2kۄAyw#˸$ ;c$kj++שՕlE%dlXVV+,6hj(X٢cfƢ+,6hj(X٢cfƢ?U*( Q@Š(((((((((((((((((((((((((((((((( oțׄ-h_&?Z(f?Է)K?2(ko&Uua 0Qn·+p3Rz4ٴmkP6F #Wp*rU${&-$hx+-blJƸ2\\Iv#~.x <-u:n#]n773/5wo;{LΘpd{)^09ϩQ\M$\f6^f6<yEƛVWTqAgi$]2v.L>ů>j|3F]䁶ްJ:u\sJ1wqW:Q_tQ@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@ 7A?ZGMP<oSxZeQ@xG7zP/m,FFvXߗf5A2g5f~w5̶QI Nc)#ATuyiqyw&vAo +9pj.q Mb@_gLdֺ+K47Hf24VJ̀3}}=({~Gu [WaZO,yH`;X$*<4=3Ěv}$:1 #$`f3}4ϙk׌jͩx:Z{ؤ CY9\LNfwos0QU/6PʳMERp985Dǎwwiŵۤ$FUA$sX&Ԯ>:iWgg="~Bx 7rA54{.{oiַ2yQ$ɂ7#pyu5>}ǁghS_KdnReE;@BP20hk#Wd^_ښZmmpȌLʭJ6V;sըgmg;_'B.K~>mhi8&W\w_ ^Z/#i՚O<ca[7&wTvӷ#v|e,KuW~wBSҧ2mOB% q`W(E yg♭ĐD.`Pʨ F'֫W>\ӵ~t?n䱸2sGG##޼+ W^ijז7yNƮxFhC}Ź ~' 7QfD/F Jb<kH"يKNXs:ךSxA;ĹY56o.0.# 1$}dgh杮 ܉w%˚1PSG Ey?*-CNҵ^e5:L9W8:m"_ jֶuK]BX#Bb6Ñ)I \.z5_ir$oWCӼK7FuwMavrkLxs;7vwcIJ|9:LM;&A$~5_ ~ ig>,_3 4BΑF!%هM߉<7kCh-#"գ$'%Rf@n;OxiIӷDۯ?ޢ?@o-:[ko3Qi.W_ 8튧;>oh/!;V7Bo,F⹪ 5A=#I!h.y%?u=k1eFOxҋ*jmiw6WRXdVjt5ZsY;F I3]mFD彣ègh%XB AI5_n4^ngǙ r=* hLqw2{.%(:&/ |&O1}$HL4d`c gjqlqv #ńɦJ^t}pnۗb!F  l4-;Oֵ]Z5C{7]8^8=ZtP;~=j{GɖbymExl ̱DFpPd]-7MiZ/#K!9K39bO{MWOT!aІӡtQH((((((((((((((((((((((((((((((((((((((( oțׄ-h_&?Z(f?Է)K?2(((((((kMQ, 9,TdNf|y u 6-ժ<9 ݞ!ü~*|]'ޗ].qW_?< 7C{Krn+pU ӭxuo_7_WYd  ywGNS^#W-.*E2! ul(f$RjJuveI/괭dz]1=GdK{pgGeb2H^3CƁ%v饊dHqpp5Skx:\*ynQHhYU*ܜp3~GVTIn߫=RGEEQWbPH/#P (@j4Z%u OyZϧO|EG;+/TEmjuF A5HCSYN ;e!;szgm4; kgLPO5$r0Z֢߉>9.Gk%!LeĎ@H?6XOj4{[xWkPʑ&~ӻs:+%IkZ`ܕ[uױV:a[,fW8 VV-ZH}cM%e%d2B|D7t;wQ5DI(+썘QNz V21u(Af^Gvg9lRf/Z&_ ꗚuE-\_$j *m!qk>&Fu,j{}nٜ?KNN kw3y,"!܏ 9w4V5|??k>5i'##'<;UKY!SԬ;Df@.T1N:gEp:/#ޞ5-*k].$m@j!y;@r9R9 -u2+{MF{8Y8% 0ޝ+2MFM[OK;9r8%)Gl[,HVKt[H?@iQTu]:ItB[` .Aw.udžu%4Y,ue~CB7+@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@ 7A?ZGMP<oSxZeQ@V_|AxcJmK^8pX=N<zj T sRMW"U|;{wܗ[v Y9x'{/Ɖw'"KpŰA%T` peJo2UݮzGQExEPEPEPX~%__i\" 6ӀY-}HM46E0FAxš~YKm eqW5sUz},̛#*HN=G[m;iǟxu/|HtCpv/>M¥UІ 9y]-~"J5&X[+wYY䰍^E%ާtO_ -5%n`@K@#+m`pH N>6x=nXlL:h`ܟ(|9!:wZɵ`H]#P̟+d(| c{{X?cد`;"M`I_ vN+*ɯ|1n|Ai!q"))p t߹FH*J<ķw>;ǬxXl hgGnwm 㩯Z.|mGM3:_ 7ryA6.p+Яg#]]æ gz),|m/k5ͭFKȄyRΎ69Ekxu k_6p(pXYB{ϨwtIYԼ]ѵn.EI $f^N VaHy=0 {ׯQN,ko>|Vrʅ*VeHpzJ~,>?fJ]Nk$ q:* F @la S+KweW$W$GnmV ~+#u;=s:OKcY,PPw s+Š(EPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP7MQtEO[iրEPu]xĖI5eqgcI$|_W-e%{莗~/VG=Q(*齈\geD<9iZ͹]_n 9RA_J|>֗{#,)mŚL)~KAWJǡ{T0/1fRqϯ+貼3ԏ,_7.;0$̏H%kh$m I7 [3$ HiU}BRQḍdFeXp@?P+Eix(ʭ%QXY[um -II:+;cQTv$Ҷcq¾_ u aZ-┳~G%Wl?0/NkMxzSΧei4?"*1ד|aQz_~I?9~7zÚuֿA%~sz9vU# {Ufjp^]xn 2[j:[")J~Ҽ5> 8V0/5v[;J'-v u\~"Xl ?ƚ-4b]NrsܼZ5߈Oh"K*9[&a`m\]ثEy^%Bi3CCr5Ho$*ޤڠlj܄R crI)|M-~]mʸso+]FU}sרĞ$fHԵK};MHyIPr~%&xKF9K+>9"7Gf`ݱguEyxWz?5{8>>/m)a +m.A?1Άi5ψmSx Mn QNyJ-^{k+4ZamJX R0(3\wa\mαHW-%#Fm @'$gk+;}Lxay"-@ݭybMR'ak !U#I,t,dBo+eQ;GMǚMW=X>*kiZg r.F3NG+rTDsB1/g=G~oiidoH8qLG_Ey.CS7)}#KKm5ݡc="0r3!]sxzKk] GYإiu`#SՁ32O;_0p5:t .]6]>-<2D%d0 #ڒQEpmz4Ԯ)D"ieVR(Ebw|{i|-5aImVO0YnTQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEtEx+D kElxZe<oQEQE>.Eni-ZYCwhXLA35[V׷:]H+ kdR{;dݡ["T}GQ+]"mYwef JXe|FA">b) o4hwI/m`X=Aד`;׍<oRFi8!A$N܌5M65[Wƾۏ|kP[?w|,ry{w#qz]JMfiKq-ŽwQ^xQ</7Mj0<I w9.@;RXxK;қv뜌TO+WԬK_ KZdFܷo|zX-s°[ɮiךzq1㸹L)ň$< qO𧈡ь,6ZpkmY7'˸z(:}{Lmm5[\Of&"CцMx * M+Mf;Lsz8i\GUF:⺺(¯^ڞ<-]vȎVA5Ke_X>#n"T7B r =F:wdבx߅Igc0`eNIr0y$ua0l0r~_քʢ/he8TbsC_3xC K#Pe{Ifh&@Ft9ҿi-2[][÷m{kbmeÎr=^ ҼO.{d\ *UUe` =5э1&ք¤g3[^2𮼗BЖE"a4j{#nݹsXt +)&I#YmDY7%ܬFzסQ^kԽCR~'3&q^iG+0;ViYٺk:W-!5- xO=kJeY?d.\cn˓$sZQ@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@ 7A?ZGMP<oSxZeQ@Q@Q@Q@Q@Q@Q@Q@TWWZsw4p[†I%(,$X"_3ߡDMʅ Z>~p#<jwNִ"5?4E(g $gi :(?0"1'Nxfҧ%~8ܟؤ)->xf)!LHR"PT ]ĪGN+[y?4l?OjoJ7@}ackSzQ(c/achޔoJ6'?Ƶ7Ҁ2'?ƍ}MF9}ackSzQ(c/achޔoJ6'?Ƶ72y8$|K~Ø6'?Ʈܤ:SXW^6mn_i!spvUci#Um =B.cV'hAAr*r0GU]*\ß #?֝)]Ӣ*J ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( (1"n^赢țׄ-h xRL-( ( ( ( ( ( ( (<{ZWxsK[}5(.TW8Oޥi t;N ^Z9KVG@rv,Dr w:`g￴͐ۑݻ~1sbitm;DFjIo.$m˺?96UzмokWVwM̍,>h` NIg~>ZZRC}$(q{`7mZuΝx/u;!tb6r; \6wφ5Ktylk/\m䟥[Yզo|9_K[cđ<[@2u>4;[mwS%>E`8W<3gx_mkhۛvRDZvrO>c2C`݋,[l 8tyO!zu%Ƨ` mqbyFf'C1'OjΣ\c8Q_}טJimƠib.4bo1W;g!#1 Ya=?ߣOtsVyq^]\H#uvc3]xp=.le)\07a>=i;[m+YS~lrxGxvZ_ZǐƉI¬@ OԚsN3:ڵݕe ;vlcIK]UM] n~ytuX~ަr_辚 n辚 nAc[{5kwUM]UM,ukoz>kj)tkwUM,ukoSG޹/Mt_MW7nMt_MW7n[z5 t:ߵkoz5 W7nMkoz5}5_?5t:ߵWoiDҹMt_)u 4iFH:U2F?Aco\܀Ide" w!cJqՉ|[Q2&}ة]|aوIق[F0ͬYGa}";┶*+S+2Š((((((((((((((((((((((((((((((( oțׄ-h_&?Z(f?Է)K?2((((((((8 #Ǩe\BblrOѤ{^ʴ"% sD]Ğdw hq:rr]uyTӫ.WAEV# (Q U'G_ʝE7O/G_ʝE7O/G_ʝE7O/G_ʝE7O/G_ʝE7O/G_ʝE7O/G_ʝE7O/G_ʝE7O/G_ʝE7O/G_ʝE7O/G_ʝE7O/N0( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( (1"n^赢țׄ-h xRL-( ( ( ( ( ( ( >4^Pg--\u.A=~mfVG)ڬ"i58Zx• z3'6ln/ᵲIf`gc:u~:׿ȶE$FԢoғx?<4[9n)m;ݏ|W~Eh1xA2I&KG;m< dWy{˱ U}mѫ/;?C%=Y}qjV2yWvɴ6RNA}_x+H~TpTHQr2I3|_C%moOI6|Ȕ 7lhNP}1\go{kgqwo*6ؤ'+üEy/Y}v;mnzls튽igy NHQᔐx Gj@Yg.oZdP#Km#F:( 8`5gJtbZMJֳ,nRFhAԯNm໎I:_|DQlۭ.q 88všWhrCYY0vn'X́\b2 t5]M&ޘ\U/ b @|' 5q|[jqZ>fSEߜ``T>_%^:y7qsJעȼY[\zaoo%5$d,rBKI13^h$EpN\!F>Ҁ5謭z,ΛI˭JT{'VJ>}B{;h$8D 20Ns\bkQm1y{e1 Nx9CJ4b]i7֗L}2@\|_᫹4_#&iyeq[QXw0մLjxYܣĤJ EY4iptu\cP}(N $5fk5ΓZ\67΍8bp0|&ZSiQٝ(CzQE ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( (1"n^赢țׄ-h xRL-( ( ( ( ( ( ( ~)9}jL-y]C22¥$* T[Wҟ|/gx;ំiXF;0܅o<z<1xZɭ|?c$fq ٯ"m5Zqwfh5y'Ochqjw3ʖ4s_\]ΎD†'U%B+MHnr:2E{%jV7O?|\++ +>x[Qt nEt}BMva˃ 񽮥Q𮌒%ȑ&pmsV`O%Z}(هW .NO =?`icmR("f1\J㖙ud^8 , ! :rIhn8/ =qkѴ)k5FzI#М׾QI=dž!|CuWҮda2  s}kZh][(6D`2bǢ`J)IYXTxS.Fbϧb3r8a<V||ÃQj6>-56F <^Q ϊO:E,-a,]XK =Z@amW[FkWS mڟZJ)7q:lNuaFf[)iH[ύ>'-K.4-9v7rZe ͜xKi浹Y!đd`r ~i|_}'BswrK=r+mxCĞ t j.oMq#+FvAxቫU.^fpGR#XmCÝ ɻmu_gY#ފQmf*:l݁## xKVkY1G;-A!XHHD4[Km pcX|>]uݮmnn`"Syџ?uҊQ*)3Zh/-b<ދSм+Bd)y\E=nl8eu:66WV]Y,L#&p7$ixSM?CacI'=Axg 5+ ZII3or.,OQA#1\_BD{k ꏦGct !;[=lYdo:YsWa.=}6|E=%ƜnVK9# *(8,CdkjQ64o#,(FT>XE,V5SXdď[Kl H*xsح=Z޿rkilE"V@Wcrydޣg$WS<_OJmiZ _I 8teXœ)IlWS+M>1 /~N1{Vw<'/[AⅷѵXl4*cn 0Ղؑ$x!?ZOt(2ZMi ЕUHD{'wJ-A_ 61H#|рۑ{xZO4 i @ "5vV.zp j$g׼:,-7K$Ӣ9MG]o__l܄R crI)|M-~]mʸso+]F]\߶u_+|{sZ߶x/>FcۿǗs*f\'VY*ӂ,ߓ m c?1<5RҬ詧%{'yb,3*=ko<]te4PX6)\_x\0lj{RGb1z {|49񗁴yŴxVWdl{eIՉďI|' "(5'Gdo= *//Rs|7!~ |?϶H<+ߺFn^ԃr~H_|le7qip i^x[pxzᛋkd೔ /zVQ]Hp^:BsM~DD*]6>yv'kio1ݻw|z#>c÷&,#MM)K x>e0|KE|d" 4I2Z3| Sq`;uQ?[ [iM#E;O(R]lW-}5Yd";D `{l<[s^U94-.QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEtEx+D kElxZe<oQEQEQEQEQEQEQEQEQE/Anbƒ;YYK(= pWU5m ˫{MGkҳ+ =FN|uFli *Ŝڄ1dH--bK8Z y,mwGcxFo}ֳkGc9=*_V,sS?WfT|9ٟ7^57ķ-q#,7icWH~.VZ5P @gi֫a,BFkV.x&Byb4((((hYig}CG||wv,EQEQU/-m..⻺-yF[b㠫4QU ;->tl<U((__y>t<ǰEu k+Vj2F<1'NhJ(((cYhݽkyW#`# *QEUk;{[Kx x^@6іؤ98*QEQEQEQU{y2\nFFAf,EV,on廴EgpPrf(((_Zir]7PZZ2O tjZweݽ圹緕dH8e$GP( ( ( ( ( ( (o]y{ٜ3Y(((((((((((_&?Z(WxA֊٧-xR@ (((((((((7]{ŧY0=ArQb?:A@)W@|z"Qs . ^3#vG֫}j:s%WǧA F5f58.~5zяkϣxo|"j#Hzđi a;W3Irx24ImԉVy&B0X3_ WY:5}6\-ݛof;[d 1_Jm}=RG-+U5=:nFxĈElBbI mN$q/$ڴa7;\) 8$E׎z= ỵ*>]'4_oϾ6= 8tz +Zny{=սpn.qap&/mMmk 9 *#GǜXJk:5y׶[Ku*p}pMrzw5H x_QỴL˴,c`GiK |5Bx}bݪdVVwiWP(<8~umEkmFXIiWV8kmW~ 0Z}4Ţ }ިEn^Az/#M+'bM''n&ѿX20e2y#h4oxađY+=J9'{ՀGUץgmZ^\AfX. pF@9ut':VT+m,!|\_I{[AKi-Ƅ2,Q|𱐸_=FxVگK8n$no}k߼`GR;ga=zlbS=fQՏ/R6mz=RGdX_U!ێ/[kC!2 *^G>ҚG:$vHQ/̤ /~*֣/P]CtE﯍0 cpڃNj|5k'A8͈Yn*;QҵmVz:l:TbriK` aڕCƵq |./t26&[K*0T222:W5z޷B-->}|n&@7 NK3Q:^3n}ZU>ʣY|GXp3$显t[Upnmn~DáRXdvlpc^cGl5ψDU$nSmrF`A\3+]M6z,Ae;@dy$T 'A.Yf}C쫷΍2Cѫx>WѮu%fkmN" ͔(B'h9ұψ7\]~Y,4=AF~w0{`'OĚYoj#n`C4*o;O8EQuoQ[jVvjfL8$GP9ҹoV~ӮVi~5VGHȒ?zi1PswM~Y45-RSswq<O G %םciMvF} i]{Ip|kUҞŴcA!] pq۸7|7y|[5vx:zHkpJYHյ7,~RG[d@pAPsY'RkxjD셾YemͽFУ'8FBPOxWE9!Gs,;~l p㟇oᝧcƳبe3YMT UM>3N;pڟ#y1N==[]|ejvuL{5Fr $FR3*5ss4mF]JK@L6ٷll'gvϵmxK;қv뜌Um?̖:kr,>O#VSp.=jW_p>I"2i?g<1y'jvYz-: ħݘ*.{̣=O^74mszƏf 4C 3+{^g5 Q.ב,BeaT=5Gn|1oɥ4uH"<_Iwm@^UG^wv }.O_ 4l`nj35k\׼Ohq1i/1 Uvjڭ߄tuKwskuc& $#+j> _jmkGPҎS571krAc8#Xgrzfh4Q%-*\c M1]λy\:L E#.y~%‰|$l}AHSp|U_RZКĺޯmWþ]6hBךo(2H4d2X|bxƺm4 >+9|CK2h#Hf@ұS=S7⋭:iW s nOwYDķ"[VIH@\,s޽~M4-Q4^VDsX>]A 2=fh --Q}V-zkXD :Hd 1q0ʺ2tt{{!k}p󥮉j{&]89Z%>2q4Y%8.oW=̣=]{Ddp2KUee^O0 `@yBŎ]V,PƷ#>N0`ֈ[a56BmK]լ$2L'psWq7ٯā.4rYIUB%'`[kh+.YŜ gAW+%PxCퟎ5hZGcf&2#hz|!i^,rĽB[t! ]G7 h'o%gVq iڥq]\FL U`JFFG _j:VO[MT7w6V?jN@ "aЩlA,2;WSè)bߒHW ~[ y/59ei-7knm=3 HaT㋻Ɩ0Co, $Hbz {:tGXR+k@~CF>sFx/NMSk`H?hZKhKH. iU(X\n^9ѽ-4%ƄS[ˁ/cm X`>7%e?o|߻6wh|[κ@c/>ۏ|Zw1GGxP:\^+$J"\\ c `'#Y[%׼EmcifHZH:FH*J1!z(3{ pG=/"7*31ڳ5?_ 5/ AʓWQ!#9ew( J`F:uTռKm'q&^so"$趍 22}+o%?x@R$FHIއc3 M_|-_ W G 6zQ['~)nSy[|&#ݜǽ=,|Sh)amJsOo,Y\t w&<{{c;CT44tS&KC=Ex^ORs]ю5CD (I<9jĚޕ]/)lWi,x[!v+gٴs>[?w~W[FQiXMV An%gv1ڹKz֞*|":pyQ|7c 6q$pi575)/4%#:0Ԛ9a8z~#5Լ+iiYZY=AF 4Zҟ IjψotR;uRL$!A$OL} kvIO-ž/YKoFU( O^ms]Q-lKF2=:R2O쭣t(b$rg5i'>="UxoׂsNIOeyiu sm<0PMeh^ |*ֵ 4A Tʲn;sרHXmαHW-%#Fm @';o_-iFY@gm9Fm/zm)(ltc+ ֜.{eĉ$x¶qխ$x5DITmgإG̥D;XΧiJ]3I/MJ)m5 ttvGrpF ۓ]7h6lSAuh.r0p{b)(@QEQEQEQEQEQEcx+D kE 7A?Z@4֙O[hQEQEQEQEQEQEQEQEQE|Y^?t[6|ipJ=y N8kc'FcyBk;.K0-+go5PFW,u:͟LޗB8sn-ByƼ|= ]6Y?mRZE^6 F7{  OC$K Mq}Vv^ʭyEΪIҵB:wqBk?kpFWzχK}\j:Tg}$_g˂smPWs]OO6l~GCo=_Ϝxz FZb3mV]5yk˷ 7gMhrc4ry ~xa#-+J#[Іk!!7d :5 ڵ).N~3ѦL( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( (1"n^赢țׄ-h xRL-( ( ( ( ( ( ( ( ( 5=Qn<9zMh|pl>7 ++]ھYYMz,nAA#!X]˯韥w`sN~ >Wt؉MY:i? '#lLk=2+վ+Ѽ)'%@wuQ\YA i>:~keJbaB@I 9\)Ե9t cg-"eyXcky6V++B"\74+_,u!0dVS$lA${` rk':|o̱txt٦^ ]< *GGN -rO մSK{t$UD)$ 0Iȭj?_7JE͹y1^UަmFYR)&dB(2@}?xCԴWG/VFKՈ H9//Wּ i6@ .۔2k4o]G89jlUݱnI u UOMIZia11F p9sœp?gs7Á^吏E3vRCnp>:Orkc{Tw}.? hY_:PK4!V;W!y}{Ӻ~0ot n;)->  Mێx$8,om7=KJt}BdkDXϰnpqY:uL [[dJ7@V\so]G89jlUݱnI u#т;dku%h&J}cn8`ZL2Î3YwԶ? dF¿l)&+8 TKV~,:gI87L:߂[8=ou^ܵŮ4SnL9uN9E=^"ғQnE\sEcj)Ӽ{w^–jFETe*n0~_kO:NGi'xdWǃV뵀#rށ7MG^๳o &E'\F2qm{ka}]<{tX18ܣ9okzzoekY=$f Bb(`H*O R>RUޥ:~$ 7Fc##OqJ[}iƲ M>dK`%Sqc4j #Q C3Ԟ;υC֭ CNm浨jGh.Of :]/7#w:nKf/N}G\(rxr2gl->J4Բ, TKvU“'3-k&cmWb,(sn@W׽GQ+]CQXim| ۶7%K0e|q˩Z#i"QA'9:|x +AڵuK[!`AҲ,Nueݥݼ2o'Wh̅Tl quq2 @^\ސ3ڤsΡc{>snb$q C$.8'#<|-[~/TRmdi`p%s 5x.^m;[=G.*Mb2ܘ$g4VޅchXX˦@rHMP^k75:j#[D2TEah׊o5>Pi|mp Yy`<|1#PwaY!O#TSkg,oU;N8kY[ydD9dA=MŖyuYL(+9LD\ːN{yEi6Q}+/.O (t)X]}lIvr흧88Q֚nk-`.FH_hmU7xf{ox7k Ki?l7o-Pmĕ<G=-=BMB}·h\LW I ]C;|7N:,2A#GDMѸSsҺmG_ZiFlO!} TFFyxcP| 4|Cmqa쵁]'geGSŖ&ot>C`.&+[%?<:7_}Y>l'v1!]邍^3_ ;Kӵ(/hm%Ԏ2HT;R:W) j.mϢ0jMG d'1}mz65ǟ l{p3q)Iu~ui2_zKpwȊQYr<hgk)H16O0q_`cfHSCrK'̧fK|g%z/- QK+K럝WˁpdSVW_c\iZ֝eqg l;rd {פL8n-[KH8L+]*E}U<y/P z%}zu>.] DA+I"snv1։$[֭ CNm浨jGh.Of eajoH^OXj7 v7@ v75G31m!;Wq'Ԋ-kšσ>AeEԴA18l.I:H6c~ .u繒)]7H ș*>@<3O½&FZ|ȑvU. t֗[Öմ=g۩-Mf,P6rN5<'ۛ_>>ע_g篷^)0:Ҵ_ϪmFIaʋ͏*!(7bFwb1[o}[ʲ `2;i>Ojm5[]\d$qNI@݂ 㨫=0L<4+ 7q~|UwX'ˀFzZ> ΎIH^IcDQ1'J4?:1i=Y `u dR(TvL9Q[|?kF>O}ڬvǔNcxRC@#MKAJz̿hWX$q'W{{4fFg[RktH\;rȬ8=Ky[xLj̶q1RY?+2_h^xu7Iu}j{1gai60JH5k~-|-JҢdFi)T<ƚorNO=*֍a&M$,5mFMV `&IBA#.+.JoD$tڟlRLZt,` vU985?Qg&n$]]If]ː 0H5_פCgɓwBd1 ]y+lͯm/0"%F3~/14GjWA>Jc240wJ _ԼCIŝq[# ,||Vĝ?+Qҧ.Ca,QH z++h#4"FUG: k@$)QEQEQEQEQEQEtEx+D kElxZe<oQEQEQEQEQEQEQEQEQEWxҴˋ XkO˲8q*93$h|]qh:qO{8QqX-XW]τnI4Vvd6F ӂEP lm_i'Ec39Z2v-j,3ş ?vKźZ]>;Y&)  CN]nOc5li[|Tdnx~ t]ZFZeϜ8rl!e%VQ0jh3_q(:_ $ agrQ^op"Klk;@B0Q gNE5>k@mEР66#0GѲͲe8o}kgEs L%fYbqpL={7- %Fj I>΅v-2zì^QPo\p,NO& x::~]ef‘䍘8< pԧ^Swut_y7tgq8}C5lmekxc󺪅Y#Fwg^ekE;wrXxp> ]Uq j4쪍4m˰$U8h\zU2eӭ&|9gI՗8U@n_gŘc#zz%e#ѧg\~M`5kZݐ;d^WX?~/k[ڬ vəU?h{sz|c}~oٺb>1Yo-/_G;P$;B$`GBlgq7o ±ا#[O9b~o{&w%|+O*v|QEzV=|_?ugG-DžoKK}^kb M a#.H #5RVw=v x<45 }ovqI>Z5r ;*Fgq|{C6sx+{6%us q׊LV%_˟DiSߴy^W9쎘;xοvCiMp$(%w` j5'AqieehE#+T' u4KTW |`<dҧ˙,!NXzGceki[k|v"%İvܭ"|$$z=T.6Uߝ2Fܩd}̿(;r p/>$i"nL2_ #I?IBZ=.Vn'I TgRc y 62rx5!oK_~ot{{=;WI_,xHgk:ƗN3O DrJrF88FKF.44I4'=VH)E0-NB*\+ƇFiNmύJg` evDc^|]KP ΊKy2HH ,q߮[$j+<-sxS< ])9X,$A嚵x[E/OɯXE|g*$ĕ]ּɦЯe>'ϳݷж8pk<5\KmKO/RI,[E#deI\`vסN?~tYѰ 3l%ڤN9CguSoÚVnݻf 8q үl4 | ִ{ךmqvI#19*p0: 3oO!:nȮm%O 㩪q݉3ب4 V?5^!m˂Mbj%I 9K$$8+vY69۱5G31m!;Wq'Ԋ[IZ{Xfxdy]nI u<[#C,t\kLDmoW5 =R/Z56[$cX}p?ieq'v{^;чl~xOF4S^ %Z5c`d;w[ U+O4mcFkѦDmL1 Im,8y=oFB?cWoyqgWI_7\ K^4ɮ̻grs)v'sa~Fw|]{?vѴt僚!5Bw2\ulWc_=WCҬeӭ [XUdcD老/49> {+dЭF \b2,]8F1TՕĵgQ^/>|7nچL-fo,LleQc ۛ$~}Ŀ>'.|f$ĕ]ּɧm.+E|me'xMg=% Ē q_QPՁ0|tPѼY$VjBGr ʘ W"@Z,5)aMB)Afܸ$Ԍ+ ֧7R,.I8-",OVd yV.5?kIpJȬ2;>ոA&{Z:x{~Vɡ[e!]8F1]tOwΆpVWMk1bdC[8>z; jwW<1kzm5游KIZOd`J@A?@!Ƈ oPLm;Fd$a{жu=Kڦyaݷ~-881o_ hYwnnp38Zi_5/ iu [1w mnJO˸r>=]j[|L[[M$Ah Jn31J5tWx[jՅޯ&npgҹSJrj>F^yu `~rsa{&w%|+O*v|QEzVusm?\Kkh5kbiHwT;^.[j[M:"kh,-0PY7c''kSh|9W|kZuHn>'ۣae0;.޸Q>PP[tYiTI"R;N-W7x'>~m|&/3NRDycH4.Ft! {Wqx_F<+y~5T)s'^jX?[WK[C~ݍw稯*]%ŜU-E`IʮKdj gi1i+kI9YdEuc~TV9(3 ]Ex#VK˘wFMcti<ϗpq{g/]5Asf3iVoeq+ᶜ`yꖠ;BKCmY\,MlʜGs-~[-Sĺn` 7a'Z7}6)+šG2Zv'Mi@+KV+X -<1esΡ\mvC T[h/m'9FX]H=AW~:VkF/KW(e[X GjC;φ)Zo>/ 63޶a .$ϸdzy|ǧh~/XEYRX/7v)ʻIG9yR;|g\: O8(bBES}tvZG; Z-P~+*3Lu>9]Mx<-fTDzˌRsѱޠh菊1|)>I>L#ٳ}޺J C=eUu/xbPokqpwv* #BRcgSPyVW7~ty?r92s5~#O|KѮVe+g%xwZ5MwƖzʱɌH$$a5QWdcޟ8]jV:A mE0)8@,0Ij>7gwѧ R).-n )Q*q7ND.%v.,c :(xs~'n5_6$dӬ"1`JBH2CbuuxV J[;BKbIe)cghC%[x F `x+x[J)庺P\\Hr@zַ_&?Z(WxA֊@lxZe<oQEQEQEQEQEQEQEQEQEV_<=A閗! ay H<xET'(>h;0jy _ ?r=FX^*;+x$-vnq+B譍bT[*|-nnu J.k-ݤs8PI qN=_ϳ%yk[lߌ83YJp8(敧NU6¯aG`R7ZU彅سH|3b0nFpy{U(zki5GbV#ܜM\K{̷ѫRvp'r3Vh~k: ՆtM,aGnߍkE 1/|%o|?\\ M,Q?%rzilomɊ% EdxoC水Ѵ,fǛokԺ6qIw:[! kF-_l5ks4PMX'EI'kv׷W]Dʹawlz EgG1hIKM(>ƶ!9#f6$QoC.ll4m6JOo $rH5EQHeOx,]$RьaJjOo'H^m `p3U) Sú&uΫ׷06#~ EZK{Ly+R.v|2pG#5j@Q˻.9&6r$ $Č$J &Ѯ+ocQ/E'p3[P|:&44[#`y$MGxwEE9aͥC{5EbG/ w?%ϜrFSp<ֶ袀(ǣGY%Kgvc Xu'9Vmඵ᷉qDP0qҼ=2i:>cq7Kml35nOo'H^m `p3U(3F?N?}|:ZtQ@tA4M.-#IzfxwDծt}:.#$t`HJ(ŧu{ K]VTv#5t[Xo!aCrڢW|)##EEmo V H#(*"VnMk;D/[989ע1? Uz^݌bkHq3kZ8(8R4UT`:)PN S^闗{<:9n1q[m2ZZ  `01*xwEE9aͥC{5jOo'Hdh`2 TP;}+O+{ HDUfwry=궏DI4mMa",=ʁբ1n<'ˍDhD7/gHOEo%a-ĖQ[dzDj~bA[P]DdC# 2#>_i1\iiq 3G,qXa d88+jek5M1kT*fѴm6ɭY0)X$\t°#&@cú&񾳣麃0wjہO.˥2]:һM@g8ٌcV8#EejXѴBXRV_`qSin`7}Ւ+)U(iz,-i1%  RK),;K{I1 DlFUf(WxA֊<"n^赢6iK?2?Է((((((((((((((((((((((((((((((((((((((((((((((((((((((((WxA֊<"n^赢6iK?2?Է((((((((((((((((((((((((((((((((((((((((((((((((((((((((WxA֊<"n^赢6iK?2?Է(((+'|\| q 9,@1J@ ǁ|W;xGZƷ6A2 1PKC$|+:r,pq}yr?;nikr ҋ9UqaѾ&kMGn\DW<a gt[&yvF.]9-8/1_8_'B_?p|FdlH.{һ Q\ 'WީwPL|4ZJ*ؔW~˞-tuƙ|۰#`\dH +|?ߑ3 o?tGEILoDtTLoGEI#FQ@ W;xGZƷ6A2 1PKC$mBcJɤbmE].hMKX Hǘ%I c|3\Jmt;rƒ$ʹ3 'H>qo⿈>,rח#nIvOֹ sMFֵ 2k+-h*Y 2=~QjX{WmQGn%ŚO pL^0KpLG xyy⹷{ic PIeu#!A"+>xZM]R2F#9H]pu ^ox͊ ۆhc|kϲ˥7FSZ5tBɓӻMm=̐r8`8C)qI}k/9^ꚳ9+ǖjob?u=45+m"|:4ϵvSײ'դu}#Ğv6Y[sgpv^Cbzey++sVo5K؀X'w$ '5mxVzr"V#̀$$}FaׯJ-tUs¢Rl/ Nu+8w:߶8稯~Uo&Υtk˅LE8Ep7`3W5 [H}:mzyؔ" `㓎?:is卙D_?*<~U~=_xQZŽ+e^Iv0<$0AGb_)o?U] NF Nx4|~U&UKWĚ: Q'C>}{~Tr0u U^ݛ)\팃Ϲr1#dc~r(hWP}y#n.$Py6!Y#=~i`sϠ5qO>!֨Jӭ9I㵺t;NIHL*,Uܣ'jt|+IYtݦHbU 8䂤Z7+qw 5fNXqkZT/g8r%lyZ×k-֗&zdG[,sXqJqToӬ>!+cƲlc|ך>v]_$sȧ ;{oD0AϔI';IU;C7aΪQvKo}Mc'Umd!iQE<"oYMҵ84F7׉bٚpH*$ W>1.xbD&D '[@9+8vsӼ~Ty4i lYO#;Ϛ]i֭ύ.=WeCFP9W(6v@-w;"/柕#[A44ό֓kzMZ0Tmm;ZX`vcEA洔P}yCdc~r(E> QEQ@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@ 7A?ZGMP<oSxZeQ@Q@Q@ba_i I|X"RQ+jQZ]Ĉx2?Μ[¿^=džó>Ukrp Uvxz鶖? .FO,I9gP4x~p6 E.?XgOyBzjk֏%ZKm[dt-\kj]YD{9Mw)Wppr8#Х{e$mc@/clHK{$ ʌ]"n2:ի>]~,4t#4\\JiRG\үOyBzI?R׿[SB >xañI[l2l0F+ަI?R׿[Q = ZK9rkv䵞Cjlj3-{Ǫ練Dӭ <*Fa'&]/iDTAZ־%w,E,W>"<5n.#\YP+5[(-.bDWPGPJ\5/lw =KV8=k k"qRf࣠g-3IԺnT|## eHzqi7VZzs4#FT8P:*$)k-Ǩ-{%EJܪI[#)m';G]?AlI|ˑ 倬A$I;~Z&ĺ0mO'{OyBz4f3u^ [{O pі.$dd0ʲ8#gú7h.N$M=c ꥾a9OI?R׿[Q = ZKMe]9r zLu偭uf`Db]|J6@ *I?R׿[Pmne"EEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE endstream 54 0 obj << /Length 55 0 R /Filter /FlateDecode >> stream x]ێ# }_`A<[#F<; `'8O$^b4݅cXX=*yCJ;wi)O俖~Oo?忆˸{is-wO}tA}az1o|BW]za~YKn^+o7N/4?OO2nL_=ߧKWF?s0^}ӣQM ozۀs >Ha!^8h9Nn wi!YD kf9xۻ GcU>Ė[㧩ؔ"0ŝn/ V+w.qPp!J@Dڻk]IJ/^ s+8Y`wmVo|Y{Aad""aA'G)j$$$101}x1g=_قxeV}tUJnL>et \@.a8.P1 + J(d+'81 Jp6bGmG8Rp%\- RD6(~'# gZOC#^ٗni|R QH`GgitV 0]T::ѴjA&J`}Q萷 @Cݵ])1tjwi@6:c+Ƙ'P vN,}n HJ㢛1@}&-.yԦt1l`c1OMЙ CLʂ; Dp!2e gxBTR4eR0EjC8B#@/JmX * W-X<3!SJhm8+ڑ:/8Xd\!+0uRZ&]Q+C Nb5Cwє܆%(ȽqZOthP¥4̲wq)f{[kpsǛhK7h%-`2sAb-Naj(YtE$) ֈPIRE( !dn@;-8 S:~JIWd&񞼝gHRg\yY E-Mw5nbB7eLVZt \_T̶ii&f#]س۱ ĵ0 rŌJƔe:Ħ{gALJlZxb +<a]9*uw UBOQ/!ГslF`IaV1VJt2&an$t\1Ra]I?<Bd *QufSsks.TmexJ&a @dNx놧s,a]!(#j8P0򴄝B cxFցHt4<=TnU$ BeB4kN~fZb9NE)m'/43z0T7|./k2 'gj%ɝQẗ́'$C= gc$'+pF+ޮyR&~G9Xlo:>&vWh`jFM=g&8y$OjѹovsA֌8Q!ɺXrwRlS;4U$K4ud3k:=ɿM!̮n 4IJAe9 q_g+aڊ!Ωwhbh+"y>: ŵ>OXեąp\øF.FEEM(F1K8۝\ēeM9䑉\cԞu߬ {|chƸ"~/TQeXAJvpf%G;‚ɐ$A2C1I%]-5HX$΅Q Dn$P%nB VWLzBi;qmvPWQMWRq"& ݙ%%Hz T<{0p%*gO]3љV񫙧!9RQˋkɜ"|R jI‘4J1,VePꐡ0.[f,'1DSŰߜp*wp[V"R뵮?ȳɁзY55ևԵĤ"RbP\g*`C( #8X+ʙ2ǣ=fФX&UEa*>v֍(\W4"tE H=^ DȞގD' 2` =%M2K;+ v.֔C+.g.ב>PKO?/] 9]!367[e_4LDڳ1;1{>;/g}6[}^2%nҔgDN>YV޵=l/U/47k+%kLϔx9rN`&r^;G]yTGmZJd#1,IIVh)"vDac#,OItf*䟾u7w-PHV#ߨYݖ-ψnt)[h(JY&UsD}VL!%c綥*^xҐVmWдz¥Gi:a&RLڞ;70`3ʦTz畣bp(oi5* C¤m)_l6=^6.ow:[׻ 􉗲gkR~#ġ;=)Q!>*q S7p7v?TDh PEC &5nɝϟ?۫y-tMN&C9^k#C2Al$bz$.T9^c5T:P}&ʫ2 --{AٶvT.,(*9%xyV H";SqN`W FشY6l SUy,mϢdK@'[5_>ZaQXD.i!J;9es7)W/"Yc/iᐰň vZm}wU(srCS#]jjR=ZsY^;jBI9JU;SNUNl>x498e׽jE#zTuٌTY"$A:1{K]]?dU2ar",!]Ma75Ĭv'ΐp3*ǪnW~a[ʗx_"$ߛhrf]}w$ۀ?w0Ln?$f~/.Dy\-'Re0:Kp=8Bi#?Pv_=ucQӏy提4Mxa}ys"紶ʉJ Ç/j;`9lxXmTlK;)=?-C6!ҹyx' Ptu2do"ʋs%-r\c[Α~8ama> stream x\Y$~P {ϲ|e^9qTFdTvxl"XTfEFF|q/s'?L>?߇n/_|~|y~2!߆߿?/& ͽ/Dx߿=\O ۓ{^}/Fw{tPDןi}?=|營s}>̙.8_}Z+'x_9l.|~0ۺ%LnD<;/|xw xY-WqU Cgʹ-XF2Fd]&F3W!wL0Ond[;UOp׊皏pLĂ.a!n%q@r e;fEc:B u4^?$ ED6פ3~VCr_)Kdyq ΝÐh9 /8"dVa,x_LphrHxh'C;(+,cP_ÉZgǯT_ lIk ipw9J|sla{5R5k* #0*D' 7IC[< en*=5.-ci-li<հ{DWLS!=jƬZ}_H?c3tB/HDn1 Ћ {Ahc4v'{um8/:YbFk>w|Bve9H (]w|˚ruxӚ98W\H.,- )ekl0(35y\P@ nDÇ8;¬:[FdCPih>`c57$hjƨ'̬Yɣ]܌&]Dzkf!ͻAYvCl x6BFIƀyՕ^^ipCWײ{myvS\æ ejZ]R[(7JdJkᵮ$&3Z)Ma-;q<A}c9|{;/#3G :54Uf2Jh.a" ނ}O[̕-cz(ExH/hG rw+~7ܫpj)=}fkR&옫 VxP=5!+d Q YjAbo@z0/Xd/û1#''*<-Ȝ]>+.Ζq?g+ԦI# Hs*KL ͊xtƲ x/=D_k[*V"(xw⧖ Izkj$V1Ϥ+E HfzWxzez%pG]<[cn7Mo6䞝ia,{I@ KDK%ZھAʏA>4=χ@ 2=sJHv|\LH Qv`k#B! vQi&ac9tAmEpE=-jcMu>@{'S%&M3Y܇4j!N;:R$P;FiOU޴c +,KnRQ9)KEU`Brxc~Ӧ_ +)wiBGoleGMB!şMF`2}E7iF!S̬;?N'e_=fd+wR p̉:!K!vqGTՊf,ƤŚhk;8D;HO$fyҖ('ՊD6$41IU7cBaS3{llXψ-=Žb%4ݞ5k2z3ͣ3v'33ޗyӡO (n)`B,IcFe% Oxh'>igA$%p,TsV @ҹYaF ;+FO,TP0>rShLҢ+Qs:I$9ԄY JXf9- w/8Z^LZ]̏Gd e_*N3ۮӥB+P rU">/[Nzt,>dGZ;}6u=LJ=@V `!ݩV_9˘MHز"a{" 򫛒:&j[*J۝sk!8s&r;l_Mhzz`j%^U;F,,\VIiAϴmLKfXز # Kl| Ҳ,:=֔me;(*Q YMN6g֔~=[(]Zm[1Y'c*endstream endobj 57 0 obj 3100 endobj 58 0 obj << /Length 59 0 R /Filter /FlateDecode >> stream x\j$I?y`4 䢼7søҖt3$ ͞=[<8_ݓ?L>9?u_|v8=-9 O?·to9l6ěŃvb~=77˳ig˓/OƧO!snóI > ˳O~?./Ou]fznUmFGްp>ޟ4 9 cq/pap_{"Vm? uCO0#x\*zEOe@#L(\ &GesnN/a1ŶDS^ߍY?5#?IqS^35/"lku<w W BhRÅpɫ)s"8zսNMZ0á)YN8M}ÌK5Cjwi*qo 5.47;БĔ;*zU7OU Ҁ g($^ iܸ{eP g&RV۲Ž @$SR̤yT"<`uSYˡAA K ڌsYmbułA"Ifþ,24!5Iغk fhMGܲN2K}dƝ I>]&}FϚEf"/WAu(.C-l j\Qiu<ݴҦig! =sZC /Иc+u Ri!8z3[/zo!ve=b=]n5ANa"WP 4*|p3ڦf"=Mols7&H_>7]c|e=HTr$@`m l3 ү"aI6V4&`)5dK6i8VL`c{!A:AUWX~bk ^%G`" XVۻɁ/ sEKudvpPP.{OkHRg:xb'̳ߢefL+yXduBP5=3 ] @d5xQi'h/J|^mT)# EC'& 6I=D"nȴdbV& SMש)iv]atf-$M0ЙGyf@1Gb9(m$H:8FplB+:Vƈcn`Ef ٦%- ,)ڵwsc6)wSEIF<;!Zr!x[f 2,Z Pa&pFv v$.?qaf͈]h"S^UI~2+T7ltI4]qݦ u"3*v+:tIWk=lNo%  s2=kvx/7<⢶Wh"11]c9.A6BB#mꘆ{ /tԲT"u^d1ѻ. 1nG,jfC2/*v@kUZlXNΤ ډ>&T.h$Li]/#s,anS]ADq>]̈́Ff3̆ myIoS@<Ƕ̘s7I!)CscFYetcCƛTQ -ߌFZ!+gSr6gKGADtqaf[GQY }+p2lWXS)Wx!Z؇_IWïF, n!lg#*7u+3vjyrlRJ.]0m9ڐhY_3MJS6W)üaG)[`|65.dXt{,qedcQbLX[ 8\;!o9O^#ң5joUN_GV؆)N&Y‹G ]E.ZVIH\Yɑ\rN.xuƋ΄I$;PjѮ$vD[δZ6)+~oNZ3}noQmyXhqrL_n_:B#lx )%7;}&ՀaLĒwUEłX Z>U"E{653]튌f; ZA:fqa{*z?$tpL*pA=I}HM3>R 6B3̀弞 wKA|E6dKJŷܷ .4W~c!`cD{:[T1򭨄dWg(ka1͇xoŦ/d8mNa}9w ^!p\Nb/[%{y2}S[SߤboR &Df:-vpdTZ_]J'v̬q8$zKoBaWc7q{(=AȦٮKkW};<듾jendstream endobj 59 0 obj 3091 endobj 60 0 obj << /Length 61 0 R /Filter /FlateDecode >> stream x[[#7~?pC?/QI}$M`,$/]Vdgΰ0go|{__Ley}M?ݷow߯/lr(BJtw#)p=si/0R۳Ozw>>",2ڧS#m/H g\Gz' 9+*N/RgC&nㆃߡ1LF|r!FuE׬Tj!TU ҭƁuDzg3]_hv(V zuIbBI[ )$ZTkt&O c0,M+>t !="y%& yo宪adFD%o[-uVO^Uסkf s2X+`- .*6YP" |@ 34FNՠUpZHbP-8!tu(3[鑑+S <{W0rbHzNAW3I*ە=%gy^iIN"*}ߏ{6c.DgQTbj=ԃX/B AyQzIOiYH IjǕ-:IesJ+& @9&R\N/K7M+"I /YES1)I+;U'V87G&G#%^)ZAJVl.tfV `3l=xxg26!L6fB~b*P*k'2DZT<ĵ4l ^葂LM :xS^T qN/.E-JsH)67aj9װB_8La؃ L1Hm(k$gD5[(v,OqW Nچz{6@t.y a!-o] E[/hU$^RM=@fI w``ge#3)sJAHLP{1NsYy*gqٖ Yz3Yo ߼hPq5"]Y}kޔJ][G,`zwt?#N,"HF=Mhat e Ϫ6{P0*h$iKa/dbhE+Miż;KAT֨b-alg$>mFд)>b)-&*&2O-!6p"N!qӓID.Z̐55P fyPC ץC#e2JFBG~,]3i%$}!y+lK|NbqŧWC&2g\$knJLnF]3,OĖzdmO]Yh'crtwjE +-F_oN5 hh|jBwF%?5?rQcTU[ݪ2xfp}}Ďeəb}a-["̼Jji8P-Hk}M8'X)S]pFu𱒜4e-KCza&O07OZi_KֱpvG+tpNeL ۚ1:2wm<YmOuB ޜ(US}tVCr_xm_` q 'P.͈0U&d ϪCy5d"$turt7 K `0yw5~_d1ayo8,1CۘV([ eAd ~=H=`З׬_T0pR4MO h-]ht>JL9`|~ғzF- Fuk!z?~-R޿`8a$څ%yAjj)YrLcSm|Pu@`W']}ǞO;׸I`6?lW",,p^0?`Śr*04CЖjACߨ}9e D_qa> stream x\Ɋ$77?බ\4?XYU"TetSP(ec6'Kq_?~%u?LJ7 Oo&n^| o^}|8g>iy|Xwg'OdHx`tQ[{gv}U4l@6e)X}R2'0 Wmź#JFzXF:Ž y.sCy8eIȓ4:҃GP,ᥑDG`lcJo@T0Ga$)ܵCFgL)J1A1)aJVWb{h Ca8/n N#NQ'5e+ Ex:ֹ. ջe}&IJia@'գkB${)X) g~ /qo]jUD6UJ. \y"m9fۍw&Dp[#xZf kڞ^1jR5_pE|-}V NфMy{ LΡ-Yu\;v˺]tU^䞦r}i+Uh$6Ug}Pe^kv qWL෋~)B@8^B—RlJZ%|a;k0KY*gipPx]$9~3&% \mVNJIi5%sȦ*sVǐDaLS1*K(@*៪|^ɴ=tP1Qal]0y)ܮe5pZHAmr*jqƶ2TVIdCJ {$-Qe1}˰iFhdTd` Zuy:2lTB> vwr:+l…]v޼)6ż<?5)yrƬ&n)IP }4%R+TnL$WcWC:ҺVL˱yjj*)YXv%*4E>lڻc lw@75xӾwm6;QXx#v `,2 %6#]M9R@ZC&Mq#iL%"**|F|,2faXT=+] %%6pTxYCU3P玺@},SLIHum)6PtEwfcɲQ!!5,6cP!L;R7Bjmh@;* 2*5kRlڇc7wvヰ ޚޑ15}X6{L;}OK_E|H_"4lwNW؝DwKW֠Y &۝Ѝ+$[( T9DV5c:*v'yM &M ޽̻Bs#+p3,nj}2MzV9s4jBԌo|^I%BgVc3êM93~6V([n 0Hy*5w—O'!3)@? C@wM8}ס n"G:n^&- ?s 7A׃D FbY2`5_v 8b|:9z PCYo"n M} X $(]p:tP,Y+DDԚznZWba4fw{MCNM1pWJlZ%Ĺsh^t2pP 8] 1bv%;1IɌXZԱ8%]M/ 1Uj%ؙniߋ `",s (\FZ ut#ǫD7l TSك؄ۤ\-ՐV]l`>nm7q`wwݪ(lڻk30a=Y=@@uVgφ&JsTzXޭnX% #R _o^/8-ۺ7eFkxxQQl6ZJ ϷS^FAh͖e;76f^$d|]׫Ќf"`誐Pe}w2^_Ioqn(6Dj{qr3 3 s92.;Jgk'[&hwʚ"*ώSI7؉!b!2f2en8#Ǣl~d-o~.{F^I,XAƊ!S|1G)JNڽkakAxߖteZUkugi%|tT>gDJ6yp_dyo8ߧ3Ba8u؛X} Wa@ O,4Y+lâ"0l"7NǪYmJ#yL 瑩}%#Qװqb->/{SaA7Ksx>X0; BR X.Y׷Ƥ. *'wH_t5\-1apyendstream endobj 63 0 obj 2562 endobj 64 0 obj << /Length 65 0 R /Filter /FlateDecode >> stream xQj0 sD6:%Ǵ~@8~W$"PvvgvV@aD&;^gjj:O֝V!Gѽa`K+tRRmI1#9g5T綇 rƝMId42Ԋ]ɣOƕ}Ub%$ǜ#t툗/*loY_(t|z;:9l1?0BuM}t2޹?x6ŀŶlendstream endobj 65 0 obj 241 endobj 66 0 obj << /Type /XObject /Subtype /Image /Width 870 /Height 638 /BitsPerComponent 8 /ColorSpace /DeviceRGB /Filter /DCTDecode /Length 66255 >> stream JFIFC   %# , #&')*)-0-(0%()(C   (((((((((((((((((((((((((((((((((((((((((((((((((((~f" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?B(PQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE-SIcwe?oT[z)POQ巪bE?oT[z)POQ巪bE?oT[z)POQ巪bE?oT[z)POQ巪bE?oT[z)POQ巪bE?oT[z)POQ巪bE?oT[z)POQ巪bE?oT[z)POQ巪bE?oT[z)POQ巪bE?oT[z)POQ巪bE?oT[z)POQ巪bE?oT[z)POQ巪bE?oT[z)POQ巪bE?oT[z)POQ巪bE?oT[z)POQ巪bE?oT[z)POQ巪bE?oT[z)POQ巪bE?oT[z)POQ巪bE?oT[z)POQ巪bE?oT[z)POQ巪bE?oT[z)POQ巪bE?oT[z)POQ巪bE?oT[z)POQ巪bE?oT[z)POQ巪bE?oT[z)POQ巪bEG}4v6WwR*[Qp9<%cxD{'m[4QEQEQE>SLcweWP_]ڕ߉[Ѥ]]?wҵuM?L_G*j~&^#brpqS^+E|۪z4)+\42DxA*Tdpdp`׼e7|.lm,m+>6Y0$9=(֧eEyυ(Zj+.WIMRIm.%s$UJ6ܑA_ƺlju]^ ;Ð%MOw>p.#$vq{EGRn(#:b>u@jR#OKX塕&㸛:eG^,cQC\5?h=Ն=I(% 2\] u^i$˱ M~y:A>VMT!?֣Z^yTO<C)#$d o5\,V-Ԍ+"#9f:?j>_ׇ?Xz :} +J3e@x!IOzw|m{4{]tA$ oJH888>Vd?;Cn"i| I3>,x}st=mtJS{qtK+eB)rbsd?_~&a9ѣ&vsT'f2vRAGya]:TԴK{9n(c.w} 9d?}wU=Ěv&n- Xld FGrCG?(b|9}wQCOb>ؾV>!?֧}El_QG+ad?}wSؾ/0ϲj>l_QGQØgd?/(aGnq֥!?֪0 ݪ}?Y~%_ [A\Hm{if2`mS^Ǟ@c elujH@BA#k"^:ִ[NY}e},O08^xgt[Wi'QQ]\Cik5o $V d k;(Ξq%imy5hBDahZCwk ͤo2 #& d2*! %?]ˬ߻_1G#W_2WGE"Nsuk(j]csuk(j]csuk(j]csuk(j]csuk(j]csuk(j]csuk(j]csuk(j]csuk(j]csuk(j]csuk(j]csuk(j]csuk(j]csuk*km[$jn~H\sҷjeQLUdt)<Y<%W?85:u)u'Xn,R  ,1ܓjJWO=I ZUaf4=VKBAmVB[$pF3]FtM:hJݍ"0i*totcB'z*7K2/ZM>Ώ|eEr^:JJ/?Ʋ5+͞o IhTt~V6:֩o}muo3GLo/2~Z_7+gKсiTSyg26@r=Ha%c;JN)*7K2/ZHeﳾܜHy?ƙ-p?⎍Zlju}3N5[є<I!?t2IUTw1-M]cFFA./:. 5u}3R$ɺO: b`y*3@/E^YB6@tuf}CCf((( oțׄ-fk"n^趭(((|v?SM29[69{"I%Үb( O w>A;EJ$r1X`Vx_Y|jojOg\S{_3Zs>F`2K.":w3U&nClb0<t5Oyz&ͨKghӥr*2ҿ>юWiιCfFu5?4<]#eye+78G9(xBWI6x!,-t98%װ=N`* 2Iv8jkhg\S{_3M=ĢN /t?OyA=s^l9Bە 8j?d#B>Yϵٻݎq#:??pЦrо0E9NLA6-^?*<{j [K]uz6%+px!'oιCfFu5?5.I>Vh:evR1 '>g\S{_3G#:t%-F[޹Fu5?43=#: oz?pιCft2eg\S{_3G#:9r3{іs O8jkhA΃-F[޹Fu5?43=#: oz?pιCft}rq7q+ǚI^ܦgv8Y>fu*Wn,g9?ϭIιCf2a>Mnoo2"I;!C®Xp I )Z$Gr=>h@i|7S[м0v.w{q}"3Fvri9+X}Mxd+9%Eb8,=FF}Er_~/ÿ IΊl+(#9n5Y$?-85KRݴjѨ1]`68QLG=H)t?:<~t)t?:<~t)t?:<~t)t?:<~t)t?:<~t)t?:<~t)t?:<~t)t?:<~t)t?:<~t)t?:<~t)t?:<~t)t?:<~t)t?:<~t=t:?蟝Ew"5u' (GZiojk,[{h݈xEVV#ͥiG%b&[FF@ ~y_A$7jrE"tm"#˭tf7:yާ}`rWiHe85i%ޙj60/!I>.:Uw|{ RǦ^DUI7< '=6NVo7l$<1YM¨I٬٩< [eZg8H.+,pz{) XlµVY^'Pe+\A"i4+}V/d ^lw =V҃1#77u]:.-n٣uyKEURrۯ2U16oOoI{oE ^*^ǡ`2G`mE,k$ ,IP8r}TR@i$z,_)ԈEŠ((( oțׄ-fk"n^趭(((S,hfn"oO(/Uu-2 'LXaI> `կxzO Ec}? e'!^)?lXhI+?P|_m26U(9<~LP:+ooG{ztvTWo'ޏ?Q\o{z?|mD_GeEq۾6/ oo@]n7wOtvTWo'ޛ VxbmZ g<H@]n7wOtvTWo'ޏ?Q\o{z?|mD_GeEq۾6/ oo@]n7wOtvTWo'ޏ?Q\\~!Фx ]X ZQ W1YotQ5'@u#XQ\1p-Ri&mkhiL̞pY`m i?H(f7M׿ճX57^ [VQEQEQE>O)}@ 7A?Zcx+D k[4QEV2}fB4Ҹy^Am͝\^?mZF@ڀɖ9e=k|f-֎#jgwϨ>⿴4'|>ִ~2cEgEW?|95dXLz:F[Y-ѥĬF X'J \ţHυ<;?;t]y|"5ݻF==Ex_ 3JԾ%|'Ӆ/: F%`:"^Pƍ7K;}=l&hx.E\[pZ{<6$3 Iwdc $@?$GL—fےP0H$s"{(=EetR\sOpniR[{dEɝd267qR_|\<G"d1V{ oNIm8pЊJۇp%|C('g 02sךCH'1rl#!$t rqٻVgȣ?R {p(rj}G^DKTwV_⹞;eVȨ0øBgz ki)K|=7ZTT.:~"iGܧv<~9q=Eax6:0KԡT6d TH$d⼺{}?Gatk+Ft3,F@dTӼ1w߇K D6CؖyɹPߔRQ7QF+<{mA-l q{u6En3EmK+аUIM.mlmzd`Wdj7v{6(=E|վP=Ġ$F9>\u'9O >&Դ?jW \Y-Ȅg9ˣ[&+;A X\V7Q\ż~'4;΍,4x 힗 ӼOY:4}oTH Ђ#WSN//lTӏsldi(G^YXFp*$cB|=C}es}ݵy Hn8*$ rF8" VSa? XR\EgxƗ A@$uS޼Szi5?$e߇K;J0o3a28-'=STjz` Gq5:[*|bVfQ^AIJ[࿈J^&##\1yB,4ίpn`߆$|k:vRuKgYgk1`˷q]~koY{lW˒~^9< nWI}sgMKF{E. -0f=&H\޺ DImkXD:ЕTؤzׄUaq=./RKP7K# ?'Xo@>ۜqkhiw" $WIV7OO>IĨQ4ngӥ91G;g<W7Q^A+Q_xJӬNKjX,wC&:||1\o :r&)Mc[S9l| D&cq7cQzc_!m]-\/''8y9#& ~ƞu[ö\\%J0eB@Pc Իp3J4=8K|=׈ۃfA7^ WEW iVgȣ?R {p(rk'^Tu i`' WX+#9-:Ӭo]Geԡ!.lN ;{|@|`> v]Eq$i). 8 pv{nM2M*Ig$)0#z8## x4ԡO)}@ 7A?Zs}= yUM>ذT?/DIV8AiծEvkw\&!6;P+O+~5^? ҿ[.\S{8? ҿ[|; ,G,=k%&pwOJiOQjwVw:ewqfe’< w! 9U9ҍgE5Uִ-F\H]³ ` 3F}jd+d+GPԬ-ີbHgA"8ʐA xgOд[e)Ə+ʃ>:w?:w?cU5{մM*` nm#:)ԭuXhZ}@T@ 7N [hdCʹawlsZ:w?:w?>psA.et6a%HToiW]DʹawlsWtߕ ?tߕ \b6*o;;ŽpEc7N@OGN@OG8X}-Kaac-YP Db@$}I55a%,l1V?tߕ 9Eƃ^[i%іw8# jrxoW"X4B KuiB8'tߕ ?tߕ 9lF>5qA^%1maN1U :L6iS,^@#a2|3md+d+7#(?gO#nW{ך>^\ZKykjCFZ>Q>Q!l~ӿi~W(ӿi~W)sv(tߕ ?tߕ 9 Cyf2RjznKgZ[^ˍ\FF *ΙcŞ+e++b%[x:o?cH4i>i}UE_~ma?ڼ|۶ovgd+d+Ô~ekmgg|-X2rp09$5?3qHi W9'M}_'N}_25E#H2QD9EIPSD$Nm0߱Ì1jd+d+s 8SL]( !n6coSj]+I{O666ı&}p ֗N@OGN@OG8X~ekmgg|-X2rp09$5o GbPկ b=X'@s$t:w?:w?B;c[MT'[Md+^MVͶYTnNt,AoiW]DʹawlsU*߬^o[$t2q5>Q>Q14 GMe3{[X`ʁ88jK=D5-/O.]En,N'$Z:w?:w?,sK7ton^6]stߕ ?tߕ 9;cmT:w?:w?b6*o;;ŽpEVT7~o%_ӿi~W*ΙcŞ+e++b%[x,W;UTญdAVVf Wi~l#좎D*d>?;;Ž`/ j&A%'q{8B}wkG;O-jnٿ۞qg>Q>Q9ov:OeϚCc唻I$ ?ok:ŔZ(wo!cVl%'ڽ'N}_'N}_,dD:ΗX ߳6zSѴomK p0 Ns޵?tߕ ?tߕ 9[[k[[hcxGQUE@6*o;;Ÿ8Xl~'N}_'N}_(icisqi7w<øa1\:MVͶYTnNt:o?c񧆣Mb=/"O $.;HkC@hYWd'vϬӿi~W(i~W(SX4F 8$^amdޠ+V]{v1-#:|̤N@OGN@OG8XPEGF*?QSd+d+sv(tߕ ?tߕ 9;cmT:w?:w?c6S:ySȜ觫tip]<FR5S-hiKs6ȳ'|Dui<)1 ׷MӿݛD=X%_;ٿC׹6"}EW͞э_uEl7M׿ճ@Q@Q@Q@4|v?Poeuv8ζK^Jߋ? .:[2*;scc}k<9"'UrGj5_^j:­F[ɞy?wY$w  /'?J.N gi [mb"Q)'I[' ZwB:_:OCGs&gkwğ%j?k+cw:2zڻM>goB%pAz*ek W}({>TU]o}(W}({>EU{>7Ͻo"-QUwϽo"m UV>,oFUkA>i&<ր4誻FP*Q}j}o{oEZ{E@FP*Q}i_j,}@G/Y{gjP*Q}j}o{oEZ{E@FP*Q}^ŏv?-f]=ߟgN11~g}(W}({>EU{>7Ͻo"-QUwϽo"m TU]o}(W}({>Ut/j7Ͻo"X=`6^W}({>EU{>7Ͻo"-QUwϽo"m TU]o}(W}({>Uo?o{EV{>tbchN}o{oEZ{E@FP*Q}j}o{oEZ{E@]эV2<yw{oEZ{E@FP*Q}j}o{oEZ{E@|XcޭV|pnEN HX~EhP\ď_(j~$ȧ7|Du/>TY_v/7ze K_j)w臯GC(=ƿ&?j٬oțׄ-f ( ( ('ݏi>SL S>Si)kxZMZ@T0Gْ@8X|z|?)k4^xx نg剶C8/) zIhgs>Ҵ}j\.iZ>Cur;6'OM8y2I 3F(QEQEQEQEU[EZc]zEPEPEPEPEPEP]7=KU]7=KPEPEPEPEPEP[EZc]z@Q@Q@Q@Q@Q@U봿1U봿1Q@Q@Q@Q@Q@U[ժy?跠 TQEQEQEQEQEQEU봿1U봿1QEQEQEQEQEU[ժy?跫TW3#E9J#)_6QiK㏩>x-ݪ YگJn!qP">+hxOڶkƿ&?j٠(((cwe>O(ǂ4MSwytb=B5TWt+ddeUkb8!u%ƢۉHl)kq4RgӢީq6NP&N R"?\wy_5¹Կku+wΓIi\sU 8Ku"Eiɕ&pg9=*'ùlsp3Դg:|_m~*#*gYϝ_:|Z*gYϝ_:|Z*gYϝ_:|Z*gYϝ_:|Z*gYϝ_V=[XiH F9AZuV>,o@uߥ ?/U(uߥ ?/U(uߥ ?/U(uߥ ?/U(uߥ ?/U(uߥ ?/U(2͠rְ2cg:|o{vF5Z _o~(β;oV _o~(β;oV _o~(β;oV _o~(β;oV _o~(β;oV ˫ E-4#?_o~([ժe>v/Kje>v/Kje>v/Kje>v/Kje>v/Kje>v«XXY Z|FLcvꮛ]э@uߥ ?/U(uߥ ?/U(uߥ ?/U(uߥ ?/U(uߥ ?/U(uߥ uahمcUo?gYϝ_:|Z*gYϝ_:|Z*gYϝ_:|Z*gYϝ_:|Z*gYϝ_:|Z*gYϝ_:|Z3,,,-k>l&1;V/QǻicUe>v/Kje>v/Kje>v/Kje>v/Kje>v/KjϚ &c)q忥hU[EZ)_6QtHNo҈J_}H, kW_%7Nvob@Stf_C*Q_6{F7M׿ճX57^ [VQEQEQE>O)}@5}r:$V~]>$۪S\퇃l'ᮧ_:$գe1=B^y<=FmG]nÚǁi"KIYҢ} 0ߗb\mމ?J.RnGv?iZ>Ҵ 8Е] ]+j4q`eOTΟ!?[}Fe({>EHʾe({>EU/FU({>7Ͻo"Q@|Q}j}Z=@q'c:y?跠̽{oEV e({>EU/FU({>7Ͻo"Q@|Q}j^Ͻo"mTPeye1l Y{>4/j@|Q}j^Ͻo"mTP_2}o{oEZ*m}*W̽{oEV ˧A>i&<֬{Ec]z@|Q}j^Ͻo"mTP_2}o{oEZ*m}*W̽{oEV Um@G/Y{gkN_ym}*W̽{oEV e({>EU/FU({>7Ͻo"Q@wϽo"]=ߟgN11~Uo?ym}*W̽{oEV e({>EU/FU({>7Ͻo"Q@|Q}j̰{!lf#;F]эV{>7Ͻo"Q@|Q}j^Ͻo"mTP_2}o{oEZ*m}*3\/>(|ӂ9߱QZV>,oVgGsͯG]5s??Sm:җR*|,K/ZUMӿݛD=X%_;ٿC#ʡD}EW͞э_uEl7M׿ճ@Q@Q@Q@4|v?PgO[:E-yĿP5in٬[XǞ$y}7=G85O hwq틘 R\ӰME>Xk<)/1ZRޡ-ʜUjV3vvZZAoB4@3X''K?\Α |7qkB sO{}H$uaLUW>z ncob~ӊG9ȯX|;v«]XZ,am` lsiU/Qe>v€-QU/Qe>v€-QU/Qe>v€-QU/Qe>v€-QU/Qe>v€-QU/Qe>v€ 7=KVe@`'͔d:`*uߥ EUβ;Guߥ EUβ;Guߥ EUβ;Guߥ EUβ;Guߥ EUβ;Guߥ /?j.-{0Ґ@r69gYϝ_ TU_/KgYϝ_ TU_/KgYϝ_ TU_/KgYϝ_ TU_/KgYϝ_ TU_/KgYϝ_ UWMwƣ:|Vh@iU/Qe>v€-QU/Qe>v€-QU/Qe>v€-QU/Qe>v€-QU/Qe>v€-U[E_o~*ՅfRF?PW:|_m~(W:|_m~(W:|_m~(W:|_m~(W:|_m~(W:|_m~(봿1fXXYZ|FLcvgYϝ_ TU_/KgYϝ_ TU_/KgYϝ_ TU_/KgYϝ_ TU_/KgYϝ_ TU_/KgYϝ_>,oV>k[x."ǖ@s??Sm:髙"k֔8SgYگJn!ŗ-ݪ  UD(=ƿ&?j٬oțׄ-f ( ( ('ݏi>SL qmK|G=Em D c' MY毮[gD·ז;uWr8#±\?dF$֕!ķ$r3:υ(gtmn[]ZD@B1]=Sֺ:OC\o% qZ*`1KO M\|= kd`Е] ]+j4q`eO4tU]o}* -QUwϽo"m TU]o}(W}({>EU{>7Ͻo"-U[EUϳv??ZӢ{E@FP*Q}j}o{oEZ{E@FPǻicṴ{!lf#;@FP*Q}j}o{oEZ{E@FPy?跫Ut~} 8Ǔ՝o TU]o}(W}({>EU{>7Ͻo"-QUwϽo"m TU]o}(U봿1{>`CmEU{>7Ͻo"-QUwϽo"m TU]o}(U[Ѿ}Z=@q'c :*Q}j}o{oEZ{E@FP*Q}j}o{oEo{vF5Zlb9}j}o{oEZ{E@FP*Q}j}o{oEc]zY58)!c-@s??Sm:髙"k֔8SgYگJn!ŗ-ݪ  U# (loțׄ-fk"n^趭(((|v?SM2+xuOyOQ[襯,RTm׆oc(P<b 6IIr)vK`g[襯0𿉴o=;YVV7q+|OwXHQ^,i$LrwV|?ţh:nem,BqZn{+U<>s}nOGzfI >s^I"4hQ@Q@Q@Q@U[ժy?跠 TQEQEQEQEQEQEU봿1U봿1QEQEQEQEQEU[ժy?跫TQEQEQEQEQEU]7=KU]7=K-QEQEQEQEQEU[EZc]zEPEPEPEPEPEP]7=KU]7=KPEPEPEPEPEP[EZc]z@s??Sm:髙"k֔8SgYگJn!ŗ-ݪ  U# (loțׄ-fk"n^趭(((|v?SM29o x#D<-ݥ]>عP(U; oo>XZu{ ]Cto" ,Wqm,T;u|rͼ u2{F=j3:?W>z n|;v/Kj/Qe>v­Q@/Qe>v­Q@/Qe>v­Q@/Qe>v­Q@/Uk E-4#:y?跠:|_m~*W:|_m~*W:|_m~*W:|_m~*W:|_m~*W:|_m~*aaf9kX e1 e>v7=KP_/KgYϝ_TP_/KgYϝ_TP_/KgYϝ_TP_/KgYϝ_TP_/KgYϝ_TPeՅfRF?U/K^ŏv?-Uβ;Guߥ EUβ;Guߥ EUβ;Guߥ EUβ;Guߥ EUβ;Guߥ EUβ;U,,-k>l&1;ZuWMwƠ:|_m~*W:|_m~*W:|_m~*W:|_m~*W:|_m~*W:|VYJA1 Ӫc]z?/Qe>v­Q@/Qe>v­Q@/Qe>v­Q@/Qe>v­Q@/Qe>v­Q@/Qe>v­Q@m6Q?_m~(봿1Uβ;Guߥ EUβ;Guߥ EUβ;Guߥ EUβ;Guߥ EUβ;Guߥ EgkoݓAQQ8Ҵ*|XcޭP\ď_(j~$ȧ7|Du/>TY_v/7ze K_j)w臯GC>+hxOڶkƿ&?j٠(((cwe>O(毮[gD·ז;uWr8#TQj3FvQ;]?TOuZ\:*]+ŶS>1H] e2 z06qMImJ' Z?|IBVvr]HQ@<* .{gڮ}j!+w?J.VDžtev}8ބJ2'VVx|O\-E2}o{oEZe_2}o{oEZ*m}*W̽{oEV e({>EU{>t~} 8Ǔ֝U[^Ͻo"mTP_2}o{oEZ*m}*W̽{oEV e({>EU/FU(2<yw{oEo{vF5Z e({>EU/FU({>7Ͻo"Q@|Q}j^Ͻo"mTPe{4NgVwϽo"EZ e({>EU/FU({>7Ͻo"Q@|Q}j^Ͻo"mTP]oy6 #͗s5Ut/j<Q}j^Ͻo"mTP_2}o{oEZ*m}*W̽{oEV Uϳv??ZӪc]z<Q}j^Ͻo"mTP_2}o{oEZ*m}*W̽{oEV e({>EfX=`6^՝mMwƫTW̽{oEV e({>EU/FU({>7Ͻo"Q@|Q}jϙ ݗHiI oب y?跫TW3#E9J#OR> {A?')|q" O(3ȧ-m/!}[Qin]B|._'YpUl8Gǂ4MS_틘 R\Ӱ;ck- fq}~m lyyj8`ADjw%hwWwqooR\?ޕ@.}jb¹Կku(sSs*&I >s^?\wy_5º=-dH.Zre| YOJRHh_o~(β;oP2W:|_m~(W:|_m~(W:|_m~(W:|_m~(U[e>v«]XZ,am` lsiU/Qe>v€-QU/Qe>v€-QU/Qe>v€-QU/Qe>v€-QU/Qe>v€-QU/Qe>v€ 7=KVe@`'͔d:`*uߥ EUβ;Guߥ EUβ;Guߥ EUβ;Guߥ EUβ;Guߥ EUβ;Guߥ /?j.-{0Ґ@r69gYϝ_ TU_/KgYϝ_ TU_/KgYϝ_ TU_/KgYϝ_ TU_/KgYϝ_ TU_/KgYϝ_ UWMwƣ:|Vh@iU/Qe>v€-QU/Qe>v€-QU/Qe>v€-QU/Qe>v€-QU/Qe>v€-U[E_o~*ՅfRF?PW:|_m~(W:|_m~(W:|_m~(W:|_m~(W:|_m~(W:|_m~(봿1fXXYZ|FLcvgYϝ_ TU_/KgYϝ_ TU_/KgYϝ_ TU_/KgYϝ_ TU_/KgYϝ_ TU_/KgYϝ_>,oV>k[x."ǖ@qWIv wg񍭟W)JMK57xF{_& >xo%O}o|6?}}ܗ<} [O)}@ :E-y4x ࿈|;qwEmu7H]p3j忆tH+}yn}I㹷Uܧ 3?ڲ" z|;&vUh㙘t(NUF;bF}i Q}#yj'9:OC\?J.QO mĕyz<;77#=s_۾$+Q_9[іWiC7Ͻo"-QUwϽo"m TU]o}(W}({>EU{>7Ͻo"-QUwϽo"mMwƫU`CEU{>7Ͻo"-QUwϽo"m>,oV2=@q'c;@FP*Q}j}o{oEZ{E@FPǻicQ}Z<yw4誻FP*Q}j}o{oEZ{E@FPy?跣}*{4Ng@tU]o}(W}({>EU{>7Ͻo"-QUwϽo"m TU]o}(W}({>4/jYy> #͗s5g}(W}({>EU{>7Ͻo"-QUwϽo"m TU]o}(W}({>/?jkwe/pRB>[*+B ~$ȧ7|DuW3#E9J#)|q"%_;ٿCՋ/ZUMӿݛD=}/<GQE|57^ [VcxD{'m[4QEQEQE>SLcweV< NK\/@IW$-|*33$S+r)vK`g[襮/AO-NLH})Z;0ҿE 0ޠUrJ{'(rsňDghđQqY&5-?[>yi<"Ir OωEBWL-Q!c$b=+U<>s}nOGzfI >s^CLѢ*QEQEQEQEV>,oV|Xcހ-QEQEQEQEQEQEWMwƫUWMwƫTQEQEQEQEQEV>,oV|XcޭPEPEPEPEPEPUt/jUt/jEPEPEPEPEPUo?jŏv?-Q@Q@Q@Q@Q@Q@t/jUt/j@Q@Q@Q@Q@Q@o?jŏv?-HNo҈릮gGsͯGZREO)e K_j)w臫_v/7z_$yT?(1k"n^趭xOڶh(((}O41T{w]>عP(U; _5/\wOԮnhiծTpU0I]'euv8ζK\^⿴2|&vzhxJy$6sMZ.1ln\ ÿRCb,o@uߥ ?/U(uߥ ?/U(uߥ ?/U(uߥ ?/U(uߥ ?/U(uߥ ?/U(2͠rְ2cg:|o{vF5Z _o~(β;oV _o~(β;oV _o~(β;oV _o~(β;oV _o~(β;oV ˫ E-4#?_o~([ժe>v/Kje>v/Kje>v/Kje>v/Kje>v/Kje>v«XXY Z|FLcvꮛ]э@uߥ ?/U(uߥ ?/U(uߥ ?/U(uߥ ?/U(uߥ ?/U(uߥ uahمcUo?gYϝ_:|Z*gYϝ_:|Z*gYϝ_:|Z*gYϝ_:|Z*gYϝ_:|Z*gYϝ_:|Z3,,,-k>l&1;V/QǻicUe>v/Kje>v/Kje>v/Kje>v/Kje>v/KjϚ &c)q忥hU[EZ)_6QtHNo҈J_}H, kW_%7Nvob@Stf_C*Q_6{F7M׿ճX57^ [VQEQEQE>O)}@5}r:$V~]>$۪S\67OZUn1C$WOiX} lKl,ꣁGdwb,nGlxZFY_O[Wi D;/_BljtIh^Ͻo"mTT^Ͻo"mTP_2}o{oEZ*m}*W̽{oEV Uϳv??ZӪc]z<Q}j^Ͻo"mTP_2}o{oEZ*m}*W̽{oEV e({>EfX=`6^՝mMwƫTW̽{oEV e({>EU/FU({>7Ͻo"Q@|Q}j̺{>tbcjQy?跫TW̽{oEV e({>EU/FU({>7Ͻo"Q@|Q}j}Z<ywꮛ]э@{>7Ͻo"Q@|Q}j^Ͻo"mTP_2}o{oEZ*m}*W}*{4NgZuV>,o@{>7Ͻo"Q@|Q}j^Ͻo"mTP_2}o{oEZ*m}*W̽{oEV lb9}i_j*m}*W̽{oEV e({>EU/FU({>7Ͻo"Q@58)!c-Uo?j ~$ȧ7|DuW3#E9J#)|q"%_;ٿCՋ/ZUMӿݛD=}/<GQE|57^ [VcxD{'m[4QEQEQE>SLcwefx9;@%R{'sE>ݘi_A"a oP+ǂ4MSwytb=B5TWt*|<ԼQs?RmyV)Q0fmV @*Nj|ȅr4⣑++=K_rWGź[+NL3 >XqJR:*uߥ ?/T EUβ;Guߥ EUβ;Guߥ EUβ;Guߥ EUβ;Guߥ Uo?gYϝ_V=[XiH F9A@tU_/KgYϝ_ TU_/KgYϝ_ TU_/KgYϝ_ TU_/KgYϝ_ TU_/KgYϝ_ TU_/KgYϝ_MwƫUaaf9kX e1 e>v€-QU/Qe>v€-QU/Qe>v€-QU/Qe>v€-QU/Qe>v€-QU/Qe>v€ EZ˫ E-4#?_o~(W:|_m~(W:|_m~(W:|_m~(W:|_m~(W:|_m~(U봿1β;U,,-k>l&1;@tU_/KgYϝ_ TU_/KgYϝ_ TU_/KgYϝ_ TU_/KgYϝ_ TU_/KgYϝ_ UV>,oGuߥ uahمcEUβ;Guߥ EUβ;Guߥ EUβ;Guߥ EUβ;Guߥ EUβ;Guߥ EUβ;Guߥ 4/jYm6Q?_m~(W:|_m~(W:|_m~(W:|_m~(W:|_m~(W:|_m~([ժϚ &c)q忥hP\ď_(j~$ȧ7|Du/>TY_v/7ze K_j)w臯GC(=ƿ&?j٬oțׄ-f ( ( ('ݏi>SL qmi$eMM/5_\Ήo-O 7Ͻo"-QUwϽo"m TU]o}(W}({>Uo?o{EV{>tbchN}o{oEZ{E@FP*Q}j}o{oEZ{E@]эV2<yw{oEZ{E@FP*Q}j}o{oEZ{E@|XcޭVe{4NgVwϽo"-QUwϽo"m TU]o}(W}({>EU{>7Ͻo"-QUwϽo"m UWMwƣ}*y e1l iUwϽo"m TU]o}(W}({>EU{>7Ͻo"-QUwϽo"m UV>,oFUkA>i&<ր4誻FP*Q}j}o{oEZ{E@FP*Q}i_j,}@G/Y{gjP*Q}j}o{oEZ{E@FP*Q}^ŏv?-gϊ$_4अ|TVGNo҈릮gGsͯGZREO)e K_j)w臫_v/7z_$yT? (loțׄ-fk"n^趭(((|v?SM2+xuOxyOQ[襮ONcqjz+jVEř x9;@%R{'sE>ݘi_A"a oP*v%=CCkWbVVc1困$~%OE}}kZz+`T-5x+Gune`ZZO?ҹ߃gu̷͆nw8 R&jtL؟ߩ<>4⣑+$4(aEPEPEPEPUo?jŏv?-Q@Q@Q@Q@Q@Q@t/jUt/j@Q@Q@Q@Q@Q@o?jŏv?-QEQEQEQEQEWMwƫUWMwƠ TQEQEQEQEQEV>,oV|Xcހ-QEQEQEQEQEQEWMwƫUWMwƫTQEQEQEQEQEV>,oV|XcޭP\ď_(j~$ȧ7|Du/>TY_v/7ze K_j)w臯GC(=ƿ&?j٬oțׄ-f ( ( ('ݏi>SL[5O hwq틘 R\ӰZ~REχtJY ZGIX3Tx6W_ho+I#*m'o g1yg*槊/xN]V+G{};I3UĐh'u뷶(?j: pRyʵ<{q]&)/tB-J ԯzV/uzN=[P:ͲiP޴ nA I@^3׵r¹Կku*t{ ][ȑ\\"8{ΓfF ?Zhhe>v/Kj/Qe>v­Q@/Qe>v­Q@/Qe>v­Q@/Qe>v­Q@/Uk E-4#:y?跠:|_m~*W:|_m~*W:|_m~*W:|_m~*W:|_m~*W:|_m~*aaf9kX e1 e>v7=KP_/KgYϝ_TP_/KgYϝ_TP_/KgYϝ_TP_/KgYϝ_TP_/KgYϝ_TPeՅfRF?U/K^ŏv?-Uβ;Guߥ EUβ;Guߥ EUβ;Guߥ EUβ;Guߥ EUβ;Guߥ EUβ;U,,-k>l&1;ZuWMwƠ:|_m~*W:|_m~*W:|_m~*W:|_m~*W:|_m~*W:|VYJA1 Ӫc]z?/Qe>v­Q@/Qe>v­Q@/Qe>v­Q@/Qe>v­Q@/Qe>v­Q@/Qe>v­Q@m6Q?_m~(봿1Uβ;Guߥ EUβ;Guߥ EUβ;Guߥ EUβ;Guߥ EUβ;Guߥ EgkoݓAQQ8Ҵ*|XcޭP\ď_(j~$ȧ7|Du/>TY_v/7ze K_j)w臯GC>+hxOڶkƿ&?j٠(((cwe>O(毮[gDז;uWr8#&'0ekFѰVmmڛ0S>Si)kӼE9\hi>$Qwff`sE;!%M[ZkȖR($v7aO;WaORi^3,0 lqsl7kg%ܱBjP͞H!Bo|<׬M&Cur;m,ym}*#*m}*W̽{oEV e({>EU/FU(UkA>i&<ִ|Xcހ2}o{oEZ*m}*W̽{oEV e({>EU/FU({>7Ͻo"Q@y> #͗s5g}(봿1U/FU({>7Ͻo"Q@|Q}j^Ͻo"mTP_2}o{oEZ3.ϳv??Z}^ŏv?-U/FU({>7Ͻo"Q@|Q}j^Ͻo"mTP_2}o{oEZ*{EV{!lf#:ǻicP^Ͻo"mTP_2}o{oEZ*m}*W̽{oEV e({>EU{>t~} 8Ǔ֝U[^Ͻo"mTP_2}o{oEZ*m}*W̽{oEV e({>EU/FU(2<yw{oEo{vF5Z e({>EU/FU({>7Ͻo"Q@|Q}j^Ͻo"mTP|pnEN HX~EhU[EZ)_6QtHNo҈J_}H, kW_%7Nvob@Stf_C*Q_6{F7M׿ճX57^ [VQEQEQE>O)}@E> lo(>18<%i+GwfW@HB <1T{w]>رP(U; _5/\wOԮnhiծTpU ڟ2!\De?JI)D~gF\$6Ao5xX,neYDbeK$Hri-u|JexăT]EAR_EƊıYחU z; I >s^?\wy_5º=-dH.Zre| YOJRƑU/Qe>v e*uߥ ?/P*uߥ ?/P*uߥ ?/P*uߥ ?/Py?跣:|VYJA1 ӢgYϝ_:|ZgYϝ_:|ZgYϝ_:|ZgYϝ_:|ZgYϝ_:|ZgYϝ_:|o{vF5Z 6ZO(ɌtU/Kje>v/Kje>v/Kje>v/Kje>v/Kje>v/K^ŏv?-f]XZ,am` lsYβ;@_o~(β;o@_o~(β;o@_o~(β;o@_o~(β;o@_o~(β;o@]эGuߥ aaf1kX e1 ӢgYϝ_:|ZgYϝ_:|ZgYϝ_:|ZgYϝ_:|ZgYϝ_:|Zc]z?/Uk E-4# :*uߥ ?/P*uߥ ?/P*uߥ ?/P*uߥ ?/P*uߥ ?/P*uߥ ?/PǻicṴh@Yβ;o@_o~(β;o@_o~(β;o@_o~(β;o@_o~(β;o@_o~(β;o@|XcޭV|ֶ]4EH%-+B ~#ȧ7|DuV',q`HC!$g{UA2dzKg2}~7V ?tSOt 731#R䧅q(xOڶkƿ&?j٠(((cwe>O(7;@g[襮/q_ISi>|c?kxsW-3Eg[uOͺ9P^kskxăS2~#h+6⋶mMQ s>==Ý>F}=&ͭ i.O[ id?V'djOjwm)ӥisn9 ݴKq1Z?۾$+Q_9T&tt50M\?J.VDžtev}8ބJ2'TtU]o}* -QUwϽo"m TU]o}(W}({>EU{>7Ͻo"-U[EUϳv??ZӢ{E@FP*Q}j}o{oEZ{E@FPǻicṴ{!lf#;@FP*Q}j}o{oEZ{E@FPy?跫Ut~} 8Ǔ՝o TU]o}(W}({>EU{>7Ͻo"-QUwϽo"m TU]o}(U봿1{>`CmEU{>7Ͻo"-QUwϽo"m TU]o}(U[Ѿ}Z=@q'c :*Q}j}o{oEZ{E@FP*Q}j}o{oEo{vF5Zlb9}j}o{oEZ{E@FP*Q}j}o{oEc]zY58)!c-@eA]bыZ_?uF-5ZW[a]DSi7"QAF7M׿ճX57^ [VQEQEQE>O)}@:<ӭR'x1r5=FmI5 {{{_+aJbr T|?)kP|cpxKS"JV4 CL0G|7\ďi~0tA#6!{F}s`c.MC WIHdB} eP7˽@V exDբNt|w<.̂Bp^/ ]w#HRkM*mf;~@~b `r{8krd9>W'#3b~ӊG9ȯJI!hE ( ( ( ( y?跫UV>,o@(((((ǻicUǻicU(((((y?跫UV>,oV(((((o{vF5Zo{vF5Z(((((c]zUo?j(((((( o{vF5Zo{vF5Z((((( c]zUo?j /+/ĿZkp-i7j_mvo%pEj(oțׄ-fk"n^趭(((|v?SM29o x#D<-|gO.c.#_J8UpN©iWK>+f'{x5k#a&`Rw{WI]|?R$ p1杞;$ ᶵM^}N9[}v­Q@/Qe>v­Q@/Qe>v­Q@/Qe>v­Q@/Qe>v­Q@V=[XiH F9AV/Qy?跫TW:|_m~*W:|_m~*W:|_m~*W:|_m~*W:|_m~*W:|Vh@i]7=K/KgYϝ_TP_/KgYϝ_TP_/KgYϝ_TP_/KgYϝ_TP_/KgYϝ_TP_/KZg k )#c+Nŏv?-β;Guߥ EUβ;Guߥ EUβ;Guߥ EUβ;Guߥ EUβ;Guߥ EUβ;Guߥ EfXXYZ|FLcvgYϝ_MwƫTW:|_m~*W:|_m~*W:|_m~*W:|_m~*W:|_m~*5vMFR DJЪc]z@eA]bыZ_?uF-5ZW[a]DSi7"QAF7M׿ճX57^ [VQEQEQE>O)}@5}r:$V~]>$۪S\67'h>&c[Am<dVP8OZ[˿WOiZƗw,I%^q*qiɉ' ZΌOЉ\v^JJO[ޥh^Ͻo"mTT^Ͻo"mTP_2}o{oEZ*m}*W̽{oEV Uϳv??ZӪc]z<Q}j^Ͻo"mTP_2}o{oEZ*m}*W̽{oEV e({>EfX=`6^՝mMwƫTW̽{oEV e({>EU/FU({>7Ͻo"Q@|Q}j̺{>tbcjQy?跫TW̽{oEV e({>EU/FU({>7Ͻo"Q@|Q}j}Z<ywꮛ]э@{>7Ͻo"Q@|Q}j^Ͻo"mTP_2}o{oEZ*m}*W}*{4NgZuV>,o@{>7Ͻo"Q@|Q}j^Ͻo"mTP_2}o{oEZ*m}*W̽{oEV lb9}i_j*m}*W̽{oEV e({>EU/FU({>7Ͻo"Q@58)!c-Uo?j /+/ĿZkp-i7j_mvo%pEj(oțׄ-fk"n^趭(((|v?SM23<|?)k4^xx نg剶C8/) z5O hwi|gO.c.#_J8UpN°`V ^1s bG=fb#$sT3bI3]״!-r q4p\M$eRrA+O=^&jQ>I[;`g(Ϯj|<5];Lյ+}KP8m?YF؇bHR[|;v/Kje>v/Kje>v/Kje>v/Kje>v/Kj_gYϝ_m6Q :*uߥ ?/P*uߥ ?/P*uߥ ?/P*uߥ ?/P*uߥ ?/Py?跣:|VYJA1 ӢgYϝ_:|ZgYϝ_:|ZgYϝ_:|ZgYϝ_:|ZgYϝ_:|ZgYϝ_:|o{vF5Z 6ZO(ɌtU/Kje>v/Kje>v/Kje>v/Kje>v/Kje>v/K^ŏv?-gkoݓAQQ8Ҵ(!_1kRK Ŧ֛Pl?*m7=Vf2PV((xOڶkƿ&?j٠(((cwe>O(7;@g[襮ԟ$N]>;[ԇeLJG^nsW-3Eg[uOͺ9i N[m;(RJ'']9Oc3G{<0Śpݎ~q^Ikt50M\?J.VDžtev}8ބJ2'R$tU]o}* -QUwϽo"m TU]o}(W}({>EU{>7Ͻo"-U[EUϳv??ZӢ{E@FP*Q}j}o{oEZ{E@FPǻicṴ{!lf#;@FP*Q}j}o{oEZ{E@FPy?跫Ut~} 8Ǔ՝o TU]o}(W}({>EU{>7Ͻo"-QUwϽo"m TU]o}(U봿1{>`CmEU{>7Ͻo"-QUwϽo"m TU]o}(U[Ѿ}Z=@q'c :*Q}j}o{oEZ{E@FP*Q}j}o{oEo{vF5Zlb9}j}o{oEZ{E@FP*Q}j}o{oEc]zY58)!c-@cqJr*t3pkbW J##Qt-G6W:~i1LVP_rVjWWq&HlE9ߴK}+Ě͊HҭOy"?-UU vbIbOs'APԚvWί<[O82qI-uER,xOڶkƿ&?j٠(((cwe>O(TOuZ j(>*Vd.-vd)=+`;}ކ?"huZM*מ$"5{vaYybmwN @*Z/Zk,3F#"FVAW,4ņA'p8^jm}wA p aku{F7X][!db%%FX mUa.JV@2cx#@P6n}}*tL؟ߩ<>4⣑+ҒHi4QE@Š((((ŏv?-U[( ( ( ( ( (*_j_j ( ( ( ( (*ŏv?-U[ժ(((((*]эV]э@((((*|XcޭU[EZ((((((]эV]эV(((((|XcޭU[EZW O(+ O҈}ƞ𮺖MoA.#h2Jd1z W[wE,ZiBYf 8sƞ,]<f.d*1 Coe}`[jNk"Hi!Q$]Eܢ*K1k"n^趭xOڶh(((}O4d^!L(DHcnBPS??vZ( #@{]??vZ( #@{]t 6;[k8ILN]cxU( ϕyvi~- VR@XO.|?ФhmIRlx9]:yvi~]ZߡKEaVR@XO.|?У˶+O)h,'m>VQϕP˶+O( Z( XmT`YZ'KϕP˶+O( Z( ϕyvi~- VR@XO.|?У˶+O)h,'m>VQϕP˶+O( Z( ϕyvi~- EFRy( ϕyvi~- VR@XO.|?ФhmIRlx9]:yvi~]ZߡKEaVR@XO.|?У˶+O)h,'m>VQϕP˶+O( Z( XmT`YZ'KϕP˶+O( Z( ϕyvi~- '~UZş蟕A|}l1De   A( 9RAam *tO:iBFqժ( Q@57^ [VcxD{'m[4QEQEQE>SLcweQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEcxD{'m[5_uElEPEPEPM2'ݏiQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE_uEl7M׿ճ@Q@Q@Q@ȸ+eanyo6=TBrOs*> stream xZۊ$7 }@z}r+qa 6abwd%=}=:6gèM;?~}}Mrx{}N~?O3h35|ח1VZq>VΉSrqG#v{_]skVjuT\_`?j}kv2g m:6xǝ/y2*a"ÎcӺG9B1W%Gb%Lh}8$@Llʳ]HsjA@_eh)-|yDzdn}jF%!C3wM:rI/?wG'xJ3(2#.t6ЍqJO$l udr E0ݠ]L),0`> ZY!xU"Z-RC<ç\\t68TR=B,rѾCwkZAw@/p'mE$[q%"Dz4 Ʃ8n4V9lRO2H%%K*wKBn.%YLח2P0 9:3N :@+8J4-͉Rp_~ J[؞)ƅ: 1%::ʂ(d_1'ߓ&1ML8cWec#EBAyȵlxkbZZR_oy9_ÈgebHY㤂vU:r8u~ϘQ0`Ww*؈QF>S5}S[gbT XRi["~VQJ@^B˰Pժ|DjHo@Ɣw*n**j+JIథ![s_AeŮY/9zQ0=/\lk%ќ~Is%A(;DcH YMC`un8~y^Ŝ0ߤT@Z2=^CYԒ;v׎U f+\*aQKZe/9CQ{ bhn T_DbKJG(j͜x˚ b@R657T3b&XKڞΑA 2K?ҩ=>=]wȣBuSsJQ]4RΜ$ۥ3""\ ISBWl= hs]z ȅmVLXC^j#P #<0ñ5+ p_Ûrı=K> stream JFIFC   %# , #&')*)-0-(0%()(C   (((((((((((((((((((((((((((((((((((((((((((((((((((hP" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?BTIO[eީ}"cJ#(#rNI-_Q{Xci%),uɐ(޲m Aޣ9'2~[iV)ǺL+n/-SymئQ^-SymئW##Ow:-#S]Uޤ8 F+j*b**Ty=j*|OQ巪bD;-՜C̤@U :g?4u,7bP[͍ `rFzcjk_֡{YymأoTs ^jz-*E2U0< $z[)N*+5;[z(?LcOQ巪b>|-Φ^[i2݂=bu;-՜C̤@U :e;F6w7FU+F3-Symد|3AOW]Yqf%ۀ6<'$g>gSЧymR,xڬQd#К!euUz:ѩymأoT2GmأoT2ީ}/oiuQEs&y⋛I*H0e#APEExCZwɪKmKq6-^]c$NqkQ֣\qR"{N3tqکGQ\+'x<4:uŊysjN&'Af_*q귮|Yu=?Mő Eb(e1lgh@'~g^sP|_TڌzL;$4eq\]}RZy F,Q0s#AsFZczޱ :OonDRW"8 IxҴu F sIҍΟs}TT9cɬ_z, m :CyqFPG$@t77W3+zo4ZfoPt(TRǒ9s^e_A!7IM{KQH,? p# cWC e(~zlyy?-z \ : nVEup>6snS#+( P*Drrs#=;ěKM>z[:Όb66z75O~{d\5Z]Hw FxHS޹ C"8cy$qfc$2(cWZjIJރ{jŽ5^ T8 sZ:LJKM:K>v w NVwCGq>^&]%޼DLMUxN :%ޣ#EkVfnp(a\!?֣Z}}E>V>!?֧}El_QG+ad?}wSؾ/0ϲj>l_QGQØgd?/(a3ZjQrCA#Ob߈_G+1`Zd?_a8(OI*[$)eKqϨ^a|IR{^]IkoFoWby 88╘z\2r#uvsPYC!5 Z=hЭ'>`5d8՟Oak-וomq}g>.Zt:H]G $1g? QM]LK*Dc8cpd)m{ 5̷R5ĮdY;ĞI'ׯ|%t?+EڑrHػ0}ɵ;3Rʻ=22=+Ƒ)4:6kuSg" '8{KImg';|{U=%O>x{7wE1Js$ci=O54WE]"xGя5_k++###`|q񥏎|nu-* #-Qivvt:GϩCXeE8ue͔U`y xTd>~57/W_bFe?ݯuk+=j]c?Xvb:(j]c?Xvb:(j]c?Xvb:(j]c?Xvb:(j]c?Xvb:(j]c?Xvb:(j]c?Xvb:(j]c?Xvb:(j]c?Xvb:(j]c?Xvb:(j]c?Xvb:(j]c?Xvb:(j]c,&Gd2zYh_3xöOM56mZ4,$$db@8<Jg/%o͋nxcXXO`y2Z|gxHkA|J"Ko'ݜ1]>$ _O|#"_946ّ6&#3*aZ<.@ qss~XČZCԞ%3GfѼ'wMYYAm#FIR 2=yY [<ZӬY&blH*ptֹ2}?]6k[$[%v7H|q>^º熵}ro ţj-,T}J<:*J8/x_Zp\WVoKF(̙X -^һ(qzN=<6<AJ(0MBZ]sLI4#[-ʪtFLRฌʐ 5\߆GMsScFŹXnI' N9xV[?[3xU'uOxWV,'6;FQ<N r*k>"4h/;nQlYmfQ{Mu2<,3S0GJoFu5?43=0gt=%4Iu5ioA" A@m4ς1ǨMf!lel9l3=s O>uk ^XupxkU5KQ ^Z<m'+2>m[QV ,ϡŖck5 ]#:??pW8X2eg\S{_3G#:|9e{?ιCfFu5?4r{іs O8jkigA-\#:??p΃[ތs8jkhg\S{_3G:Ftoz23=s O9e3^gOKs O6O 2IE<5G$~4r3Rէ\A)$4lcp Yp} Ƽÿ;zh9+KۖrۣwRO'{7f}mŵ䜟cKιCfizD bOaP|:b فПU7}Oڍݣ $1^V3uV6ZEoq RwUoiIjU+Gw˖000Gyngxjync*iml9,f|;x砢ɾ1| VncB$M T\߂nxE\-Gᯌ&XÚA;Rܡ)I"Rn $u<5gr~6Vsn /Kv?|+i/ 0PqF~4xrG4#K.2VcTHPq@[l?:<~uǛq/6Ҋ-Ni>gOΏ:?蟝xyDyDyDyDyDyDyDyDyDyDyDyD2>_UG=ነGGe|>Pۼpoide*$Wl9_O/aet;&\n#r_UYI,(x, UՊ27139VEhvޟaZO~LִgİIi#6.J 1K;Y ϶:KNџO+崶+JNIq^QkME!RS]n>]zRt(C=c8a]iAie$\;\픘6#ԋM 7M$x-> #Y'2I!O r9ʩW^[?"u8}HQ*'.KtiF4R}mOI?ֺ ̲jմq"E'ETT\>ڇKc>?)ο[o%Pĸ9`23vk&)!rE"d`pT Vv\K-jc-Xb#̀VʌNpG?eq}l %xyu櫇R|N#m./.m2;`pp?{? 4VG\qm#--T2,f0\?-IE׶V2H<6:=ݰ2+++5!E+JIlJ1M21ENuUs*~^_pSj]4qI4he\oe`EixJM$ X ƟçiڜЮȡM& }L}Iy$z֟#MWR_N$HȪq 'МWTiuINc+ ( ( (1?r?F\cZׅ)}#LcM] }kLXأXA<L2?#vG'΀0* h2?6Ol:2?{IƷ'9:ސO}4xoz?5=͓z?@xoz?4GW@]5=͓z?@x{OG4Ui?'Ώ6OaUN??M 'Ώ6O`M  77\_[l:/oh3ΟT.6]w0Q‚O,|[x|-eoZ#D6w`rJ9?j=,;O? -@qHUMմ($FS>q@eA|Ǡ5G f{.uci9r@9i.,(\"901lN9),uɐ(޲m Aޣ9'~?Vܻnl=W7fúۻ9VT 6:`UT ]>jiY?&´?@mSU-Ҭˍ:kiXHnF+|_xzO #M;3ѹEauTGDn$U,Gg t?Rdn7;*+ooG{ztvTWo'ޏ?Q\o{z?|mD_GeEq۾6/ oo@]n7wOtvTWo'ޛ|c4),yVVevB s#Q\o{z?|mD_GeEq۾6/ oo@]n7wOtvTWo'ޏ?Q\o{z?|mD_GeEq۾6/ g)K*ա F} @dQ\o{z?|mD_GeEq۾6/ oo@]n7wOtvTWo'ޏ?Q\o{z?|mD_GeEq۾6/ oo@] K@Հա]sF;wOtvTWo'ޏ?Q\o{z?|mD_GeEq۾6/ oo@]n7wOtvTWo'ޏ?Q\_$>1Yo/oh_N̬/)9 DCqtLx} k0=h.eH ua?~';6:śﳚYc `g*N~<x{Q{ n{+2cpe$08{Xcra5V]WsέM|ck P$u e}+;z3ۜs{W Eg?Ygmj[[IKE9v;2A%W֧ùr^mEi# hѴ˖,l$dTH ԢbrszX>U'>û"־׿@_iY Ǯl@q&}F?RJy>:-E&- ѭv*3#(>WΟ>b_q߉[{k]lY#Iq *wcznoZ9EsQzxѭtNҚ@zp.Fm+#ZּIhC_^o_D)aFsҗAϭyn͒{j;3uM#4jsxr[{nG  אBY~x3-ٶ?ϓ-? yթa_KvnVRKU )y" iVgȣ?Q4QY NG7?U=&B'=?鼔rBѼ6o :ZYI#j"FO= uVe{g%xn{fD\@@s#cwczƣ_GWFSr ,Hُf[?QݏQX^M-cIqs\(Yd9OzXmτ~sD]㞪 aUfm;Dw^Ae "eE*0*>\Nei"6ahvmm\nznCӴ}?Nlww7=O?$fI bU&uQeP? =pۇp((=Efyd+bq{^wȭ3|Ty0Nrũp>2ӵ?QKK?+sIuw*rNgpn- Hdy]nI Ϟ+Mw],,L.b,! Ol⠚W>j1y֯\s(`,88F@G"N}O7QF+i|C|-ix\iii}he=ߝ󯖒F@9[ k {esu<6ZTMNٚ5ira"Kۇ/ X:z\'^>7n"9^F xcIyhIBXY\.tŋ09Il_'luMAZx &fjGB/8inW։^׼M)?B׍-NV$q HsF Nke!Ei糾{ ( fH\qr:"nǿnWx4Zƍ2;= (K!¬NH 0YIt ,.|8ujvAci1.y"cIFngo|zo-Qߊ|[SkKCxZCEẠ/d-}{N0෈W=ZUJvKψ=SIմMJ9$PH܄p nIŭװܪ$: ݭ٭ċcK9,T+ǚZx_J:$ c&4F6H=Eax6:0KԡT6d TH$dRu+ƥ\cmm'Nr1X_|--&imLG[lߋ@_oNmg=Eu i ?Ҵ{x4K-");xRw9=,|7IЭK^kN.J 6ݷP7=pn֟ Vkf)8fCW~`{K/|96.> Yf$T۴rsN@OGN@OG2o1 $q"D@)c7N@OGN@OO9Hv(tߕ ?tߕ \b}-Wtߕ cn|+f,7Dn:Q! [u,("ı I>.Oo{m^u@gn'=kd+d+s sAgY#Mbnٕ8izej6Z^o\&YA NHڵtߕ ?tߕ 97#(?gO#nW{ךvhƺΙa,G1t!kd+d+s'KNyciqme^,)F18c7N@OGN@OO9Hv(tߕ ?tߕ \bto4l&J>U{2;=V˺VVJ2@T>Q>Q([}彭Ww{>:Fm][Q~ekmgg|-X2rp09$5'N}_'N}_,C?QFEM>Q>R Q?QSd+d+sj?o;ڥڗk1)$lX't-ϙeleFyJ>Q3t6m-Z_(*Wt]IY,$[ !&;6mR|+S'N}_'N}_v麵lombdB}v#Gh>ã6- (>Q>R Z;ߵiVAirz!Ft<`^<1f7t8ҵtߕ ?tߕ 9Xşz jlV̤tÑs}ŭ;ƭ$; `u:w?:w?c񧆣Mb=/"O $.; 'N}_'N}_,PT7~o%RYvזc| OsXqgwJ؉FG*N@OG8XԴ;U6imynX?qț8`FA7ޥ~׺]޲7G$qn*N0q;;Žd;/t/Oӡ ZnaF*whdzmޝc>#DF#tߕ ?tߕ 9ei&uY-`Hpz'N}_'N}_,C?QFEM>Q>Q!l~ӿi~W(ӿi~W( Um5S|m7z>U{6KsY[6eQ%8cqҎp7º[qOqe>,I}ZI:>t9[/G$Bchӹ;;Žd1l9i:Fmcp&9T SIi2Y[ad.ZЩ[vAh0A#ji~W(ӿi~W)4ÙQ&Cmw3hKyep[#wrT(t "?[rZAqvopT(0 kg'N}_'N}_̂<~㲳JӒQ= n C y>g;O-jnٿ۞qg>Q>S Q?QSd+d+;cZPi?ٿL'N}_:ew{,tdyopi~gkogivCoƋIIWtߕ ?tߕ 93o GbPկ b=X'@s$d[|9џƾ# uVx`G!/,fKpx]N@OGN@OG?@JK[!mx@Щ5KF惢3Ht ÛKdwh7;ŽpEc7N@OGN@OG8Xl~'N}_'N}_,C?QFEM>Q>Q3tϘVu6IhQ"EUPPcU-?W'ͯk3;g޽O/^p?Oo] U͉q.}aW)y/oϨdS$Fv_%tf HL袊HƴT Os[5i#^2h2?4ʑO#uZ_aa.p4 }k qOcS]4v-6PY+*+@`3k?ciJ|2zlJql`zmǍ4|=ol\$0GgY~ uIu 4l%ۼڱɔ,Fr:7Ͻo"-QUwϽo"m TU]o}(W}({>Ut/j7Ͻo"X=`6^W}({>EU{>7Ͻo"-QUwϽo"m TU]o}(W}({>Uo?o{EV{>tbchN}o{oEZ{E@FP*Q}j}o{oEZ{E@]эV2<yw{oEZ{E@FP*Q}j}o{oEZ{E@|XcޭVe{4NgVwϽo"-QUwϽo"m TU]o}(W}({>EU{>7Ͻo"-QUwϽo"m UWMwƣ}*y e1l iUwϽo"m TU]o}(W}({>EU{>7Ͻo"-QUwϽo"m UV>,oFUkA>i&<ր4誻FP*Q}j}o{oEZ{E@FP*Q}i_ji{o6\r[;P?kzBI.7 /oiuVjO{i6ڴ*Ptk@Z]+]G7yR&qEe\` {b~&hq"X@|g$נ~(7 leomfgK+ 6NqW>XŦhLkmx%iٳG%2Kc9r;iZ?F>TPIhvc%jÒ5lBVDQE# ( ( ( ( ǻicUǻicP( ( ( ( ( y?跫UV>,o@(((((ǻicUǻicU(((((y?跫UV>,oV(((((o{vF5Zo{vF5Z(((((c]zUo?j(((((( o{vF5Zo{vF5Z;P?kzBI.7 /oiuV)O$E3KjḠeH|c:F'?#ÂUtkD1y}v­Q@/Qe>v­Q@/Qe>v­Q@/Qe>v­Q@/Uk 6ZO(ɌtVU봿1β;Guߥ EUβ;Guߥ EUβ;Guߥ EUβ;Guߥ EUβ;Guߥ EUβ;U-{0Ґ@r69|Xcހ/KgYϝ_TP_/KgYϝ_TP_/KgYϝ_TP_/KgYϝ_TP_/KgYϝ_TP_/KgYϝ_TPe@`'͔d:`*uߥ 4/j@/Qe>v­Q@/Qe>v­Q@/Qe>v­Q@/Qe>v­Q@/Qe>v­Q@V=[XiH F9AV/Qy?跫TW:|_m~*W:|_m~*W:|_m~*W:|_m~*W:|_m~*W:|Vh@i]7=K/KgYϝ_TP_/KgYϝ_TP_/KgYϝ_TP_/KgYϝ_TP_/KgYϝ_TP_/KZg k )#c+Nŏv?-β;Guߥ EUβ;Guߥ EUβ;Guߥ EUβ;Guߥ EUβ;Guߥ EUβ;Guߥ ETRЪ1U봿18y][׸ׇxJw?Mo]wG./g_W|)y/oϨdS$Fv_%u Lp?:(c1?r?F\cZׅ)}#L2b2XK\ >"tFoZu]flǶwm|KcwYl=so4:PIn̬3{Tvr[hC,)f>]Ҵ]Ƴyዻil\!3߇[}OPIhvc%j4U/FU) ^Ͻo"mTP_2}o{oEZ*m}*W̽{oEV Um@G/Y{gkN_ym}*W̽{oEV e({>EU/FU({>7Ͻo"Q@wϽo"]=ߟgN11~Uo?ym}*W̽{oEV e({>EU/FU({>7Ͻo"Q@|Q}j̰{!lf#;F]эV{>7Ͻo"Q@|Q}j^Ͻo"mTP_2}o{oEZ*m}*t~} 8Ǔ՝o>,oV{>7Ͻo"Q@|Q}j^Ͻo"mTP_2}o{oEZ*m}*W}*y e1l i]7=K2}o{oEZ*m}*W̽{oEV e({>EU/FU(UkA>i&<ִ|Xcހ2}o{oEZ*m}*W̽{oEV e({>EU/FU({>7Ͻo"Q@47.@9ޭ]7=KP^(W5{xw?^sߗrq+U}E{'Ÿ'7+WO?O4oeW^i3+=#G-S-?el5ZxZ˚٠?4|_x+*PtNuZ4]c:}}")&[R>d ΁=|I+7V:ޥ͏y/%to6SP+{|J)λ[8f/ V d/ߊ<3 hW:ƻ.k[leѽn*9',p;~Wb"y3&nN^@8A*Oѱ?X|;v¦NE*uߥ ?/TEUβ;Guߥ EUβ;Guߥ EUβ;Guߥ EUβ;Guߥ Ut/j?/Uk 6ZO(ɌtPW:|_m~(W:|_m~(W:|_m~(W:|_m~(W:|_m~(U[e>v«]XZ,am` lsiU/Qe>v€-QU/Qe>v€-QU/Qe>v€-QU/Qe>v€-QU/Qe>v€-QU/Qe>v€ 7=KVe@`'͔d:`*uߥ EUβ;Guߥ EUβ;Guߥ EUβ;Guߥ EUβ;Guߥ EUβ;Guߥ /?j.-{0Ґ@r69gYϝ_ TU_/KgYϝ_ TU_/KgYϝ_ TU_/KgYϝ_ TU_/KgYϝ_ TU_/KgYϝ_ UWMwƣ:|Vh@iU/Qe>v€-QU/Qe>v€-QU/Qe>v€-QU/Qe>v€-QU/Qe>v€-U[E_o~*ՅfRF?PW:|_m~(W:|_m~(W:|_m~(W:|_m~(W:|_m~(W:|_m~(봿1TRЪ18y][׸ׇxJw?Mo]wG./g_W|)y/oϨdS$Fv_%u Lp?:(c1?r?F\cZׅ)}#L2b1wmkVbĶ2XK\ >"tFoZ}hؗƞ/g^X@޻$Y211\:Lj;'B/5?YtG5Bmy^UK(ujsxDY& z:@M ِFW73!7Ͻo"e*Q}j}o{oEZ{E@FPǻicQ}Z<yw4誻FP*Q}j}o{oEZ{E@FPy?跣}*{4Ng@tU]o}(W}({>EU{>7Ͻo"-QUwϽo"m TU]o}(W}({>4/jYy> #͗s5g}(W}({>EU{>7Ͻo"-QUwϽo"m TU]o}(W}({>/?j.ϳv??Z}j}o{oEZ{E@FP*Q}j}o{oEZo{vF5Um@G/Y{ghN}o{oEZ{E@FP*Q}j}o{oEZc]z7Ͻo"]=ߟgN11~EU{>7Ͻo"-QUwϽo"m TU]o}(W}({>EU{>7Ͻo"-QUwϽo"mMwƫUSKmy8y][׸ׇxJw?Mo]wG./g_W|)y/oϨdS$Fv_%u Lp?:(c1?r?F\cZׅ)}#L2UxMcNѶեYR|cg]Z3>)xgN(5bv9X#E$4`6A՘vw+=F}J]y6,1o`/j:IDnyD~|3G@x0C R ^ jivO2K+(HP8<UiZ>ҵGb~|.&(Pt KZՇ$k+; ʉ+1*FQEQEQEQEWMwƫUWMwƠ TQEQEQEQEQEV>,oV|Xcހ-QEQEQEQEQEQEWMwƫUWMwƫTQEQEQEQEQEV>,oV|XcޭPEPEPEPEPEPUt/jUt/jEPEPEPEPEPUo?jŏv?-Q@Q@Q@Q@Q@Q@t/jUt/j@xw?^s58y][~]oˋxW h_+><ѿݗGI]yή(kOOї5X֟9ji.kf |_x)}#@ SKtHgԏ#ʑO#uOc>og%Ԯ3(ޣyC<3xķWֺKksb#kn5gIa)Rsz}+o VԜigM!@';+ល}cOk1׵=c,HFyh1 Ugr./W>z n|;v³gw}KI-nTIXhe>v/KjC*gYϝ_:|Z*gYϝ_:|Z*gYϝ_:|Z*gYϝ_:|Z*gYϝ_m6Q:ǻicPe>v/Kje>v/Kje>v/Kje>v/Kje>v/Kje>v«]XZ,am` lsi[E_o~(β;oV _o~(β;oV _o~(β;oV _o~(β;oV _o~(β;oV _o~(β;oV 6ZO(ɌtU/Ki_j*gYϝ_:|Z*gYϝ_:|Z*gYϝ_:|Z*gYϝ_:|Z*gYϝ_:|Z3.-{0Ґ@r69gYϝ_>,oVuߥ ?/U(uߥ ?/U(uߥ ?/U(uߥ ?/U(uߥ ?/U(uߥ aaf1kX e1 Ӫo{vF5_o~(β;oV _o~(β;oV _o~(β;oV _o~(β;oV _o~(β;oV _o~*ՅfRF?VU[e>v/Kje>v/Kje>v/Kje>v/Kje>v/Kje>v/KjTUecUǻicU+üq% &q+޻|\_#ϨdS$Fv_%xߊQ^I:J>~&utQExǤcZׅƴT Os[4SFO[esկeP}D߾ː8ֺ V]5m:FP'>mRxDfT6p ' ZʣoŗM[]'I0ɄM%| U9j0ľ%YFn 90lsRmՍoЕ]wğ%j?k+JvGkWΗ.QmMs >Tct@{~nU=BQ&@W̽{oEV2{>7Ͻo"Q@|Q}j^Ͻo"mTP_2}o{oEZ*{EV{!lf#:ǻicP^Ͻo"mTP_2}o{oEZ*m}*W̽{oEV e({>EU{>t~} 8Ǔ֝U[^Ͻo"mTP_2}o{oEZ*m}*W̽{oEV e({>EU/FU(2<yw{oEo{vF5Z e({>EU/FU({>7Ͻo"Q@|Q}j^Ͻo"mTPe{4NgVwϽo"EZ e({>EU/FU({>7Ͻo"Q@|Q}j^Ͻo"mTP]oy6 #͗s5Ut/j<Q}j^Ͻo"mTP_2}o{oEZ*m}*W̽{oEV Uϳv??ZӪc]z<Q}j^Ͻo"mTP_2}o{oEZ*m}*W̽{oEV e({>ETCl7zUt/j@xw?^s5_..{o5"I;'lc1coyݗUױ͋WxW hՓPPe?޽;u0 Jy?k2qpI;mQ^9֟9ji.kf?r?F\uSFYR|cp?mj)L7ڑ!~t cFе[kΑjp2q7Q]K| 6:ER//-yI2;aM0rA1c$Ik^ݒ]kSI 1x+Y*? "ܝ}JY-X$ɨ^,$񻫮GLJJ!؟ߣb~?\wy_5¹Կku)I#_0)nW tcHd+5# ʞ@=;WUe>v¦NE*uߥ ?/TEUβ;Guߥ EUβ;Guߥ EUβ;Guߥ EUβ;Guߥ Ut/j?/Uk 6ZO(ɌtPW:|_m~(W:|_m~(W:|_m~(W:|_m~(W:|_m~(U[e>v«]XZ,am` lsiU/Qe>v€-QU/Qe>v€-QU/Qe>v€-QU/Qe>v€-QU/Qe>v€-QU/Qe>v€ 7=KVe@`'͔d:`*uߥ EUβ;Guߥ EUβ;Guߥ EUβ;Guߥ EUβ;Guߥ EUβ;Guߥ /?j.-{0Ґ@r69gYϝ_ TU_/KgYϝ_ TU_/KgYϝ_ TU_/KgYϝ_ TU_/KgYϝ_ TU_/KgYϝ_ UWMwƣ:|Vh@iU/Qe>v€-QU/Qe>v€-QU/Qe>v€-QU/Qe>v€-QU/Qe>v€-U[E_o~*ՅfRF?PW:|_m~(W:|_m~(W:|_m~(W:|_m~(W:|_m~(W:|_m~(봿1TRЪ1 O|A[v!o_pӹ& &ky S7-$0>z۞{p ts]qGMķ^ᾆrK :ƼgV7{}w}k@X (,q9-E\ӓE5ZxZ˚٬kOOї5@>/oiuVTW:ymj?\]Z[ u N\{<{[S1 [QХ"&ce1Vpp{湯ku˫{;qmkwN+LvdLKx5O,L'nYr9; gӴ؛M G wlZG=Y˖c$h;:OCG'kwğ%j?k(' Z.ܝ-'p8, \E\k:\WF5 R=uQ-E*Q}#-QUwϽo"m TU]o}(W}({>EU{>7Ͻo"-U]7=Koy6 #͗s4EU{>7Ͻo"-QUwϽo"m TU]o}(W}({>EU{>7Ͻo"-U[EUϳv??ZӢ{E@FP*Q}j}o{oEZ{E@FPǻicṴ{!lf#;@FP*Q}j}o{oEZ{E@FPy?跫Ut~} 8Ǔ՝o TU]o}(W}({>EU{>7Ͻo"-QUwϽo"m TU]o}(U봿1{>`CmEU{>7Ͻo"-QUwϽo"m TU]o}(U[Ѿ}Z=@q'c :*Q}j}o{oEZ{E@FP*Q}j}o{oEo{vF5Z^hw͗ |V+޽Ƽ;P?kz˿9q8>Ot~+U}E{'Ÿ'7+4bcEi#^2kG-S-?elO[e>/ohƺku*ʔ?':F'=^:/-,,2\[T'p9SPrCM.48P#d1PIZFq[KhC,Q/duApI\cx7I~'|C^i $)0n :|7&[DO]Kis{8ub`<$^YiZ۟ [=KEK[x>m{A xeP <ײlO]MBQ&@HGL!Vv? A[Ve *FQEQEQEQEWMwƫUWMwƠ TQEQEQEQEQEV>,oV|Xcހ-QEQEQEQEQEQEWMwƫUWMwƫTQEQEQEQEQEV>,oV|XcޭPEPEPEPEPEPUt/jUt/jEPEPEPEPEPUo?jŏv?-Q@Q@Q@Q@Q@Q@t/jUt/j@xw?^s58y][~]oˋxW h_+><ѿݗGI]yή(kOOї5X֟9ji.kf |_x)}#@ SKtHgԏ#ʑO#uOc'Ğ74 25|v­Q@/Qe>v­Q@/Qe>v­Q@/Qe>v­Q@/Uk 6ZO(ɌtVU봿1β;Guߥ EUβ;Guߥ EUβ;Guߥ EUβ;Guߥ EUβ;Guߥ EUβ;U-{0Ґ@r69|Xcހ/KgYϝ_TP_/KgYϝ_TP_/KgYϝ_TP_/KgYϝ_TP_/KgYϝ_TP_/KgYϝ_TPe@`'͔d:`*uߥ 4/j@/Qe>v­Q@/Qe>v­Q@/Qe>v­Q@/Qe>v­Q@/Qe>v­Q@V=[XiH F9AV/Qy?跫TW:|_m~*W:|_m~*W:|_m~*W:|_m~*W:|_m~*W:|Vh@i]7=K/KgYϝ_TP_/KgYϝ_TP_/KgYϝ_TP_/KgYϝ_TP_/KgYϝ_TP_/KZg k )#c+Nŏv?-β;Guߥ EUβ;Guߥ EUβ;Guߥ EUβ;Guߥ EUβ;Guߥ EUβ;Guߥ ETRЪ1U봿18y][׸ׇxJw?Mo]wG./g_W|)y/oϨdS$Fv_%u Lp?:(c1?r?F\cZׅ)}#L2b2XK\ >"tFoZu]flǶwmEU/FU(Uklb9Ӫo{vF5e({>EU/FU({>7Ͻo"Q@|Q}j^Ͻo"mTP]oOw|ӌLy;i[Ee({>EU/FU({>7Ͻo"Q@|Q}j^Ͻo"mTP_2}o{oEZ3,}@G/Y{gjQǻicU^Ͻo"mTP_2}o{oEZ*m}*W̽{oEV e({>Ef]=ߟgN11~g}([ժ^Ͻo"mTP_2}o{oEZ*m}*W̽{oEV e({>EU{>`CmEU/FU({>7Ͻo"Q@|Q}j}Z=@q'c:y?跠̽{oEV e({>EU/FU({>7Ͻo"Q@|Q}j^Ͻo"mTPM/q; ː@>cwuWMwƫTWxJw?Mo^^(W5wGQ^I:J>Otך|11L袊HƴT Os[5i#^2h2?4ʔ<wmkVuM.XNg|%0>tHgԏ#Ob?0ZHn5;im(e=`h8 <>=ݾip3][8vGIh,eqkĞ74rQe HQpp*KO x6@[MDs[-Nu;d|s+gkuؼ@ߊ-\^YOR:f=^?^qGf)n˷kx|d*I!Ubpp$χ瞥[9O±$k; .i7 fd`aࣹSj꿳/ThEUβ;Guߥ _o~(β;o@_o~(β;o@_o~(β;o@_o~(β;o@]эGuߥ aaf1kX e1 ӢgYϝ_:|ZgYϝ_:|ZgYϝ_:|ZgYϝ_:|ZgYϝ_:|Zc]z?/Uk E-4# :*uߥ ?/P*uߥ ?/P*uߥ ?/P*uߥ ?/P*uߥ ?/P*uߥ ?/PǻicṴh@Yβ;o@_o~(β;o@_o~(β;o@_o~(β;o@_o~(β;o@_o~(β;o@|XcޭVeՅfRF?U/Kje>v/Kje>v/Kje>v/Kje>v/Kje>v/Kj_gYϝ_m6Q :*uߥ ?/P*uߥ ?/P*uߥ ?/P*uߥ ?/P*uߥ ?/Py?跣:|VYJA1 ӢgYϝ_:|ZgYϝ_:|ZgYϝ_:|ZgYϝ_:|ZgYϝ_:|ZgYϝ_:|o{vF5ZZZ@VY@`5[;P?kzBI.7 /oiuVTW:ymj?\]Z[ u N\{O~(K##[طWIfu[FwrUDI$w]1_̖rV1Υ9Rp}8⎍ϤhzUn\)pPRI;l]Fcbɾ+|R{P+' ZwDn ?Zܮ"W֮5.+ ]أLf@|f鞀:m"W}({>FP*Q}j}o{oEZ{E@]эFUklb9Ӣ{E@FP*Q}j}o{oEZ{E@|XcލoOw|ӌLy;iUwϽo"m TU]o}(W}({>EU{>7Ͻo"-QUwϽo"m TU]o}(봿1fX=`6^՝m TU]o}(W}({>EU{>7Ͻo"-QUwϽo"m TU]o}([ժ̺{>tbcjP*Q}j}o{oEZ{E@FP*Q}j_o{EV{!lf# :*Q}j}o{oEZ{E@FP*Q}jŏv?-{>t~} 8ǓW}({>EU{>7Ͻo"-QUwϽo"m TU]o}(W}({>EU{>7Ͻo" 7=KUM/q; ː@>cwtWxJw?Mo^^(W5wGQ^I:J>Otך|11L袊HƴT Os[5i#^2h2?4V ]5m:FVeJ񎟓wmhOzaZ×wv.-FBd  ?OxoQeonk|$ VWĘog^ei2GQgzugt뫯־6y-?q -6bN wr+ax.>k a۽zW"7PIhvc%jÒ5lBVDQE# ( ( ( ( ǻicUǻicP( ( ( ( ( y?跫UV>,o@(((((ǻicUǻicU(((((y?跫UV>,oV(((((o{vF5Zo{vF5Z(((((c]zUo?j(((((( o{vF5Zo{vF5Z;P?kzBI.7 /oiuV)O$E3KjḠeH|c:F'O xcj O\;Tyf’d 'zeiRO;e822i iwDdt>KsQ,f? UYkٯ/\cs%MZud8t܀ Oj᛻H.aVL"ym22\Gv³gw}KI-nTIXhe>v/KjC*gYϝ_:|Z*gYϝ_:|Z*gYϝ_:|Z*gYϝ_:|Z*gYϝ_m6Q:ǻicPe>v/Kje>v/Kje>v/Kje>v/Kje>v/Kje>v«]XZ,am` lsi[E_o~(β;oV _o~(β;oV _o~(β;oV _o~(β;oV _o~(β;oV _o~(β;oV 6ZO(ɌtU/Ki_j*gYϝ_:|Z*gYϝ_:|Z*gYϝ_:|Z*gYϝ_:|Z*gYϝ_:|Z3.-{0Ґ@r69gYϝ_>,oVuߥ ?/U(uߥ ?/U(uߥ ?/U(uߥ ?/U(uߥ ?/U(uߥ aaf1kX e1 Ӫo{vF5_o~(β;oV _o~(β;oV _o~(β;oV _o~(β;oV _o~(β;oV _o~*ՅfRF?VU[e>v/Kje>v/Kje>v/Kje>v/Kje>v/Kje>v/KjTUecUǻicU+üq% &q+޻|\_#ϨdS$Fv_%xߊQ^I:J>~&utQExǤcZׅƴT Os[4SFO[esկeP}D߾ː8ֺ V]5m:FP'xuO鍧dcHuXRcK) rq>[b me. %0=:_zaZ×wvܙ.-FBd  *:I?(FvM88<m}Y`i.[GZf?Е]/WZ}S]q-im RC1G^r{7V+#gKv(6٦*Cٺg=}*(Pt KZ/h^Ͻo"mTRW̽{oEV e({>EU/FU({>7Ͻo"Q@wϽo"X=`6^֝U봿1/FU({>7Ͻo"Q@|Q}j^Ͻo"mTP_2}o{oEZ*{EV{>tbckNŏv?-/FU({>7Ͻo"Q@|Q}j^Ͻo"mTP_2}o{oEZ*m}*`CEU/FU(2=@q'c;E|XcޭP_2}o{oEZ*m}*W̽{oEV e({>EU/FU(Uklb9Ӫo{vF5e({>EU/FU({>7Ͻo"Q@|Q}j^Ͻo"mTP]oOw|ӌLy;i[Ee({>EU/FU({>7Ͻo"Q@|Q}j^Ͻo"mTP_2}o{oEZ*i{o6\r{vF5Z;P?kzBI.7 /oiuVTkZivNJt;)DSI'j3,RBRZK^[֛M^$wM$3W2dcNJ5χw-;T`u!LFTO5j ՝]Gk VW`$Hχ瞥[9OV5$t;gc\Z3Eu";ᐬ̌ 2w*y]Wuߥ ;_o~(β;oR2W:|_m~(W:|_m~(W:|_m~(W:|_m~(U봿1β;U,,-k>l&1;@tU_/KgYϝ_ TU_/KgYϝ_ TU_/KgYϝ_ TU_/KgYϝ_ TU_/KgYϝ_ UV>,oGuߥ uahمcEUβ;Guߥ EUβ;Guߥ EUβ;Guߥ EUβ;Guߥ EUβ;Guߥ EUβ;Guߥ 4/jYm6Q?_m~(W:|_m~(W:|_m~(W:|_m~(W:|_m~(W:|_m~([ժ̺YJA1 e>v€-QU/Qe>v€-QU/Qe>v€-QU/Qe>v€-QU/Qe>v€-QU/Qe>v€-U]7=K/KZ͠bְ2cEUβ;Guߥ EUβ;Guߥ EUβ;Guߥ EUβ;Guߥ EUβ;Guߥ Uo?gYϝ_V=[XiH F9A@tU_/KgYϝ_ TU_/KgYϝ_ TU_/KgYϝ_ TU_/KgYϝ_ TU_/KgYϝ_ TU_/KgYϝ_MwƫUSKUKB( <ƫtW$>?tWE!\[8WW?B|SϪX i]Ia]8Zʌj~6<Ěe|uzدVS$Fvo%_[]^,-.++X$#MŶ9XVzn(NG-S-?el5ZxZ˚٠?4|_x+*F+<6ֵk..|Kc-'DfN\ց=|Ks'ÿL-Gg | 8=)Y%]Sĺci-V+})RcK) rq>Tct@{~nTKrj}o{oEHTU]o}(W}({>EU{>7Ͻo"-QUwϽo"m UWMwƣ}*y e1l iUwϽo"m TU]o}(W}({>EU{>7Ͻo"-QUwϽo"m UV>,oFUkA>i&<ր4誻FP*Q}j}o{oEZ{E@FP*Q}i_j,}@G/Y{gjP*Q}j}o{oEZ{E@FP*Q}^ŏv?-f]=ߟgN11~g}(W}({>EU{>7Ͻo"-QUwϽo"m TU]o}(W}({>Ut/j7Ͻo"X=`6^W}({>EU{>7Ͻo"-QUwϽo"m TU]o}(W}({>Uo?o{EV{>tbchN}o{oEZ{E@FP*Q}j}o{oEZ{E@]эVe 1պ+FCJެou-*&oV·T%"J(kOOї5X֟9ji.kf |_x)}#@ `5XӮmiVT86ց= կ9yigygm- l(ܠ6@;ʚO kڅWx߬OCvSw7T լ6SbX^66Ne?4]"->;&@e2GHey$Ga^^*M[RGDž~{ŷon̎~^z׾}k|6u},ƾ!KYa0-,[OYŸ5[j*Q5 Dk?Z֬9#_0Y)nTIYQR0((((o{vF5Zo{vF5Z(((((c]zUo?j(((((( o{vF5Zo{vF5Z((((( c]zUo?j ( ( ( ( ( ǻicUǻicP( ( ( ( ( y?跫UV>,o@(((((ǻicUǻicU+FCJެou-*&oV·T%"J(kOOї5X֟9ji.kf |_x)}#@ SKtHgԏ#ʑO#uOc'Ğ74rQe HQpp*Η jM`u)lnKe:2 O~(K##[u־zK$)}-L=3m=3tVZoiij.2-ky?ńnx8 =sW|DnLݮG=O"JYH`+mBIq{'Qvɹ/4]'X.,.ngd`aࣹSj꿳/Vli;ceʉ+ /Qe>v­QHe_/KgYϝ_TP_/KgYϝ_TP_/KgYϝ_TP_/KgYϝ_TP_/KZ͠bְ2cUt/j?/Qe>v­Q@/Qe>v­Q@/Qe>v­Q@/Qe>v­Q@/Qe>v­Q@/Uk E-4#:y?跠:|_m~*W:|_m~*W:|_m~*W:|_m~*W:|_m~*W:|_m~*aaf9kX e1 e>v7=KP_/KgYϝ_TP_/KgYϝ_TP_/KgYϝ_TP_/KgYϝ_TP_/KgYϝ_TPeՅfRF?U/K^ŏv?-Uβ;Guߥ EUβ;Guߥ EUβ;Guߥ EUβ;Guߥ EUβ;Guߥ EUβ;U,,-k>l&1;ZuWMwƠ:|_m~*W:|_m~*W:|_m~*W:|_m~*W:|_m~*W:|VYJA1 Ӫc]z?/Qe>v­Q@/Qe>v­Q@/Qe>v­Q@/Qe>v­Q@/Qe>v­Q@/Qe>v­Q@4T**jUt/j@`èTi[Ճm#]SETD·TXVOIESi#^2kG-S-?elO[e>/ohV&]Bi@A3~'.@Z+5[gt=m@9UW֮5.+ ]أLf@|f鞀:mzMCG-kT?1{>7Ͻo"QHe_2}o{oEZ*m}*W̽{oEV e({>EU{>`CmEU/FU({>7Ͻo"Q@|Q}j}Z=@q'c:y?跠̽{oEV e({>EU/FU({>7Ͻo"Q@|Q}j^Ͻo"mTPeye1l Y{>4/j@|Q}j^Ͻo"mTP_2}o{oEZ*m}*W̽{oEV ˧A>i&<֬{Ec]z@|Q}j^Ͻo"mTP_2}o{oEZ*m}*W̽{oEV Um@G/Y{gkN_ym}*W̽{oEV e({>EU/FU({>7Ͻo"Q@wϽo"]=ߟgN11~Uo?ym}*W̽{oEV e({>EU/FU({>7Ͻo"Q@|Q}j6xrnn_j PҷFCJՅo9v7vG=IH(3G-S-?el5ZxZ˚٠?4|_x+*PtNuZ4]c:}}")&[R>d ΁= gcc+bw[YYbq7H V$ ]sf-q5ILxvhrN]Ź8lk+%&(//$}݄ޙtJO6w *2j'psUN2 7>3,քt[-"5;^)|٣F$ĒNLצlO]~+ZI,Z1B 2A\wy_5jIh6v!H+rfEŤw!Ye8(Tں/K2w-QU/Qe>v¤e*uߥ ?/P*uߥ ?/P*uߥ ?/P*uߥ ?/PǻicQe>v«XXY Z|FLcv4調_o~(β;o@_o~(β;o@_o~(β;o@_o~(β;o@_o~(β;o@|Xcޏ/KZg k )#c(Ne>v/Kje>v/Kje>v/Kje>v/Kje>v/Kje>v/Ki_j,,,-k>l&1;V/P*uߥ ?/P*uߥ ?/P*uߥ ?/P*uߥ ?/P*uߥ ?/Py?跫Uuahمcg:|ZgYϝ_:|ZgYϝ_:|ZgYϝ_:|ZgYϝ_:|ZgYϝ_:|Zo{vF5_o~*@ŭ`'͔d:`(Ne>v/Kje>v/Kje>v/Kje>v/Kje>v/Kjŏv?-β;U-{0Ґ@r694調_o~(β;o@_o~(β;o@_o~(β;o@_o~(β;o@_o~(β;o@_o~(β;o@]эVPUPyVou-+zma?贪XVOk SisԔ(c1?r?F\cZׅ)}#L2b1wmkVbĶ2XK\ >"tFoZ}hؿYxcI}CV=8E$j9g'$s? }R xS*w hcM#j˯i:ǀ̆X5x"u<i]Z_[Z7Ć+3>F{џhA[? ezg'.ú^ ;ĒG]rU؎ c' ZJX$nN ?Zܮ"W֮5.+ ]أLf@|f鞀:mE*Q}#-QUwϽo"m TU]o}(W}({>EU{>7Ͻo"-U]7=Koy6 #͗s4EU{>7Ͻo"-QUwϽo"m TU]o}(W}({>EU{>7Ͻo"-U[EUϳv??ZӢ{E@FP*Q}j}o{oEZ{E@FPǻicṴ{!lf#;@FP*Q}j}o{oEZ{E@FPy?跫Ut~} 8Ǔ՝o TU]o}(W}({>EU{>7Ͻo"-QUwϽo"m TU]o}(U봿1{>`CmEU{>7Ͻo"-QUwϽo"m TU]o}(U[Ѿ}Z=@q'c :*Q}j}o{oEZ{E@FP*Q}j}o{oEo{vF5Z^hw͗ |Vb9ou]P1*DADG'z1}/k֥ $HyLqJ`\.pH- .k .MC/ԭcH(zUAMlGY byN02q_;^ ״mC7巈4UE4o3%D!H*A<1}A_W_S->[袊E֟9ji.kf?r?F\uSFY1p?m{GkjFtvm44K$6W?sخ3]xZYe᷵<ь!tI J?A̱]Ь8et$ۂpN*i/]Y*Gl3y-KZ}o@r\xclTrJQ׵z_Vᶙ}RͫwY:Ƣw_wِHRBfdUA?G*\MBQ&@HGL!Vv? A[2VcAET((((*]эV]э@((((*|XcޭU[EZ((((((]эV]эV(((((|XcޭU[EZ(((((_j_j(((((ŏv?-U[( ( ( ( ( (*_j_j )uƧsKomI$4؅tp~U#I8לt/&{w)Hѫ*JI$+F)RЙW4o6._đ*$YD\6D:#uZٛ᧋&uK^]*i<.Gln76v:Z}/E1?r?F\cZׅ)}#L2]UF4sfF `y1kB?vA?vAӼ'][\c5#y qz[~]ZߡKEaVR@XO.|?У˶+O)h,'m>VQϕP˶+O( Z( ϕ +^=iP˶+O( Z( ϕyvi~- VR@XO.|?У˶+O)h,'m>VQϕPڨO1֗˶+O)h,'m>VQϕP˶+O( Z( ϕyvi~- VR@XO.|?У˶+O)h,'m>VQϕP˶+O( Z( ϕ +^=iP˶+O( Z( ϕyvi~- VR@XO.|?У˶+O)h,'m>VQϕP&"!1ƈ !@89?Ο=P,OD6IgId hg EbGPC) 5bĒKI$I${,QEcZׅƴT Os[4SFO[eQ@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@֟9ji.kf?r?F\uSFEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP5ZxZ˚٬kOOї5@Eu%P;YE¤烖 qԴP7?2V/IbxzO Ec}? e'!^)?l@hI(GO1[4P7?2V/IbxzO Ec}? e'!^)?l@hI(GO1[4P7?2V/IbxzO Ec}? e'!^)?l@hI(GO1[4P7?2V/IbxzO Ec}? e'!^)?l@hI(GO1[4P7?2V/IbxzO Ec}? e'!^)?l@hI(GO1[4P7?2V/IbxzO Ec}? e'!^)?l@hI(GO1[4P7?2V/IbxzO Ec}? e'!^)?l@hI(GO1[4P7?2V/IbxzO Ec}? e'!^)?l@hI(GO1[4P7?2V/IbxzO Ec}? e'!^)?l@hI(GO1[4P7?2V/IbxzO Ec}? e'!^)?l@hI(GO1[4P7?2V/IbxzO Ec}? e'!^)?l@hI(GO1[4P7?2V/IbxzO Ec}? e'!^)?l@hI(GO1[4P7?2V/IbxzO Ec}? e'!^)?l@M}Cio /iXJ.?^EQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE endstream 70 0 obj << /Length 71 0 R /Filter /FlateDecode >> stream x]n$0gs  ݤϲؖ2 ]X*#2*H2!`4,VŒ9?;Oi)_~wO?ߖ~OO_>n|H)o߿/?8}OC}^ܣwr{\ /Gw=&x@_NۗS.?;{EޞpgldxSNp]Dz `Fl?ۓp8'utf#lf5\h=El6ܜc)OڌO 4З u*j{b  KAKYuhjsXis0y'  cq*ThhХpAaLDpu# vv#@KSoH(8'liZ)~}︢{V A!}"Ӓp/7|a.2eCDsxh\z*d?}sW?1|Ο~:ӟUՉ)f :ʬ+ V3 T"0[ Uqi{/xq& 6 ]͵1ZV_=|-rX\0 crs` Եƻ`G$ݡ]yO4#+I!JJi|hɷA\zM;eu23MՍYNѢVM1K2BL˄+L̲0$hcH Y*2_!Рx; !>Wm6Ec%;gTw4DfOȞ"l 8_9컈t{1 %xp?Ҧ0W S#Mq>&F , mk%/߱ 5;ucۧZвP9d -֠z ?ZVDm$f) ` o#5lIA{wb]JAGME8K ԙ(_V0M1~(ua{OvMh2LmW[p``+8tQ5yE0GZBόz&ޥ,X$("aDD6b Lzb}P܍RȂ /z5a3Mk kp,rVn}*_{1m?ia{IXYP>6C<@Mٔ 371mԲilﲎ;O k  #}6dմ jXÙh" AR6W!.JʲiT|;64M62{Q-^ }[Ht+n& ׭!HS4;NR_'HQ1iQ+O7itc2t{u0@wwE9[$Jz*s7b3rX ,}RJѫFHA֤z#mj%l0nլpAћ"J}ҎpZZ(8 +ܹ붦=ko̪K/ r WL~9kʦ zPΗx0uxpe3+ƥ끇 2wJjwlGP"|>\O;m'EJuLOMČ~nVUrіaHٳ:F-2qRGN>M/@TEducI)Ze"בHDQ^; ǪPW֕ʬK@.G ;1C &՜!'t$C%VlSB ILt\1Q)Aw!\jW®ՆɉeڠxdI3 dvDmwԕ6qq;YgA~,EX]"~Y"DʀR 0]Yٍ.QJmam5ZIgVz=)Eh.in G)>^(WЌBXV!<q|M(岌'9e-'Yf 蓘v6q:'G}=oe[ABO{! Be¨w=W'Vbڱ ԉ5X氍ɻ״X (-7A傌Ԅ|S u6AY/Dq'v~hR^QS;Kxbu$M;ĶQc=X@ʃ8ug3**ifACEVێyFᕁyre]PdQ3*0J2OxQO)vutʽOR{nɻuTLwMoz )=PUz -"jFWXbPEP>;YXWF'ٔ6P^t)a^4VԥڲX ەb D\f6,1r.]:w ܥջt ݯ.Z7(o{Uummi4~wԓf.3h@Zb ~K&=o/IT8ԼULtC8FQwF0.d; 4ڊASk{6Jjwhd+IVCinK4!"T]^)M4 Wde=yl 6] 9-RS_,a0V$%kl[d<.g<(hRJ7aU7^. ˊ/|B鹜 E25}Wjٛ_se JcޚM9X 8JrqMe'> j5Ak "4,2&U ]oxwŸj%S0? nӬendstream endobj 71 0 obj 3668 endobj 72 0 obj << /Length 73 0 R /Filter /FlateDecode >> stream x\Y~0AOz&p<;$Q-.Ό< zϝq|?y?ۗ_w{Ɛއ߻?CCݷo_6]ԏyq G;@|>GLn'gQ}FST.3L쒻a!.=!\ $>z뛳oiYOO\]pQN|6)o'pf: ]RÙꛚ]%W"IXWDܲc}abf'wvcϿ޲|'aZ'uSy9ht68U.E $|0 M$ -PP'8DdBٵ1'+aJHW!QMVÔ!S%=,7{A iuB>)D ֒'o2- CQȄׂ!X-lъI߹d4%ٴ^Qc-r$-هv̕,&wuu6nBB71-rc~2JX3HNy)} e&G!`bflZo0 #sh8=oGS[VDUjf!=b,7#I28hY6Xs+Y# m+Ӯ+,mʗv7y1;F̴M8 dr%+k&A ^d>!GŀIvEImd[sb(cqIrl;e)'jn2t-f)`v]3D/Gn1 i$@|{!xAiYn2̐1?$K>f&Y5~p=0L1RbAs̏a(\qa^ӄ+5)}zeLKUqd+ZF4AŝVy9[D[55Qx*A6R1#2KNr"pYuJS-)Bg]Ii($?$wL[*sw?ua\D L1^)\}m!das<&XЬ"fɣU6;4#)&_CL$۪` 122ٽ H|fk$+t<3f 0lID<( .K̎D)An=y)Ng]=BB۰PPL'ROcvq7zNaA|HDaӴ_7x0>ksl!> χyɘãE/ >xFnJb8Vë́FEYMm]2"M8ZS>}_~TK|" 8O=3oRt }P'eχ4_uOTa@IeDlCszX|:! VCa1,?%/тQMzNu9f/f~,5ʰEBgB\TaղNtl0,/z8<#1Q&GL{w֌sF6uywzگUX'-kFFh=6T*/Mz-s5ǵ4HA•P!<:&>į2_&AFr$-bU$HkAa7 b>wJ,Z[ssFQtJ0a1辄ro^ R:d8$}DwBT@c-*3JcR3pT༲*BC;#Yz\B`j jnv- 4(OʌWiehMB(\Av!`|Ut*/"8]me3 Ilj|-v dn9$F/L=ghUeTi%>w9j\Ƹ 884Yy(qV Z#\[<(fT CU=yi-mmAZEk3\ْ%yt9Dod:ɔB.*EC(geHUK/"d@ Qc-O__K% l*]jZ -B&Um ygWcBTe4tUbompL|3g`}kRji} d+T33{% bҔf0-#E LĦdÀ7ˆَU" EFm k`Dyt|f_hS{Ճ"~\5%>KC%/$"d!&4*~?=Z~`<;ZY)~DI| Zٺ`uC"V"ީݦ}MtfsV9jfUv#A޼B6[Iv'j\K8 gE/+QӺI[@|JxqL jP=cVk5p*5Jqu"j3+I )N`Y+_i&&QGz%3Ga dr™NiqeY 1`\?0h;.#&V !(a{i ôVBAEx҂d#koVo}Sl^94#ߠR oi^EyWa~.Ź![ JE'if'}`3"䎻a2RZ>{h$KѴr3?5MØ&IUªTJTJK ^eB'&wB61AاQp_ɷ]Rߕ6A`qA?s^5oe#'sBOʑ ʅK] !2Dh2m.Ǿ3_G}{qԵ`JO{ݧaʇfu` QDjB[Ko Վa#NDA~,DC YwXvz Xްh3^<:S/H'Ul&߭'啃le雃E':QZO'(ƌ;%0^lkDmvOf3r&a9C`#,4$1ڷ Ь2o}>mj.o+"{NhYYڢ B-sQx2ƟQ>ࣦ#Yo&y4gx4fҠNW\_o)jP8UYNS0Ibd4JIw/~ 4+>A;zQ#6-XpeK1s-蹕#Mdq`q; *ozdÓrgf]}-[?Tpw{T9y묎[6lD/g endstream endobj 73 0 obj 3778 endobj 74 0 obj << /Length 75 0 R /Filter /FlateDecode >> stream xXۊ#7}7Xja c;q df_]! 4jIu;uԯλn,4ܗky[ߝ]0_kr{}:ݥlm#yXV7|CX$$D?RDPvHE"^VPN5Ga۩TTN!95ty ]cbu1'##9b[igV2"`Ä+):WU6?t8ɢQ3yXa![gĽEpȲqxII9B&=pOhUH@ZNd4pbP,\!_aATMbSJWtf,% d"YHaL$"ۖŤb)96G% XlD;X4"H8sNvXLSNqghCg`o 8r:jUo1CKoj7{_]j,R$Ϝ6`T25H.. &VAzOq,a/9hk=c0 1K23 8s00/၁}&$$Se1CCJxl[Z O&`S)P;&Pr"dd5U6hOo za(k ac :yWB!("7a}I(2x @ЛY.ʐ1^V4e,:&@8`7Co"dMzi|Lْ;9AhJ9Ob`6e/K欂Q <ļ$$Qyc Y)SC!l[o8֛}1R Xhp @"]vlǶ"|_{+\{81 Rݚ73)~y*Z]l}RtAH/9'VžC*9ڢ'ذ4 |ågMiQ3y -MR5t@G4ؘHzlGR=C^NoOVjK=7Ͳs5}*ۇ?Wh0VY\WAm t/itkgendstream endobj 75 0 obj 1134 endobj 76 0 obj << /Type /XObject /Subtype /Image /Width 230 /Height 496 /BitsPerComponent 8 /ColorSpace /DeviceRGB /Filter /DCTDecode /Length 18620 >> stream JFIFC   %# , #&')*)-0-(0%()(C   (((((((((((((((((((((((((((((((((((((((((((((((((((" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?B(PQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE31$p3F#?zxJe?y|Pш^E?y|Pш^E?y|Pш^E?y|Pш^E?y|P~}X_~Wڭݻn g]oțׄ-hf((((+yRL((*m>O=E[#܇0A/EtO&t;s=IdJ_xI>ҼDͤ,Jl@x!#sZ-Viyjw\M$~7b5ځ|su C5! AQڅǾ滭J5C7Z-#/g1&?wh^G1zgLhEPEPEPX 7A?Zcx+D k@4QEQEQEQE2ˎkff8קM=k|q= ռ_K|1h'䀜0aFqC>jQ6/ckg||3w5C%ޥp/4,z޾8r9eKH[E·w>91j6q+ndɭDl` >^>wH_*>2C-wn~qIk|i6(t['V$FI+0>`IzY exܶnI_ooOΞ"\ܳ>ȺXm_0ͯ&Ohd~F1.a?_1GE :k+kɓb!@<f%Σ;YJ3 $l$sϢS9;h|1G# qlF0 r2xk_ ~wzYfbp;W $v[f2x_k5}`4d{0 }TOVo~}܌ATOVohoҎF4?ʃ ir0ATOVi8m4r0ATOVohoҎF4?ʃ ir0ATOVo~}²ӡ}xI' r}7^2iexZO3TՔKZoE`KX 7A?Zcx+D kY4QEQEQEQE<_k$$ Nd_͙G[_^Zڤ& ڊdx5g>!.-?46m̊ ^@r*N-ֽ%h-쌪Ԍ #?yj_igaw>'դt姌c+~kose}qXvfhk nrn BY 2^VzʝXͦ{9G _os+y {9G _os(C{iiAl'Q-9Ðq:YkmkyوD{"q=rkIcءTa@-?{9G8 {9G _os(!Ѵ _os(z om4m5-?{9G8r5Mcx-Mkm]$jƭ0aSڭ YKkaq6/7MX 7A?ZlEQEQEQE俵ŧȡdwpN0c4hr9КzվyuXd #X#}{_?b\FϜ~ d _!Yo Ym7"\H`g >fNJ:g V<ǚiʝO35NмS+-lbU|9<>\i|15\C$a}Ugo^4oI}^I@0%DEB9ٷRƐkWdi.&!d1 Hs>q^V58ͣiZ5ިOcGٛTh\Q,?foS}kּYE]B 7q䒠UQ䜒:,Ø>Z7֮gBZo,PA,uG @77xՇWm*oKTV(l30avFx97֣}4ߋO͹ˏa!7AO9ktdr aEf}?gi^/vN] ]+*Y>Kn6y'9}3pj G0ٛQf7-ar";Oq%$aw5+AokjitEl7M4QEQEQEQE<_7o [Դ[뻃 ^*|Yn!Uհ5Js>9"LH=:g>dYYZ"7 %8yժШFMKș$֧]N5{smqt[pG&4F 9ńuv}y h$* O?gvŅ䧕.,Qf8xkj)uیb ,L۷ṿ:8 <\&/7G&/7\7EYO+4KW6qVIβXkTܨ`~R=Eikj)tkj)t] ̩m& 4=7P;ym.1ܜy_>&aۯGYxLrۤ2 0>c=3]VM]UM&'Y. τ@"׮3#% ?):^Ϩ.#mL[HmUʹxW/<3uYNxD,U@1F]dsW5}5oָE>p\JoXHc i0#ca.W]y,b'n ̉ʐ+>kj)tkj)tHM6u>q?kj)tkj)t]Q5}5o?5}5o.fnj^An5=RX S$2mKɺL`~uc&\=H>7"*.qp:g2بN"n^赭WxAֳ,٢(((('z#kw+8d1DW$]_ܻAg$ 1 (sNM}W3/c_I{.a-5Flqٯ7N89RNW8q3|=*6 n p{%_ک.YQ岻Ih;ҹ9P"N:jW: }`-̾ q%#o^5J?-i9YZX(ΛVҿu5>yG*?/ه_2kQ/_ʵ>? >? As/_濕R5S__.eK<_濕j}|+}|+̿)TyK? >? yNр0*MLBUe(*3kpiK'oțׄ-kf"n^赤3f(((( )^6ȯ#d|Y`_^Y?ǝލEv>RLl9RF22_q+x8clb,F$@ 2!eR2:z =[JpS-sԔꏍW+mV&ްHwT״? /_e$HYZN?+Jѷr`s^l+-I;g) Ud8kw-^cʾ0t8=h4xAg.t/jnF͵9P~eٖ-\6|^?uN9Y!^2+{*$apPV4xgJVu/40Wo0sGlև\o:v͸yv=7= _]궟+VI@o*RijԾfSjΦn'5''GҖq+_&?Z٬oțׄ-k3Cf((((++xcGItQmeŴWJ˜ V?~*_ l̉}y'mL)I/A"R:61 nn"7iX"Ff':kcif0+Ȼ[kr׬hX\-=nA3qi﬙yΤ0ꬭ0e=zk*ӵZi51 }YLb6ORs25c4k3b7@rNp5f?smﯧC:ud>?bt?#_?]ChO~yvvgؼiA>O/g<EYgؼiA>O/g<EYgؼiA>O/g<EYgؼiA>O/g<EYgؼiA>O/g<EYgؼiA>O/g<EYiB;OqɑV46ѭC,?Wcǰ}?4i6[WxAֶk_&?ZC6h((([FI>oe@ cFF zyp_43]Cvԑ,.Te\1!]vU鵱^x~~ieׯO:{F)i?39g~ hEb5w9jGbHQ72ֶG15-}`ȍ8Sװɯ>=ҾLmv>Vk#3;WH' b,UUVwvٔa)9+XG -_\Dck6[ 2{ ;_Ce^˾{ VF1dϨ5U|ChQ&m_j3]=ϖדo Kpqڴo|@*|IT+hTyKKH(K@Ӑ=zQ+18OokE?i#}5ZYqԨܧ[ҩ꺭h.2my$X`yfQp+kvQR[,$}$d0 $ כwY ^XB[N%9<%B¼ o'Q6C,Q;@20PNQP-,PE 7)%T@O+ п2<%BÐR扪^%ޥiQ$##"bNjVZ~qyr5Ţ;[8g#{5o焿_?WMd \^մ}7YjW)#eP}p7ntۍ'MMKY-C!{UWMd ?^xK7(RsIMKclSW$QӢAZolCH8Ppcڲ?^xK7(y/O"K92u$ͮ[L\^Ed]?"k?W'$Pmwg >ͮ[L\@VOٵ i+(6Am3rEkQY?f-OHEd]?"k?W'$Pmwg >ͮ[L\@VOٵ i+(6Am3rEkV7M,6̆mSNxsa^ 7A?ZQ@Q@Q@Q@G :aō^Vgq5=JO6Wi6K1$Gg:fn_3dfn4J?*WhJ8 Ѹ ~qbc 0_B]x@'{4$0rGeƙZ_]ʓ&]He89!6IoMlCMw%21F8'^Xjz~mԩ1 ؅Q2H^B h[qIk+wIZz3*><;#/zۻ8iy>oO,ݞhAm 7O\C T Hɰcׂk*۝s6gy>o?Kg^M{ V ck #uo?XԵM7OaV b~SV# P}G ֠{RV y%젺X\`wct.1?z.=i6p>V= ^E1kzmy" k_-gr˖O*iO0+!2;@NgOiZtimEB@Hyuc4m_%Gٚ{Y& ,BVPb~!Zm;,wrӧټC1nlcq]k6xl WYEP"X21H>=w/-qG)QXr;tS< =M)l׆LlG ¨k|p |j_4ȼApo,pjZܓ[7&ѾX< _h6F䖹5.yӴheܷznJ1$`2mrZ61\ĚRy.c2q\K>VDm#GO>w;WxAֶk_&?Z٢((((J21fNΛI%#]Ÿ9}j}N/-HGƪḨxx۾F5W7\7ޖKt,RFMQy/O𯙴T__0ͯ"cX 7A?Zw̎*cuAMEPEPEPEPޑ𵣲,e+C3 sUcǞ5J᳎6x\ .x,=zW?+7~][YO[ƙ>k"SIFpum5?]ssn5 6}3'%9d5߮~8qN[Cn/GK!N5cvpdU 89F3r5o| BN׎VFqs6]pT@''^ĿnH:KG̭8#,eUr+ק*z_M/z׽ڶg~!.CnO??Ə??ƭyǷ_jw>>oι?x\}&6r]jMo/U.ʣp8h.t_g?g?b~%٧}DE& Nfq\g 1fƾP%Ŷts/lO}|E}'Y}_r!/f g,Øssտ<{~tx1W~xǷE\Οˀ.Lfa jO#b;KeP'A6_&?Z٬oțׄ-jJ6h(((yR^;[G/aYtWPeoGo-.$DGS,ۏ_b?W+VS\3X܋!H *x.x #ՃWU0q~_֤*J #yӚh%ŧ;`8×p9ӎ7i~Nl yhK1K1 xt %'ϳz𿈏3]VMnoǤ5/Yƚާ :5 םt] :"my(Գ;rIЧ:;ͦdB 3JSwEտSwilOkXܥ"ާW]VM]VMv:7Czι_Mt_MW7nMt_M[7nJ^@I;/X/AZ74Id۫'ʺLxc&\Il/$R}UEE8N*dTV[X 7A?Zcx+D kYlEQEQEQEKzŧ;yj/7@-0f8P22H_C[㺺Hw&=:ar !At9*W~ 4Y&cUV H\FSA_2GĚׅF,RWߊo 3TyiGf?~Gh Zq*2m. }cx+D k[5tE!4QEQEQEQEs|-}# JF ?+3񅌺|idں\۾z8VXdrH8<_z+|GѴr-YbīdpCZ$'iۃ_KgўyOuwµyn|g_ήw- *0G`~5?f5|W[Ҭ?48 Olz^8K,#O:J'ױ]:_iEk۲J}F0ԹͿ/Z{V'޴y_ʎk_VG-ou?#?7?"1͍cNs#֏1hAs5 '_O _XKK_2;Kl,j G8/n<8P}[Pѵ;Xo+ȸ)Diڹ|1~ /a8fiydqvMS4mONMNY&00Vî҇Qo|Qu? jumI{̮H`r@$W|m~ [iw |Qwn:$THy7Z4ONQ ?+\ns32@1W z}oZ<ʂ}oZ<ErM|6NEcxvo7RFI8Re Ybu!OJݏտku+fn{57c=o٢1 n}[_rh oF羭[9G#v?V(Qݏտku+fn{57c=o٢1 n}[_rh oF羭[9G#v?V(Qݏտku+fn{57c=o٢1 niZcel55;UF*j(((((((((((((((((( endstream 77 0 obj << /Length 78 0 R /Filter /FlateDecode >> stream x\ي$}ogڱ P[Y?@2H/}GV]2΍`DTfDs_;}|7ݿ__~MO///6wS߻?O}gySח[X|?'7Y?(߼?mn_=5軸=77OۂQ_ `?zrUnMmwx-M-sM.dKRBݸM-ɨXvurgP. - 6i_څ-kf (X7/L;&]JM3b1_Nk:s{Gj({?[ָ$'2» g:'XtIDtJ5 Qz}ȑΊCst B=W80jJ'5L H ~Swlb77{'mzVM./tON=^ԾXfpyTCnk;ɡptA |M/`tqaH ^Q/r q93k%c&2ZW $DZ̸ǜ Rizs҃&o=qYa'6`-;@S|#*c9֕Ql{:͢‰s 9F+iёŊE B'!*?ĥ\@n8!IXn8XS)_M*򱡁Nv^s'JHu줈5bCHAb9'I!;綸Hu1Vtє*aLi*tJj~.5 7s\( 87ŽnVb5{9 ϋ0rVyhɨ G6ZYr;qfy~ÂI]+N[iqUtNtŠS./ :yѣʷTsV.B2l)JL)P52$i1GJbTv `t1ev Hc25?ϙ * v؀Jفar+ nb,ѢV:z%)%l2eG]䜽 JVU쮡kר?-*2+% E9$[ >$Z.)7δQb1Us眇#<EQjdw@ݴ$mN\__~kP_!# WhTYl=`os$ //@jGj8&Ҝ{(Ӣ͉UVPC^@ka|y&~L. ߩ}Zp϶տ9}/]r~sXXrؘ3%W<öA_Uk!Q刈żmРD煦 K1z扇T^WpM{i ZkLSz碴,7xrRHa(aoϜ׃U8AD x V"Ț);8a zk/@3HFVUd){h5D ˰*p"5%iww*BCܐRըa(p=Q42ile6N00hAr9]8lL`µ~]A̲.D2+gwR_5qχrfj(_4Cׂa,lzɅq6,爱 ZEiLأ,',g.&a%<2%Pjү`(|_>R~‘_=&DNg6T}Ǝdתu& r貪*ȬO!\-5h i6Gk$p(<~ äM=T9["$(ecRtQg>?Kj+ea[ [o6 #}vb>QáBꕀrc $)3w2"bC:hQ'rp(Fct6NAKNk;}hx#ޗw=E SˁUX׾$l>ie9޵uk Fm>ߪ^@yrG{R1qPğVgF֫#| gz7EHϐ6ȶ4اQH(WVo9_ו2d(g``27M*+EE,7ʳRrmv5Y-Y@q3LM[$_RRr:]NGס_`Ygk.]1i}`bPWVii9yƎ [ O b'FB)~lH&GE\jV4 o|y ֝y)K)FKz2,B>P]i^s K4L3?r19s^;#j:a\exxd4P^oYT*ks(Z4`E]hxX8{"I Y<@F/~"UKWS[bg1lRV]LT8}\qj}TELdVys)`Lş|(/ZΩD rp H$lSR0o)#a"rKQ\ )?TfV:c +> stream x[Y7~_u%09vB,'/fV4umI::sgwfgѺ_~~siLJ0=ҽ?κx|wcw`j{X Vw|ఀWx7 b~Og.u~\vk =3؅g 91fYƎ#`\uw$^Qc7.bw9Px2"uvhbAHt.*` wqd$hwkmǝ+u3Z+^.+**8$_wx\߆qC&$ɝQZLqiǓ*d%͉e) @P|$0x;ٴ/.4XO@+8BĞ. 2A ΟIޢ|"aRW97HS D"]n"A"c~pzH"?gPJ BM3FtG `q/p6YC~ 4WnwF8BSD<%xVPU2C2'Iscm!cK p6VC;C )8m_%8EiGzO=MVpX . !د\z rA! z;hR\GG³bEW2_exӭ/ԄPyfjQ ,n%w=ehAXRd@-8T>As7zn kC@aC!_D MWr*~*5Dmr6wwp c]}. p7 H8Z`H^v"V%Uy"rK4Mp额b܄z%4=pUi2qg)ljl˺`p~)yUhm{Ym-Rxw_7s^$Rb*ȍU>OG+[( 'GKP$*P/ jyBTjk2q(VˁMĸ79R@.v45;'")cer@(PPᎊD,&Qc&63mrp8%:(baD K`(@&d%ora  FjaQ8B 5> bȽ6D]mNo^j 3><1tO o kY0DL{1EqયZfΚQQEdv&RH ^ $Ȭ␂/Fb> stream JFIFC   %# , #&')*)-0-(0%()(C   (((((((((((((((((((((((((((((((((((((((((((((((((((" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?B(PQR*41)cz'(?@ 71)cz'(?@ 71)cz'(?@ 71)cz'+#7ŦB9)12;H>Ԣ((}O4((|DuA\`j_/.}$9֪璍re'*+> ޟo}`ZyhQzw㘵iBҴ 4m򤺽92͑נCUӺ\& 2W_ɩˤk#Ib?.3\ Т((o*Ҩf[ ?J ( ('ݏi>SL(|GˤY\I[&,35TuVD&5) HveV敯ȫewc=2.{=aH9/cg' `֞}Z{ES}mH_*ۆqpjO'ߊ4.3xcꨒ0_1TgkgVυ}B[ W:]X  0'# bUdyuzv*;#_I^6Wg]~li0_}}2a'GLCmM,yo s:W0+9ltTꨪz~c 76=pjuJJwF2QE o/*kſ *٢((}O4()M񤑷Tu覝@s 'oOt͞~~cst.fY[*W(+ P!Qs(mqǽQWirwPv\wKǛ>:nPqLk[wUV&UP3*sSL((gz$v@,~X/A$vQXoVi 5-Yx%"H摝q 1$ C>e/j ?_^[G/Ҥ sz|-M+^ӭXKeYDIY[i ]Fx{ƞ#tOk 컫+yel6?+A=q=炚4R Y'qf`sM O^ms]Q-lKF2=:W-|+/_34V d(w,FIHgG}r_ծ;X;[&Cy{$Y:`cWIXУׅ)Ld#WiKc'l(o*Ҩf[ ?J ( ('ݏi>SL() $žèItoUC)# Δ+-QYQEQEA__Ul7TTEPEPM2'ݏiQEW⋙f z|~-~Ѱq#9һuK5+8G .ӴzR?UEqK"NOU| Ʈɒ8bs|#_}1iIc"eEt9R2 :<t2HO}6/p'utrԃ7(dcxAPE[5A__UlEQE>SLcweQEx@^l([c/$}=01޺xc2e=iN<ZE\w*8F MKsmQV"Z-cܝQE+ſ *٬o*Ҩf((cw{sxzU妛sq CltN O? W##o.ۛxc{L2H$Iy6Bi<hOU5-.T=012<^xOHӵ=cSq pɪ]][[v1B ג+L3 >cmGQKo,P H 2rAؑ|}$N􇿵m[CKow167 NsIV4/wR~=Ѡ5̃bT 9dk^4\mKI:Ю/- !˷!㌆gD^O^  sLLh0-BõIfRsXy5ˡj-Ems` ޿ͳfg82?xмMO[4kV,H!wO33 [$<sVej:V iwqa:E2ra;kcͧoCZMSLcweQEQEQEQEQEQEA__Ul7TTEPEPM2'ݏiQEQEVNwyhdd7x8ݘгEygž,_V֬|9tK (3b@ld;Yks+thV ]YN]I &pm]N 7]o-tﴛ ff4e\A>c5袊(+ſ *٬o*Ҩf((cwe>O((ژ:uӌBGHO3n83jVN .d&ae G3+ ugJO,!`g) z)K;$PwgwlcƸ ]IjIIL~F#`fys,ע((o*Ҩf[ ?J ( ('ݏi>SL(KYn xP$TE%dYzG|?\4}wJ'q9X\)&5RFt۫Ƥ wN5WI5 ,.zrFW |V0 ({Ep_Abu9VPU# TF<7V\Z9c`FC8 sQZXP[U:@drq@hgI"R$QGRI -n!h緙GR2HA-cxAPE[5A__UlEQE>SLcweQEsx%?~*о}@JGڭ 8nDݴcj:UHZ+RTFpx4MFt.դ{{+xi,U($p=4*,?=NmmL-p&تR-''|KkZUiz]յRE1#ЉD\j|JyHc1<⢳{o}v_׵;+h$eHt9Rqq$Ǝa|i]xu_Uœ>bcF_21˝+⯉/l+yiy[ AO ciy.j+`+>{Zo[ԵKEBcu v,YARw$N.ڱ4q:<'vSFa,7LH10 G >!O&_7^';"_Ck^af,N=qܽ& 4{^OLx(󴺴lc /!ILa o94ZEoputv ܤ|nj⵴*D-_{uHdǔ)s=kjTR"oX> ÿ3m|s+m %Gc6 H@%QEQEA__Ul7TTEPEPM2'ݏiQEQ\cUҭ|+Iɩtr0EpEe 3ίm3Pglxc[i <<|Àp;`TW|'/NU3,%I'lM ZWP@~%1:Ŏ#5 ' &6BV\eV<)QXڏuK+4z!QsHđQKyY=?u]\?IM yaM+\d-^QJu^:., GH\nL3b23Ma5֬~3ϡAjz+kj۞S6 E;0H;q=>SL(.Um[[{m[d eY#p2NzW]Vl.gsGk Ĭ}HP2}Bw  xĖ|jzCs]6jnv'v9ᯃ-RGyjWkm H접]1YC#?]!\{߽^eimai6ֱ."/Q=R-ƽj [2_ D r$5p> `IxKߊqxIXE:[ Pr c281ҽW?fӯ;6#V7Vu0L,jxFIz.4v6.+9Leٗ:U)V7TUX-TeQPQ@Q@4|v?PEPEPEPEPEPEPX-TeQVcxAPE@4QEQE>O)}@Q@Q@Q@Q@Q@Q@cxAPE[5A__UlEQE>SLcweQEQEQEQEQEQEA__Ul7TTEPEPM2'ݏiQEQEQEQEQEQEV7TUX-TeQPQ@Q@4|v?PEPEPEPEPEPEPX-TeQVcxAPE@4QEQE>O)}@Q@Q@Q@Q@Q@Q@cxAPE[5A__UlEQE>SLcweQEQEQEQEQEQEA__Ul7TTEPEPM2'ݏiQEQEQEQEQEQEV7TUX-TeQPQ@Q@k2\gCn<=re֠?)O?[4P7CAM'> i?-SIl~O dEc}?['!?l@g4?)O?[4P7CAM'> i?-SIl~O dEc}?['.faSͺ\C;,V\ *C]QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE endstream 82 0 obj << /Length 83 0 R /Filter /FlateDecode >> stream x]ٮ}o Z'.;|Mcz;'8৹7Rυ; &*7Hap{$ }ިKɄWuU18 shO`~ >@8c4XKaD*`J] ppUhf.fkе%\9/t)t 9XQI;%nId }ydLUȕы 6k&s ǔ*ȇ.RjjJS$ _ RD>+K((^<+0:+uS6QhP!Ip$Mp`̤mF@]hpAӫx$(_D%H1bT| MPH]9x}D;2HǘƩʶ0XtL.#H@(ؑWJP` Sa۪mI(xP7 [%Q\U@cP.9pޅ*˕Jk|VϣV6 >^ŸJH%!%%Jv̑Esu\Șǔ9UHka Cm`r2,XRXAP"2;"0+kif\* 03wAٽl7*]y8( %+ 5 x–xܐ-5D YT jKי$wUuIPM&Ѐg$\`^l\FIumiBiS(Yqx۸g**n$$JQ*h"P/ƳLӒ{X5-߈on*pQL ˆfZ b(e"1"et ߆†w)27^g ݖc#<^ -m$^X 3wBqdhJ [lKfw[s 2P-^ hؑp}mUfǤ.6)#xylq*"ET-f% {gVZ" n~)W0PU[. J:/co+[-R2♖f_sb>&ca{\U%)છ^6.d)к/2IsQ}lddbQ(fPZ? h_Z]k2/~S@lH5OR?3ga4g*fkȠ )1 p&h) SjC&fޖL뗘uٺpQD4"4T Xu(Qi{zuC#L # xF&Je9hT&2@z"MdAo*ew GH4jV)")/GAV9Q%BҌv\jrzجj8a,e0)n+'HW^CM,GT.THhuŊze= ,# 89Ա\% 8PHG`>k`f;#2t˰/P*?1_,n]Sl~8?O4\Z+8] dXO lo*VX j䔲4%үþKgÐMyci -uHOAAŜ:lIxy;lATfq# ;4,Y6h Lb굍rAϩ(~k:6ᯃD)LXN6HazȍfeAlB !%A&ӲM-_kTXTe*g9},I:_lICa];\[&Qȷd6*m;9N[3;親ٯ:}&k]Ey{{(/O]m!kΪ]p,-pJ\^U ԋ?AE씗SUK?$4̟W豁 Z[}׶NdPfб̘͗yu͍l<uu^ZOp԰HGʺYpf[[s+Y9PM~N]mX'Kz{:[ci8;ٓRźb;6xxLu{=G!|]0t{Q;Cm;傚W0T_*zhju[0i5:F~;ǠEG[w/4Ì̭LS1rQ<ɮQ0V8TnuTIF].-X0Cԍrq4㷇W[)!CG&qZ?})j%AGI> stream x[Y6~-h@~@.ݗHݮêlLB*͗46u_iz~~455/5m? '3=i\O5$zXL4[%9iod ɤ8`&wl~VkLv}3ܸ$N2ұ=10<9cuQWu*En)^s5 Olt *<cj5aވU+ǻxhU>v( pWPdǒ!b:wP cJ`vPH)o$E|Ȃ -![hf[z 6ԭkwcT e[: r< \f--Rb.H(q2a7kH4(ӜSVgDމ`Дe 7w)nϡx0AR$ղ+x/AA1GzBYD(-)Z^* lY63Z‚b6,xpiن**-q$U3) "F藹G Far'58Vz$.9aZ}- UPSk[K&*>2Q4@T2"`ڤz{&%)M~1a-T{њ#<ǂ<>Th \jsǴrI˚>J4۬2ʡ Jb"dymSI^I]hЯX7a{2~se'QyUFд*nM#Į$,M^_*5HP rX˥<+-WNd2|̀5 ;K&+ʓryAd"וl|칯'gX51*3@U} SWݴY BypYZWH}JE!1-YR/U-lMC`I̠221ӬYd*3~JF6X\2x\騹!_AC> stream JFIFC   %# , #&')*)-0-(0%()(C   (((((((((((((((((((((((((((((((((((((((((((((((((((" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?B) = Ch_柙7O2~iz4(_柙7O2~iz4(_柙7O2~iz4(_柙7O2pK_h:*My/4n_7俯Ѹ%ƀ#~gh He&<7俯tT_h?@Rn_?@ ~gh޿?34)yƍ)jF nٮ#).+\o<ԂI|Y&v#?. wRve;Yg o0#f t(-Qt_AfkQi {>/z^ZVZaQ8+N?LJ!W%v$cϳς WhWkxtvjr.V4і9᳹Hݶ3+pG|W6#K gZV TMXd_*Y$m8wNGO≝V73G7%z4Kn2 A'5\])npk6T)UVl㞵5rvs4~c+u5Q-ʋ (aEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP7M׿ճX57^ [VQEGS]€1|b_u6F_M lپwA"xJ]IY'URP$g'sI>w<;(G~ノ?K-NJex^_ ٵ6%i\88fXkέyIlSf/_2ׁ.4 Z[]/p-ıҘr:HcVW]BW^xh|4e:?M^yc*9TݗuP_gҦk&^c*_2h:/;;K+v%$O6s}km-o,s*3kK YUD,[/V$(ӽfn1+u̿~I?R׿[TiF)R}UFnkWBK+wOe#4PleVؒ͜7xdC}C\M5b2Hu0rȧOyBzI?R׿[W_ZX1u:2v];S37䆺'AW^j^ OړȖ{֋ pB;H>YD`&JL )A6V.+yIظ#O/Һ,΁K[wSW=SGf25VtKs_lհYlqx2i& ._\O%|CT5.=ZȒY Kc|N:0 rޥM0E3üž]F!cQ)xت,@8S>"T;3҂~^4ǐYy]Oޠ+C sj&QԮ-G]AQ`@'V~O/?G@|~hvd~5 >1'AW)}YAoZx$yejk_P1+!  ;*g_?Hګ顣[7ֱ_Y\Z\.'gV?MF(lUPm-vt܂' W:O1k' XLip'|pAv~|}dmbZ}.i51G]BWMO+7;[hcxGqUE@WW$1++.sLI<]4>ZT2A }vyK uP_gҺZ&'bYI5YN/[Kҥa g(Ziim&*={Ϸc3^#[m&RrD7 84.i51Z$g)EH[@$;zn㎹:ZOI5=gYR86s57]BW}.i51V{Z{ &g-}njxoK/G8<ί?HӢI/%(0b:*//kkWҵ(5 Z\ {K ]@P"c *~sI\ֱn֤qLx9'`|T[(#i)~4|^-%Umԝ/5KG/ftRlO7=\?jbFs0QWXEB;#6'vW%A\=E8͎qW+ݏgmGR,Y].-.Vf9A\FTsA֖?:ޏxMRɫ@ں13lm \)Xj k3[2)AB81Ur H=E8+OxOJNMś5LI#b  r_,|JM-|A/!w;S]&xZ-'@5ʬ)";W=zi n(51k"n^趭xOڶh(?2xOڶkƿ&?jl,I GG2?1 z7EWhLy9 s> ed|>4j- f(cu Q1G&>FTf/E[MFyzZ֛upCorRNRIǥi?YRo}gM kRv%b?Y>,MmQO_G> /G#{(acϽekj9Xdy4}?Yڢv1~,Ml}_&_U]7=K8Xdy4}?Yڢ; l}?_&G> /[TQ1~,Ml}_&_G> /G#{(acϽekj9Xd{5^y{"br:o܊読|Xcގv.R-ߕ[q*Ѣd[q*<~UEч!7Z4Qr[q*<~UEч!7Z4Qr[q*<~UEч!7Z4Qr[q*<~UEч!7Z4Qr[q*<~UEч!7Z4Qr[q*<~UEч!7Z4Qr[q*<~UEч!7Z4Qr[q*<~UEч!7Z4Qr[q*<~UEч!7Z4Qr[q*<~UEч!7Z4Qr[q*<~UEч!7Z4Qr[q*n<e[a3j%mN50^M|2xs]<Тgj00FrT4sZB5B!5R7\14jY@e?>7\14jY@|XcޏM?MC42Gwd^YGF(ߞ ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( z?[VbxD-t)lx|vЍ`P?AEoGo_% C4WWQ_2{7M׿ճX57^ [VQEGS]€X57^ [VcxD{'m@,#oʞnioiI Y$+#i!rs3{^-GNpYN% &TGW!Oc&wkKmJJYaWfݝ$ 硴l(iS N7Q-mW e Ιo궗7>s08Q۵un'Q-ƋTU_CˏrjFZ\EUt?ܸy?>.O&-QU~.?O&C˟ TU_CˏrhWrht?ܹy?EUt?ܸy?>.O&-U[En'PsvJ("R~xG@ ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( z?[VbxD-t)lx|vЍ`P?AEoGo_% C4WWQ_2{7M׿ճX57^ [VQEGS]€X57^ [VcxD{'m@d̪ʁB >eZ-IӼC[rH|F, M-C5A `A =#1+XtSMV΃dXxi䑍:Q3l迕*'l \5-G~0+T-(0.+rJAERQEQEQEQEU]7=KU]7=K-QEQEQEQEQEU[EZc]zEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPX8/_}j۬Oȗ>E8-ܿJa?h}?hFj—S">+OpxOڶkƿ&?j٠(|?xP+ƿ&?j٬oțׄ-z$6,J,Us' :w ]CRbPE8-ܿJa?h}?hFj—S">+OpxOڶkƿ&?j٠(|?xP+ƿ&?j٬oțׄ-+xNxghdui@*MNj<q1sgo=j&]eh1)qs׊|[Ǡx_Y>ηNݳџngZG#oCҬ,=-.[`sۧ5jLͤd(iWq1z/G3 U|7k:e\(_{"|G']ۢ]Ka7AL%J;~.?O&C˟TRWrht?ܹy?EUt?ܸy?>.O&Q@~.?O&C˟TP_CˏrjWrjKҴꮛ]э@ۡs5jq4}\E8-ܿJa?h}?Fj—">+OlxOڶkƿ&?j٠(|?xP+ƿ&?j٬oțׄ-O.%ݫ^ڼ2d*r{8|ןLƟj}a$w5qO9x[ap2ʢ\\|d?Iu3m>8Y"6XO3Et=Vt;dmW=t=G?iӿP>d6eGҋcA+J6][7\14jY@e?>7\14jY@]эG٦?&X[`b/'_0?Ӣoch4s|*f?&M??MZoch4s|*f?&M??MZoch4s|y?跣P Q摇 (B((((((((((((((((((((((()GV7M׿ճX57^ [Pt? kMag=!3FWxb94/nӤ5&xcEڮsnvT~@1Ox.O&-QU~.?O&C˟ UWMwƣrjKҀ4調n'Gۡ*ۡs4jq4}\E8-ܿJa?hƳ }eCŷRrqғLx@\;6n `GNtM{)/#ȧΏh1k"n^趭xOڶh(?2xOڶkƿ&?j/㴸{HaQQHZY;A<C\e_hzχ4q$ҙlGhcr]۠Y>Wpkd_c&Y^NJ5;yo-7 8R^BfQکD/E^V~=Edl7>3?鄵XriiEp [V (Š((((_j_j(((((ŏv?-U[( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( z?[VbxD-t'O_wկ_4-h1#R>qϮ'}xL.y?fi7 '(_uEl7M׿Œ]LxOrȍ*qQ`x;WCiWw,ѼÄE?@ 旯x%]VVa;&x;A< W3v=?4(?zӧG=AxXқR.vRSA da۸=>/\15y?A~7\14}ocjU4q|iTP_M?MfEU4q|iTP_M?MfEU4q|k yL EF۟ZuWMwƠG٦?&Q@~7\14}ocjWG٦?&Q@~7\14}ocjWG٦?&Q@~7\15 ݑ{eip~x*|Xcހ-QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEV'?Kqڶ%mN;Kc/kDB+z?_rFtO(Z Ѣx(1k"n^趭xOڶh(?2xOڶkƿ&?j z$IG YO+ѯ|_Y\\xS[ t%JdmU,Y.XᏭzƱU|-l{nv)f8\ƑBMSK׼<4}WpnvPcW<)R3h=G,/{N迕*|,qV^1ީniss3}@õun?'Uu-G~0*$4Ut?ܸy?>.O&QHe_CˏrjWrht?ܹy?EUt?ܸy?>.O&Q@~.?O&C˟TP_Cˏ, SzJӪo{vF5n'Gۡժ(ۡs5jq4}\?_rFtO(Z Ѣ/kDB+ ^OB(=ƿ&?j٬oțׄ-f ( |?xS)@ oțׄ-fk"n^趠 R=B5cn Ayg4{Szַ+}'Hw#]@/DcY-]އ.x7\15#-QU~7\14}ochWG٦?&-QU~7\14}ochWG٦?&-U]7=KM?MV^N`*}EU,q|i TU_?MfEU,q|i TU_?MfEU,q|i UV>,oG٦?&#/s,#oPQ@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@bxD-n?_rFtO(: Ѣ/kDB+ ^OB(=ƿ&?j٬oțׄ-f ( |?xS)@ oțׄ-fk"n^趠K˞G.mFQtc&nv*p+JǞ9ZP 8 5xvz.qu/sԶ\"Xm *6ʌݑ=b6u{Icqg|Im~gW)*8m͜潚;ѫj=Fo_]-xl/fiF-`T n 79'=w,/{NH5O:@ceᬼcSY-VfB܁ 9={vrj%HEUt?ܸy?>.O&e*ۡs4jq4}\.O&-QU~.?O&C˟ TU_CˏrhU[q5 1wd%'牔~ Т(((((((((((((((((((((((Oȗ>Em'?KqڜwBLJo_% C4VvЍ`P?AE}5KHQE'cxD{'m[5_uElEPOt e>(_uEl7M׿דNB\σZyC,97C =@kʲy1^u]oPw=ZE1-(K;~h dFoͳ>,>=݉[q!%OF'1z/^Ymo?Mf .g,oV|Xcހ-QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEV'?Kqڶ%mN;Kc/kDB+z?_rFtO(Z Ѣx(1k"n^趭xOڶh(?2xOڶkƿ&?juև.x6Q]5Xɹd2l۝ H :w 4(?zo:V!Ӯc-dPG}W5)-~e)8>LFY=.XkjߨWG٦?&QHe_M?MfEU4q|iTP_M?MfEU4q|iTP_M?MV^N`*}Ut/j>7\14}ocjWG٦?&Q@~7\14}ocjWG٦?&Q@~7\14}ocjWP Q摇 +Bŏv?-Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@bxD-n?_rFtO(Z Ѣ/kDB+ ^OB(=ƿ&?j٬oțׄ-f ( |?xS)@ oțׄ-fk"n^趠4j- f(cu 0=까yYHԭ5)Y$ع%cC$ >)-f <5k6d7ԕ'@A=@RIWj"P8/oTt}7UP DŽOںE˟?jnKZ2w*\.O&Q@~.?O&C˟TP_CˏrjWrjcQeJO(VUo?j((((((((((((((((((((((()GV7M׿ճX57^ [PA*Myρu?%Cߤi0ȶp,U`7u.?Iu3m>8Y"6XO3Et=VrgĖz|֛Ķ,ZUo18Y|Tcd =RP3qZ7\14jY@e?>7\14j_}ocj"uSݠ :*f?&M??MZoch4s|*f?&M??MZoch4s|*f?&M??MZc]z>7\15 ݑ{eip~x4(((((((((((((((((((((((+ƈx;]HԳUFI>[p+f?OZ1=OAd٢kq!nx<_&ndk5hݓEz~5+xN/c8hrQ\'Y_uEl7M׿ճ@Q@>)GV7M׿ճX57^ [PM%eBEp #L|mk6yjsxe|۷;W8{ O ݂M(X<;=ZGKֺι[_.w,@UWHFsm$d`F敯_|Aecekq`nf;ȄJȍHO\3WYAui4s[N,RЌu]{Ş D. S(;%Q<@=:֏,/{NH5Ί7Q-mW e Ιo궗7>s08Q۵un'Q-E*ۡs5#-QU~.?O&C˟ TU_CˏrhWrht?ܹy?EUt?ܸy?>.O&-U]7=KCˏ, SzJӢ\(_uEl7M׿דNB\σZyC,97C =@k̲y1^u]oPw=ZE1-(K;~h dFoͳwE?uˆ4uq.)XghO([]b_ʼ_W4Qn|5}Bċ$i`w]7bKoX'W Ka7AL%JÕKJ- ?JܨH(C ( ( ( ( ǻicUǻicP( ( ( ( ( y?跫UV>,o@((((((((((((((((((((((++ſ*k?7kV["^S@Oį *O_>H !".@e!bb~E=ִ;_iw:MVY\<Ɨʠq8#<;񦽣j~Khl`mn;(xOڶkƿ&?j٠(|?xP+?RjZc"um,HPY}+B»|M%4g,K1U4g늋+_6i'o=]ʎw+_6i'o=GWlӿNz*(TaXi SPͬNa~Q*g$u3޺o Uj)=Bş Qq?Eg7?FO"Q@Xq??#s|'U,YEP,FO" Uj( #s|'Q[Fb&ʫXךş Qq?Ebn(EVg7?FO"Q@Xq??#s|'U,YEP,FO"@7Jb?Q5 ?C̢XT? j( jP5EcOP4}(,iCe?C̢>CYP4CGڡk2ƟڡhT? fQ@XT? j( jP5EcOP4}(,iCe?C̢>CYP4CGڡk2ƟڡhT? fQ@XT? j( jP5EcOP4}(,iCe?C̢>CYP4CTPPq*p )?CEc W$zrXG:\WR2r#$kj@<2H "sGZE;(QEcxD{'m[5_uElEPOt e>(QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEcxD{'m[5_uElEPOt e5HўI%PJ#Uf { :GO1G> stream xZێ7 }_`A]16)Pt[d_<ËEc%},8s|~#煸H{`^PeOGyyHB4 |Ӿȗ%wAIt.>~!%iDjYl|}'I5mDºY1Z՞y* 'U1v#>`=_MyVX ).w bhv &VJڴ ԵCOL϶Ψؽ_AE x1J7qXy cIJD}꼥娥]pחݽ\__Մf%|H,3h<2[3q.rTlfo[Z d͹!MBOT+:ے#Üc\炤0X~kWY:RReĎ*q2h_ jiHF T dlW+Cdhݛ4)3E޴}P+fTKX-x@{ ƨűF:d`bRb[{eT/YyN/`(K%ALD0X[^yhSJ+nJV”T+ 5"]MD)]'t}dZ _aOmhv?@g]0|,2b*eF oB^y v 7Km ti2#eOEHaBϩ2W@"~ڱHwdVZd~t׵Mk ,VP-4xj:hVc#~*~èl@@y/ceX!?\gMuFz^A)!h5^ݠuҲO[V殉4>R[B'A94p(0|]f́ JטiMk„!'KSv'D堬=Fen?\?/?gd t9&_]A<^䚏'f:ow_eVendstream endobj 88 0 obj 1551 endobj 89 0 obj << /Type /XObject /Subtype /Image /Width 766 /Height 588 /BitsPerComponent 8 /ColorSpace /DeviceRGB /Filter /DCTDecode /Length 33131 >> stream JFIFC   %# , #&')*)-0-(0%()(C   (((((((((((((((((((((((((((((((((((((((((((((((((((L" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?B(PQO`(?@ 巪b-S)[z(?@ 巪b-S)[z(?@ 巪b-S)[z(?@ 巪b-S)[z(?@ 巪b-S)[z(?@ 巪b-S)[z(?@ 巪b-S)[z(?@ 巪b-S)[z(?@ 巪b-S)[z(?@ 巪b-S)[z(?@ 巪b-S)[z(?@ 巪b-S)[z(?@ 巪b-S)[z(?@ 巪b-S)[z(?@ 巪b-S)[z(?@ 巪b-S)[z(?@ 巪b-S)[z(?@ 巪b-S)[z(?@ 巪b-S)[z(?@ 巪b-S)[z(?@ 巪b-S)[z(?@ 巪b-S)[z(?@ 巪bY]C}eݫ﷞56Aphj( ('ݏi>SL(((((((((((((((((((((((((((((((((((((((((((("n^赭WxAր6h(|v?SM2 *+m-h1䑂ROڶy).߮q@tQU-;ogVr(޼>a(Q@Y%HGxl CpGcЊeŴ9bpFAR8 (*n`Yxs"8&6*p{{QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEtEl7MEPEPM2'ݏix/|m QVM.Cu0Er"0<P+[ėMf+WlUEYdH3(8܄l oGgZunX8Wr;Ax7Bo&\s!Jn8C[:}οmK^܍}8< yep7ÿ+v o4-*Įcvwt;+V_]YZ~ϕ lyT:sW3qgg^9[J֭l5#a{{b%'|4<>X``qM'yߍu%շm$IFYpwrmj2k\ZM^\@8`ŞC @VUԥY*fOL̀"|zR^ еG#Eu4,g5pFT`q3>{t4iΤ LV5N&,ddo? q[kE'(f)a8S3ZKG$D\]X'yw5WٗA#R4Iqw-Ð#1d=iK=Z h}ya1FBjTӭo/2K)nwM?,0r90((((ZmݽZ,Osbb | MY5\f]vg]y\/Gq~>Csq]cu;aty.T} |O﴿H5 su>I]' {֯iZF.%啄G,Ò?z85'_5aǙwݏ={w n|/9=MkK.ha^yЎkX|,yhzc.?<жS5|t|"!յ+WZwԟxQ)܄t\\$~ G>xL~*l55Op֏n%o9ɯeK;Q$:Žd{UXc' N7?7^xuM'N]叄;ys18YIʏq9ǩGT[𞋪̋P]2/E/jX[YY"aEE*7 )QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEV7MX 7A?ZQ@Q@4|v?PEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPX 7A?Zcx+D k@4QEQE>O)}@r:,e%[tQByX0$d+$-u XiM,/o^L$6D;LHsm={&3.l|!j$O7RhߖYA-A?Z{şhuKw\^br>Eo1ɦMy3;ynz.ȶ0bǜp MWY%D{F xehd${cJ-.x{V:~] DZƊqIs=ExPk o1~eE=)6ڴ&I+gNeHGힽ)j:6]H\)bp8QvZ/4eMIo a!D\mE'#WetxOߋ9{|MvHwv;#G\#4߉K&iV>S-sj;u(eV#J#H$)1 h 9 :6oM=\jh܇~&O?Vze֖Hc[S$>1/iO<6usͷ8 eMO=>k&k#Iu"rPH$W"Nf8ݝ{Hأq$h0f^?5v/Ngӥ6Ť+//'7>Ӵ֫llI5m ut.YwF~F;Y)_V|~Ook^AEPEPEPE? MkBxB(y-nAXTRցE|O]w~"Z\kFWqc1:~V~ /k]KjVnG!BerDY'rHQ+E|ߣAN}F}Fkc{tDmfK>bwsN:`Sl5;YW7Z?P.<ؔ`ǝ"P>)QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEV7MX 7A?ZQ@Q@4|v?PEPEPEPEPEPEPEPEPEPEPEPEP^C+& ]q㥺X_x\@3"5^Eyg~On@2=n@2=sZu1u1 VO?GG?G@\֢|? ez<? ezc/#c/#57_~7_~Edyj+'_G_G.kQY>n@2=n@2=sZu1u1 VO?GG?G@\֢|? ez<? ezc/#c/#57_~7_~Edyj+'_G_G.kQY>n@2=n@2=sZu1u1 VO?GG?G@\֢|? ez<? ezc/#c/#57_~7_~Edyj+'_G_G.kQY>n@2=n@2=sZu1u1 VO?GG?G@\֢|? ez<? ezc/#c/#57_~7_~Edyj+'_G_G.kQY>n@2=Xod4帞$_6h]B9^2C fzz((("n^赭WxAր6h(|v?SM22|M6ҨZ|M6ҨZ9k|׷㠎Inytbe.fi^Ѵ톟 [f4 fE$@tmB L+ʈ"!ƣ*GOsV]y.fx$2DʼnV9<-`}_SVԱX.$Hp23U5Oh:-1S2}elpSҺ:((((((((((((((((((((((((((((((((((((( !Jjoj֢(((oțׄ-kf"n^赠 ( ('ݏi>SL Ǎl*֬Ǎl*֠*Yh]ΥkclN:}I$5QQargƟrcM*$nE;@$Ȭ׌5Tխ8o-qqIVT s|Η^M_0NהW+g!*<-գ^ckcЂU_1ZJ*[tWAEVC ( ( ( ( ( ( ( ( ( ( (gǾ6Ѽ %,Cocv `Ip:hμ:j}I]5GKMt-6Gq g.qS>a\AaH˩X"BĒ}ќ$-ХeOEoFKs裥EPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPY>CZՓo?~\EPEPEPX 7A?Zcx+D k@4QEQE>O)}@>&OTUY>&OTU@xGc]xCҠ}qA(&88+7ATzok խq.Nd$8T6rPkgJeFU=?VMw?}+-}'N6~3ٮ/i>k[9tZV$b{(qp>:$&i7lB۷zx_W6:IhR"XL*dlͿslfVź4(s8Y[<ۑ~݇m:D)$䍤V8 c$a5|.xVkOIDiE $!R:`Fb@ 5ˣ.#iOhP4++JS34w|g:S߲waW.oom&vr;Enw# ʘPs)iϚ&2)Ӛn[\V )c 0*;s@Wu/G\Z3]Kr0wfڿ"e9(1qF)|]Z[]c(e5c%1(G]ɦݎ%^+@{knV9{fWYLG%3*-u)5 ZkK]V]I-[ėR"n3*PYU@ݏGOsk$XiWE5b^F­h-յFӦӵ6Gx5*cvLAIEq^)NxG,mGQEe^2H]۠-IIyYԶWGbƒ,220^x7ӬS4 A݉c33 {-+Rnaűu IH9PÞs) ((((((((((((+'ҹZ|- +5((+_&?Z٬oțׄ-hf((cwe>O('ia*'ia*(|múC]tbqerGF /z,ghl3OI$BAvWveWa9-S,ʝ/cϗL7{úLB4<{EeC3H,I$f'jmo°jZԭ5KILb.,$E2$6 6 \kyIIݚ49ǣb^_\](y)# px$𵗈v m֖S(W^2<5ENcVUlSPI2Dmda=+Q@ ӥѤӌh W YI^R``?)NbsisK-ܣ!9)@ ,@$5Q@X,"6VhoF'VӼ jZ]7DB\͖ 3;:vf򽵌 oJAr3`+j־ nMd3M>LFJn K1bcuP1A}n[Ym%Y,Ƞ$?+2A1V꯫C 72NbB T3{(&ӵ;GZoe--b4`A|tf z7l>gs}aqshm.5]Qێ$OuFttP9ɧj꺦y-o cbʡG%$~QtTQ@Q@Q@Q@s>=N),uȤO,О3# A:j+J5Bj7i.M&ϖO_Nt^6I:r9#K -B[bIK2I'sx9ֺO4+JAúӮ&KeKv˺D"@x8hy N&o=sX; D-:6.XaxPd]#pI,Z26іR<­Y1ֽ:b`qE!Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@d[A_W5kVO{sPQ@Q@Q@cx+D k[5tElEQE>SLcwedC@QEQEQEtEl7MEPEPM2'ݏioEZՓoEZQEQE($ J)T*̖Ls;J'Z+k`mi]ɧEC mсÕe F )xvj 9縖IPm໱EOW ~ I Ə33JcFv͞X/8=P~k7)') 6뱔H#h&OZ%5bOT]U@%YwA"; ( ( (3/?PןiQEQE[Emc~L?*OBc<~Ty14P!L?*<~T(L?*<~T(L?*<~U3!ʻӮ'L&e8<:זxǚ ]ZGci%ǖfmm 4L?*<~U>]tiWu橌\OC7SGVB-N,+2HahԳ4+|uɏyGOʸx fI hgcK`n`sYVVE4KLu` lvF1_*?柕L?*oLEQIc'.=A$z[ɣ@^xy"wuHGmf\4Q4ciW%/bZ3y'xb`:SZ6&}.iay"Y f g4y14ciW E{oiwP }it6VͰ%SF.g>,[VV{tluvv38zpy14ciWI杨ޗaui$M4,HI"R2`cq[>-mn& -.- h&VRB k14ciSy14ciSy14ciSy14ciSy14ciSy14&k (d[A_W5kVO{sPQ@Q@Q@cx+D k[5tElEQE>SLcwedST4袊DQ@yNq]DVVѭȔ?|E#;5PZ­^$vzjlϒlKG'`3WMm2g^0$$Ы k(ҴytOi>cķW˲Wb6'*_[\.n;uO pCn򙘴1rq#&ݐ+٨uFt5u$ԕG͊i76rJ:OG/x{BeOU#\R-ټR<4ŅFjm-)XgEH$mRud_xztu( Wس-ݺ>YA$HLFkhM'Z{}y=OOY $YB0HP('Zmi(Ok<1aN~mtMbMN ^Bmfh-Ӎ3.^ExEm||=jy5㹞Hę#j8tyQ 4 kQiB2&#Y}@(ߕ{m|Ek=wZy]N1 yM3; Ox;AU ,33"wLq^YZmkZns->]Iw݂{n>a Ю5F+6+slKmGN֡|&i@lk6 %)& bCI<țkF2xt-R]I`iEm`sb $oOgHt;;K{ƣy3Z}֍ pmWHд}:aWřٻ1$RkB ( ( (3/?PןiQEQE]ӿjSӿj!0(QEQE|MῊ@,i/Z6c6F1;(k/w U6b[XaMsH?N)>6+-T2ȃNfѸl cq^UK 9l]cv9yiЎ'V{x.GTYv#ҼtF/δo]lvGll<³#akeU\d֔FȠ ֧BnMVSNlAD+w1!ǸpJ/4-zαjwRIv|;yaW;o<jJC 7qɠlm~qC@QEQEQEtEl7MEPEPM2'ݏioEZՓoEZQETjk?OP Ӣ)QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEf^ʡ?P(((OʧOBaEP ((((((((((((((j٬jhh(o?~\խY>C@QEQEQEtEl7MEPEPM2'ݏioEZՓoEZQETjk?OP Ӣ)QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEf^ʡ?P(((OʧOBaEP ((((((((((((((j٬jhh(o?~\խY>C@QEQEQEtEl7MEPEPM2'ݏioEZՓoEZQETjk?OP Ӣ)QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEf^ʡ?P(((OʧOBaEP ((((((((((((((j٬jhh(o?~\խY>C@QEQEQEtEl7MEPEPM2'ݏioEZՓoEZQETjk?OP Ӣ)QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEf^ʡ?P(((OʧOBaEP ((((((((((((((j٬jhh(o?~\խY>C@QEQEQEtEl7MEPEPM2'ݏioEZՓoEZQETjk?OP Ӣ)QEQEQESd"]:qY:nHf0p5('nv[FT񶘙L3Z-g+N__Xj_X]mC-&LnX33VS:30QzT`?YdK#bIQEu$ SQEQEW{`JELi%qE5(";[]> 6 35H8y'\Ur6V~CRg"Jetar :sKկtZLʹCʟB߉ձ Awx؜yjNCEWŠ(( l;VXNA;jyj/3m-41D$K %@ 8 k7*Ml#Q6[/Lr6 sZjyj/uBʥ/Wq Tq)X cGm%0,b+I|Kiz޼ž |-96.boDZ85F9 嵟qxQYmːe]PSQIe"ok^/-xs9?QkTUe!:_K+N7 <4nS)XCt=5 Z?Ⱦ񖮍xz4W!ε}rTK3= vG k"b6J^QEsO)/9D=XOy`pH?oi.H W)`RW;xP+쳞]y)N嚱AEV`QEQEU! Ew>t0/?Y ;_sPA.>QE +'ҹZ|- +5((+_&?Z٬oțׄ-hf((cwe>O('ia*'ia*(?PER$+4Q1?{S^xYm&1F++ 4c9Ɋ:P((Q@Q@Qځ iCHX=SW|fҾS,IumST $FCǹWG\iܳOgi{R Q˯5lFyfUz7v=HeXTxOJ&xI-(Eu5MxM]QYQEr=a@-oCa.Q8f!@y5xkV ,`/r0sx—W:>ZKgdHQ==:uu2֬NMs,K-.{8!8[k,%0_/-v{&(Ks4>YxG;c'9^vclk!t"Hn]QqG ȭ4uу#  Q\%ůpBU1k\%УTQE +'ҹZ|- +5((+_&?Z٬oțׄ-hf((cwe>O('ia*'ia*(?PER$JHCywBY$ Ub?*&QH2$=^YW]əQ\uV=@ay8GWO**r }d;EP>Vuqc?S:ۖE'F )f'kuM]FKOuGO,n#vzYfo/%_<}xڗ7:clǧ?G^ G%8&ѷuaǟkxkg1Ie<чqF+Tny̾5i#:+ 7Ő-u5{g=}EvNʔN\VaET..V8<܀jJHfYy~++"^EU(䭌lY̙?[Ŗ0uͧߐ8cco>`rAlD,-C>߾ {fּ#cIq$]E%S!CZW|f+iQ,Ncr H?QFGӵoB!}[w}!,^l0O0$cSU+A?PןiQEQE]ӿjSӿj!2NC2 QOObQc $F1Eg?5F"+CG2C((EPEPAk`SLKOUi M5[4\ԄڬZ7]#2-]2 O&~urSjEPjQEqC@QEQEQEtEl7MEPEPM2'ݏioEZՓoEZQETjk?OP Ӣ)ǘ>&Am끳dr;[>U My/*Q@Q@tiZTiZHLϋh`l-3.{ǧ\˝Xm#,p^.;k: vGjWYctV{l9d0W;V Esv^'G\Ã?jë]E ~dsG'4`QE!Q@Q@QNRQopV;c֡"RsTn/ޱokxAD,miwSHGVr&!]UuŠ(EP>B\El /BDFydijVҵX, GvSi> ZK|'l7cCȟC[ ^!-8Ӯdcv} r ں#$Q8` kK-θ/t3[+GLŷ`f ?KqAw8W%oǍ0CCeůpBRiQ 4syQ&>NN1N3KM (d[A_W5kVO{sPQ@Q@Q@cx+D k[5tElEQE>SLcwedST4袊Dx=<ҵ\ɍzj^Y%ѭA_iW6Q%OfqWN\R># ǥ/7G]KS4r%Ņ՝i3z9QMÊn5j)f&ȧYI8,#&Y!u^ֵ@oK{TaM}Z ||uךu=CoִD~|?bUksf> A$?9,?B]%u#0((?UI!\#F4>j:RABCF{)4wa:pBG!~6A_?rj3+NiitB{˨eB#H'?1Vk (d[A_W5kVO{sPQ@Q@Q@cx+D k[5tElEQE>SLcwedST4袊DQ@ϏF6:2\ޣG˾9u:W{su{n?_dR:WPF# ڕySa5sഗYI|c_ÚIqip<}|s_3ZAgf-&bO^jOҳoot:Ŭє#"溕BLnBu9?BJ53!=ULI^EWߡSh$Z$2нuji\^мe滯gS~:F=J ȡd1S>]ccVhg>GϚt7g8DE,}z-F鄚ZGPR߅4of.0ӿ#}X!\Y$dV~>1Ɗ(  ub!EUQEQEQEQEy/*?CL((-?W*-?W) ʮ\R0AW/7|iw ^@%>:ޓejPzNGʐMsWWCoK1d4nQ#(+z.K uӚcZKw:\+f+*l3zՅrs֧x=ir-Z/GriyZ/HKޏZ}7M :I/U޹/!}Y-QUUUQ@)h$((((+k (d[A_W5kVO{sPQ@Q@Q@cx+D k[5tElEQE>SLcwedST4袊DQ@Q@Q@^ZBa#%:|*UA'0;ÏHMI1ξVIc g[ٓFhX[xQ_i"GQ :94UgdϜo oCT?6.Otx8 R.=9ϽtoKEFn.s_WQE9 ^v#Bӭ]ND=kD6EP ((((((2>_U My/*AEPEP;Z~֮U=;Z~֮R (q'uk5m$,cE&τgdRrOɸq֗\Vgsk'LM_#_\Se&B n{ȑ{u;R5Z}"A"Cމ1-ey}j} Ys략 .x>ʘ=cP?5@ͅO\M8^{p> jSzl;3^m{^{Cn<ˌ}K ٳ5!Q&=:Td+9%Kagjl,n8e0+=#t4zlw>iuQFF$TAT` Q<@OdM"I8^hY MaWWEh7 ((((((f(VO{sVd[A_W5kQEQEQEV7MX 7A?ZQ@Q@4|v?PO6?UkVO6?UkPEPSY~?ʡF7 z+?z'GdOʐhQYm?*>'~T +?z'GdOʀEgODlP4(蟕m?*ƅ=z'@XТ'~T}OD VdOʏ蟕cBlQ=,hQYm?*>'~T +?z'GdOʀEgODlP4(蟕m?*ƅ=z'@XТ'~T}OD VdOʏ蟕ai962})QEQE]ӿjgZL :U hmQ,U_u*EVlʏ[u*>_ 4Uolʀ,U_u*EVlʏ[u*>_ 4Uolʀ,U_u*EVlʏ[u*>_ 4Uolʀ,U_u*EVlʏcVcULh(o?~\խY>C@QEQEQEtEl7MEPEPM2'ݏioEZՓoEZQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEVO{sVd[A_W5kQEQEQEV7MX 7A?ZQ@Q@4|v?PO6?UkVO6?UkPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPY>CZՓo?~\EPEPEPX 7A?Zcx+D k@4QEQE>O)}@>&OTUY>&OTU@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@d[A_W5kVO{sPQ@Q@Q@cx+D k[5tElEQE>SLcwedC@QEQEQEtEl7MEPEPM2'ݏioEZSTMF4bHY!۽Z7WR7yGPjE :k(ZȺXm_0ͯ j+'"cd]ì6b5싯uQuC|֢.a?_1GE :k(ZȺXm_0ͯ j+'"cd]ì6b5싯uQuC|֢.a?_1GE :k(ZȺXm_0ͯ j+'"cd]ì6b5싯uQuC|֢.a?_1GE :k(ZȺXm_0ͯ j+'"cd]ì6b5싯uQuC|֢.a?_1GE :k(ZȺXm_0ͯ j+'"cd]ì6b5싯uQuC|֢.a?_1GE :k(ZȺXm_0ͯ j+'"cd]ì6b5싯uQuC|֢.a?_1GE :k(ZȺXm_0ͯ j+'"cd]ì6b5싯uQuC|֢.a?_1GE :k(ZȺXm_0ͯ j+'"cd]ì6b5싯uQuC|֢.a?_1GE :k(ZȺXm_0ͯ j+'"cd]ì6b5싯uQuC|֢.a?_1GE :k(ZȺXm_0ͯ j+'"cd]ì6b5싯uQuC|֬ !J"csKNKh`IIvyF'hQ@(Q@Q@Q@cx+D k[5tElEQE>SLcweQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEtEl7MEPEPM2obd&N%yz9?ASIl~6hoO d}?[' +!?g4f?)O?GCAM'٢ i?-SIl~6hoO d}?[' +!?g4f?)O?GCAM'٢ i?-SIl~6hoO d}?[' +!?g4f?)O?GCAM'٢ i?-SIl~6hoO d}?[' +!?g4f?)O?GCAM'٢ i?-SIl~6hoO d}?[' +!?g4f?)O?GCAM'٢ i?-SIl~6hoO d}?[' +!?g4f?)O?GCAM'٢ i?-SIl~6hoO d}?[' +!?g4f?)O?GCAM'٢ i?-SIl~6hoO d}?[' +!?g4f?)O?GCAM'٢ i?-SIl~6hoO d}?[' +!?g4f?)O?GCAM'٢ i?-SIl~6hoO d}?[' +!?g4f?)O?GCAM'٢ i?-SIl~6hoO d}?[' +!?g4f?)O?GCAM'٢ i?-SIl~6k_&?Z> i?-3F<߲n8JEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP endstream 90 0 obj << /Length 91 0 R /Filter /FlateDecode >> stream x[݊6_wu$[6,2I/*shFwJ`a4oQ n=0?R~~0]OzRwSf\-OF|onee|9$xOaʒ^u c2BZ*n2x+GOXYI64Ж~CS.W[<:ʋ+DZ2?}gK3>Up ggJ+ڋtQzwϻG_;"訨I*/C "^|X:W^ÆBw/m;Y™{f-クUk,4T̨Y-{`ݧ~*?7B/noŐXxȨ@{E_)e8КlCqEc'J(O,5,ȢַRz)N,G/^T@sDܟrR*gJ^<-7|r?7yBTbt;.Nd"` _hOfxgY};y #ML⚗=n.asǤ*M2r4Q kK _'Լ&)YcEPAD~3K8/IEG}; fi-Y/94%QMZ t;Ĵ-hAI$$X ! Bc3< 98*cL,ƛn֒]nE@Y_"jnJʓWGO1Xx_s;D KYV-_:(ؤefC,`#;RUlPkFav +m]2nI65=6L. Mcs;W)OOAoCDrKaZSF=="} Ӎ Ļ51N㽋z $ddcea4{ҦC bmEPp( o3j KzDHp&Ur֮nkPE!(TEZѬH^MtҰLv>q$(t3CvQȞ|VxN9h3^sj>̥t}D:邎=9f2H J,;s&kx /Sq"b=iPn.m/!2+ˣY&IZ} mGs ֟]l [AafTUF#hH(\Hȋ}HzCVnS~v!3)Baxrxvi'udPQlMG Tj ##(EW K*=fd4'un#nsAmd^"p{AӅ~@xQnޓtI(sAe"׉V DU tC3TW<quS;zGdн ROѓzbA*;%NTz~{4%uvZR`_+뀛Kn.sʰL\}<|yWkoSX9]_o_?lM}endstream endobj 91 0 obj 2308 endobj 92 0 obj << /Type /XObject /Subtype /Image /Width 522 /Height 140 /BitsPerComponent 8 /ColorSpace /DeviceRGB /Filter /DCTDecode /Length 5572 >> stream JFIFC   %# , #&')*)-0-(0%()(C   ((((((((((((((((((((((((((((((((((((((((((((((((((( " }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?B(PQEQEQEQEQEQEW>7zޅRZ;Cs4[J7,j. `s olƙzO*O62+:nɨcN!s(Z˻}\MG:ON_CVσuMjBY.a-ef;VE_!C(ݜ^rÚNÖzx+t3m^9>U/4kRtU7 8;̪JN?E({:5V59o`tԮ#VVb*€@DW㳋_CL-/zj6%M[rrj*DQ=5o].&KK iVrj*DQ=5o].&KK iVrj*DQ=5o].&KK iVrj*DQ=5o].&KK iVrj*DQ=5o].&KK iVrj*DQ=5o].&KK iVrj*DQ=5o].&KK iVrj*DQ=5o].&KK iVrj*DQ=5o].&KK iVrj)0>dEl WG*T= Q@Q@Q@>/g<'jV$$#!#ft;4bY$%v7rN@RUԫEq2|:6GN^ FѦvm8Pn^7ִ{+˔`'0dE ¿Q'޷~4p[uojOgm4]^TRfb$fM͵*+"TR\`.rFk[AҟI9u=CRG^t*@SIyO7m|mKۼ3)fqޮUIDnPy &"yC׻.ϔ޵n (+vuc{iu4{FR299u{HL3&qN0@铃ykWA$Ѻ1}n 8UA A8}g*%xKuԽ>g~'{K-seuzΆeS%oe-MB83J[őV zddH_=()J?N?S ݙ<Z_QFWWW2GCkS)(_ChOje}EOQ@\O_i}L+( ~_i}m?5e}Es/O_i}L)( ~_i}m?5e}Es,?ƂҐF Ȝ*U%pۢ*J ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( (>z2g|%qoi%]cDFFIܪqeSWSƟvFkc+'MEC{fCiJR)<5X>-pjIlڻ_nsN O_+QY֋z΃uojdS\q'+&6(dWMӼl⁴5w$aBVf;$Rj [VַREt^]0R]$1*kYK-]qgl,OtS mՕvH |KsFtbm&=܎ K.RTL Tcg'9~ x:\mt-2 OȓjHN68##9]{ Gqmj>hQYd (TmjC/;ԎeH19vݧ8遅'p{hlx[^$5m[(mcI#Ƞfb[GJ>nL vUG]m"6e c9͞OA}i _}*O}*}h}M;jUѸ`5JFh3ߨJ7Z5|ǪhS)=;(5 ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ((Zrdo+B_ C+z8nFeSIү=fK!~ֻ*)a4.i51G]BWQO*8߷3(\?jb*(aʎ7.sL>4ʊ9r\?jb3+f~4.sL쨣*8߷3(\?jb*(aʎ7.sL>4ʊ9r\?jb3+fPj'za1Qizޫ]6le L7*$Z(`QE# ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( (? endstream 93 0 obj << /Length 94 0 R /Filter /FlateDecode >> stream xXۊ0}PW%RpnDž@?-e:=#E#+i݅@di.gΜ;P= <>߿o7v.*~u~QIl7G$ 1\|f|wJњ9q^I.]LKr#+J,Mْ-i},Ynm⮄Y%k75?iؿiB+EքgVHP%WPYgLzdlH rf,E {VX]Ͼ2LD iʬ!4:w Vaa;y4۵"@0,Zx m'0;{C|0i^2>{p𶁜SEb P'r6߯-eri[oךgzOFYE @(5xpsp)lS'd:uI9ډyEyd D9)\ȘIFN@\V"qkrPaLSDCZyq"JLwi.QueXQE\R/>,~DmLDEYpvQ͎qn{_d%Hr,iߣ=c&ar@oSdtdP__>~~:RHFendstream endobj 94 0 obj 987 endobj 95 0 obj << /Type /XObject /Subtype /Image /Width 478 /Height 288 /BitsPerComponent 8 /ColorSpace /DeviceRGB /Filter /DCTDecode /Length 9611 >> stream JFIFC   %# , #&')*)-0-(0%()(C   ((((((((((((((((((((((((((((((((((((((((((((((((((( " }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?B(PQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEV߅Tfkp;E܀HEݹuMnVomylR-YWp7`݌f0#k&}_O*KgV8WO[s8[of c nxoJ/x|̺̃V%.Wˑ-x'/Z_'ԓfVQ]°2,I?Ïz=ŃjVJ/Os+bxLbpOMC 5_kvn@F2w!%ŃUԛmcQOgYo,i8QcvP`s5^_^P6m}9\#"YNlB㏽SzeΫtv-nCg<`y란כ]^_i^м%>}Vo㾅y%c d.BTm' \i:-,ZǧFgqyQa}렮k| qlm6DNI[ 6M+@0&p4PCcqƬ `dzxCD՞u! A#K+AE.kdmrWm[\ie,0sB#eTy?0?"hٯ;4ZK4}-n2Sl8'ix3ėzqgcx塒 xm vqɮxB5OBQy+p-y l̡ƬH6qӌ#5< m.kcM:sj7 &t[hc*qr?,rNXKMÙ[esq}2Sv&#Abk:1<j1G`9yt5 _b] mTQ>4tim:GTI8̢k NTu O?)gsg"xz jΝ%S29qGӧ'phݬocm%ԋʢ!A gH Scq$h0f@^EPEc^@v[[k[Pdf,ʠF$ jީ6-6uqT$= pMhQY&wq^{ǽn`A#iEPEgje֕o:Jϩ]}"I.[$`m䏨v["g;b_sP/EQEg\j[:C #`4a9z@4h(((/+ْ [xYesE$q^U?ap\GI`R' HQ^s⟋0k:r /ӭ<ج#3"U4MOKn,"OPy[h(((((((((((((+Qͫx*)dVF (x~*iY #M}>v̳Ko)I,?)Ti?<߶/mqc$Eɂ icϾx{I-kOa ֵ@R \BBSNJv+;='vُ;|wP+7: g{b-fӝX#彍"ڵH-8che<-n};Sg^(2NmZ.8⽢/˥VxP;?kxvdV=zմH1K|e߇5RkB # ǟ*mإO| X:7ranCwuC][ 3v\ZY\#nc_<djh*'ͣxS[7m4]:ÃM\}k_#<@5?B K4إ L H 4Rzclo4?IdDVr۾IvW3 L|_*5Džh򎗪D~u$#q9 @4xg<8^iVV\oLO?$[XX$%5 ^,#XUUd0#dta]=2 mdW?{ϯz(0(jŸ񼷲B2EvPRUXcq^C/xV‘0Z\0 <8cʊV>Zm |eJ]d},yt$U`=uh^ |=aB^$RH8 y]aۥwSB(EPEPEPEPEPEPEPEPEPEPEPEPEPEh[jV17^Lfq tVJWo6hkMNJ4Oٵׇ+{Iz2kcpFEvbr^<鸮4QEpQEQEQEQETwEmo,2 !Id`K1<$.~1xX$EbcE88eB= 5C _c+vMBrQݝZg4/̅k 8#Y+1QREPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP}BN-byimY'5Gxŗ:{6[A%8=p2rO$^3XXiCeQ#|Z5miJ+pX{k>GF%XG'r]ŦjԵ X̒YP:vԁש5},`r{- TvZM4=!tc]~d3>İ8Qk*<<|SU KFiU"(6-ONs5I<2#z0 dd2q#T˦#: 実oHm8 |~UEͨsRv3?ߑɓ"iQE<&O7hd~F|~Ty4 Lo4lxA*/n͔ vA%qs}Hr>>$\>;ž)>SFFɜ 1 ; 6y/+>1<7Pґ"F32pxx5so5̶QI Nc)#AWo<*妑 K Kc4Oq32oFP8دBofכvWy{YLs&#hWL8 G~MwF8uwXi~\  #$`{..}kC{zw1t]4h.G\ۭ#—w:cF9&"W#S lw\ަkm61F/p{08 W4oeDŽ|;y-3/^hn>i?"nP Auy%BGbrYT2W<8E#Ms6=1Ƭ`c8`M+JKifvW~=*5 -"Uyl{+gg{z 5oʸLCݑ^!ȣE%k}[հuMTVWO=㖮7̝> [yku>ýԀ$&%nNNIO~gxLiuHoެI*J=ikr'D",,侒X䷌UXH8r9q_6[DKet࠴:x/i62k %xeR[Ld@GK'Ҭu]P\Kmhy b\*ܮp-_݆ hlvShocXK|o-p/|/W-Σ=h}YdؤpR'7u#Fu0B[F{}BxnŃD RRCbNsj[4FVm+%Vq{&@nؐsQErZI.u Hd%c`-#d# I2>k+֩=M䵺3 xIꁔW7 BZRο>%WlHx>wS21]h, 9_Ipw4]ŔwldH"mDS<p;heTj*Ļ].lMli? bo9]7S3S6@ETQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEWUR,f$Eu uujNi{cmy\"\ǩN-{%vUyQOyBzI?R׿[WiE.f'K^o=G$)k-ǫf'K^o=G$)k-ǫflj3-{Ǫ練Dӭ <*Fa'z s1mP=)ha\͝iFqx[xV 2lsaNj u_?5eO/UȎ7] nSwQ򣝇"8Mt_)tkwUMO/G_ʎv5 eO/G;Dy߉5]oN[mF{؍il"Wf&E\2Iֻ+#qTP~4QE!Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@ endstream 96 0 obj << /Length 97 0 R /Filter /FlateDecode >> stream x[ۊ#7}:!`$ dv_Q]5e ̮eIU멒So_u??}߮?x~: $5@Obenb>`y i+6.4xs'o=5HrE  F p(ēnߓRQ~46AȆsW,P;EB I3!mtȻn8`lc$OКIi/ SI]Ոs]8RJ OylL' +TM+jk*ȓD 0*S)MBPohv}9̑ Y=9FΙmxцȄ jXք Jk\SII(V{sTS (F WoMհ,qكs"GY:+48)ewˆhK4nt@gaC,S3's%R`&ta}9){;мDJhIz9Ub؜i/)ŜDQ!S-51Pިn%Ȟh5ƪj7~o.nEcqj)>RBei𢚙e0`FDՏBT;MH VR K!w dạ}x,kWѤ%-al Ln*_L#)*ҷ \ȯ־jK:C>HMXwϽpባMGULP {dn<G6o,jXtmٌFw!YTj) ۨ@$T\U0tUbvsIik ؇{ MUWr[A[$"6"~лGuXuimv-B,vFuQ^8eFLUbkf4w5p4ǐ̥sdYo wvº*G2>j47d@"|lPgJuT%GUM|~ɇV.)*Кv#kcT[ ~s ɳ>ݒ֤Tg&\ɶM~zsɋdY,C`%lIy2}0pk4sy_Ÿ0a&"qnYyLDZQfPۅRuZy Ki^yZ/7NNHLիZ/a$h n48aΫq]DJ-*H[zycbfV/6nh^Op.QiG{9f gOҀme`@F%u(Rǹ)uwIQy8Lvs)}d?1@I5ༀdجӭ";EzJq{:L#Y^k&˦w> stream JFIFC   %# , #&')*)-0-(0%()(C   (((((((((((((((((((((((((((((((((((((((((((((((((((" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?B(PQX2֦yq+4$C/|=*Fmx|w[cFU0`dN s<]r- ^B.Ha\R?hwj"MFn"6vSvdXT<0255|9c4ڒjq<~DRLn6I$o_^88C\xA}U/ZyhO;cvݹ8jf.H?H QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE-z/㺖ʂգHo&AgqIؼJ߬?5oїT0~!h'J:MB\pu2RF #H,}ON/ϩIpYQUTRx']Z]OBSCwEU# uZ#%B+,hf,@XOrID 𥶁z#S.kZq Km,E e>a 𯆵]?ZHuinRH$dt,2>^4Qqru Mub#KkնlM\0tue8$J4;]s[pS[(+儇o$_E$Sg@43G֢2?_M/& FthG#:4j('?E΁@ "kZg@43G֢2?_M/& FthG#:4j('?E΁@ "kZg@43G֢2?_M/& FthG#:4j('?E΁@ "kZg@43G֢2?_M/& FthG#:4j('?E΁@ "kZg@43G֢2?_M/& FthG#:4j('?E΁@ "kZg@43G֢2?_M/& FthG?P?m'(hK@QEg#f^V_2굫&F[ekQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE8#6R8# ( ( ( ( ( ( ( ( ( ( ( (2|- +'ҹZAY:x#ImZu!i5 >xK+v3˱3J+vCsE- 2jZF%x%W]N0ňUW@v /3TwIӴ&[sr9|;{:r,bSog.Ǜ9:g=\AԗZB82iӶc+$! ,NW`bi Vӟ}K*dW=UH *FN#~}տΓk_.X5de1G7ػwl2&5Fq+ۭSL5G~V{=C5BQ4tnv}C5BQ4tqS? ?E] /&L?_.G!wG(.E3 л_Mkh\}C5BQ4tqS? ?E] /&L?_.G!wG(.E3 л_Mkh\}C5BQ4tqS? ?EԣMX4+k8YXԶ} (o?~\խY>CZ eFK3yy-|ݻ2݌9Fk ?CaQgL6~":V/yrm~χ?6WL~SId}"Yx8>7㫑K;BP:@!3?]GBuW;f֕9C줭~˱MUstORͻ =w;2pIkOr4R"O)7ar9|:=+Q!{A70)iϗ@cۀT3)SZx:=ǽ_xu#lҾssyX‡ٵ.wݜ5tl̶%gݼL䌳6s6l?`kͬY؋ ]j٥0.fXč9.2ÑowZXof|Okeokyv,[YIvË( ze76wA End@0@!a-m;NX-.33嶃>kcJRu;nIuaa=bE;6aq?GzHjmo1`r-f+tJ9FeoVm.x&nFXq gN4V{skink1UuzM֬E$LǾ2vDt+lzM /HClcq !mGڟ`O&_x~K@ԴaH>Qf~ܟqOuX\Dm`ѲGLWKi&,tZ{"uuO Q9ޡJ=c6w!8)3, ={ {;Y8']tRT K~EEq/}kVӯ-4o#D]:BLnH# 1AѮmZ?k66W3DiP zڣLZ}޷iG7l3SqQ.qGP >;_ɤm[kmޛ97k#rEr &_M5D$An:w+Guyֳuf.iL"?~`] c(5{˨F( !Dw $q^PXֶp@rѠC4w@=zQ@Q@Q@Q@Q@Q@Q@Q@Q@Q@dCE )kZ|!"`oEPY66je.ZllտF]Pr?M1.%U㳹'(/.I  1W]Ygj1Xr2X#'z>[Y]ǟ[|Y瞠 OAmcE?fI<|ˍCdmC캽y {S{BnO) )BJƋblֶUu_,+4IF3.,AsCX]ntg#jW UFƬ@Rk٭0:H1F~ /CNPk{b"|fApt1mr\\!X&wb_xw#8#P@nQbh٭ű9㌱'L|"tkVͥ+ (TBpsQX/^KeO8)XM#;n2Wc k#ծEhֱI{DgbFdB0tZxvAQEk2Afb6 vjjzOa.nn :A<JJs:V)|;ZhUm3~h; Lls\ֵGp#NlYs79,+Sxk6v?3e$ڳ K!P r8;:~𮛣SmJI&YI#g,:/ϰ|;v'cow|Uʧb/'Iɵf6H?~}W(QEQEQEQEQE)?\Z]tͿl1n*¿wd N(ҴYdf&ݚ`((]~Oz_nA857?k7/ws<[XxeQEO'$_kE,cM+k~ (>nh3ƾ-X+TMˉHP>U$Rē82'u*c.$FvүO:lúeogY$8Vy<0я-(l/_RRQE|ѰQEQEQEQEQEQEQEQEQEU=GY?ҮU=GY?ҁQLfO{sVd[A_W5kP+J+iK=̱WdUZ[O5^Uzy|DY"s{F*vvJ#RA#tah}b(/R|NLMe2I+N) O5W 89cbC9sVtMJ]Wm'J2BGL⾉_k,9^Ѭ,bo+Aώ"THB)7WmtkhczWSOCP-7ˏGe}!UupG!~pܱcp+E~x[O5W N$Hث#A(05k>#S.RiCF0Ō *_Y]"h+)gVi7謟 [so-oqms`JH C kWƝ!ER(4mT[+y.e2K6sjn$]z0PEB}R nJ}jk>]dU@\EPEgEA/nuI~ok ۱aIDPsFQEQEQEQY){,M`Nsޮ8zqwC@uZ֬ȡ:E-kQEVMyY˪֬?5oїTEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPKakfGw.Ǔݘƒ=z'U,YlQ=P,ODlUj( ~'~T}OD?m?*>'~UZş蟕m?*EbdOʏ蟕Vgz'GdOʫQ@X=z'U,YlQ=P,ODlUj( ~'~U4ǥEE`('ҹZ|- +ɣxN//<0+K|2Np@= ?CaP|]yc|1-P%Ŝx3A#:-^@3C,UӏF9<}1GBkm{E\ɝV 0-)E`$E9Vr= ]F:HUkyEW^0g!o3" A2Sx$\Hu[];Q&[VR26C]ijc6EF!"G:U8WVIY.*qך kIqnuED.^6xѦT*0Hl2Z,Wi>/)4@d|K'Sp=kۨ-д t4k#|aLi:C.s8]vuሾAB]Gje74F>]XRzWQEnΚ}4V}OE{[DWE:}o-M~WtK="[KإM>sv#%yQp3Cŭ:pq GPJ׃A,?n"3iVnA""GǩhhaIi𔦋YC6#h۠S;X c&H> V]BʺtITH Ep =ފrQV<;O?zrjޑ7KkhG'&(ǘL2+~ezflzh[X~XW{vU qhފ%fy⾨Մ7âؔq<(~Rx8k'O̙-rXALO'O'd(CHUe#^EnKGwZFì@7f+,"'; .ϻVw²h^=o%;rXٌ#M +w=kwrohE|29mP+ ||`^y`;FZ( hr Ov-kExOw,?d}O/o.w^EnǞx+z2xZҬRTCeIr}KZl)y|LJU O$M6c.]%dy6<.<#iϗkyG8nv&۴?'7ھ޾o8go{m%sʼA?K+\(/UHb| CV'mm_\^#53܈4m9˜3:Vc (zV<|5g,uˈ9`u&J.AIzs1miCEsǫ:ηL;o^E;CExOw,?d}O/o.w]5t?st7%1~t^E'wן|/uu+q6k$9;4JI'${M1/^:ZT; (\mfM(LHd,k(((((+'(hKZՓ4[襠 j( ɳV+/uZՓg#f^V_25((((((((((((((((((((((((((((oj֬ !Jjd_%jп?Km@QEQEQEQEQEQEQE_6~t{oMbxa2An \x[X;Ư .`z^hId`2OpAG1b~nw$lEg #Vߴo#s[D%Fe!X@8H8=+>|IѼ}m(Z0"SA,} v]> 'toy/4!S-\C`CqOiݢ]@ r\#9k9fkS.,]I>FcӃ\Ohe'ZjRCGtTwQC@](d?}wPEJ*d?RCGtTwQC@](d?}wPEJ*d?RCGtTwQC@](d?}wP*QV6 ʔUjOEKC@\E>mHip~?D$'ERQEVO?P?m'(hK@QEg#f^V_2굫&F[ekQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEo?~\խY>CZ п?KmZՓ"?ڀ5:V^%77Oq6 sN3\/A{kPm;QKs(K-=M ?V:47#73MVXcU-;<)ɮWzviDwszx>?즐*`snW[vW>]#gӾæ\KmbؒO:\j>c?tg*Z#Z|NяSNe_ _n6y=E PnǮQ^#xIq-otk$wp.>L<Ȯ{l]Tuk]'Ķ/p66}@e224eUmT*Ҿ}Ey?²\ItTX-I3-sQ/ywig㦯eka/&E>\yۻnFpC+c(}jFF١1 ː[\//-~>^O^}; QE!x؜]B:ȩn($g=¾#֬`љ IR r3P+mm5>VycG G}F ΛgNbI`S_룿[4sWiGtp⾕ ^aYE`=1`QN&W+j<֣{>+j<֣{>+j<֣{>+j<֣{>+j<֣{>+j<֣{>+j<֣{>+j<֣{>+j<֣{>+j<֣{>+j<֣{%͑ұ֪ڔ̺uHr ixiGn?q$Ii~ ^AmmzO'q#LnQjѢ85; \x[Ti6[>ZU8ROyBzJ*<'K^o=G$)k-ǫ3TqХ{QG3TqХ{QG3TqХ{QG3TqХ{QG3TqХ{QG;TqХ{QG3TqХ{V~Z(&ϕ3qFq*7hH'K^o=G$)k-ǫ5'ZT8~ryy7m'zօ惴rqХ{QSÕ_$)k-Ǩ-{%vQÕ_$)k-Ǩ-{%vQÕ_$)k-Ǫ+Ok4?k!L#ڻ(aʎ\Y?כa{UI?R׿[WiE9Q?.d𖻸$cl/Cs}7!@*{UF{(E *FQE4[襭jRQ@V\Ww;I{ Ub܈FpqEq;Ξ|#}]\40JeL!wܪ!fB[k$-|ye=HK` C3ݷr'+0NNV֖:\7ήРV` sAZω$yg_mQ`"Wp򢈈fH@"59AwW 5]FB7>ҦߵG_ƠI* ]n ˵9.\qp3jڿJ`tՓgw_[ R8m֘=ģ;؀ez_dh)՗Z%_=NY={F{]_Cmgmpz6?_T|<%,#e[{$qMII9†mm*:麵\[GJ^k~#$܇^}V%/PT:3TLK=R[5Btr?* h2?ʊUi?&q^+Y.k˔tmtwUI_ޜ̑ͻW%ʱ 3T/`Goۜ9;d@<ž|Qq94h0@ἸpJz-QuQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE"?ڵ'BD-kPY:x#ImZt/GPyf|U__E|I)kr;(r 9W!sX.slM`|`8'u[r-Q-"lIˮUJ=yz,NѮ-ŤSi̊|FUՑc4 - +kZXin^_y84#CETp9q Xi=֛iJbuY->v!9ઞqxv #Jm;{S,}%$LvCshzC6&AHvd6x4'rϊ[xB.P3\Co4~}QXSi+ HKEu:hNYУT/xuxNO  Ks=Qg bw}n g4?Z:R]Sn歯@3Dӱx[byXfh Sԯ Hq"rCqڮz-!E cm,LB60#<3i}t\nmaK$[#~ еZƴv25kywcmP"N,3Ғ)5mWLmBKԵx/4RAqߑr1v[kֺͽޫ`- j2bHn[Z~=uɼ43\ۋ]S:,٧Mx ΃?{3N>nk\_jr~ww(gy]`5Hk$u bN%n/F +rLϮ@}O^+ԗMGmIu ʲ?+m^ٮN|6]jơ}=Y%"?-T)$)݂ĪUdնkv5ԑo`=_{w3< 5x9ךLz͆;XLYXwLwܠ4zG햟%7Ƃ.×JyP)3w0.hV];d#&vdE]ǬV<ce.pYI*x'w" |8,@º}ֵsW_HbHX=g#6>D[yG4REFB`8=7{AYIa(tNBG7vMEC>C_,nMEC>C@QE2(((((|!"`oY>C@uZ֢( ?CaխY:x#ImZ((((((((((((((((( IƖڎ{f=UAf=N<zkuR;NŨgX]p9׎濴;`d[!#VįeU22)|/ xK񼩬ޢtY_}w`fC˸w)>e{%+%Cu>|in`Y4^g 9X¤NUk+~ xR-Rf`f 8*ĩ_SxVWZZ\cu5H$,H%p3CCF~}K޺Qg=*K@r=__G:nhQY__G/t +?/ty~%n9Eg~%n9/Ŀ g/#4(/Ŀ g/#? z_,ᶆb]s}$(((( ?CaխY:x#ImZ п?KmZՓ"?ڀ5((((((((((((((('5߅l= o'Tr1q9]>a|Am-;X'4IfI$Iï}-*o3k^ɣȩqVs]HO$ʨףO[}_HJ7<3O-eXp4Ot=TN2 }6_ڝݎv\C$ZSoAVFoA5gǿ jޢ o%2̠B3Ƕjxg%CG2I);kF Ui? W=d]s2?񩬵-m>(nQٰ2pWYLLas&(aEPEPEPEPEPY>C@uZ֬ȡ:E-kQEVN![j֬ ?Ca^5"xQ~+tJ%W la*vn6s^Y:>뷾t;6cQmyUA3?$ <7B϶8g[np*>=QGcȖO,.I& `7OxV SRgjTzTdU3ԉqx˱%G4@$Cmw&x~^AǫyhWg>fFa>"58 u\{uEt?+` y^B$$ +ž|Qq94h0@DrUkF-b~g]=q4G)PoFXkJEtpdL /"mXZ^_1C%LmPr񇄿#{oټIUiy|揋|X,.{3F"kytŒhhV/A*AB{;xѴ}DD/}&PX;|^:SC1f;{{)8)j32$54 ?wuIl,Eb%6" CdYx; 2Mp ->q$QێF O9:Zx_-k;ia5vr< @>b1ɹeKmN=o0/٭.'{myk[:?%Ϳ׷Wmǝ;˷=7=|'.Cź^^ k{ERUiW(~m:2Kv 1m3*S{Q}wIIqc3E~Ll7RC(PT!KcźƵc݋y97yo 8`s+3Vlڭ췗Z c\yrq[5n>H[yu|%m1:RU%۷FhB83>Ot-5 B[-sۦ Tq㭃GY{yM~NϻI3ݞscoS0 M3V67F:x=r(Lr|]o2mKKk7ٮVU@ï88 j#NJ.IDK)b'be !0]͌Oꖶ kSPwQn(]}NKeXxP58ȳ]YIk̋ JmD$naeˈu943o#X2#②63.@`HO5[YS7*v*#RA", yo&eͅwdQ帒(mr# '(t][\ٻL˷|gs1BsrZΤc3Z&m52[DR@a|P@H-4yi).|ec2sS:Puۑo H1zf >@VQrteDr@Rr>#[x^} /&ݮm;S[جU(:`)n%]7<IEa7; ɭk2 x%>fc#dzm>2]io=YK%PFdU'kD31L5:MNLndmay|gj*c\ ޿+kwdiךȆsF670G|Wyi{^{[UV5G\mGAV4w=ǟK_2>ęuy%I;heoV4u; ̖M$ r, 3Hrq[5oo3|ʋϞƹ u}_kVqYw8'JT̕6Y'IfvY'IkgD> ѻ{PFUI de9\\h-Q6 P e^E;P)K S}Cim 6֐ (#(*WJ8<#Iݵ%ܺ4h((((?U*?U*e (((('BD-kVN![j֠t/GVd_% jF / .j6?R׎层wQsSB]x{gWMrsH% Rž;h gVu6X2xf&a!r\y3Ȯzt_Z.WK oKM?ێ$2 ^}]h!H1Hr6njrC&#kh%xȵJ!nUAX`֝ɳK3EYtiu@84ooo6S-#@(WjZe'kmT9U7+r 8 z$ᴔ^XY5囪2# T9aYk,f * &ׇdrj %4P[zqQǾ"ӼA5ޞezEΣז1$("'}*ºmZWk,R(ύG#p"F9 =1A'+GZm}g-%b4v]X۩&"{sB^4zJ[H!y]}9"+\ďDHm^V< H9W 2q]oyuJ7# "q#1C3xKZSҬl- TEƣnI WQ1ݴGWw"5x9uLsiql(ݫSwrCpZto <,YtI>cI'N܂J鑻z :ծBn͒yc`P!U~vQ;|- -ɳѡr17913P`H=ޟӥoghu!Wd?w=;Ö )U2hy-95FxcPaȸ[9OU&uzeI#>tSfm8=EXX5+Y&o-t뛈"*&w:99/kMIJa5Lisk=3f#/

    }z9f|Gom/CWαrCHld(f=Td@A_l J VKqw,{'Pgnp 5i6l59Xn!@>´>CXg|GS4hB_NN#ՓQPCS'S'd14NrA@QE2(((((|!"`oY>C@uZ֢( ?CaխY:x#ImZ{Ɵ<;ܛmMvlL BuJ ڏo3h~ m q;FcdX.0ARx:XXi}iYW~!pp0Tw]ZJ\nZtWLWa$ S F s^ףjZ֗mW1XܦAAWƾ8}M36_mnbN>Foz?eaټ71wdѡby8X$}u=;,n;}S^bZj\}ME?m?4y?ƾ)_i}m?4QOO_i}.2ChOqSGCh ?Ə/ <L.2~FR}i`((((((()l6X[-cTr{Q@~'~T}OD?m?*>'~UZş蟕m?*EbdOʏ蟕Vgz'GdOʫQ@X=z'U,K4671QQEQEQEQEQEd_%jп?KmZVN![j֬ ?CaEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPY>C@uZ֬ȡ:E-kQEVN![j֬ ?CaߵwwUM|qIO4&8 HsXҴ}G_VI֦1i72Yl7dp{⾮t-kKu[hnSdч_ A"]WI|5y۝ @ng 4b8Sk㟈t_4OŶO.!{u#OOCv/z;=BD"[ jľ@8V= W5 ԡdn22cf%I,8x?J,4n$]^:KϢܒOnax %Oi)UO}HSz!wdUPI$k'JG{u*3+kuRMq#,w r촢%# ťsf;حyjNÐ;wt!߳i&PR}E_Q^&ciQjV-kr]"\ݘ\>آR0~l-݅Gj:2S cF{KgDw7 e$w #Qݬ\E2Kn9 bU`{ׅkO|U 7_h"ӵ-Z=Fk6ڝZw6."C+B bi~ дN Ff !iF#\Gg\S{_3G#:\9X'OY*Y]^ 6qA ?4ִapZK^_4`2c!]ιCfFu5?4s d6 {;s,+A'33JI`t#:??p΃kKZO3^c~󜌗c5 :ھm&뛅⸒'V1pءx#9s O8jkhAƿ47Oq8.%yǙn7۳:TR$?&h Uð;FrNHɦ3=s O|ei2igeOd,1sxnMkn٬44ZႪvP77\ 8jkhg\S{_3G:7g\S{_3G#:|9F|dqLU$trMER}M02Cu 5la= /Y<U(\G 8(Nz XS j+'6=aOv5G??]֢k;G#mwhZz XS j+'6=aOv5G??]֢k;G#mwhZz XS j+'6=aOv5G??]֢k;G#mwhZz XS j+'6=aOv5G??]֢k;G#mwhZz XS j+'6=aOv5G??]֢k;G#mwhZz XS j+'6=aOv5G??]֢k;G#mwhZz XS j+'6=aOv5G??]֢k;G#mwhZz XSBD-kU];OӢ;D d2$W%:TVN![j֬ ?CaEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPY>C@uZ֬ȡ:E-kQEQEQ\4O\ŦZީVqG,p7ȬH dVŖmwɧF%v޲țpى;q@^ƝQ@CA-U[- ##QEQEQEQEQEQEQEQEQEQEQEQE*n%z>QEQEQEQEQEQEQEQEQEQEQEQEQEQEVN![j֬ ?CaEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPY>C@uZ֬ȡ:E-kQEIgMZ=梩eY'Pit\,k:ʮso%o~Qxp&x+5]ZI--_la"L&U[z 5:Wt-{~7[uMF]'>m[*<2xRZWe:46Z[ǫ*N*v}ȺXmkQ@2.a?_1GE :k+ZȺXm_0ͯj( ?_0ͯ"cEc'"cd]ì6b,dd]ì6b싯uV싯uQuC|֢uC|?.a?_1ZP2.a?_1GE :k+ZOE :k(ȺXmkQ@XȺXm_0ͯj( ?_0ͯ"cEc>+xz=CcQ'ʴ$`2YĮcA(>QO-ψu)dOB@b.sgdkԿkoi6,4ő#,v4`:B'*OE_ PҴ[E˝8v~Peq>y7mpUNKyOUxR?Oe#z  V㌃r9!xzMCcQ ʻ#b2D##8Iʰm|mOj6u?u{|Vj֬ ?Caխ@d_%jп?Km@QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE4[襭jRQ@>&OTUY>&OTU@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@;H$xö͛ZCi丞;u m2>C* ?R@>'_&.{/Mq/,"(mSJ7͹?`aSxk~!HFC}mP#e#o9Hx|1>Cڟ#{\K/mW%G/*5݊uk]VkY{lW4k-{4uj>~ZE"rYw1<{+M@݅Ji(E #6Cq ~QދxĶ-ο'Zr,AA%y/+_;{.MmgQ +7B/wl^o{>ͫhRS;4oF5V1Y: d~tOZ0.5;KM-T#"U CHO[IV[Ndib \Ĝ$AqiW:Jiw:edj[BB6;q_6x=CG5+7OL6m2̲9;-=&Z6 _I crIwZDBSivijmn1OiYY U"$]́dƵMkW|h&f󊻵E F3"Zlu\kx4rf0C~^ IRFɦXlFUB ۦR1,?sVX"wb &&W*{##.ڷ[hu.%YU3y54 -B(0(((((((('BD-kVN![j֠t/GVd_% j( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( RֵdCE )hZ( Ǎl*֬Ǎl*֠S}:Zwy## a 7W|8MP [1݌1<]wQ? j9({k$(߃`GΟGX;7"e ~ rҖh1aSjq^j2:mV]g 9J'9Y禮0$mNI[CqPc. Y!#[1 guSj髴M ΂@cHNFqnH7 7h?=> 3PӵkkIy<(B;+OF3t4/G\iZz`71G}/`QpYAnW5oӤ[ExSBy.g +1`I[{IHQu:LM}գ'yyde c-{ȼQ_mu{_֖Xy#xݞxּcxB=ޟsq-bޒD2Ҁ69ۡ@&kXΛI֍i㜎G|]7oɴ4뻭6;yR%T$rmv~Z9?#g<<)NțīqmH#ʌOZFזF\XAq C:?!88e3oa>S.^@ߡ~%gOOmT;dUlʪa(y#غPRiK[x.PAg]kr`x_^>񇇇[X/grfH$g`&`:udnc ma7Е6iJuQ{ Va9(;9#>omujiU)6)#)^sr&qTa:MZ̐E!$[* 1B5#v06k}.!b^)|`sI sR Bu[mbTR($ q+IƓx֒@F⫆%[n[k8Qe藪v-SZu[X[;)d畢hmȡ,LԏG_ |?i% .7ǒx >$zc}l.~s )yr, ;#@e,29R'U|ǣ[4S"8F!ҫ w/&JmKxV=K8݇tk$6v,<@s@b1y 9"63}#t1X~G}_n;]H-g\z(ڃnϰټ?/ݻ[mV(Š(((im?K-KhF1Ȣ&@Ǧ,pHb1vs@u߄4h_Zמ %xr:3 F4GtE!Ѧ K#m b#ԟې+ 50T]֎kO3'9%{]Bcv#t,ȗR2Ĉ{XvCMKHi㼎]&6jto~5#X,Qws=raA -H?WI583\N!JH߂́FaeZRh;z8vVw0]FkSŚ(Š((((((( ?CaխY:x#ImZ п?KmZՓ"?ڀ5(((((((((((((((((((((((((+'(hKZՓ4[襠 j(2|M6ҨZ|M6ҨZ ( ( ( ( ( ( ( ( ( ( ( ( ( (8toD/ėZo`9?q =pi:jpOu pX"(v :;ⶱwV^y͍EmZ;x)  1QY^^+K8*ՔB5Վxt%' l)#pӾtxj+axQf{ MwZke%2Ow&J^ P)8, s[_nv tM$nI":&Tgp2v'}k01kkD¹p<6zCE"/ hUl"h岏N7%ѭ߲2?l*ޏhe`%Y%yJ79,@2xU((((((((('BD-kVN![j֠t/GVd_% j( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( RֵdCE )hZ( Ǎl*֬Ǎl*֠((((((((((((((8xV/|SQmn2 zp<Տ4gZT^!CMs"9aX폍r}+wDZIiA} T~ ypqIA VѤPD8B(p2Bpe?4ܚO]7苣MI T%pL̬VU䪒8W4p-.MrH7mP(>l_:|;K1ϯFç\]#D<ٶy1#t=u dY Fぶ5<~Ok#ژ^\"aSo6v/% ۔Bqpz|O5{Z`fWy6Ckl:|Zgk,{1,#,w(Suzl4I-/{HĢBjfXQO4nf*ѯDյLO8乆5SkHߺ>#/'>9`&v;ImK#ƲlWNIcp=KxJuԿ n]oھՀvnc;{皏VWڕw rFFȎ7xؒw/=>kmKY 2Q_,mei 1=jz AER((uzc|,qNY$5m \EomMkX$qG38 6I'iSm7hEfEPEPEPEPN![j֬ ?Caխ@fOXOs= Ėv!f ;Qj; Ӣ2k;G#mwi|QMF{kYaa dwU@ʿyR*⨵-F]:LE!7 m{n0@,: P@9G??]cic{:S_BbcVڬp }*RJD?T1Qǖ G+HM?k;G#mwkZc'6=aOv,d=aOvG?ֵG??]֢?]?k;ZP2k;G#mwkZO#mwhz kQ@Xz XSj( ?XS6㵭Ec'6=aOv,d=aOvG?ֵG??]֢?]?k;ZP2k;G#mwkZO#mwhz kQ@Xz XSj( ?XS6㵭Ec'6=aOv,d=aOvG?ֵG??]֢?]?k;ZP2k;G#mwkZO#mwhz kQ@Xz XSj( ?XSm- Gokh ;U@dR@Q@>&OTUY>&OTU@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@7~:5[wQ6Zlp4|T|\O^69tm>;W!\w:k1 U_WZ}m Z}Eq:?5rS<7o>sC+jy+aQ}mO6ޗkrDa4} s2z0=GW4g5=>mK%',@:UtHt$ʱm=q V(ҚU&dߢƪ,Ac ƀ:Z*pA`rooFid¤jIf<Rk7\P\Bt(&DėH" {_Gթ[Y 6U@0`NO'<սA^ݥ䂣Y-M>U[}B;D\oe0;fPՆŠ(N![j֬ ?Caխ@aNw"MREKegy^6=#^ɳV+/u@K< E=jzw=q7PpO<[4k[K;)# ᶃ"IHMğ-I%P+jyW_6:ńpڙtrg($@rf)bܜ4歫xpIZ]cme34jS#n OʫPfqۈ 69qJuC|֢?_0ͯ"cEc'"cd]ì6b,dd]ì6b싯uV싯uQuC|֢uC|?.a?_1ZP2.a?_1GE :k+ZOE :k(ȺXmkQ@XȺXm_0ͯj( ?_0ͯ"cEc'"cd]ì6b,dd]ì6b싯uV싯uQuC|֢uC|?.a?_1ZP2.a?_1GE :k+ZOE :k(ȺXmkQ@XȺXm_0ͯj( ?_0ͯ"cEc'"cd]ì6b,dd]ì6b싯uV싯uQuC|֢uC|?.a?_1ZP2.a?_1GE :k+ZOE :k(ȺXmkQ@XȺXm?SM>wTpRD\gjVd[A_W5kQEoEZՓoEZQEQEQEQEQEQEQEQEQEQEQEQEQEQE__i\;@1qJu{g|[˻@W] _s҆`0 ھ+Z(ƝZjc^S N>$x-kėl8eX8#8U2x5fh/IJsz$p2H;A@hQYotzT3cҧp{z_::̤Dr7xOTMG=Hhqap10^{: (NqZkx;K84ZIPp}#q&M$sW|FYx_ǺEχ5koRkOy$Vѱ &C }Hv"_H no ˜O{Ik0Ic+` u5SthZ7VeyKsa$nNݲ)ڻLqO:-GVG-Ʊ :$]ۗxO[z! PnU/ wkgo&~BDsB+FQZѭ:#VZq>;>Y[6h{H%I2wJ| qqҹO4;Bm/W0=urmï|񖯮A/tXѬc%nރq9~9=4/&iHƲ+`Fpyo%ꦹKYOimx-AqG2( L/Y5*bhC,c-uxWHb5]`·W Qglqv'Վ{z+dQE!:x#ImZt/GVg#f^V_2굫[};\UkW6` 3W!-ׄ#+䚆2_IW`!ym>?/g[ JVy@2WŒ ^sQX7mVW*OKS+Š(((((((((((((((((((((((|- +'ҹZ( Ǎl*֬q> kbFUfX\SԊg Edj_лO?G j+'RO?/].kQY?ڗ.B?sZԿwS~Ku?i VO j_лO?@\֢/]ROB?ڗ.5Ku?iԿwS~Edj_лO?G j+'RO?/].kQY?ڗ.B?sZԿwS~Ku?i VO j_лO?@\֢/]ROB?ڗ.5Ku?iԿwS~Edj_лO?G j+'RO?/].kQY?ڗ.B?sZԿwS~Ku?i VO j_лO?@\֢/]ROB?ڗ.5Ku?iԿwS~Edj_лO?G j+'RO?/].kQY?ڗ.B?sZԿwS~Ku?i VO j_лO?@\4/GVd~+mVKCu{6)QֵxSƖ1wZpCໝdɳV+?uW IItW>2G:tҭYy8$77$gk"i(ѿh赽7^ENcT0 @2HW~/|u2yR鲰PėtA}W?|cms,x[[g) eXzH=JX6kSJcx88ki__-< SǭOӢ? //:&YoA[ %ʖRd $<:΃'RtF ,#S+RJ{<3_!ĶV*ly rXnl}9Yxf=?okgqkQZ i"TBcsW99_3ba**3kZl:)Esc'-5MhAi5U IYEo.1TGoL7.3ᙵ;X2jln@ nH[}_4^xM$(mNG89$뷾We3aEle0%NH<=M{[x.e1bV%Dx2$gsr[; !fϟ,3$[J`=@Q}*oQbX8^T2+o"M1H;_şl|,miq DuŤf,F2þКB58m崲wnH lfE @#Xfo\u[tKb}Bow $b쪀Np(tI N6]]2[qP<+/C\hϥ]^[薺EԲG*ȨrpWGLSK[\xk;[>y4Bмd`'w;}fǏm!ҤZU2+G<Ș̘yTao|q\=՜Sm=Ɇ}$~D xwׇlAS_ekƒ1($Dm9(gc i ^VfXդgXԱ,U:S%ޯO|LwW:!k[4HB\ܮ ̋MD5֩XDCm+# chQ Xѝ:[!Š(((((((((((((((((|- +'ҹZ((Au;m'HΧO䙄1 o;A'$HjܝJL0H88bF03F 4VUK+gM'8@ϥ2hKw:$q*q/g@O6( qAq У8SW]"J̈&B#Gg&bkCDʨ{3`Q@\ڢ2{H_M7ۢد۰\t 6-FUǗu5$O' ր4O[V^Uh#db5UݤݜU<gfWq̈́b+;@ʾHoܐ.iYV>#/쮯,u6xK8\O>?6}5wo<:eƀ4謻_zmOH{XQB:ҵ((((((((((((((((((((((((?5oїUY66je.Z(p (Q@Q@Q@Q@Q@OX,].QncM'E;rI$$Ilw(p 5!~RH(:ף8VA>y|LwNCmhD;aqfp98{!{4KIKgp&w݌aӕ'8$ 2 v_zU…hODκ(((((((((((((((((+'ҹZ|- +5+֍kw"mRK젚G:p$䞕VO?P?m0uֺ|l5ay%3Kn叙h$^0x]B>-tUmЯ&Ltס@X@!7YžM`]M"$ϷdM }[N+[VSU&a>U/svvQ¶U/svvP[[AK':]!:Zb=Ts;._NxzuލiwpLF|B%cIVO#mwhz kQ@Xz XSj( ?XS6㵭Ec'6=aOv,d=aOvG?ֵG??]֢?]?k;ZP2k;G#mwkZO#mwhz kQ@Xz XSj( ?XS6㵭Ec'6=aOv,d=aOvG?ֵG??]֢?]?k;ZP2k;G#mwkZO#mwhz kQ@Xz XSj( ?XS6㵭Ec'6=aOv,d=aOvG?ֵG??]֢mgX򥰹wI&K,N$vk~gOuj+&F[ekVMyY˪֪γhsj6ZueaB g{\7嶻l2ŬMw] ^H@7es; Zn[V8[J!>V͢{^'Ҥբs6$lf/1d^I"4-CǖZ֙47]iW uF@ONpH'u+}%F̸alfac#p s/,eXiaιUomGc|9Y6&5ylke²O9E`ql5ewV;*=rh]<i7Q9u> yš/w^oaA4e,u5XE]+y@ήL.3 ]*XB'm-I+YU˹|B@?O $?|CA'EtÀ1s?>!Ɠ?"cId]5dO $?|CA'EtP3 i?,(4IQ@O1OH'?Y'$WMEs?>!Ɠ?"cId]5dO $?|CA'EtP3 i?,(4IQ@O1OH'?Y'$WMEs?>!Ɠ?"cId]5dO $?|CA'EtP3 i?,(4IQ@O1OH'?Y'$WMEsiZtDŽ0.H˞@c9|5XƂ(aEPEPY>CZՓo?~\EPY>?m>1xo테ȗŌ62|ҧ?2/<9X$a'oЙEs3oy>Y'% _ċ xG÷(l6!`dy#yiP?E~ST&VWtS_x2hZr||rH,\ 7v{[.G]Gl+lBdTA:}徣am}c'iuO #r0 2+䯅5*ٽuRu-=Q^QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE?mkVL7Ѷ@d٫וjɳV+/u@RNk,MF6<{<8 ETմM[NR.-']F#FE`ݍ62qqk%];tev8F=92s@.IdT k#\MpS}դv*z A𦑡]=Οo7Y<6[T%Urz ܢIo ử.g72ۇpBB?x3 tO$MNF\I˾6Vp23[TPUt糲kj#%V8ܡuprcCǹMkBE#Eq,"T*095Q@XiֺFiiy6v,0ǸQ2I'k>bh#MǘѝqpdsgaV,QES4-kKӵ[hnSdч^܂ +  \%/1ƈl HR1/]'YU( wGb_ ;yt8t|ɦ&4"|&uU^zW;gG#h={ru[np(ڹS}o3~aJ=EŒaF >7A^1:+3S}oEf}oMP4ϵMQ Ɲ >7A@XӢ>7AGڦ( tVgڦ(TcNTj,iYjS:+3S}oEf}oMP4ϵMQ Ɲ >7A@XӬjS 1((( !Jjoj֢(h kτɧ[f?@hy#5Y[>Ҭocmn`<V# Aw׀gR<>~#mxP'#7d̊yPK1k4hOî jm`*+*ɐFwr+iϝ,s>Y8F"s7-x[Gw {X< : Fʱn"%ZOVf8(ߴx:^_bHWh H!  Z]Yh^\Yܢ[ɨۓ ok/"rFjv !/xa! L뵶V,1 aK|WsVkkiuj%Vfv@+:PN '(SnqF7ݜo߆FDj&qyQEtF@ FNp~[:gb̶:-%b@nPpGUtSG]NJ,VH!"/.Erl *y ;'RίwTXBUKO~< 4cuؽl>mb#I']fnڵDy_۱%*9,;W-$Q ZO%ޖLcQqޠ܀@Y?۝+Đ$$-G 2 %)"ˤ.bgS5UcN6ySZu IZ,1yA,q02YTߒўYOaqMI4,cvo&5eܧrCs,?z5#TUr!/0 ;BI^9zC#Qjn|;M$7wj /&x*唝$oQvZuV}xc@K'B@87$ .SUӭoVi&(yzs2G6\'*n8#tz64S\ySK;V"ns玸-cJլ1T\mI pS@&71*ŵV(^Wf,̪35x[Z(myV &Hgh(% oxF_4f04xx%YTR-gx%ao&} $=q_pzM=*V&MR6˸Esm$~mNJ:m+zZ5/{XϘ?c1hִAma8gUI  B@$L}Lo:ǝ$nDjH"ED?@ %^k~M=5K-CM&TcIRFs=/:7bԤ-VWHaYe}I!lA=B:ޭk^!ix&OC*ʬT"g4"Mބ]Zj omC 'g(\9\95n:ƕk}tmU;YRgucivʁ@\?*21ޢ{ :N4e C!#`|hm6e\ݙso,8~_|rǚk;sy 7ou&yg;8JdHy%uHfcu$׋Kc,<'>&g[}XY2ll˞ޛ_eŵҔ8`NcGA8? |N:ljl4 -m%hY6x#B ck7_f;Gt:aۨdd[a%ċ>4_İ^[h4[CHr$^#4K/MݛKcns9cS^lF[d4w> PJ3&1xZJ4mtٞ7T+d8*F )b3=43U{cD֬n Vt G;- =I]bXY"FTK.F7)GQ\'1x Po[[y`P?,bi ; CA*:(֪iVa<[ 7<>R32r7rp3]n^XEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPL7ѶY3ߧ:Fֵg#f^V_2굫&F[e?mW7W~bBPK1W,Oœ||ziw6M!-ⷎ^2H,+ 6Oj-s&ӭoERt^[k^<|1}C¶0ǫ[K4]HZY@.2U[9MP*=JjZ^wZ||/zumt[V6-pxFw+p01>~m WEVM GFSH|. kE|iX298cעju-~1hݥ8t;U rr7g9n PtRIi;kt(UUR]QtƽEC*<~nx1V(m.`x-PGR2 Q (((*9&&em` 8n`kY7QW{>5QYƵhΧcjhQQO ռsKHH2=#*J((((((((((((+'ҹZ|- +5+'(hKZՓ4[襠 j( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( (2gOujɟF?6ֵ?5oїUY66je.ߏ^F} Y%\4>cb?/θ@O4gZT^!CMs"9J9@:xN{ j|;Nܧg+5I^m\m_'ۋpN0;}W*+)FTkgU}:dpyf25/o{ 2yڵ7jmbJq?e u6VI%o0](l_CmsSXA hwr\A{ ggmpY?. gvИ I$cYa#nR}oJyw֮L+2H< HiA=1ykUn|7cH^ ('5 31@>8෺vO-Q!cgpw 1|[ Ay+i,Y&K2.;jkXEgCxx 22Zw8Vֹ6%>lq<\J;#ʯq$>=KA'&Ky5.۱-ٜ-26XN%(#KۉO')1;5YuP4oڈ+(s (1WU~ť4uկdvS;J,@8U'4 tyyR:A(FbVݴwp2~FX0H89{]$ xZ6k V$yey#)r ޢ@QEQEQEQEQEQEQEQEQEQEQEQEo?~\խY>C@QE4[襭jRQ@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@3ߧ:Fֵd#~`kZVMyY˪֬?5oїTEq>!iy.nŵc®Y<88^;EmNB[odYV%@$m 9w,vgiF6w?ʥhF}yE|+ӯ kZnin~Ơ 3[澑'h_ں/ lxpH :2Fwd̯ޯwނh訢MB(((((((((((((((((((((((|- +'ҹZ(|!"`oY>C@uZ֢(((((((((((((((((((((((((((((&]Z֬owmkZ ɳV+?uZՓg#f^V2gόN.H[c{mzsNƟ xkAǁ Cm,u)ieDTUohׄѩ_C$~nkW .Fϴ`11a\t 'x3 */{{&|RNv953s:iZVkk楽O6KYs|(x~mcG3\xu6}pN#|"1^\i:nXI嶡<?|3&_֬,9c[q7xǚ׎-aθ.e!*H%|ZļǛ˙[]mcXMϡFbt!ylt+jvs"][tOZR@ Jc,#I6SZ YDe;slݍͰpVnǨQ^Si J:M.Z.&RQ;_#ڧ|'oIɩ&$ "d&P@e8)怹W F5-y䶞"""YDTnŌ37 XZO_Z]>;#e p\IdxqnmM 'x)%p"8&6*p{{בĞ- us2nO%as"d WmuaHڄ uWsTm*K2;I$ N1`9ӵ>Z[ Qo.-cs;Z ȁݖn Fshw5mgZ#ɢmÛXdkZ6WN09V.f[Dok&݆[ Qp1riEy5ό\ɝnS[ p3/6\鶯imI8VާhǎXފ0Y3٪8_sЉӌ$xg}OiN}a܀DmAߵ7PFpG9]ec68bXdp$Rj86&n_ܴS>e/cG6c)ng9U䗯we,n * ^z1Epc|hj6bhM;ة+.nq7Ƨ䲖9|ﴘ㻙 2ݼFNyO5Q@Xw?<8df0$e8#WJG#IxWG湚C=ʄk.$u~\ܢi^4n-&H 0r".Qx$pxoJ>@)L1G p\T ; 玵EcvFh/˺T\YfbNp2q֠7lX줒=Fݭ.Z{ ز]-NMOxIa)#sFOs늫tK !-qX/1C +rpȧssZP9-gׅ$tה^·s$21.bW g<4ْhGBN O7O`Rmo5̲chv%GaHEcQޙk62Bhn$ +`s95 ߄t; 8aю(""jaU@y;P?]?k;@VO#mwhz kQY?XS6Ed=aOvG??]?k;@VO#mwhz kQY?XS6Ed=aOvG??]?k;@VO#mwhz kQY?XS6Ed=aOvG??]?k;@VO#mwhz kQY?XS6Ed=aOvG??]?k;@VO#mwhz kQY?XS6Ed=aOvG??]?k;@VO#mwhz kQY?XS6Ed=aOvG??]?k;@VO#mwhz kQY?XS6Ed=aOvG??]?k;@7ѶY:=ٺnZhCy'R0%G;Rtwo!sW3KWW V=ϫ诏>9i.,$+Esh|98@.x7"F[&@# zɴ)z .b{WxMQ^QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE]k_Iլ ˴\Kh$tO$ p|_e]_v< ;D6 rR⻟ڻ7>[X'6wn) #H Ž {:odٗ -yLќ > dns_啝, ,#26MtpTW{þûOxTK+ik]pXre:牵k 7)gxoћ獔91k'Ѽ55_1rXiͤ+%r '#9uپ5e6WCM&(f$6߼ʩ璫{g,[WX JM+iʕѻŠ*O?O[*@rW'-y>orQ%aP}G %r/F65KXK'A;bpHȠ9'-y>o`@ǽdլo쮬^pB%I!XJ2iYxu/Oju C`mdb5|s|Q¯GY o?_9(c5hp'AҐ)"E8Ѯ{˸rZvv|Fkq|YORsiQ.wYT+u_}a>/^~xnhy].k|'4]E /Z]Ao1sdĀ.89j^#Ý[6^VmK(Lߐǿ'>V JwVo}&R\W9|(񗊴5;kojmn . ey'ozrj/zD ~.wZ%bF(LXY/~V9xv񵖩%'Y%9;lf7RE`i6 +g+.@ аuTjc9wr(&6qJ;\}u?Ə??ƭ\U|A&i:VJ" "|PjSGQx^״}JMm :2VFSeee#B???Ə??ƮyTufEu Rlm乗`lE,Pﳟ??Ə??ƭGs*Z_ꖐotmsDz/,Iss9(Gr$s7:a:Jno-繍+s2ǧ}/9=h9g?g?e>+[u kM2ll2yK FopT/A%1OrW=M#Z.c:Ճ6"V5߾N{E_??Ə??ƮyGj;)'?ƫ cc 1kT̾kמLXW,K:֊lg1=p)Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@.ZtV;,2ta׷ r`O jb$sGdP[208 K#X>$平t裸dyIVB3zY~k˥|<ԧQ<0ٶKIn%AFDua1^?xCsw*yr\>]۶TtBj$f!mMtj_: = ZK|y+{-EGTG'K^o=G$)k-ǫECW{OyBzdׅ|Y]]iڅޙW1cl DѺ ,#F rw{OyBzg#;WzvQ]FISmCvÙ\@6Ofe2O$e $v9 = ZK?'K^o=I4Vu_hz>OyBzI?R׿[SAΫMhz'K^_=G$)k-ǨAΫG'K^o=G$)k-ǨVn4՛-k圱/AZ$"ZГl㉏ BS!h W==Lhs+ym"I rE"WR0U8 ׂx.54k!8f*1uWjpsFF:c$i Pc դP$o#ar%>SՁq8sav*AIj-ҿgm&)!;kd`fx|5^N,9ƌijĖ=I<:d~2z0#x_]⫧bbj9/ZF ;#Ik7$S|EºV-L$o:hvs7^WG eѿ:/*L/C.Ucn5_YOqhֺ%M42I)#d,3+)BOȦiv@eŧOvф,Su>fBFL/C.Tetoh_89"1sӚ?2 /EQ eѿ:/*kS_z9B]||mp[gQ\M.Z.cս:dQi|^g\ٰ1]2G&^Eig|mOD-m7΍WH1YiqM;!,V6CL<(]xÒdt> eѿ:/*L/C.TZnsSxDIH4}B;I,(}aElpxВMDi?/@?/?tPO?:}jS:}hγhETγh?/@?/?tPO?:}jS:}hγhETγh?/@?/?tPO?em Շp*QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE endstream 99 0 obj << /Length 100 0 R /Filter /FlateDecode >> stream x\٪}ogÔsSJPnx1̼R,ʈ 彷6ʹZEF8~;!P_:7ÿ޾Ru׿}|}22Ln<_>oÏqo_T^/Sڞxz;$Ø9nr{)0.62@N ❳g[l;rl"VI$I+&?}?2U&_ŘO\]D!V +W"K23e]ۘ0Fxa`uBeƮw eEqSS\-ŝh5$O(s- DH pEC2CEhB@ͥͭӁpќWm3*AyʘÉ4tI~}sx$P[I%)BHȋaԋYf)'|G)J h@Yzb7+.IJ0]rwZ„)+biáf3<5(Pr1G0w4ʧxb2c1n{wMv}z)a[' ³EA6Dm˕뜕>9$nqc HD!o,{E=8&gUpxUJ ٩cK*Jn3),[nMTykOs#:.#mdB8TpwD$Ş(TiTpZ4P̉Ct):0fNz g {tUg)gM0N*٢wS(EBxЅb^%B%x1z ,[z+I9 IS9x)'4.zqZ1{. Ivd#lMhKo .-mPMLZ{s7 w ZXM;DCw' Oh+g]+k[a:I_+rJGlP-]/!5 Chc.Gg8ysm@Gh6nM+R*Wr.˙ऑ]&h>y֮DdTwd,'FuZUƮC|+Kk'|Co*ahɣ祝H=Nt?3t(ɳ\K}^_o--c4J2,.f> #8x#pbU:R,`{)B;6B3=5%2R_$Z()(rۗ@Pm`tjF˲bI%PY~KB/} \PfJ߹.#K*TKd{yV(B4XJY;T5hN^7Yl~I)ױn8-\6)5A ar%KZjcI n# ^8Rf!3Z֬+rYIlA j;~o jm@TW`q9L<ߩ01ձޯV o*Qz|>Gmv Ϭ3c3@_΁<g5SF(Y%jY^)vja*V`4NKCPpoxRuğ+^߿yO ]QGkqOYRw3ÎJ˻ bS);/`CnB^2|~=񔡯1Rk +k[i!_dpBx>(<:@6k;'goyy6ervapd[kg99@%Y/\~1ZetF?SV".e0k?ܸf=y]> stream xXMk0?\ɶ`B@?BcHeoJ Ş7o\곪jͿ_~T>UN˯p==4mm{T`QVߧ5QMˑ[:z2Z/|u=ZE]e9!o`w|Bɨ;SYjJHO ]p IktbկaC wmӚ4Pa4p`&j)` @UYNp݂ ! [ȉq>j.PE8- u@ޓ ;0 =a\V(AN 2YPG1mJTurzaّ:uZC0&I=Kk3o2'dw;YapT̠\xar P0g:7"+NNe("S zr:S8C߄4wD\vJo|E&*?҆`M SwiasةB^r;߫2.T+T. PBQo(%PP@F$@XvGT8\R0zyXWxdl!u3`EWoKRddA-5#F^Jg:!#5#cy g3 ۊ//H[|)YQ;':fa$J{luzA*&CkDHSN- aX]dDMbGvQ:锾wu"bou z^gtGyhG RދcGqr1|Ub" 1)- :_w$Va(wXT<DQgMüCRVtE]g5)9V+2\Q,z65HgYrD67J?[Mf1T y^Qȕ.ܺr{K`&DLV$*R~ϧë M7V=v4N|DUQ;͈SQhendstream endobj 102 0 obj 1058 endobj 104 0 obj << /Type /Page /Parent 103 0 R /MediaBox [ 0 0 612 792 ] /Contents 1 0 R >> endobj 105 0 obj << /Type /Page /Parent 103 0 R /MediaBox [ 0 0 612 792 ] /Contents 3 0 R >> endobj 106 0 obj << /Type /Page /Parent 103 0 R /MediaBox [ 0 0 612 792 ] /Contents 5 0 R >> endobj 107 0 obj << /Type /Page /Parent 103 0 R /MediaBox [ 0 0 612 792 ] /Contents 7 0 R >> endobj 108 0 obj << /Type /Page /Parent 103 0 R /MediaBox [ 0 0 612 792 ] /Contents 10 0 R >> endobj 109 0 obj << /Type /Page /Parent 103 0 R /MediaBox [ 0 0 612 792 ] /Contents 13 0 R >> endobj 110 0 obj << /Type /Page /Parent 103 0 R /MediaBox [ 0 0 612 792 ] /Contents 15 0 R >> endobj 111 0 obj << /Type /Page /Parent 103 0 R /MediaBox [ 0 0 612 792 ] /Contents 18 0 R >> endobj 112 0 obj << /Type /Page /Parent 103 0 R /MediaBox [ 0 0 612 792 ] /Contents 21 0 R >> endobj 113 0 obj << /Type /Page /Parent 103 0 R /MediaBox [ 0 0 612 792 ] /Contents 24 0 R >> endobj 114 0 obj << /Type /Page /Parent 103 0 R /MediaBox [ 0 0 612 792 ] /Contents 27 0 R >> endobj 115 0 obj << /Type /Page /Parent 103 0 R /MediaBox [ 0 0 612 792 ] /Contents 30 0 R >> endobj 116 0 obj << /Type /Page /Parent 103 0 R /MediaBox [ 0 0 612 792 ] /Contents 33 0 R >> endobj 117 0 obj << /Type /Page /Parent 103 0 R /MediaBox [ 0 0 612 792 ] /Contents 36 0 R >> endobj 118 0 obj << /Type /Page /Parent 103 0 R /MediaBox [ 0 0 612 792 ] /Contents 40 0 R >> endobj 119 0 obj << /Type /Page /Parent 103 0 R /MediaBox [ 0 0 612 792 ] /Contents 42 0 R >> endobj 120 0 obj << /Type /Page /Parent 103 0 R /MediaBox [ 0 0 612 792 ] /Contents 45 0 R >> endobj 121 0 obj << /Type /Page /Parent 103 0 R /MediaBox [ 0 0 612 792 ] /Contents 48 0 R >> endobj 122 0 obj << /Type /Page /Parent 103 0 R /MediaBox [ 0 0 612 792 ] /Contents 51 0 R >> endobj 123 0 obj << /Type /Page /Parent 103 0 R /MediaBox [ 0 0 612 792 ] /Contents 54 0 R >> endobj 124 0 obj << /Type /Page /Parent 103 0 R /MediaBox [ 0 0 612 792 ] /Contents 56 0 R >> endobj 125 0 obj << /Type /Page /Parent 103 0 R /MediaBox [ 0 0 612 792 ] /Contents 58 0 R >> endobj 126 0 obj << /Type /Page /Parent 103 0 R /MediaBox [ 0 0 612 792 ] /Contents 60 0 R >> endobj 127 0 obj << /Type /Page /Parent 103 0 R /MediaBox [ 0 0 612 792 ] /Contents 62 0 R >> endobj 128 0 obj << /Type /Page /Parent 103 0 R /MediaBox [ 0 0 612 792 ] /Contents 64 0 R >> endobj 129 0 obj << /Type /Page /Parent 103 0 R /MediaBox [ 0 0 612 792 ] /Contents 67 0 R >> endobj 130 0 obj << /Type /Page /Parent 103 0 R /MediaBox [ 0 0 612 792 ] /Contents 70 0 R >> endobj 131 0 obj << /Type /Page /Parent 103 0 R /MediaBox [ 0 0 612 792 ] /Contents 72 0 R >> endobj 132 0 obj << /Type /Page /Parent 103 0 R /MediaBox [ 0 0 612 792 ] /Contents 74 0 R >> endobj 133 0 obj << /Type /Page /Parent 103 0 R /MediaBox [ 0 0 612 792 ] /Contents 77 0 R >> endobj 134 0 obj << /Type /Page /Parent 103 0 R /MediaBox [ 0 0 612 792 ] /Contents 79 0 R >> endobj 135 0 obj << /Type /Page /Parent 103 0 R /MediaBox [ 0 0 612 792 ] /Contents 82 0 R >> endobj 136 0 obj << /Type /Page /Parent 103 0 R /MediaBox [ 0 0 612 792 ] /Contents 84 0 R >> endobj 137 0 obj << /Type /Page /Parent 103 0 R /MediaBox [ 0 0 612 792 ] /Contents 87 0 R >> endobj 138 0 obj << /Type /Page /Parent 103 0 R /MediaBox [ 0 0 612 792 ] /Contents 90 0 R >> endobj 139 0 obj << /Type /Page /Parent 103 0 R /MediaBox [ 0 0 612 792 ] /Contents 93 0 R >> endobj 140 0 obj << /Type /Page /Parent 103 0 R /MediaBox [ 0 0 612 792 ] /Contents 96 0 R >> endobj 141 0 obj << /Type /Page /Parent 103 0 R /MediaBox [ 0 0 612 792 ] /Contents 99 0 R >> endobj 142 0 obj << /Type /Page /Parent 103 0 R /MediaBox [ 0 0 612 792 ] /Contents 101 0 R >> endobj 143 0 obj << /Length 144 0 R /Filter /FlateDecode /Length1 44436 >> stream xԼy`7|hFH},[-['qLIY!$!v NE [RZh-](<5[ m%sG>}~g;f93 ː@4YsiƫRl^niREH6f-OBHB=[lmoM7 z\n%4<rRhF&W(UjV7FgXmvx}? CH4O$SULMm6WWߐol*inA2`q`,Ige!rf8x_e)Bh֠mzԎjcutZEGmB1$!dŋx\=6:?)н:7-A"9ע j-3qߡ:t37{`q? D=;\3f4mEנ[ q6)UywL4@G )CSAk~i.ڍs3 IEqEM݄AUx aN wч?1G"FA@jAϡ~@g'W>Ag_3ge}1Y$o-r9$v<Ľxއ_Q7SoPwO}O0de˧)*7 O7Ї@x0:^{ &<oa5ZEјoa|-]VR=\ިAb~e+|wC?D/~Z)h5 Y x!^WmQ|B PSߥ~I}L_%fXS {@7,.8%'?t轒d)EJ3J7;qx#O?;|p4Ri]Ӊ&p> ЏW@BD?# H3陾DgXЗz_ux߃>2>_ǿ¿ſ+5e8*MSmj 5ZB-Q۩{'I P>J$NO{#[G_C0 #?#0!Y/B?-*AygOrET1Q1UbFAFyи5?;/ x+BQn7cPEC 3Fq-Lٯ ~!f?p-$ w/CG FԲ{a,zY ~#Y|ghm#+ʃC! SCJSlx]J ̆T=#9Gr|?.bK:KTQH5+zQ{iWoޠlx/F6womf\b Bx|Aǧ)'Zl|CMC %ڌo' Z7uf1 h5`9j x:K0?̥h E`+{\Ŗ1|C}.[[NWx, B۬3g2NQ )E|_xQ&NLװ//[ bOպm$>Y/]–ŕyMGx腢 ,s"aC݇΅Ӻ~?.Jߎisu]:tZDcE3z"D,}蟁r+ٽs9m\wQo;g^P+oWZ.Ehi/hуIe \ETQj>v[<89K*ΝV;ą ܞfTy ;^.]\qB x}H8|ro+qcXt n+rC2k9r]ēU=~U*\Ğ)t P lga1<}(3@A ۪ieWhRol~D{0U]JܫHqǍK*d"=L݂x-8|9v'tfݢ9ߍˢ˶p=DקC3=eh09;F=qH--fkmM]}p.k ؤ&#˂,8,Qq;=KgbWKۃqe #lx?>wÏ}6Ӏ] ß*݅t0*)-Wӏqv6dϷw;nn?nRq \cri&PkƠFAd 1DbG猬bGkv~p89D9$R a\> (AiP`-HL5A=LATŪȆ%_y׳Oa׍7xb;PS*w3ύYR+$^^oı1l.*ja纩1?s76RZ^aW(0EZk|DxqCN q8# Nۇo;w߰ΨGa_kε/f/R O'|:X'EԼGDԃБEzѸBK̠hʧɖ\/D=\j#ߺzBAZ 9B"Ɋ$8Qfizj:nS^nW2?[jۚy>+݇4c111Vo{<0ƪQ<声?:t1`Xp<HWlJTMUѪ|}8Ujh9NP,4kphd?B--aq7a0X=|]`S68~bޓy쟞 8*z~Fܳ :| ,jFlpyeڊ\+LSLWMNSODN5 ˘ӗ/UnQm^ώO˭698\מUu!,$1JaPh>ovx@u _2eNNW}w+~"< -\s}s^AKV[>Y)RfRJa,rgt'.[WL8C\5 샽)¨WP"{K(yjǾo{EYxξ}unLXY1mh$]6(֠+.'*"ɂV5Z|=3BUV'Lz;/8ްUc[߸\aii~tMH*\팛Z8uzȃ3S?zpLB؄|':s3Li?mTkDT [E՞.)B}&d4&obbZ}? Z:dB&|$*Uo\U5홈T55K hC+&u6hՕ>jϛDk>q\+D ^I ޲DCL}O[5;j0 y=!rNYySrZ--ͼnlݜ guW>EE0z0'ο?3ƜtcOPG#bͫםWRdi'ufF$QKόL(mLU3R_KD3FQc>#ej73a{FMhV mzR?zH 0ChFZ2mY<9fvd(>S3t`)~P ^e˗<2dәWx0V.Uv#6|rDpꒅ+e4r}S:l^]ޛdž:%)EU q:qwKLa*5z0"JVԁI4S[lݠ0dVA1PƜuccΔMpe!`-VǺhH? :֠|^4xemVG u'X8[m򊮜~cS[^ig+8Pj^{m޸zS{<VbVTI |GlF^0pKjpJ`SQ c\l5m!_`%eov1_76bM9o5Dzy.6cMMxcʡ z̦fVNeBn[]c5v8rZhf%Zmm\1v1 LhͶ)]D|4:jc/b7&("LA$wU_[4ca[FWhDm|mߗApGCKvȂ @@֝e}E_Kb>x` l0 @ 5OV" LhJ!$ra%J'ԗ7*#, ".Zb{yǤK,XPjCUœ1=1>T7щT}Jhi͹&Ǖ:K|菳Q>Z9B%S],8㺻RBuz:[g2 @b}9hWJ߈oSLt 1c.>m@4'bbFZZё;a}'I:pآY#pd,ZOH9 HEb ә.Ud5hz/VرZE ,j } K 8<#gyڇuȄ<0lYdÑ~i婩,u]0%} 'MJRPiJ\؆}LQClĈn ;J* ~~ea}b +d/p(76Jʈ2Jb9GlH  IKQ#+Vju@^jV Oܱ;\>f%cqm5;w ͛SZo_&L<Жٲj?^j8 waVζ)Y;cCA,.Tcj#{͐x@ۛ"U c!h#[Qkˮ~'#EjfNz 8.X/!v ʧK/9k0",I)jO}5 lHUf$Z308QD9qehlʏP2PF$^W`bHX'GC&fT& jʏ~Ky~\-%[:y7 u-w#^ضX:"5,X&Q$'*`aFg,LTZ 29~rhj92od + 7M} ɮXR'zz2Z?3[vj³ěnJ^Vֲt W;R;=FQ\ML/M]ZE.Sk>zV{P xS% c3U^k4T ̴\n'i''7V )]zWTGZ~UhTfH&Lgj=*o >~O˓Ќ_ z"ٴſOcϘĪ-IݏއGhˡpݡrtk`V V= #9K}nYDzzV*Dȷmr*8 To_KUo?P(=qwxeyk~򊈳#5xkifZ5򀍢Rs!徭So/}?XeM\\X~7 ӳ\+L=h6Ο)/0#S(ua V"`N00[/갲T 2Lcz5* 05Yź|M+eXO什IP`%J8 Ug l_?Pdʼ00T YBl%.+Kg1] `?<C=eAϸY#f_0!l[}yu/Z_6 DZ[MwFܫGN/dU86f(k4GovwEP9)'9#0<᧭2'nIU*GF(Xel sT+B$b[CZ^3sDt`Ӻ:Ơ(3 +]-)k>)rK.%K)) &`u$ZOۭ'^^ Kc7 !R*[sk?׬c!2!=kL?0Ynqftz.kT:u#Fٌ86Px)/VmŪՍfsSS3fLut;::Úձ@ؚ:;@Pu8-1FŊTF|70oi\rg6ᦩj5?tB)H_(Ja-rRᓊ~8I:xRt6t5:lB[ĶϜa\LFdUv  RȵϏ'kSuvm h󓠬#OV y\rra89ΏՐ9-*FCypOOhM̅J5_~Θk&.zds1{kp/4F ƈB69"an5&] p:%kaWc`9Ti}\q = z W9i?|}V}< J;o}(&>ı@t; t7= nI!vaٸ 1,C_ s PlyuPRe5% K |ň Ã!9Ocs4QN$ﻍ*)050N1Fiz/=p—hZo˹&-W۞o.M:"kE׼?iUUxAuZFEhJҢ:K&?-}VNtYe -g'/N_s[Sl=]XNlVUOhZc{ QGtNW8Y'vF]N6yZSED*D SS+N)dtBtKNE59'.d[4dO;A+j6gH7=X!2=)O>U8z2zV!tbP!i-iG΃V'`g4Łԛ ?n_s}ڲ]RL368d͗fW>#WzG;߶]*M8g fW&5^%Sg}`Aq1X-Ea vE5^N<_zU+dQGŬUM 5T/z&MTk7/xz;;?3>gUivb5,@a);e&sȞ`$B8LOHd@- =0BmrIAWkJ`FcB]qB)e ɯX2u޶wW迸yk[Pq#mnY@U7H0NEH'@sX*v͗<2?/t7575,~6_)3ds%ٜZ5ttqVQokɍͶ1#L403f#L$1Fק3uZFS-%Dkkn`0 E D#f1#a3`@`kXPBǢj>g$IX3c`<~N E)%k~XyNFcRco٘M2+# j"y3_gˏG bGa()lAYIH@_*'C$0@_x Z:xUw]϶ug6ڲMšhϮnYH-~hCb0 wz&O7Ѩ1<ñk ߵ ajBH-xQK`lfXnp4fezaR$ucX#+QOD>>_q"ld@c30aeY]fY^mu_ɼsLPSÂf՝ rW4 |Kި':guttaa:tX+~虛ѷڶ) .}ֺF"Utnw6O?yg2hF`A_TH6*J/E25Xy>N6n3^1nyE~o)O=`|Lw4{ؓNTj,O&9AQ9yǩ a{s6~?_(XJH6bc=^?I7;Dp$" |b#*>(:S蔔`'S8Qs8|n)J4oΏ$'A4.Ci M)['ՔM3g,L-Gԯ8Kg{SPbgKrC2@I U|J@wᢔ8gė9w▴`ص ~k# )ESݘ%%pT9q6UI;b͝u_`W0&r8%bJ8>MZӢ5Ez]/j^D/YjW;4%xq n [Hy8#h˺E-iIZp(da)_[~$'+)hy@ƼdT@9G¹ "DJ!И$#!+gaz^s+ǨzkU07x>4$G'}ӻL?4m5ŗSM;ҧ ԑ?V6y7'Hd (CNY [Bz\Lqԯ x1 =o͉^z:?;)ؼ1``=QjLVcB65hVjZ񅫐3"dT=5YY$1!FqGL;Jk̃$zyU42tJrrq@V@)olW%z 2j̛°$r$l]߃$>}TjR/ʴoX:{-W}Y5h~/ڶŲG_-Ҟ|\ ugMXcG 'Ofd:XR?lI!ޘ۝;inT ޅ5>5f}VU.\件iٜuakg$% M#L]RQ:+AM'C? n;H"'I[$[^(aQXG5L"8 ڵpj_cuUC?V&G}g?nn4VZ_eyi )֞}31{B!+}/m3Bfd {saк^qҪ< ]6ߗz:~r*# Jwh:0ZNjG4;

    :s]ZJ}t3QBefy<̓>_GH d?rZ=RO0ckGǜ􌖍1za]+52L`=0+Ƴ4<Ѽ!ۖ_+&ȅjKPҕv=LD,L X*j_17)z<* mqy܂"f?  0T0d  vàPc o1SZJXkZµJ[H7EUZPuXdS0EGûO` ,3%z*/j&@uPJ0P¨+ER!.c!n.Q+@43J7K3gmljl޴=[Дj&_G-m³d}sGqBn.[|PRЧ~4IлPAZm}4whL/{MU[-u>)7 II&1~{8߫,ҵ*w=h7TQbt j:Q6 ccE:hIi6f~3c'~6Yq'Y,T“ Ҥ pmI Yg@gm,H RpB6LU;Ʉ+HG*•l,P&y[ǫr`nk~>7p][5˯R]߹5-ZOQ?\DwK߸bOFߘ gsojZKx Dt^eϜ={.]4.hhC誆q]V-xHQ̈́($lK٤,o[?O+ 5,FH-Yh*LZVь(ԜI D]& fDT relwf;;S.R W'FG\ g ;+Dk-_2 DK,(B0Nletl W0 %]$,儛s dCIF6̥]V:S+N8/{q옶lr)!y}p&rTRinrнHl9 I?)n_>5yy۸?^(ayoj{RSP6S`  n q:Scx\+&r [pďɝim?mKc,Pf맺bfO" 5߼C;/ ql{jG@'y-}ɛ?#2-Y-1tr..\33]_p<#9c}Z5j] ^UpռO?4iVw i)b`z{@t  I،.vZӖK20{Т\wDpCғ90=zzBSR9dtވ&Z4i#4ӀaUf7ݜ߂䕴Zڟ~jCqheC3:Rz>j6VC)6HD(:'J?@OZc>ٚ9z[hnil-B.Y)\ (ɡ+ObJץqđ,ẗ́DV6sD"-r" 0oI0ۉ=Fi )bSpBdjU[Z|sX+RC?MqE9O wv2*뷘b{mN ][7}s9R^D|;]\Ϫp^j؃ǿه$.غkp4eE8p5O8={̐M]I`UtaTD:Jx Tx`Vd2N~iHe`AAfj b"sskn+:c$hքM/!H-.%f%_Je"%)Ә8Vlpmun9U<&&nR8JUxq =G1:3ˍgHsF&ۙ)G^Ԙ >Zsµ_fwJ噴[FiZ y:WT_~Z/C19ݼ& bXQ4z{xwdw1ts)"QIAQJJE,|6)FĕJɢPQ:J"D%l4)cJ#HYA|;R%é$;xИ_b"p7F){.rb\ lκ'8hLt~yu`u_/ڭλ)E$NhX6O"Lh3EM kğF9 D#x;魘Iݐ|.5,g~ll%rE‰gS+U:)YAU J@N(b)="ԝxHk4RFY2tg։* ɔ Q"'HGD Іmح>IEF$M/ 3A$C(,  BKڅ!tg':M2>=؊Fw(\kob/LuR=˙0ʎo\0sW<| 7v$~<|jiݛr|X*+ ƴA/<P~A<)qғZ*-'u_qSG'/ ŘZf`dʠrJNҢ`SP3'i-Kyߍba,#C2?&1Ix?tJ ʦ 0*liC#~J/@=C="2He@OޤpV8ȋ^A8MNX7'}tƽ\oz 9yWͪUGw {B x03=K0" ]ç||R{UC]Ȫ*k Tۮr>eeFwm{@8SZw |@㎂+Gtj!O3C[Uѡ/yelӕ Jp̌+I MXݷ=skgۯ~g=G~@kP*'s}a{=#K*&OeΛw8.8q٧e&rl%l,zJD^  WۻlE]V,AO>{kl8}ܻÝ^Yv5xޥ;e;h޴KZ\[tݛyHxx9j`߭n;;|ڂr+o(69e'™s7εwˊ<8w|VjrsG=K>5ץ({czvAkɣ v+-Tz}J(,ՏXqsnut7Dzq+tyڢ{-OLyx󭢭iȶV,ku+nʰ]h~zwF}]ؑ~ٍIGzl/ؿ_/yh}ԍ=MeU.\񾪕AN{o+Wn^Q#VuW<$p5x \ȕ]7{O=+x;}*f&=\]Uc֙LkB0Pi0 F&U N1 FWfr]0AXTV{3/bTgG Mų bF|+ʽ8e08Jޚ$=J DZ앭FA[ {=]j,i _.^f ?gYp0J(`esVʼn*ipܿ)ze¬P O_U%RJ1waU1^AHn9_ݖ֝i`e}>: &\-:t@rVo#w*Y)E +Y !o%毅x;:05@X8L 2_)XONH/R5u(h}HKKWο4^U$І=mW @_cP&{ 6+;pD ~rh7)˳@C 1t ~G¨0;ݪCӬMqp*o[xK%U%=?meVKWmW=dZmy绮k535R^'K7.[nCݒ=y=Dw'fQ|QQTaQE\% XU0X 1.zdXI, V\&!.8vA`r5IBs2HlQk͉&5`70'k,+Ȓ$)%9I4!kڂ^3XOZ;_aQIOZ)(J3XkVbn(Kd0(jL4khz^a-oV|{  -P$A V42[d0`u'Aַ u\`I|  ] <\ҋ; M$3XA  S):'…`.nF_a0/!>RJ@rg0ſ a+0⿈ a0M#Ք` w2 \Oxf0 5c0%/E}3 4a\O D"$HBq}d $NbR K$k,0=!="Duٖr$IBZ7r}~ A>LQ@!hC KmzI 20!#&#N҂@9o@YqQ6 kMf{I[Gm$A(Q( 4d 7O_J* y4-AvAm񧗳H(T."S+Biy pui i9 &Ìbw ,;0_0ʸ<7.*¤,VMf=˙zL{d{Âh f B1U06jcK8R$zyْ_q/1i''I姳cI&w<^)y,9W+έ9lTq~0K 8!_:ݔ[))B9 آQlyt1LJr꥾#cyO\?e9z0/xNEkD 2eoaVy qgi8?ܮ\a^RlUL?b-G7\eByf<҄Pd8 i8 ;+g6)t񸘡wen=H|vX,^~.pBl6r[$0cO~ J-\6fgp܄_+F[IlF\=fhR+rRdcݧ3y޳&F`H%qC<OA6'H<&FCq]0{4MI1(PGF-TR"%ĘHIq4.ncݩ`4o;+W۶I$i"D<L-=?z.6bogU1/ K#.1>}P$RXn7SK nXXIi|2\$, IYO]IlHp('V$$e Ci9M-IFrbxLJ"Tj0Fz@uéw$ HޑcZf^dq)J5lս{FqSxe΍b[:;7tn3:PxDe>b"eUx *K逜F‚"P6I %$2#C +> AzC8(EPe! [NŇ$YId@DTHC3u(0kXIű`4.%LJq+X$XD' A brT E@E\:>ep1LJ:@ޢ/9QHi:QLdL5HrdvJBATC+B~t.tZ!8$VF1փk7"'i0ք4ݧx I "dL;dA\;1 aF8*Pp/TtSMK7.TtSMK7.TtSMK7.TtSMK7T,]y6? LU%/㮂eL.\QE?JUvk-bdlʫ_2_eCѢ]"ܞO SkĮ [Ĺ zEg1v n ] m؃9P.gϠ b;9|I86 B`<]'g|t $C~AT^8 N/)Rk0`E ,١f)0+Kz|v!!@iatQ"0MD!B4f y R <6^&]C@Au 0**^ys%ӥ>NT6ͼK҄/q%CӍ,Df-j)"-S~:"PʹVHMCkkÀ_T};GӼ>3ͻ\GIt}εie (j*_1 Ok|fɧr.@oh}tp>|թP:W@WڶM8KS9a66vЫ?ذ۷Ryߩ:O ~];[hN/cdL;])_?S*T>}&U^KWB6?DL{6_)(%w&#1[ V]O *׺ʫ|wUq^#.lSyU*a?ĿWL  8`-6+ Ա? Io}./!G6(rA.کcγr}p´0͟J# \9h9hHI A&С;`eV偲&M/5Mƾ&&c]a旃1}q3e]hhAѸS4Fn5Uxl3O6E Ea`m1Ӯ&,_4jH3]yQʫH\%,MA9Hqp km{RRcEKq#&/I#e#ӎ(:A+ XشƄ#uaRh"4ngӕ߶}*yzJrM@yY 7mY7Yކm,xƯpӶpSiDn۶˴F[/BҎQ v$lɤv8[OY/M~L袄 m7ٺ\mkj[fmm*sВƃqKܝzz:T uڮRi 4fMƠi4F5DS4;UZ2HGfy[ 2U(=k=-S-)k港s=S/Hπ8~c]uұ*!=}k,<y#}gyZ򩂵aUN'K-[֝p=;o9=ۧX|L]+^(uGiԿ(Թs]hP7(2^RI@"u2 JF1bC4E5x:G1J"AŨD98J398'fQWj;f_퐳ooB_> g|rSIk.]l~XCVGWYuK\/D9LkH{7١2L M _VeYSt$YV}G}uYylbY/JcYfH·J@=:]c]?tF?NTAWo* suNKd]cOzAvZH @dҍ m t IR*nXJwQoqG.S~.L!T endstream endobj 144 0 obj 26099 endobj 145 0 obj << /Type /FontDescriptor /FontName /DAAAAA+TimesNewRomanPS-ItalicMT /Flags 68 /FontBBox [ -497 -306 1119 1023 ] /ItalicAngle -30 /Ascent 891 /Descent -216 /CapHeight 1023 /StemV 80 /FontFile2 143 0 R >> endobj 146 0 obj << /Length 503 /Filter /FlateDecode >> stream x]n@EHC/EdBrXbg>Cۃx|o'֡*f׵Yz&slf :©ĊizDjH\]pu,ibלpƛyX5!<Ᏹ c۝aM&K4M8V ߫s0 ?9nOs?)! Xu&,+r-$t\Yu8m,oPψiπg^k5/WFk,{56xtmS8}rF@i)0}X}`+>Z8ǣkKOQсǡQDW0c>}r# }`*0Bx}ީG0BN@[#GqG17`JcT}чGGh+}> endobj 148 0 obj << /Length 149 0 R /Filter /FlateDecode /Length1 39612 >> stream xܼi`ŵ0Z=ӳL,f2emY`e,lْ-E !6`0brq;`dH H & 傓8 ȍqH@w%@r}zMթꪳ2."iWK¶۶7/|!vM?=ߎmm7XwW"4wK_owϩ%-]p/Q ;4P5c}\&_ PD_8:2ԡMݗ Vt~{P6woݤyЅF*~>809DSpN%A !s̰*5l6r{>  '_Fa" _A~&_ۅ7 pIȊ_/vzݎA]G Zp-G*A^ZȍXD Fe]܊q݅h1rftϛ|]~#pXBIMCO3GWoB#hz & tҁG'D+ѫxx2ut _ԓQ%Zq{䃨F'O z}IZ'$ O4Q|6{Qkl32<< }f`mS |5O FkNt_3&/G6_F݋Eϡ?Aox)4UR]|g7fhA"܏41W'|%`1]6op]vN(kUɚrj0uW+nǯ1_dƛC}0>t }X؁\afW7L_B. w^Aע'+Ohل;>< {]%nW=U«uO)jOZ.\9Kb?AOi^7(~sidKع˪ꗪ53' ɊwMjrR!߄6>܍珣B?{~Nc #b'qfw^V|/> >?acd)aJj=Vϊl2r<~BwJ׾7 _ppxγ@4a m] 80z =^ |~~MK>%N T S^ inY{ |5?0'dݍQiM0Q8e+%#e-=-oD:3QܼV\39mcFQ }OfnM{֬N{ĞGN k ;w})"tnk^gU?/޽{C-y5BNe⭫£o$.@1v.#22+y~b Y}0}{/] Egxƽ, X`.]wkmֽvMZ# x+ɽ-(:6ԍ֛:a}.q%~yq1V+ّZsy96t`!O?0Ѱ?>р?4bX`BO$5 $]2B&oCG<|tlTBTvDGU05O A> AKT I(-):F=Xtx{X Oau$y9鮡] 0?'R)(+C]PD2!VUQTVWWUWUZŨӈV1&,XnLec>a EwDlۗONsԳN;vg?n?ag^ =)`uNC;p<lϴC5M"uP۠!lpS^&SO&a*؛oZyG;/sTNOlJ!:(#L1ϐY/x4ٗB,!2K.iv1Kpp?F} ph<.lf tߎz;&27q&" n.IIoHj #OH4FG|J7w=`H4WO Sk-AA>srQp A&X/H&nW* *BA « zr椆Ռ$*`%JDb[XI#yjӏٶ;l(bL%DSz])j444fhŠNI]UUSDan%+Bdht4yvrFo s5ͬV(eͫZUqhSkjyԵ3W/$Ȅ"xyчFlHkN0ҸTdfyH-*2^h6OΚhvvVR(?.$JjjI[dD-lcl 6(5ɏ 1xǮǓ5CDӀ "Y:xkGK`.q& !s؝v/ dK,!Bȣ &hNkaB;i'II$yTVk|7n~]ǹh~e37eE=M^oEݻR(Q/(/. pZ#. ̋vF568|CUin{ze9흮Oǘ?N2a@%9'3b!ѝ⍠PI ==eyNDQub"Jn!. ?D j@1*K7c,#8y7;Ltev1y:`j(t1gS]+A+i&iGI'}\.$r}P82cmJk xFLO'Q[(JL`0k W w0@9cp/*\XXY{%7\aWܾ1\t8s)sķ*p+siVJ91!M5¸ʛF2S $>^-cyj'ΘIC067Yr[96vHFןŹ_*. +NX Lb#0H`uEG,lc~%YX8"FY0RrX8%AXz:́d:r,L>!-Tb.S>ú!Ef79Y82/+RmUA@,TxՐ<1d gF3L.3a2Rcez;uyC'4~h9Fs[&`AaDL&g s TcޅRi޵HC䊂*8/k0툣}R_!&Uc^2ѨEQFŘeb 8c "fe zo4)%%Yˁ]t D5鮆ZPZ\g"@:J&ѥjSNjj0?kmѻzhu!&/_8ɡZnѽVN}$ 50ZזK s7Vު9X6v/5Vh;U_UBk]ݷ;'ZWGzM8mN+ܔKp[*] $7]8kzo۱B>f_/_riuqqSEe-*ڮiSrpgAp󪪳 Byq`iJZb+t\-W/,Vkx8\n ߤ-6'b*ŦJ/dkjlR"o$Qrz򥍘\>bXt8Ȃ#X}h V͎ɈQ@NӒZšF+6O ޺ו{5 kp,'Hp$li𤒧n>af^Qqdԉ ^! gTD <'1"EYk`%F| oc"܌+;w_}!nU=u!o >M c7\*A:aӓvc"Ի#( \VgЅczu^Q0dj!0Efl0 _n+oQĈ̨[DcE%º].^)|5qV41ؕ8>BBJt@hBo`:CiBdoT"K&2՘aʍ~O-is.vM ]jAZxc.28^L?o1cuFqdQj,e~Kp >b^^, #;Ұ$OGdy;~2CxCc=y|Lti8] 4Gm-\pO6EAq yc*.QIl ᭁ&L9ji$GBɊ$Wj5*R80*P+3/9'+*3<]SSx)ѧǭP|]8wuU8\(SǀimȊd##2yijJs\9w^XZ^^n[ڤ^166{BmW .Kޑz{n#C YūȮ0fl6ݎ!a*pRXT|vFfw !NHcێXY"?B*n pX# $bHX^"["<jlU,ҥCvF ?  JSB8D!>LxzfdO˪FVIBDVI/F3̉9Yۗ*p樴:heO Z1٤-Ifc2ʉc8}-)J| w³Jle9X{e9d,D96ɳe]9k t ٣.4ytֺZ7|";Ž2ҝ>»ae$8QnحerPpeD5vfRoM0'zaVɳL'uB͗+0%OFC"˟qꀓE\Ƶ~C1v;=^/y$&lr&4FB0wTpix d0SqEn/@^VéjvjjMdDӑ'3"0z g_-u荊#LS_!Ԫ)!6 Ed2$)x/\;E arɑo.'bu%2Bnifk8.!^76깹i\lDӹi/5ZU >2rIIf֢bN'zAh€Qэ\6)Z%y;" B@-AxJ^/(8K#9m4;r'r`PɅ8!TyLLNWlʹ3/);#28'îK7u(Zbbldq=D%&Hh8K*c W]ܠi>,q杶m`{3ww=~*me(df4{?S;҉tpԕSJU.VԖW5N)l7zoi}}:c= 6=\>.ZX79"*e΁/ƾ `d/;w}ч ^1FrM:cr) rO篲s!``aa> %]\׺(?+kZ]~mop{Wi %c߲9x[ǾWo*)gs#4:&o*vbp9~yM1/Jno=d8fx\4jigXh$ddlat cas7="A[*򹿦5ޕ"6 ^#ҤmpP+9qfhƈ '%&#?9tCǦ{Ju=H^,y+$Kn G ,M!ЂAsڐ;ԓOH6hACuZSM K[r`˛r \H3HnE c'9Lx"(TπBz1* MUh$ 1]}PՈ^ r4YX]\pk5 WfZ:̜۾hjsyg ~:xŷwq%.9qE7 6ˏb _(|zۘmx@Ju9}mxB\.}YgBE?*i@,4 A]4jX1JJP< s:$H}5W+$Of,foyV䣈gڛEYi͂:Mq%)|mS O@'򦫼DDGqǣ¸D:.$p#ubF]BݏWa%dD:UZL_~MÑK ѵS <7UCHi+NN v.;7^qe--ڽhkdhrbs5&QFfh@uyXAzƘ_<-%h]^vuԅױs`9Ր4=zHb!!=V!莊S=ŇYQCBFh&AIqfjkZVDs9̜rKUJԲZ:ZZY7ZD<1Yk<Й(ks Ŕ3s@zd'?s{٭<\m~56Aϗ2HN-@ LmN 쥾K}c"{ZQi=^xGAu z5LƜ3jœ ;y֭* :v8E9ky>h2y .A؁Lfq$!f89# V}wSCػ!4!겓eeL|6g80+B2d?Q{K.,ucv"+rڣͦe"EZ-/Ǯ$tR}2'ܲ\U𓹳/eE6՗5l‡e-}/Vk_kz[@}WNJP8`u[kAj9*3֖ X lԖjpkLzB2EQO0vQ.-XRNl ^BbV;Ñ$rgK rB:U\,q\BI I Rqg4>d?bbE%1gE,0V%<g,:*'^y3{g]+X~׵コ_9^U4 .O+(09-9xo9ar&,5(粔|$Xma1ŸXlerZġTVJ|Gى2L*(,S)n&qQ2vOFo!y7zrF93*AQ +E@6-)Mf4=!:UH=!o<&8!HJ|$. ħVj쁡cRӼHiN` `rgZM;CwFw<}8vmSӋOћ^׎8UpLU@{։?ѷQehyi{sy5Ub6!^U-W"#]&/銨k?]|I.ވ*Fɥ16n.,|}xwlwKחE%R5~*r-!k3}>v11ؓ'KsbdOu%;JྡyBGŚf KA(}5;13(ZQP*|xkꐕ2FU! yڌO]P~:Φ4PfuKgj"[jb n:Q-D %4 č.~+>i#`4ڥ'4g|hs;yJLg"iQͩ'<"@7N}/r̭ yՅ?xvV oylR_~?W^:r }Aul.څŵOA+X cjŎPkSipU7v1?EHXAʻRGcƓTczqN,*h*PC:Uh^ҠV($ CI=T!v{HYnoǕZ;bWvʨAI͕&2u69M a)Ǖ_;@?:1/)Q`:zib:9)?j=I,GN*>{,^qy֎L`jy]@"JR^y7^jc^n|˕s#MM}/NǷb‚~mwΑDRH!rVº!RUx; |0nA`&l b-*yh4[LDS`<*`%yzF(w~TUP&r!6}L" جZk20_ ՓPhoӕ rt3JeOfdG=뭮K!vvqJpL[{%]{)5xZP2GPt,C$Xoij{ĞLQ!=x#jE]Rsfq)"O'WψX?N^]p>g]"IdB!Tпn{?t&f._"N1!<#^ǐ7';9Fs خwőO (P(oeQWJq-gUM Zc5—|1k- SVGMgL" yM+ɄGj-+/϶JIn~o;R-/>k^rwoYzB'=M8o]ݻ .wr { uV^:yRX^T=rfhR\Ne,)ؚ X*Jʏ)%]#zrnרxԂi'ACkq:Tʋ2,,dR8;R?_p~o/KJþ:[Ȧ͝E-  B!3 aֻ8Nh:';ñ(%pVYq5dvrI0<`1b[- ,8e  ^E']N[2;Kq)8FιzK5tQmOL"]*gDTDכX Mvy~sVWXؕe(q~-x͑ѰuBXCxYOv|v#z }1AzBhq /̫ﱦVY>z7]e5+muo`4B hg0:/zZԢa<~ -ao^Bp^~;דP{-| u"W٪3b*s\uz+~o3͓|5a;htt]G? <u‚H8ZGgD툥}s94pԑ)R]r@Sb-DK,K ̢2 BEx)0k:t֫؀)ӵ){\-6i俫YA*"fQCUaNhse_5h Ev[P^#/*:956yQ>ޠP֛NVZ sPy*Ja -RX F; Bi" R`EO B(07T`o`Y@ߠ_+077 _Q`o5\q ޖ+ 26V)0?f} B)~^Q`o(l'8OpRAƓnR`ONwP`ʧgh^~R}F~@fdΣp'sx2WQ8L?L̯x G d 8̐~ d鼴 ^Ka:&rOP%R`xn-E; EP7Z RGv46wJ@PPO[P4w)7=2]W6mFN2T RQrZ;pzz|xF?DuCss{>3>a:>mdzvdt5 9 ÕYg>{o13cNKg}RЦaH*@m/P΁A2iEB#& (Ax:J_2Br_/:Bާ1ɼ4%c;i^äv:W$$Cyr F١aΊeZ/EVPzѻdLa= ӣ;+d{ )ULt\Dۣh3M3Ya;ZHI[hM7I$m3QҦOi3j )@i-^:JnGlcH'U Hk)fFJg`M;GMaDznzo9ϖ9KV^ IC3$b mDo&emVFyhT EQLٯȡ#n;UQͱmZ&gOSh4}Zd<{2&n/󥌇͊^?2PܽbXi+q w+0n"p#wБmwЙnTұ[yF(州#?dDHA\)Ӄ{-u)Qѣk໑n2T=mWhouZ6A f5 Xe  ᔙl(Wѡ=CũN[ ɎsZP SN5Kh_~Dp@>Y5frdV:9~t d\4VѾeNSJLijOY Rx iڃԷ@/hXڥȄ{|L wLkʞUBeʯS$36+e#Ӧ6JY޻(zM9y4"j~rgӶ+R 8S˒N׀2/s4~y=&uZcQ(3v~>S-,W| nꏟRzMb#e3tO(kn:A~E;4^g<ixFn=3z[B9BeWũ>KG[ (xbݟўgV(#U,=S=i6#" bK2(e Z÷ Be)\-+yU*! _Sr޴=\cw]^!ai_>y` T Ã[6 f[F9ҙpƭfD+-@Rfo(߿oˈp~HޞzGŽۅ6uo3gO]źe#qٚr-şxf[z.ӫd蓖~=7\#[z{{hzBG!!,m[7GzAtO݃};fV so^Od toػ0?29-,_e`XX=ӻy |i_ {^a=l{1$'Ӓ's\4fw``pZXO׿O"lzzGo -BԌl]3;ưqw^a`s/ bƞa `dڵ##nCR@od 07 =G,aAغwXH€{RBi'F:Lၭ.Be[z7oI48<@ (6qĺp0Іn+dٲ!{X*$ؘElˁNk'4X% $fd'vmDbѣrDT'E%/UOC=YPh(+QѲױcWE۹߶ׯmJR ~QX:d <ϖ`/XkƆĩ@/YntH찠E<0 Uj]Pbb= 2ջ-~N;""D@H/RzX`%3;o)\P%UF; IqJ ĭڕؑ)7g9΄( FP",? t}}ua= *9U}Od^y3v'dO4~`KO!$R kz2t#]]\ `0cIlP^>a%CاqsDXp.[c>`.fEȳ 8n`EQvVzSuu~ްa&ڍZ-5[߳fGU>oifkoG'HRReA9d,PBˡZĂ~ߡD-> Z|@hD-> Z|@hDD WpL$}_P&\A{q} s;\(wyN.ΊC=unGU?.da>[Wmކ6aɰPgZ [{tݾ9dLGIг~ٚ>xY+R+FЙk!?ʾ{yGewO3F.2J{җOh#w^&>;KR 7zp^E****J_`TdN@60Cω>G>LX&; 38~l +Nᯡo| $˯yWWۼ6bl2ImҔm&l6yW/_Q^BDyIh]]-/xhYyKȬE~Si%U 8*WApɚ9$ۦӾ-\pN ?%ZU uV`fS35~zVohq ow"zy2YbSIV~EJԬM@dt-)@ O ?)xlU~eUkU*Ć_aoMw=MyڦLHor S\rrrre_\YM9pȫ9|wFSMSIS~)_Ք.MSZ/ ^&Eݤޤ$#7҃OȲ Qhsz,B^BbD 쁸!/_.Ҹ3QB)mr)sY&|b snQo k^ > x7A 3S0/Eܬsb̲@/ޥot/(`N'aNiji;]<Ü*WY)~oXMqr{'C2 g2 ana b,Pqy^0ϛ\PR8EAv=MS!a>)iF|MYj7xRVY 9 9j)dns:>/K6 YyT^o_!ʸ&ZZB<"b( sj$3 .~dO0}o$1Է=U6~u4f'7?:?tV߶YDŽ Q,Qφoء3,AtxeK=c+?}caQ 5RH>ƝChqQ1 Ajw!1ְޣ  4Duje2׾,j,yu5{[n*1YLd4LI~…A-2>H>NRhܺ1UjؓsLK绤d/iRfXTI+ih,8%&+άtku}|8+Is5v=Z vj_(ImC;!SF{4-}xh)j2J YCͩf-sN>ڜ&t7̶yLۉ#쬯;q_mG>‡۸#&|iZ;&ȿ]NȌl.n.[ո2[ge/t]]ƔC –C. ߺ%LnȂbk#I#+HzK/H/ Iν\.K⮦t /4 oWW\C'f-nW~q ,nN;)Ќӟ]hwkg3㡓 .\S36A\7"KɸO1[1o&\q{yV V\F\L 7>[8X endstream endobj 149 0 obj 22457 endobj 150 0 obj << /Type /FontDescriptor /FontName /BAAAAA+TimesNewRomanPS-BoldMT /Flags 4 /FontBBox [ -558 -306 2032 1025 ] /ItalicAngle 0 /Ascent 891 /Descent -216 /CapHeight 1025 /StemV 80 /FontFile2 148 0 R >> endobj 151 0 obj << /Length 399 /Filter /FlateDecode >> stream x]n0EH;N)O)>Դ@`"59d/Ky0LnuД{ԱUKs jGڨ.ģ<m%}vFqT'\pSw9=_B%'uhm/9TGy*9=8JP=Ro(ʦK[ 8imGɌUcY![i:=&Ljed `Rc7Œ 5[,  Xf$l`1Nd@A5},F>ql00B c1#BAgSM˗ֆ>hc10cq>Sc-?~ cن53ڦE &endstream endobj 152 0 obj << /Type /Font /Subtype /TrueType /BaseFont /BAAAAA+TimesNewRomanPS-BoldMT /FirstChar 0 /LastChar 38 /Widths [ 777 666 277 333 277 443 250 610 443 500 333 443 722 333 556 666 500 500 556 722 556 500 722 722 556 722 389 666 333 777 500 722 556 777 833 943 777 556 556 ] /FontDescriptor 150 0 R /ToUnicode 151 0 R >> endobj 153 0 obj << /Length 154 0 R /Filter /FlateDecode /Length1 24252 >> stream x|k`Tյ9L23yL8'L $D2! Ph2$2d 14VkErO-C#Z>JbŶTjQ[o}$Azc&^{ksNpq tzħ$aز%>vHwuoJ#2MmӋ?`{m]ZCH;.Nn _KeCvIGśzm:뱝齸xl]N߉Ұ}=@݁P71 w}n]l_ 7~'A $Y1ǰ2x2\+ﲱю=VV%k"v$2U R >٠H`a8><k"QR0R2)Dh(R 0H [ h1+!2p ?/n#v?I䯐΢s" Ն DANdX6C\u.9HZ!*a!, Oh$Z\@ޟ' Q-^o5t;k6x AV/@Halu0@&Gr"苈5 OW?O!H)!!/)SABqȃC\qZ"FC.ax^A%LK,d W p'I╈{wQ<^ߕy;؏_.r=l&cc)͢S?NH Bpp Kq;zKkWD},ѿ'e݃ڊ)eQS=/ZG?&({:~ F_¯7 >'$A ж mryɓrD^%ߑ?TiAMh;݊kt>v"=BMM" ;G n8ILEi/{KPşo͐d6 547fL$(~ 7@9E +:AˈֿFZdF6ds_({i%"BG0 Æ'aaJtpTŞK0v!#^hF׌~B vs!^@>?S̠ Hgd=G*NE69ěo G!۰^ˆ&r ^xZ1'b9<,tI/' ~Qxu7NHMQnB0QF/P}$}1zdǸWÓ4xF1yњ; X;!ƇTTch/cxq>FoPҝIS>(3Ât,!N $s=Uʹ9vŬe3N+).*,pOsd;d&gfSS&%'%&ج8ɨȒAp݂Zf5s Ӌ 柎Q9z:1۾0=cĦ΁9jSPTGȺk٨FNpx \ވFVPk5j4[jk^Y3^A3BTg^:pKAG"ΚHrjkkk2 "Ź1y@5_&"UGdgہ{ \?bVgwڈmdk$qݚH%M$Xv aWYs``9|,vmlD8oK_Ϥh/FFl+ڦ|Z|1:9.jFD`EPzg @ZgV2ܛ +klL69(ENֲ1w!Bm !pRh(8FK̑ٷF4[A[Bh9#2aH$ūi"ݧ?}wq+ҺucT4xG6:Us`&ݵ1D7#2FD;]@j0?(yTGG;G0("oݶ|1gԜ%_́JmeZIVBVB^*c@*xf.B:i!/i1iMz 󵤷3O2ɤĆHdBhm>j%iy@Jl@Q\(d6g 鏓 `#PZI8)-!RO2']{[nĆc_[j%'6bn7vH@6l"Y)xX,93ɔt+F_"i:V% yv/^uu?8U ͹jYY}O+Uɫ]8ࠩ]WYN$fL1 Ja'MJr$2`a+Y6%ڈh;qԪm'^NzʋkO(&yʑN6qlrIPܤxRzB Q !RdWlWd!'ř3TQ6GhƔ) r{"1Yږ-fVVNQZko&m٤)iZaq4E5Iv O AUC͢=%EHR@VD3ьgBpL, $a.LE(1)HF| $qIDB>J2'`9EtXIT&ȏhO >F39|7ΛƎIHA7J1B:-ܝ8v*xvQSzA b n)r+)`/ffPf+~[wvHb@yC3sSOK,%^p,Z !-f҅6(,eSV'dȯX{ۧ%1K\̖1''g@5.;G'R JUDŀyii7 zB8.;EX.˫ km[[B<#VFp> d,5IqiIReHf=N!";Rf#B"⽃dQ QK+>vG'5+mV`d³b{H%c!WG;[~>̫v 3`&}`3*Fx+V`my w $ntjh $D+]pHaa< D5=c>Id wd&ϒ׉ ӟ-tž:f h6*1F=s,D6jRx! @on~8yRS c?a5K^y0Gu9k;:3Ivg9$>y9$R QH;: 裸(R#ڜ#J##&evM˔4 & "!ɂ #4ۃn0hg(x6CaݠA0q jYnӒN>1R6[\#<9`IMr 2IHSD;F&oJo*ogYSqo7 杖 GLu5pNiIHxl\%uo˕zci3 r YJK-yP,HrZ\(V=Wƽl2`B25Y^*ADQQ$s\d Sxpql3 #T`Eʣx|m1d  ÍHAxLMR@*} L`*#QYTT#YX= $D8N) 7t=e<4anJP+H*+K@NOp_]L!,"*b3X/|ug7Y|)q=c P#QGsGB,O:8VJ1}h.K.V w qLGɫtpX,3<'b&V:u>>bh۸mٛxKRtX)*6ܯNO tX\1=&j6FŮqЦxR[oVIF:L1$uX鶭:,BmH g{R%H2l $%TjV밉za3LK|'p.Y-P,La ؟n/ar9,a[EPWqXfz߫è F_taFc~2uH'=[Quiao/t~GuAfaofPQY3tu~>ao^&&q:a3gOmaJ^80}Əaϧa<(_yI:rȿ؟asx'#?n;S:8u0p}TOl@aM쩟AE.p6`Pςs8J9CJMq V 0_W uq:q:* 6B *<9Ѕ%c1D]*t"jxIx3VHᄰozӠ%]5VWMCZBXq/bkraG_zW̙iq؎GBRd8A aiyS_Aq|foS&V~s&?ה> s>}? TWUʰu5E|6χTLF,n sil]n6Qz)i"7cJr5hR9 s)D^T١˾%.Dhiy9olf'n;9EM*kѵ0C>|ڼ1u5 q;vӐW翗&r< kq8-mX&.RCgKŏFEf5n'zTsN>;YZ-~}2 RhCLFM_n@߉ָVCJ;8wgXD텍urz4X$٬sc{iLf|MW<̯밝]n#2ޢK[0~Fx4P [:8N7=Lm'?fY/5ɹaZ㣓ƭ7s,klz[OM`L̶[vm[6p1m]x,hZgk֣M!ƣ65K|kF[z+V7]1{$̇4)1܆:y܌VO0ƓoǚaxtDvKu"54q4^4][뛰R x&ReNxbJ2duY%nMؚ:֯&n]6Nq"rLh?24{?&FK-rQz >SD歍j̻tibgXt aݟt{*\9X ֋v1f_=q ],cbΥEo/稛K֯g:Dn]b[l]IZN ` ;8n㮓ӏU4z}\6'桱8@\-Cg5Ѻ;_n>#6u;E|gj.{3ǧghn|kK:~IC<[[xn;eqgQxi1y$R>s9YlϞvRڝ@3`&ޙxe_3{ tLpdτXجr({VY??cc_ykՆv$cZvް?Хvw5ް 3b@G/ p޴BU pH] [|UAc^U]v[bgu-`-TZ4T[o B30WO@䃅lP{PV_7Y }Ԡo?}K #ꪕj7 KemmEUu|}V4F vO5AokG+RK{*`ԃW]jgV¾N[_ yQ(C 7u Z@Чvz}6o >]*Q#ݸA_/ rlC^ҮuRl]>nb Zl#ad|]a[ \ԤM!yÝ8&9bL gA+.E]0j(( f!/f$E[zq!M~kGnH@#jC-Z|&n?7Wt0.ްc!}ѧФ4}=&-[Fp n=C4PM!7Olvz7y/w!i_@No;l 6v#kҊ,!FwN=]\WԩlQK=QfWjo8ׁ>>e鲆EUW5,ZT]6_pQuҕjՂKj6ěM (֘ԘNQAK,.7 yce3[ifmׅMAYbڈڽh̍pf4fu1s|LA_K܆r狩0Qjz74@!W((&3kSx;z¼!U]fc= ۫}-~ :g\E)vqkcs~fhA Xw˖{wنpniFw0n:HKw'*W5%tB\7ǢWO/ė v;|sP{Ooק3P>!nl-qyuN<6A{ fVV!7k̩i Kf갳dڴ3:sLufyYEYE+ku❬Oϟzի?Qf&|=fzIr 8Wc T'<|YygCVpH8׽ ;DŽ >lM5Xލ{7rȹw#ލ{7rȹw#ލ{7rȹw#ލ{7rsFƞ|AGHΎy!֚58O.XDj<}V󏉔k>1{_[{_zUX1ʱ.{g㫱W}\rdH }^U{Z-Z?q>;7h]J9Stsj\%z :T1{a3 uחux] $'z_s!vq /y0U_dG2~qHapRψdhtV .Қ9N|ӷ >8Rk$a l* MXXDTpLq4LvP\~puu"X[™Z4\VӴ)9pWbيE}O7&We qh1s^`yX>b@C1eX=6O[oxVZ_e"8a.mCR ÁT*JR,G"uN, Byz8p K8rXqe ι) i:*LH{dztLIdjzj044w9rJ|4aك ( i9lBWSe܍pN>;E-VU8e(24#|2',,]X`K5 aI (9Ihb7F@ EHMx)uC$P&yD2Lx?w` XP]8n>~o(o2VCy*V-Cy%Xy򪘜\w9d Fp5۱^57hʡjnvTd݈.^A>=5"!?\#t#O9?G;^cuKY/8+v7=;g9Pé[w;.pp쮬r;vnvp4)?߱h 9V2x!V? /w;jpj琣*S p\uq>01GYiEZ?zԱ*o98Bry`P\%ΐA<+ȃɃd%Q)%N1)")BPGG=5%$]E(pbH$ un,w݈]鮋(ZYo` mT#tus$A]<{^;Ba-Z9puo1F 5BʖJ{e܄5g4W>vCx`Xv\AdMȭu+FvMn2 :.rJu}NSjkTV5'S{ /46֡9nvălV!EjQ8ݭ9h*csx"ax{jm^U8N?;a>وa$M 49w2rQH&8!(e(Y:JJG~%_CvP]||j+瑺{X^Slseħͽ/c?$ ƈ9/bv_iw 8ah+!9h2F,E p qVV!y6da0S_~~V~>d\l[Ďb}k5ڏ]/Hp(> C]$e]dukrm\ӈ}E>A}{F5!O=<5x0e`d<=xt{{gs;y>w7s:`VƒOs <=_xX`ɟ_&$؄O#ql 6&Xա endstream endobj 154 0 obj 11552 endobj 155 0 obj << /Type /FontDescriptor /FontName /GAAAAA+Arial-BoldItalicMT /Flags 68 /FontBBox [ -559 -376 1155 1030 ] /ItalicAngle -30 /Ascent 905 /Descent -211 /CapHeight 1030 /StemV 80 /FontFile2 153 0 R >> endobj 156 0 obj << /Length 281 /Filter /FlateDecode >> stream x]n0HCOi$ġ?*PKŶ9$zjJ+ѻ3Fh&'Z$!]bhlDKGC;Ebas9N6_Gd=aP [f@(P~.?"> endobj 158 0 obj << /Length 159 0 R /Filter /FlateDecode /Length1 31676 >> stream xy|8~}ٷLf<$lB 'D0a5A# !{b⊀ n[ImV%A-qikk+oE򶊶%3sD484B5o|4#$nZ"u!$\~wf!djB(-y~lFhN 1 *6G n 1(?9v-R+~eyC@{jx/!IWgooQv 'ؕy>(!du>H˄QhuzdXmqxNHLJSRi龌L0Jbi?J}( 艉 EO6OYɱ 'oq&0rEG_DdG+lCiȁVEt ~ ) ݉>>acT*DpH#=c w%.t7):5jGAUF_E~pL4=hs4fTD߉~|=scB6^~=G( [ ըmF;c؆c'P&)>%x1y7DECQ~K¥CїP#_z=$%rt1 m пߠ?3؂g6gDKRREGO%܋| ?'$R죑"?}6 赠#m]=.^/Qzn3V'%U0j'>]G"wo(y|@D.us?w#o}L_ʯ "Bap@x\xI8--bttƳ#"mpdtWtpa@;8Sp̻ Z_/A|ގ{a$@${$+H d;<u9FN̝ ERmn=ƽɽ͝>NԜ ?ſ%\,a0&%ΊDL| {IfIu_4]8 gւa ; d#3<v_Ph;-8J)*|s m ?827a7~AR`vsx>zAn)<_K6kVPyac-^O#oAs+y#5ا$ q``en}QlG7X)QRq:>FKz2!Z̓ }׆.h P`CkP p-NKÃ#Fѻx w^ ҂Ч؅qS&aS }z4:XA3z }"?w6̽m$ hN@]g3WW \{ 7N ;aE0>GAai6٤S=``N?l^`j+t jf:|DKUqN4]PJFe0A%$Ľ>& fauxD\EQ*]P>wNqQaA̼ܜ _z75EHNJLpx{j1NDFޚ&9k >…y @E`ZESXsqrCTJ S^9FWk|kAbbf ]mUr7Mm;Cz./vza<⬞s &NVU*:0^h -JLIi ua60 %6ACc;ouM9oK0hcXs`ܪ"tn[P}zk"iqrxlYlh>4o&֮a4rcC}Ct%tUմ 9 D3oIJHPFQBse7%\mT%˷ }nK^!5C& Ӂd:jOryBffR5ͦly6Op H$.hiC)}XHx_"έ 5bKDA'p8''MUDZ29c咼M#d"CCu@Ü|`J Bx`Y},uCHi&26 LL7yAb1@|Xg8愱4c+;T֮<k=٦B\"Q!ȱVP&iȔ%́R ,ׄ-M c]J?4ӈF)˦Y[{Nvr0_GjWٹSwN[ ;krΦ:l%]Mޕцr[xX ( % |C:`ֈBpc҅\93K,_//G[£ ŚbMg}V*;1y'7 5JZHHVj[!c^eat ך$-sMdRl]v\`vֹ]90pS-g Tq5FbKMe;Y%Q!~O1v rMϬx/vG`vQ$E)2 i$:h3K(SR2 Y(2u٨T0\ AUhӬ}̙/1h1jyX!$;TD-˂hQSd.pkGICH18 h@asx)ZhD{!0fQ3_4vƗT*W/>e嗏ofl3]4,_y׆+j3@5G ixhXsϦ? 1p)q't`-,?Nj#D?zpWvlI#i%S^P+]]mc׺7~˳$FBJM6QHUāD"'$&%HvܜІ Uʲs17/`q7N՗Y%eJ™ۯ:3 =jOky9|ޞz~h˰>=ޢ$hDltG8^%-BtViFJ$%I2@t:-_i9AFzF#eHXLI HD/F҅ ^bi+hA^qctx?#~F.kަ.^nޯ{;̽^@7#=*8l(Hc%ά xUp#ѣfw,79c9`X *PL 1{6b!~Oއ3j|1R6~Z8ujS`EUTKܬbB6_oy c;_P,; ,!VQ0Z"yȋMJ$ Ɏ&-JCv}սwN] &&ZAܛMQi] IN+*Ӕ4%5dg4VLգd_Q%9d>99#jS[$Y+RD <\ 4/\ 6C3#0ŮQdi3 >pԀ 7$,cHqqVZ'Љ::;]#ݧvɉN0D d_4最؝sZ; $Gw#jf9LP֬Y"h$@լGjȧz-Q^X?v%|֧iUW[3adz[n8ԭyͭIrҲ깑_ي\sWJӂTݯ}֣R̄|D"}hͱay*9a~^8ظm.__dٯCގt9HG:+-!XX[f=2zLb, R!'ez_saRpt@1J5ʠ+MEe<+Sg_N7 ʨr@ΧI{JhD!ڑGf=ҭ#VAyuuiEXNʭzHfgV^@x]x4@9ЁHpe;R].:"Ki5 |Z5ngE9SjPsSvaZzI)an>塸%s^mxb,XؓV=d0:e:w6' n)׸gƷuGti{O[5q(5%MCRHK45-9|-fKٚ|c-_+&4 Hԗ"`ڕ!_S摰W{`nCKbcc79n܃oSM/<4 l%"KkF_˸r@د{Nq$ABFt33 ^3;fZhL2'+xdĿS;eQrp_#V`6LM&br04`  !ASfshf,np1/Ky;EϥaL*ZP\:f cq3۱"K)6-߰>xyN9ktK$ُ,3?x}9~F8߫,|U<*X 6֒Վ׽dWsaD;}o 'F~/ɿ/k~n5;4rCwRny^&%4%v%DS r'VOU2pvbUkCV[#1]4n`(Nۧ|?3N,瞎=$,G^!z >xM?eWOJ}QH KKlB܀·sYxT/O9˼bJA·Huם9^ce>[WWjxm<-m_םXW>6q%`c"qiAZ 3Yy()i~GvB׫ͧ>$@)"F [<$k%kKǍդXOmcF< NnZOA 's'" :d ۻG18S8΀E~m<*fW{JV[nn)4mZ_d\jI*eJ %)%%ޒ4I Vm˘aHMMJiJnJMY7ߐ}=O>5۝qv8WLr83ͱA;d n;ow'\98ՆKWԆ({tlvCbzEc nBs@= k~XKzc[Uc\뮾2kq;Yy]NR{˪ oG;k4Ep}KsƭѴi5~KEZ(ztE @'$R0|0d4&> i1z:=bnLIb<RAfx!r2mY٢I,z2"S nwҕYȁ32\L-|b$84Rom 8 fR2Ng9యilZb?Z<񓫎ǧ!aĝ/[2@o-z7xpir䤼삚I8}oaͷA )qghXvRP2քWBMm.Ӛ 5 R1J$2֢-viym6>Ykf;h;jm GA=!xvZ1qpRg݋b3ˊbKFa' tEန +wJlVwCUɗ3+7qAdQ"ŕA2tzݽd?9` 6 BHzJ]N?qTKOg'a ⛴;;^U_LC1˞783ds邔)T>^^nߊ_x(G6 nz$^z|;^;=.ioO?C{`|bDYIQPw pM&hI'ƑqPUְVPd!b.!p&8ވFE$$zn.ea򭏭wM ._X2(v|ppH?[HuumF)_qY?ep= fa4%Cp@̓0/"oԛD Aq"GxT7*6٘oDr|A|S`09yF>4Ʃu]/ "`{cy?vOd/ ^cΠIGݥ>^r,p2Ӻ BTF*NK U}.bWv_L!IK-cgEz7؋z,IM+C7k $g(M3n{uu=w{Ͽ?{}nn ^_1;~F{O<}o'䞳>L??2?aQH3?ƃw`fx/];^CniUjj[\9=)]=x4WeS_ݩkSgz]1-5[f{ku +AU;;S7HF1Uun#UJ e >Ý 'uУ3ݍ4KS`YЀı}9`Sw[1kuOA×?9ln*"'y?^jʵUo k?|=BjX[s}gQ@}[ɳ5 zWOV5c` s*EUZ;SW}K&8!3d155QVƝ<cNM>1'iJ%6h Ui@<{䥡{ܖ_uUַlVۄwٮ.xG-`xbNciT؝~$Ј}@8 ջ? г4{W[hH=/7#NPq d;Aw| ڦg A>he΅8:2 {ǚ-",MF5Xd<6" gR|ǛpG4$?tHS^ihmե זo\1iplm{VZR/TULZNԸ9"m.jq/modX$]4h++onE_os]=ԏ鉬/FvʾifZ¯-:?Y'\,CϤy5,`b}f@_&|ALf<q p7jvk5C = Njji0wD}EOb1Od%Ps/B3d%<v JIr) i.)Ev(-&/ɻcrR+gL"Jf "R<FpoER=^A@BR%!-@.@a uw@KFۡ\.]o@X\|?i%_{%%pnF,t##'Lo6FYU']q|í .4K_ZVhA=,TV1<-(UO]lJKkW!k\u1* ֨0Eydm*, ZEVa Pa .֢d 8Yh{6VM ŧ4 ]f|ṘU#Ry*̡\|ҡ2XTaTXB,UX,Va- *#E*GqOFqq*l*lB3! )M{UG G,@yDyp`E*##KT.ίTd2XW 0XK*UaDw |0ާ _ |ݿTa* Mد ߄7Tx |e |0WOf`U0*#F=Z~[y4#3E* \`̠ ()*L!(3_Tay d0̓ z{VaY vP v3F N:u d=d:C* z SFu ٔ?FdGRa'E* fr԰uew0FaC >L L./0umA](ZQ5C.CZuH}* ֽL1 j6LX}əhlD8Px >(OXm%Pl|9Ь91_/ -h!A AVFy$CyȨ[ ϥ0v+})]z(io33;a\:.L(f6TcRDY/a-mM{XKi xY$**l&}|끹ȀPu1Q!aT:Xެ`sG:6f`5҈Y5L?j{* M/&$PFg5!yZn {>>#ͪ~  2 ݬ3NSNs{G72z:S*vjbfFI54iS\hL[v!JB ˴t#ub¶Nb:ۀffduN𬅍 2lcKՑNxIv)k`ixج?ĤtF[tMjWigI[1qr4}HX_::C?t9DP?Y͓+le-3]ߤ=I=TMMYXk;H]c6)M¸vɖULl&m0Nc=bD]LڙݜLm|~f2v&NF` R/Zt &񙓘iL 78m%`W߯4Kzx^ꫡfYJdhLzϣkd}l8ڥ|JG5/6% '$[GG8ߟ;z3O*Q,Ȅ3B%óJy)! z; ժZ-~.EŐ(,TM{Ɖopol 4+ۂΎ>ttuBrrU/@ʧ+:7Ӛ^yQh\qC{ԍԫ r/fN_n%C>' ȽT ,c U:לcz6!(uGpsoW (-0žP/혢wtwfu߼yvUag6woo3wm.|& 67Bm,YrQ͢+-]"//^zɊjՋ4ꌺm QSDa}bl1TmtSfmgbj t ۯ{A3 k t(Ι T tO |a Ca"рa-(wbRȓ$&o l L)`:eb&rzޮ`sηW.;Q@KKheʹoLjc=D0͝=zcJUvnڿnc} Qumcʫr܁?N-Z`/^sC]A:oٿЦPps\}k$ 2e&boJtau֭My@jG0NoEX@li\Z8;_PծʂBťr鬒2i)_ۇC=Lf9c# >9g{-55{{;Cϩw {mk^|߽6w {mk^|~m0yBf!r11md5~Bf5zA@y:@ݹML:TjMlj,dMs[TbN+c}::!;y?/gy˦c}yotjkXM--B6U[M7|cLkkoTW"ީߧG [t?t4؋as\RiAu s$:;6Hk F)03Y! @ <1++(8!}o-J;w%\@^B>fȓ!_ǵT͖+x0Rs"ȫLq2*uP̜pPG~S` wVOw%FNBv,CJVkE+ JXJ`_Ǟ 1x\r@.C^=x446*m0wp66a"T2Q$LL  0H]h7}eppiEs',0& kMtf![Cs LE/ph)$v:Rr]kHk9cB \7q"q \2Ff΃09JC&)o9: (#W4?^D>N>@"928"yYw([ C)yF0d0XPN xU6GQe:yBd B~rcӤͅ)5(q8ǁ88ǁ8Pgǁ8P'qG+$G(e$G((3VH @c@;c@;hǘzCaE(Œ" aEQ" aF1@1b(b( S~Hcѐkq+Y,߆>cVtנC,=X~*efc9>!O&`):!tHބ!()QRyT'HADRqxP<" "+Q0-v!g*-)lf6>f۳q\yf  0q\|< 2eϜ!,~>e)9G!]RW+:yJP8a?y4} ?3s[ވoy`C yGJgS;\ x{ӡ~sy:MԀxE!υ#l5-œ)Ec=O9bG*V%[:-.Ks%*͐%ƦhLFhD !/Ρ|i_zC"O<->I7r t qv|\kF[&,x㰭ծS;"EKsjRݥ0jV֏(1^0Q[˱Uag-:ϣI}N#&`rxOc " DjkjhP?wsrZwU5 l4A3@G2E{2bx> Έ| ϧ32<SCCp:pi81@[ucX^S,\IJXGy u֑S(*J$J S8=sǞ 89?9x?PkV!5wmjskZF@0 VzC/e\:^^Ye%X5TV{U 猵crtVN;cUT6Wб*Xt Uz_WHӿaׁ7%4wXQښxG4 a#$ڔWWI`&_&ֹ)V|4pʊ5TUJ2?مCU},g:&=O~{?bp,C% jjui#1h́I>:r0F. BpBrQ A8lg2> endobj 161 0 obj << /Length 402 /Filter /FlateDecode >> stream x]n@$,^R@8Z:}i|sn![w*xsMKN\+E\[ߋ{ ~K^k'=5j=>ڹ(O8|uڞs(\v*,SER\D(>ӾOǽyneSɵ-Jq=-0S>= Yu<_>; *@" tH36H怄4lf[ol #{6($lIg@dOI1'^9Ip(}b;}Rv}kcZ'I􉑦[kG-> nc0T0B> endobj 163 0 obj << /Length 164 0 R /Filter /FlateDecode /Length1 1448 >> stream xKTQǿqz:X/ԁ!0.& k`~8E Qm]ԢEhWAЦM*\F^W'? >}993\vBnYM< v9i/͗foKhҌ'>?9( $ *UTa$]z+c!*9ե3GNz:2_^{74\57l{ݶVᅪk@ӁCQZ?DǬ'x -͚i8 NXZёP8jWX(%ŇV pGxCh}3ިwp{Duz|<3G8W2a}pL͍6_lU]C.ZMUfƥrz[UH܁F5R&Q7C44Gή]8-Yd9'n\f|P`_IVxCo%"\Cϒd7_kd)KfbH2$3N1!qiɌS\a G/iE}9dGo&R߀1diKsG 0FK'XsV+VçbZ2r|9_0Sy}8mcY3=^NMd13Y⹪J}pUn"*>k3,T endstream endobj 164 0 obj 667 endobj 165 0 obj << /Type /FontDescriptor /FontName /EAAAAA+OpenSymbol /Flags 4 /FontBBox [ -179 -313 1082 917 ] /ItalicAngle 0 /Ascent 917 /Descent -313 /CapHeight 917 /StemV 80 /FontFile2 163 0 R >> endobj 166 0 obj << /Length 239 /Filter /FlateDecode >> stream x]j p`"nP dљҴ`&cyJ79rԿD`o#LꀫۂBq66*d"=%,þF\z;9:J{ 1pxnćb^` PaJS*E.^1"Ghk74^* HI4YPV'%C)E> endobj 168 0 obj << /Length 169 0 R /Filter /FlateDecode /Length1 54636 >> stream xԼy|T?|ιΝ}d>L23I&Dr!%HLX,ID "Z7X7\%`@hj.Z&헪TSh3|Ν<'7ss,rg]5#-@ ]ľ@6-[N|vO"ĿwUwpR=w5V̋~m^uÀݯ=jW= cfs/d qw: `u3w#B?z ֏3K_qQxe$c4"F(j2:f$ԎFh?ң MĢ 0!Z sh7z-F$V'lLEȊ PKG,5jF5x.JC{:IjA g&I-SeD% F W%QjZ 녥݀nBѝ@/w! #fa? xU@u[O g]H%Md ,w]1f1X0GYIJle:{\&Ko}5:V99"*:-TFU(= 4(,O%As@vjH¬5ix,Ű̇e!^e37[|(~Y| wC7?0@a%iR7m&Hd-,z"Gɻ 3U2KI66 ؕ-/sʭp/+\bJ_ _/) ~ }["/x_Uב/L/χSyNW |v fuaYqq S,y4ϒL3Qr׬![@6UҏQ!D"{[}p/d`s9tu0  3^?3S qǰ>ԋA~ 1YD 5LtT? F8B,!'< %~6bgvw&QiSA ;Tbsq;bA]MWX:me^r6OF(5 -mз͠/$o?ߊ"pqc鑝TL= wu]ܯQ!Ċ=@@ox5B$ZW|8I܆m>O>og佷t%fN|]Q5]Ru*-F+>KQ-u\́}xw ؎A&rϡoAv6vARТU0nә([CZ^PK|XVր}=s {{T5Nh(sٚL:ULTcH8 Ev9vl2 NQcQrjG Ut;v,Ǝav|aG>M?ΔgJĂ؈Ԡ8)Aq/wL vãr{:hp8վj8{ĩ-Wm3nw@n6_Jj 45{`D,7mj:԰38e#8` O]|⎩S\~gUr7/ .FÆ| j3hLjWзA;whiOB<|afI'}1ϝ2lx&ܱG]+D}VqxoӲ1L-=[;a[,co=;TJqX\atAS:Z:S:&Ws XzxCf |:m^ra\1QpðLtiqy=ھNN W /bXܳ]h~ Aq?8,ߣ #ڤTrp"1\YI o>NU#d8+Pv% i|N -။;"Z:ts#̧GpyO +# WkFS&`M'M53,o:f\nMHgc&L5nswYnm>e8Lv KaT*}.x|.Zn d* ^+Fvt*;Rerrr{QdN#ĜS]B}:~]}M6 D:ӼA.֩uOK㘀XhLtB]} BQ~lf捹h$ EVύ؛Yw?)f+S  ōcW~Ꭾj=+jFir/ոgin-6@>5cJ6M͎c6MM=*N jyj=/ ܪoknqBJխ[5y[DzYkLūra"mUA#㒳!/h۵DGˈr^j#fﶯ3if;1{LHlo@ǓE2*\FYVe+Ã*ƒaV 0?GY,}^)y]B5/ "x|<'6ǞO=;ƠlR^Y?;D04G=%HP:`Z~;șkBT+DDdd6tnN nT̉8Ә܂P4(n M🨬 hwPj8d]X3jɃ\Dxّ:)i4)`u&.Fk5jUP D]ankL̶L-q[j,t(,L#T{Q.t$޻qIm3ZKc|_mʂY^et|es \ՂorbK[&T{|w5:=IiYvĊ|߉Xu]R=1اJ(DH09`XTƦ8NU%Ƶu%0BZ ׌͔**00L*a9Z]A8$`eSBK sOph0E%dm55"T@~?/Wo{.7r+@}]ߒoN-eBg+ƱDccqK;Nqߞx n|2XZɩ`_^]a&Ss7ر8*F{("Tۼh G({SDMأS%]IjZtTmc)lr8C&SyL63,Eh70+=7`y) #+s1Ԃ/QWlyYdG`(#>7RhYf[}Q}Uo:/鮛'u6%j-,b{g41Νx=8^;sHvՑ RPI!`fPユ|{ ꂣݾ5ZZ߃DwGT7_c^3& L&cW/6Z k 4İIq[axCsa{Y՜Me|o*lPhΩzb.3u V0`b4͂:Rqo4PW{#`m4=)ﭝHc1}A`R1[I3fĠ!Te׾Ѩ@@0jMF;%gjk6mcW(B4J ԉמIFu}GfHP@.R_ٮ. TJ9v@6iѸU'W*N eFp\n^y@?}}q@>RI䋙 V3VƂ\U@PP\8jAM4(4f"m`H(r^AR)<6u=x퉉_r8>vv^u #ߛuGk6ۜ~5:t'f[7@5yw}E5+ޟ9_4E%_g2GaYFfИapޖMZ&4^Z!yQK.3#ۙ[c 8dbqY{q[Q)Ĕ1lJŵ ^k}A5Q'"K~2f_O9O˭JCh+K)(O:e8F2<_#V՚he|JϛBZpR+O')*ZNYk]+le< K;#vm_w{3kc5BkQtE!赇qNj/:2SwÒ5fCUeYo8Ό]`CǜG7nByH3Hn{Tp ]JJu̜GnrK+S9¡0_f-_1R*Pl#;[ۅ-Sߐ Β2f,J=|̔m gx-yݭQ+D ͵2MG橖~ͼͱjXS9=P1OD!~gMlX-fݖ͖,5ّ҉fZ'M7jf FKi +^kleeg+*8T X(jxR|Roa6g)zg豞Do6B DR>ɁJܗ M@LB@k-`Ɇ~h@7w<@NLetyx&XJUJVc\)h*oƷ-uyK%oIzU"8 X*SN,glC|V%쏔%[mY~vm8v-d[-b۟1~̿dCG^ i PL)~|3J3WWVPM#n:UƱƦ1c+=n k$l17VXeS<|fd\_ˆ0%nbZcĹc&;8wEGCk"))3k챁@2MYJMo5SyUfsw'Oy(4/!z(ҁE4I[݄4yvw;^hq|z6'H6][S-Z'iQŒ%Î`LI6(, [HCʤT3!1rv30c](NRmqѸGl0`+*p`*! xؘǝ e wTGw뮮ٗnΉeedzdO$yp44`[X_o^R>R骩օ-xj}j Sk7DJ!x[X1`Xb Z=l/; So{A_PSEYu86uE|Ku: t$kgs U05Ӯolu =>B: "SV<:A. &"EY_]}"x FQQt5n%Xe;BЌeZE9}% lAD#q7q妷WO{߳u_ 3(.I\d\'fJq+$4rޫv^ ;rN*cu0%}T|# 2/˛k7w~ևj]#Z f)f';vF_ZPRm9QHї[4Pܰ]n.zW(4m9t'U 0;K;0;ՌJ$1Ri Nȃ!NͫcxO7;U#X${SJoO~~0t:15%ߩڔ܅w]̀e9poڕQQinuAVV#JVV?(~/ƔŒ3mu뒷g?f>tkj/1bNcGp qj;%c9I:~l&S(Ӱ\q^SJWV#ą+y k6i[&Mo?g#L5CaFp:)+{zDIQ wRL?c i% M NZ38X i*t:yWDg-oyg;Q~7Vĕn$ ^7cқhHEv20]Cr{^fݠe9t[ّ}2H4`:#`$I%1&: %u* NRu!*hI/r(W\i 2e0#LS!)5g$N3AL:x΁n |l 6OGAcV-sP2\e_3ob=K.\RSUՃ_|{WάSӖpnډ vʙ~X3\сXz{ZR%g~8͞VcϩU\b3Y9 (v񻔀Tk#8".s'ιzz}?HJ-tju:[ FPLڔDi(KTt x"|XR#}ٓZL&xG.aTH8-i_ c2pE+HVw!8~_t0N/ZLfǎeE:4]9+92Ibmf@&qffM]|3Pš GaT6~"9Yӹ?bc r|c$OnFENF,#T`2  77..z;Óٟ>tnkSJ듳9΢ϤR~Z'Og˜+8zśU]*Ua+*zOR>w .`WɢG)T%T*ʯӓT@~ԕ .˔ef-4\)atBëWe&N]sL&!ڜybZ5ˁ?cXqҢMLOT|:leLMXptfC /Jz)eEmvnO;v-QZ[6F7dٝ}4d={bja|tȰ@[lOBj` '7%4%>~7_<a]X.g,TBX$4NjB=  C JgYӎw1GUkeo=z?ˋ RC{2z=|Ofjծ^э[n4,' 9:KȆ&Q> 1x}2ˤ|^e@ TLT)i0TqC^&jPӤ<"RjoMل>YMS&b $&Zg!y$ { _\"Gks@0 掣WNj3A0*oNHXT8}R:ٽw.PDBaFbH,z#Y&LlRY[ 7~,c>ߏ.QDjq8T|2r9xG˒:6yd#s]ߛ];\[.?:?\gOg]n}>빵kkQI%,`zDZ+PCj  7T+[Ƹv[0'E)H4VfW&haoXR`EW+1D<  8,O;NZ?W]F[9 }[O-'Ky?s3; usBR1&O,&Z5Uc hNFkV/+Θ(dvl"75R:rܝ,uM˥)NNr=@zxiJKb>7_9/q/O籘SOS/P>^9揧$("OIij&^&P7{^I(Z&4GL^'jz2 pX81rc2>렕X?+L*GgͩrwD 9Ih8(B""\4k:P_99'B TQEքU,=4ە LLPl: ^HzNriui6Pw?ZwNMs<WV V͙֛.[]7t5?g/ W4#\⒉ __ qK0[ΪRd@/S$w?NuĢR>Bz&PVCCfŽfʲ~?LĽFLpR ibp~tySR!S">d9h' ,_^"5}Q.A᠅kF~KEKm쫕L@i޷dY,:8au %q;O5r܃jJ`4֗8%ʲ@}Vr dheL?CTW',򽑰cfc_NK,lqbx.'k+xx^w1fˁ"(7J:1Ve}f@K7"۳Ou>>}lW5Yy qVօx'EE؀[Q+ƗFgDW+ȕU ]?xiW.ʻ>QGo5q^6(eBɞWE+3I `K򚁶WHKyBCy6|0x"II#w ,9;JoٲDrzM" *-a?\|g)NVT.E)Sf)RΑj)JFEt~:~* -6{;2nV_`_uz42>[|VgEɃZ9%Uj&[4mR'vd_j $ԓc7R?>v2>w4BN:ksNb{#%9n>$*TT%M;H22(K2~52X5D?Lp7#䯒Z(N|V2h&fG? d7w5 (Oވ*?YG"j4[b_]ժ8ȧ,sYFe/Z? g}y.2H=mq/|l@]O-KNupK;Gl;W3seۢT~}SkRhik&y՗ڶrctv[:ע~I #Jjw^~Qm^R!;{ %˭o%zߥ@5/@͏»۬$Wsv>PdЀXզeF[2~`ZV;]n{HcYt/9х(5ρX I#c?%aH #p 3.@Ou$. O eVe*dSh8H]kZz=^~-{B kj(f6)Ī,7l\ :س1zHt# Dָ?w`4T@=,jCQG~x?ʮb7pUjm0_+PbVdQ;x,cxchhT0 *'=gl6ubó@Mi_.P\)q0t$óE5Q;b2덕GVZFo!2UBJ6"ݑ`ħ/Eu+%jKE@.k󎩲kkMu_G,&낉Xs_y[+kk@fw9;u;Lك;Թ7t%9z%nhϯ]ʏ#> /$[D" Jr-.ZwJYd|.ֹ>>Q΀cGn@A(x !H-Rt 8{Vh0(gcf(H{}]mŚeo\勃zqz q᫧,k⨽|ZBL'OxγJ] 1Beo1i F`ᑝ My#y(D1| sf/;o܎_QgkU*\CAKP몰@aRZT};W&3cu6PF9c2 J|Kqc[⿎|g۝Wzmtm77,7غ|CJ< /~vʍAU@1P/J#[ش%j*fF*bR+B p$< udmz|=w>p]x;*_~*lRȢo;CF=!WX^泪R΄IL1gYݐjȬ]VW*ۍ->@ )}.?hDP(@0"z? |;3Dݹ]PxĠPݑo#~?iPLmNZt!*t(]bހ54Fo@bSiOi#`jӈU7 WY\"HfQ0kG<798,Lpm9,2`[~Pc{=ٲ#Ǡq͸@y쫊YQܑYs{?S޳}Wݪ_{K2`\\?>cVlCKn޼ %m ߹?-zA'*__a1rws0'@D?R",,ƫjj2oss{Vo**'=|D0(#dVl&n׎ScĞU6/Sa!/=FbJw1=E9K?k{ D3qJh4 I<([]c4 9gŤf!CDc+Җ{) d};GnVysg7*j5P!`Qn$Ie_`45][bW8*AU@7]tUA`*L TT +w~|7ڧ|TC\/(؟us>:x 9g^ =9NTko\OVr kQ%7IOzě-]U2 9[Li^3r^dRmRRtv#RWp9!ZJf $GG2uAÆ{GԿQsM*"=/|pD f U 6-Mt=uĨTyjZͪç 71ٍ-6QSpLs([⏈숣CFiƉ*J"UTUd+e Θ%y̛q=vj<G6}! >%aEª ǂk)RGbI\ZrZ=ßwRǒ1g f,G/h[sﭏ?:4oK^ z-Ӵ쌅nYȭ ~mN?Ň^unϟ'{h5w'ߟ607Eh>YlecRxܠ<2۴uYe'(Jq}"di]׫ԱP t.:^G91 mn{8至n(,P̘A/8 x `'%ʎ~)~3Fsj:ǂǏ#s22pQd#xV7yvr}ocփ;V?4q_K8*zo3 zvxz&=tTE=5S۫̀:fOSԤ7?ZWrЕW'BPf= k[djsc[o\wxvJp5֌sc<7_xBe4k;#LNySyf9RJҩ:s3+^Uϱ-N9uv+:>ݣyW$:]B4ZTXƔap.T2Jt& չ(E:UZYCR*%6Wm6c +!5~C}0!-~R\}G&Ņ]|ت-U ouX>0ʀg3oY`. |kCQaհ3F-ߒ= tP殫x#o XgO5? |֒94\ro,s8<.1Ʃy`u*#G@UAU&҂%[c1m[÷Fb ' ^{_~> "Φ (B"EȠ<|DŽ`0pn$JU.,RAAȵajkߛ`،H̷5x,|\ex>"x\f7F("g޽%,yvg;vJ789o9].;E)\VuN2ʹ.O^W_ǑEâ(LsuY$9{ϫ1rqnV ڎ[g ?/;/"3̒Y -e/熪w}$ۙ2ͫ=EO@G|,iYi*!-W145vmsfk{+Y61 waP<&_yjݔ n"7n8Cͷi~oiԦӛl:-eƊJ&#u.de+]ȱxV*''W `3%?@+1 G/~@oy%nH JM%ȦNrp9̇'{Slu,W1`d~HŮ@ॖ+"ÊJ|Ы 6!؍ JJI; x˜мgs `Tt MG M-tMCw-KJx+6XZY+a)ru% eXLVZd6nz_X}N(aթCo;3E4EJ ! cָgA-4yxtA#[Ox#@CI/f._dOHo^_XPγٱ,(-)+)/a`,P\Xn\Gpܨxq}_Zո k>j)Y'K\r5UtߊYX$P"7ԵS'jzeWFnoA&Wٜj|؉`uWpL\K+"U㿆ٿ/E>[!(XoYɥrVjE^IbslqW~=9Z~όJɜ*,x|&{\Sx\:uxzqz)ݵf,%̂YfnK y?V%GX.dK:K3`1r:촀gîǺ9krcg٥3[ 7B_ȳuVz '_Όjߺwqi6U4Of^?_7^m؁q^ ۟C 蘅..k-QBP1PH Uİ}BzQrx}Theog:Ua?JW&Iつx0q418g6`*I_dvh4+bTGŵGUJxVFnzMAmk^#,zš9’HyB²̋I! Qv{TLLO𙲶eHݗ-p+XŞӯ\_ޕ@E-~5&-F5@sB#=g\Oi҄ IМ@6q` T'M (Pӷ z~Lꉛ9S#Ó^rqI| Q8)%c̘P6CxɆJ+2G,Z3))h4ZM5`żE"Ez k^%ˆ{ ]fQBydA)d#+=dCqyacŧߋW\~~vP;!9WY( 4YjJ5mP)+f)p\ⱌYX M[1qD.Qs1#G<;?37IOpO'j֮Z}?^B6 + MJem4lh}7 zR0X2$8b"5ҡV6F``.b3r̪dri5:iu\ӑ"f2WP*YX\hȣú~`'4aJ)+eV˝Mm)VARX|=Ffy߂KQk pܔYK1Ԯ8ODC;r]u\bjM('-% CI !l&o.ϝxh[C|1s<8IƻߔGE|".=wkge>^u؃֯w9dO*-瘼el;++z#z#ȫ;' Y<ż):n)C#:F7ƅK0ƥ'TgbLN!Zގ v7s~'L%;aNtrCY\r" jրܥ*FZ hJmˤJrWLMΉwx'w]gs'3Ǟ;x}CfWS#۞){āޘʼx磹r+b^_ǵc<.5=\^*+<^?$ J 45+.v]Js| } ߠObxi\y驥,/m *73,= C=Z''$lfUbErw`a:A.8~Sc) ~ET'Q%/$WI10%(ȿzG6c}υ;g_ dG>'}37Ⱦ1~J0 rc6zU~̊鱵]<.16/#9/9I c'/NȟS="L_ Y{e}076ZڼIyBIѮܤFn 6]/[#rne j" [Vބw3d"e+u.ǖL]/ 9T(|0v[+ sQaAGBȆm sVn"X,sol!L18{(0ou {lffNvvS2LP0 f*,Z!^;SfiU!-1UȾ,PɄ.dt4-d X4ʴ[3ܗ6z@@+(۬i8B<2.g 7^!\vz*Enq>T7S>ՠrLyF^$ڔlUv1/X"ƌ!]n%3o$XNآ'lbC@W%p |_Cŷ/(Aalcp)Ιs]=EFdyc+WjMa|f_M ГVq9fӛטL1a*ˆ#\c"94כS>s$V]BE <{vt]زj;BC7aa[mnE͝h95_o>16dǽbQ.s|s;iՙ Uڪ&dqQ N׈$ \-O='RxOƇV3¬،,E#*( ub/?|]x]k^BϹL8: V76XcQ}'=;\#ڙv+VVe8`U)8Π4%: aҵ*tŜ=%֟ l۩R(4snIMsm2OT%mI\'{&F5>;?d_ /l^/SbAu@SRh)Ukb\NVg3 օ5MVciI~S%\.Ԭs Ռ(iYT11=b? FP1zL:bר5W6VpAaZCjV[fWCU򲊀5n¦ `ڼ|XH$T[+d2EPTr+*Zk((斕iaP v5-WT#3/M&rqqq~~Z;IY5K$ٴ 188?8T &*b)De$2F5̊IS᫦ѝ",{?5e ,)(j[kUgڊ9-7g~^ n<w6{7Hfj-(ld1ܼ/W`mf9GEj]GL-&F}ʄ9!QMckH _'SaDU.og=w'ߏK?ၕ^TeJ|q]c2e "\rMPX¨PQd(+l a sbD rcb$ݟyo8h#)lg~?v,kc=R]1r y^op}G|~7/o?u:;|% ^Xjg=`vYfc(FU$J[K{h}18oN܋N<N-/S~;Δ~fD`n-oukm9c/Hm;cs<0](~Qbp!<_F8;v,Lsv["n)t8lJD(M91ϑ+> RL8F%՚ّ$:!\s8v!OX0ч89¢fMvS`[ :0z+^^txcvyW y21~ yӧp#vL6B~Q녃3?<i,{ 呛g7g:#fj+f⯇s g[W8/jpYtٞXM8xS{;wzEovp>} S/F}=^h!_Çrι;TbM)|EH=vȳ+r˅<=9u0f66a!Xbe U*sq$ȍed)}nzJٔ6[-ȣphǡ\"!r0sh^HmbMw d/n/[)͙ktk?߮1S7xkW>ں5իpqu/)}NBbRUjyMiyMӢ)Y9 S Aժvct\:[?+~>\U3+f;ç)*m󝕐aP3?R旄fWl~Glqb rýȶO!%c QtA2$d c4 ,ࣘE؈yhUw,Z&QYt IDA|A?;F-Wbӫϯ_}iIx%∗&Rf+ *ªb3!HŮ:Ѡ2,&8rΆśXyR!@͐II03Ȝfd:v_ 3` HV06stf"e=$la>@WB]O6sG*5km vm48@H9 JX0hKd2ip^E8T%XH7iyZ cxL~XXHטW~w&,߯fqa'Ȼ<(s!AE=ϕ_lP0P* EFBaA[^ dO5`(`\X VoӱFϵiN6$06d"=★BcGzM:A7cuθjcmژ +\qܪ';`2D;ѲRd+v|A(VO *Xc Ш9 3S>a¹|Dn57h&jn!',(8ggwf3^:b ٫5^c6g~UrM߇W5یg[.._o~]%lقsBu`Į5og{=9fy7jFm5^FWP`Wz\ MH*7[y@a8}!Ϟ'rɶڬ rCzfI+z Kݹ%]`鑟Fo䑑w~>^XWixZ}-_nHX^d[],aޠu62bֲI&bF^^OkF 6Aꀈ=U>Ɛ\L~\luϒOʉ)Vx']JsYt[؝'Co} ]VҲ[k}foSak+g@6/U,' Q!h.~BߠY%dXn=2GY1nc63 PpɤѶ}^^gV>ҊiLzYNO+2]2̵ W"9ǰ7 ꨊ٬PR"Q\¤3rXXbPX/ɸ1( Pp 4Sԙcx/=PePȶiHrOP'=DZl Sً{Fb+?E͹gSD -A!bӀEXߖJPtŷ+wQ) !_D]5љأ!CίTAVgVVpؠQ eE6O<^‥Zp",R#pqlPELIF(&oL;߹S?%_&I6&CKN[u4v]R9yXkSau'9ʸ ';0νN򝈢dEm-{jco=eToG?)Uj(zTBXUw/74MW0e"aN0'~~N1`Ῠi٭eDZ|/CwWdI~^_/p8%3PY765:OuPMja]y1˹fE[B?I NSI{phAMM$|2$CLY{;%.xƖ)ftm:fLuX7ٸ\K:c%rHspuqoZb&;9O)y$/a%gxɡ`%ٞ*^V\_T|яGԕv)|Uoz$ }5"짗МO/I*{ KE*^X0UV!q"o)˩ѣshE{,tzEz[02ayۃL%r}vނГM||nIsDˆ^Ͳfæ/9'? cӵô(YWΊ D qR!/'."VYEFINJ/gxb򪢆E>oV767-,`, W 5n_"qm^8|.aKr*-~_,jLV޺(_TT^+ʳJCVc2ksui]Ņ۰⛲`\.A PnL3clrʥz益/-LRTYj.9WUyk91"<"͋C[ݛ#K Kkh|ai}ĭ1rn| ݹ Y(V+pP^]SR܃{`4bW==oUM1qVQSBfDA7h!.L#;Ϻo>e4x5ܞo覭 =8R7uo]k~Oyܶڣ}ᧇc.f]W/fdt74>ܵdF|0AdךWƇ_ *ɠ)1j/` ps>3Vht~N)B$Mm.g8%k\9ehWCX<{3*܀_"8 d+c0L1eMY|3bF<OLI K՞@v39Pq:v0Ere|8ʛ!X` W~a G?d>3v#w9GҘ0Y &-9yyr-ݳ*"D+Q#^# sC[c9^BS%.`Ue&>QʨTw.7QPTk&"_Q%9'wsrZsS)o/*Q?A. tCoՈ.sDgDoj4Jݨ.~x\j' n3`aP!{jb/vCP&.8tj %A+J z A~ eF]L #p+ܡP 5P/*!a! ?F/2C>A~>IZ'0IX sqV;i,P2w/ y kAy4R܆\'҉]쿣QPͤ~5oAKPf|zr:݈n&v)G*kV3zcCӵxα܅ ٦:~\*u]㶻* w>`0# onsŚWbw'd%ueeGT+~[YP9Rn>Z3ZOZj-/ؾֽ.?mkl@$2FHe) Y/ =vK0 ^(K ,G>S Vy V C V[%X-[^'4kV :Ӫ%X6n}T! R$Eզf M,CZ,G& V~Ӹ+Q-*`5yH5ڒ'ZTfY':vQ;( ֵeEySb +{5n]%9"F% 6rH0+*F mH0Y?`h#_H|J0CE&)&*4PXCR袰eSFR&R̅(KtSBIQJQA~.F,[ =~4..X)ok{0K@gkԅ֢QQh+B`1PkQ/W5,b L.p!xp1{˔3%G#3a_ *RZ1\ qAiՐ^zчvP7s7 .Hmc5נu4LMIIΣ04KIhL7h6ߞ<lAô=XKR}ZIit[hO'bxŰ3nd/DItuv4~(HtqXh}w !)>Cs/\kRHשt)a@/ŸHs=ESulikθFG?]B9JKOciM%%;$wvi#RZe$SۃԻu3-/[@ҍJ5cnKSK8fvKm∸^zh'[hRYE  lu= C(eXAh]%%chKZ1rSsRm2zI!l 3Yl4㒾7g ;ʋ=iD-WWJX4g?_4 ў?23blZfyRLsǩ9I}uQ>|KDKWΛ`*iяNHEK4H1'"L-fms%cGŴ8МuBL9t;˗}LQ1}6|7dǼِ)+r#$ޙK;QRĿث%M/WYhuxeBKϩ8tV .lʤ~)Hs ;JvgZ?'|z鼘M(bK4_g[2\ovϡ[߶H%JJ30=+0Q#yKV rDdM]P2%S.U*Q("̘_p`rkWw_ۛWR/N R`wo$1~MWR](4trhWgmߎd_ͯNX65͠2o^YJLKcJT:u8rYP5+^Q~PWOrGv>֓JnK'=|? AZ÷u A~ u5'ݽ,6`(mkwtSo7( w 'G C}@{85ķt $ek{PR-I~8ۖ[|`K*# NLR-Pǖ@h ;=5*B{{a~wWI ${b<4KzdK:s?oIvv$@G;5ߓwd:uJR!5Rڶ~G} w@3#=ɡ˱ %iCl'3 %D4 'Nv%IҪ HQERHKlCB eBAvҀIp e: #h$Mb%#]VD4E>=< M5q!4eDlApFꑼ;O*4ox2@{mP&%cJ' 9dK*=M k[}ɴHCI`IړHwS4XO_zkTtٕ#uw҉ڑHwz"=2F<Ɉik4-_Ժo]·4-n\_qEʵ:NML!p/h:,UTEo45Bbvvѡ@$Yú~@6Lv2ֻ0d$ OQ Ii+e\ԶHegA# @PLw!`PKfP1.~WWR1*SF:I#!aLv|<`6cCtN("Ct,P};$JHLc2< Ȗt/ѽHM58ʋd*aҌ(>VB44ɡCRitoj:PrWL(>^}Z2 T$LX06&J"DmK25\C\&_U28M%PϱϳO~zʧ+OV>=X`ӃOV>=X`ӃOV>=X`Ӄ_\1 wW{8KEDiS c[-I}=b{8~E_C!:2}r W=Y1ȧЗo]݅5^TZ/PB閬WYiG~]<ž9X*LQs")Nw77'a.VĢEP9O& KߨWAŰaZ&ñs:pgcAG@$OK~JJ}Bg*>Þ`|ԛJQ} at Ӡ΀:C)!P@qTT+qa`r>D˃uֲv"۩u0`~|<"L~/ح`#w ̻N;%.ṿlz"cT 40蘽9 ;6;isExɆ#)f@=fXIi/MKnSAig@?GA?4u àR`{ȶMV u'٭j:+=4kS !L I&'y nt(^T(({gWJ$=}>nK4`Kl)jS" I3[j!@Y6Uc*֨U jSR>z8[Ƕ,b)#kkj545q)i9L|&,ˏUf͠fL5&4mGn!%@7u8wT'F'*P0 G' p5+ jPdĥ@*zkZíqu@]!.C xžC-Z^jylIkakh1p8K cPNЏz {@AՁJ1ǨS>ZAuAG#G?s? rNPG@$ -BǨ8g{(u'< wnDu:A W P:P؍]<O2OEAV+LfXod@ :(Q@/}\r-u!0L:|ս^t^Aj6E:Bu9EBWW^ݟxu;^ }XR]Ct|՗S=(hQt/Oqh"@ xDmބFEqR1rD@2‹'%`H)_~FLi%&F~Zh PS :䣦rYHEt-מ$G<{MOx~Aׄբ)8_ ϩ)%xT4g<'<NJyS߇ M}/{`|R jۋzZj, Laj!3Ayyn|SR0E48)~Zg*Ea:*|EX+nEҬ4*JRT*JN(27zr#19 3sE+;9l3Ӽf77测ƫSEǕm6`gnh PtkLq\smyT7j^q\_dG]u:BS+h%} 3%yw50x^x).7/]_9f'jlx$F_> AjAM" |xkL} }>1зp -hVdi1U`@bbi6 ZDs@R AW @~bӎ4n`<&,*0Jsey_r 0uOwc߸ߘyzc[xxϯ?7o%fWrdx?}no8n8-$&FWC7_ׁBbHbI^7_x?Lj&y5y5^6WE틯IFm_d5.ciKm@zx y?3z?*y_0N>ӗɉNG|#@Mx~ 40XG 4(1Htz^r@AZJ ;PšA@M-n5ۣdбyS`vm5Eqh֗+S'J@JƖ4j(P|"hh0&r1Ap:EiQ9 .fiXl4IbfKsC endstream endobj 169 0 obj 35241 endobj 170 0 obj << /Type /FontDescriptor /FontName /CAAAAA+TimesNewRomanPSMT /Flags 4 /FontBBox [ -568 -306 2027 1006 ] /ItalicAngle 0 /Ascent 891 /Descent -216 /CapHeight 1006 /StemV 80 /FontFile2 168 0 R >> endobj 171 0 obj << /Length 596 /Filter /FlateDecode >> stream x]͎@H7J%$xR }wb6YGsiz}9kӦS7!W>MSq^:Z1S}iSwuj~mO|tz?di^:^fϯeE@"<%>x*e{iʲY4m2gR.9NY6YdC"P$(DW%Dp/ ay`ؖbGCi!<)W6C%%O`yʱq͒ y (*< / 'qt#[B#(Tt>08 yآ |_|h 9)F'}@@K-[P >ͼ>?7]> ӒÖrZMw=/;endstream endobj 172 0 obj << /Type /Font /Subtype /TrueType /BaseFont /CAAAAA+TimesNewRomanPSMT /FirstChar 0 /LastChar 86 /Widths [ 777 277 250 389 443 277 500 500 556 500 443 443 277 333 277 500 500 389 556 500 500 500 610 666 333 500 277 333 722 777 500 500 277 500 500 250 500 500 610 722 666 722 610 500 500 500 556 500 500 722 500 722 722 443 443 500 666 722 722 333 722 250 500 333 333 889 500 180 563 563 943 722 443 479 479 333 333 277 443 333 722 500 777 200 563 610 563 ] /FontDescriptor 170 0 R /ToUnicode 171 0 R >> endobj 173 0 obj << /Type /Font /Subtype /Type1 /BaseFont /Symbol >> endobj 174 0 obj << /F1 152 0 R /F2 172 0 R /F3 147 0 R /F4 167 0 R /F5 162 0 R /F6 157 0 R /F7 173 0 R >> endobj 175 0 obj << /Im98 98 0 R /Im95 95 0 R /Im92 92 0 R /Im89 89 0 R /Im86 86 0 R /Im81 81 0 R /Im76 76 0 R /Im69 69 0 R /Im66 66 0 R /Im53 53 0 R /Im50 50 0 R /Im47 47 0 R /Im44 44 0 R /Im39 39 0 R /Im38 38 0 R /Im35 35 0 R /Im32 32 0 R /Im29 29 0 R /Im26 26 0 R /Im23 23 0 R /Im20 20 0 R /Im17 17 0 R /Im12 12 0 R /Im9 9 0 R >> endobj 176 0 obj << /Font 174 0 R /XObject 175 0 R /ProcSet [ /PDF /ImageC /ImageI ] >> endobj 103 0 obj << /Type /Pages /Resources 176 0 R /MediaBox [ 0 0 595 842 ] /Kids [ 104 0 R 105 0 R 106 0 R 107 0 R 108 0 R 109 0 R 110 0 R 111 0 R 112 0 R 113 0 R 114 0 R 115 0 R 116 0 R 117 0 R 118 0 R 119 0 R 120 0 R 121 0 R 122 0 R 123 0 R 124 0 R 125 0 R 126 0 R 127 0 R 128 0 R 129 0 R 130 0 R 131 0 R 132 0 R 133 0 R 134 0 R 135 0 R 136 0 R 137 0 R 138 0 R 139 0 R 140 0 R 141 0 R 142 0 R ] /Count 39 >> endobj 177 0 obj << /Type /Catalog /Pages 103 0 R >> endobj 178 0 obj << /Producer /CreationDate (D:20031115111232+01'00') >> endobj xref 0 179 0000000000 65535 f 0000000017 00000 n 0000002825 00000 n 0000002852 00000 n 0000006820 00000 n 0000006847 00000 n 0000008231 00000 n 0000008258 00000 n 0000009362 00000 n 0000009389 00000 n 0000062319 00000 n 0000064122 00000 n 0000064150 00000 n 0000116003 00000 n 0000116202 00000 n 0000116229 00000 n 0000116958 00000 n 0000116985 00000 n 0000159111 00000 n 0000159790 00000 n 0000159817 00000 n 0000198323 00000 n 0000198950 00000 n 0000198977 00000 n 0000237304 00000 n 0000240479 00000 n 0000240507 00000 n 0000258995 00000 n 0000261924 00000 n 0000261952 00000 n 0000286968 00000 n 0000289066 00000 n 0000289094 00000 n 0000301126 00000 n 0000303387 00000 n 0000303415 00000 n 0000316531 00000 n 0000317918 00000 n 0000332859 00000 n 0000317946 00000 n 0000350597 00000 n 0000352323 00000 n 0000352351 00000 n 0000353857 00000 n 0000353885 00000 n 0000391193 00000 n 0000392945 00000 n 0000392973 00000 n 0000413681 00000 n 0000414582 00000 n 0000414609 00000 n 0000448998 00000 n 0000450540 00000 n 0000450568 00000 n 0000515427 00000 n 0000519991 00000 n 0000520019 00000 n 0000523206 00000 n 0000523234 00000 n 0000526412 00000 n 0000526440 00000 n 0000529105 00000 n 0000529133 00000 n 0000531782 00000 n 0000531810 00000 n 0000532138 00000 n 0000532165 00000 n 0000598619 00000 n 0000600571 00000 n 0000600599 00000 n 0000670499 00000 n 0000674254 00000 n 0000674282 00000 n 0000678147 00000 n 0000678175 00000 n 0000679396 00000 n 0000679424 00000 n 0000698243 00000 n 0000701398 00000 n 0000701426 00000 n 0000703848 00000 n 0000703876 00000 n 0000712721 00000 n 0000716971 00000 n 0000716999 00000 n 0000719223 00000 n 0000719251 00000 n 0000748825 00000 n 0000750463 00000 n 0000750491 00000 n 0000783821 00000 n 0000786216 00000 n 0000786244 00000 n 0000792014 00000 n 0000793088 00000 n 0000793115 00000 n 0000802924 00000 n 0000805336 00000 n 0000805364 00000 n 0000877960 00000 n 0000881153 00000 n 0000881182 00000 n 0000882329 00000 n 0001008555 00000 n 0000882358 00000 n 0000882469 00000 n 0000882580 00000 n 0000882691 00000 n 0000882802 00000 n 0000882914 00000 n 0000883026 00000 n 0000883138 00000 n 0000883250 00000 n 0000883362 00000 n 0000883474 00000 n 0000883586 00000 n 0000883698 00000 n 0000883810 00000 n 0000883922 00000 n 0000884034 00000 n 0000884146 00000 n 0000884258 00000 n 0000884370 00000 n 0000884482 00000 n 0000884594 00000 n 0000884706 00000 n 0000884818 00000 n 0000884930 00000 n 0000885042 00000 n 0000885154 00000 n 0000885266 00000 n 0000885378 00000 n 0000885490 00000 n 0000885602 00000 n 0000885714 00000 n 0000885826 00000 n 0000885938 00000 n 0000886050 00000 n 0000886162 00000 n 0000886274 00000 n 0000886386 00000 n 0000886498 00000 n 0000886610 00000 n 0000886723 00000 n 0000912932 00000 n 0000912960 00000 n 0000913222 00000 n 0000913809 00000 n 0000914325 00000 n 0000936892 00000 n 0000936920 00000 n 0000937177 00000 n 0000937660 00000 n 0000938050 00000 n 0000949712 00000 n 0000949740 00000 n 0000949996 00000 n 0000950361 00000 n 0000950621 00000 n 0000968136 00000 n 0000968164 00000 n 0000968411 00000 n 0000968897 00000 n 0000969291 00000 n 0000970067 00000 n 0000970093 00000 n 0000970336 00000 n 0000970659 00000 n 0000970868 00000 n 0001006219 00000 n 0001006247 00000 n 0001006499 00000 n 0001007179 00000 n 0001007792 00000 n 0001007875 00000 n 0001008015 00000 n 0001008449 00000 n 0001009458 00000 n 0001009521 00000 n trailer << /Size 179 /Root 177 0 R /Info 178 0 R >> startxref 1009688 %%EOF jajuk-1.9.6.orig/.settings/0000755000175000017500000000000011720500104015372 5ustar drazzibdrazzibjajuk-1.9.6.orig/.settings/org.eclipse.jdt.core.prefs0000644000175000017500000005644711720500104022374 0ustar drazzibdrazzib#Tue Jul 12 22:14:17 CEST 2011 eclipse.preferences.version=1 instance/org.eclipse.core.net/org.eclipse.core.net.hasMigrated=true org.eclipse.jdt.core.codeComplete.argumentPrefixes= org.eclipse.jdt.core.codeComplete.argumentSuffixes= org.eclipse.jdt.core.codeComplete.fieldPrefixes= org.eclipse.jdt.core.codeComplete.fieldSuffixes= org.eclipse.jdt.core.codeComplete.localPrefixes= org.eclipse.jdt.core.codeComplete.localSuffixes= org.eclipse.jdt.core.codeComplete.staticFieldPrefixes= org.eclipse.jdt.core.codeComplete.staticFieldSuffixes= org.eclipse.jdt.core.codeComplete.staticFinalFieldPrefixes= org.eclipse.jdt.core.codeComplete.staticFinalFieldSuffixes= org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve org.eclipse.jdt.core.compiler.compliance=1.6 org.eclipse.jdt.core.compiler.debug.lineNumber=generate org.eclipse.jdt.core.compiler.debug.localVariable=generate org.eclipse.jdt.core.compiler.debug.sourceFile=generate org.eclipse.jdt.core.compiler.problem.assertIdentifier=error org.eclipse.jdt.core.compiler.problem.enumIdentifier=error org.eclipse.jdt.core.compiler.source=1.6 org.eclipse.jdt.core.formatter.align_type_members_on_columns=false org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=0 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=16 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=16 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=16 org.eclipse.jdt.core.formatter.alignment_for_assignment=0 org.eclipse.jdt.core.formatter.alignment_for_binary_expression=16 org.eclipse.jdt.core.formatter.alignment_for_compact_if=16 org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=80 org.eclipse.jdt.core.formatter.alignment_for_enum_constants=0 org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=16 org.eclipse.jdt.core.formatter.alignment_for_method_declaration=0 org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16 org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=16 org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=16 org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=16 org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=16 org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=16 org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=16 org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=16 org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=16 org.eclipse.jdt.core.formatter.blank_lines_after_imports=1 org.eclipse.jdt.core.formatter.blank_lines_after_package=1 org.eclipse.jdt.core.formatter.blank_lines_before_field=0 org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=0 org.eclipse.jdt.core.formatter.blank_lines_before_imports=1 org.eclipse.jdt.core.formatter.blank_lines_before_member_type=1 org.eclipse.jdt.core.formatter.blank_lines_before_method=1 org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=1 org.eclipse.jdt.core.formatter.blank_lines_before_package=0 org.eclipse.jdt.core.formatter.blank_lines_between_import_groups=1 org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=1 org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=end_of_line org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=end_of_line org.eclipse.jdt.core.formatter.brace_position_for_array_initializer=end_of_line org.eclipse.jdt.core.formatter.brace_position_for_block=end_of_line org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=end_of_line org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=end_of_line org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=end_of_line org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=end_of_line org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=end_of_line org.eclipse.jdt.core.formatter.brace_position_for_switch=end_of_line org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=end_of_line org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=false org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=false org.eclipse.jdt.core.formatter.comment.format_block_comments=false org.eclipse.jdt.core.formatter.comment.format_header=false org.eclipse.jdt.core.formatter.comment.format_html=false org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=false org.eclipse.jdt.core.formatter.comment.format_line_comments=false org.eclipse.jdt.core.formatter.comment.format_source_code=false org.eclipse.jdt.core.formatter.comment.indent_parameter_description=false org.eclipse.jdt.core.formatter.comment.indent_root_tags=false org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=do not insert org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=do not insert org.eclipse.jdt.core.formatter.comment.line_length=100 org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries=true org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries=true org.eclipse.jdt.core.formatter.compact_else_if=true org.eclipse.jdt.core.formatter.continuation_indentation=2 org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=2 org.eclipse.jdt.core.formatter.disabling_tag=@formatter\:off org.eclipse.jdt.core.formatter.enabling_tag=@formatter\:on org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column=true org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true org.eclipse.jdt.core.formatter.indent_empty_lines=false org.eclipse.jdt.core.formatter.indent_statements_compare_to_block=true org.eclipse.jdt.core.formatter.indent_statements_compare_to_body=true org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=false org.eclipse.jdt.core.formatter.indentation.size=4 org.eclipse.jdt.core.formatter.insert_new_line_after_annotation=insert org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable=insert org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_member=insert org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter=do not insert org.eclipse.jdt.core.formatter.insert_new_line_after_label=do not insert org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=do not insert org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=do not insert org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement=do not insert org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=do not insert org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement=do not insert org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration=insert org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration=insert org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block=insert org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant=insert org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration=insert org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body=insert org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration=insert org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=insert org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast=insert org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert=insert org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case=insert org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional=insert org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for=insert org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement=insert org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression=insert org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation=insert org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer=insert org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters=insert org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws=insert org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments=insert org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments=insert org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments=insert org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits=insert org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters=insert org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws=insert org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments=insert org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations=insert org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference=insert org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=insert org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer=insert org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression=do not insert org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference=do not insert org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation=do not insert org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast=do not insert org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch=do not insert org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration=do not insert org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant=do not insert org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for=do not insert org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if=do not insert org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration=do not insert org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation=do not insert org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch=do not insert org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized=do not insert org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while=do not insert org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=insert org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=insert org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not insert org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration=insert org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration=insert org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer=insert org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block=insert org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration=insert org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant=insert org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration=insert org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration=insert org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch=insert org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=insert org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression=do not insert org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference=do not insert org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference=do not insert org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation=do not insert org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration=do not insert org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch=insert org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration=do not insert org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant=do not insert org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for=insert org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if=insert org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration=do not insert org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation=do not insert org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch=insert org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized=insert org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while=insert org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return=insert org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw=insert org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not insert org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression=do not insert org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration=do not insert org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration=do not insert org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert org.eclipse.jdt.core.formatter.join_lines_in_comments=true org.eclipse.jdt.core.formatter.join_wrapped_lines=true org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=false org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=false org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=false org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false org.eclipse.jdt.core.formatter.lineSplit=100 org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=false org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=false org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0 org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=1 org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=true org.eclipse.jdt.core.formatter.tabulation.char=space org.eclipse.jdt.core.formatter.tabulation.size=2 org.eclipse.jdt.core.formatter.use_on_off_tags=false org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=false org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true jajuk-1.9.6.orig/.settings/org.eclipse.ltk.core.refactoring.prefs0000644000175000017500000000020711720500104024666 0ustar drazzibdrazzib#Fri Aug 14 10:12:59 CEST 2009 eclipse.preferences.version=1 org.eclipse.ltk.core.refactoring.enable.project.refactoring.history=false jajuk-1.9.6.orig/.settings/org.eclipse.jdt.ui.prefs0000644000175000017500000001442611720500104022050 0ustar drazzibdrazzib#Fri Aug 13 17:23:14 CEST 2010 eclipse.preferences.version=1 formatter_settings_version=11 instance/org.eclipse.core.net/org.eclipse.core.net.hasMigrated=true org.eclipse.jdt.ui.exception.name=e org.eclipse.jdt.ui.gettersetter.use.is=true org.eclipse.jdt.ui.ignorelowercasenames=true org.eclipse.jdt.ui.importorder=com;java;javax;org; org.eclipse.jdt.ui.javadoc=true org.eclipse.jdt.ui.keywordthis=true org.eclipse.jdt.ui.ondemandthreshold=99 org.eclipse.jdt.ui.overrideannotation=true org.eclipse.jdt.ui.staticondemandthreshold=99 org.eclipse.jdt.ui.text.custom_code_templates= jajuk-1.9.6.orig/.settings/org.eclipse.wst.sse.core.prefs0000644000175000017500000000030611720500104023200 0ustar drazzibdrazzib#Mon Nov 16 00:21:20 CET 2009 eclipse.preferences.version=1 task-tags/enabled=true task-tags/taskPriorities=1,2,1,0 task-tags/taskTags=TODO,FIXME,XXX,DOCUMENT_ME task-tags/use-project-settings=true jajuk-1.9.6.orig/.settings/org.eclipse.core.resources.prefs0000644000175000017500000000206411720500104023607 0ustar drazzibdrazzib#Tue May 04 21:57:34 CEST 2010 eclipse.preferences.version=1 encoding//src/main/java/org/jajuk/i18n/jajuk.properties=UTF-8 encoding//src/main/java/org/jajuk/i18n/jajuk_ca.properties=UTF-8 encoding//src/main/java/org/jajuk/i18n/jajuk_cs.properties=UTF-8 encoding//src/main/java/org/jajuk/i18n/jajuk_de.properties=UTF-8 encoding//src/main/java/org/jajuk/i18n/jajuk_el.properties=UTF-8 encoding//src/main/java/org/jajuk/i18n/jajuk_es.properties=UTF-8 encoding//src/main/java/org/jajuk/i18n/jajuk_fr.properties=UTF-8 encoding//src/main/java/org/jajuk/i18n/jajuk_gl.properties=UTF-8 encoding//src/main/java/org/jajuk/i18n/jajuk_it.properties=UTF-8 encoding//src/main/java/org/jajuk/i18n/jajuk_ko.properties=UTF-8 encoding//src/main/java/org/jajuk/i18n/jajuk_nl.properties=UTF-8 encoding//src/main/java/org/jajuk/i18n/jajuk_pt.properties=UTF-8 encoding//src/main/java/org/jajuk/i18n/jajuk_ru.properties=UTF-8 encoding//src/main/java/org/jajuk/i18n/jajuk_sv.properties=UTF-8 encoding//src/main/java/org/jajuk/i18n/jajuk_zh.properties=UTF-8 encoding/=UTF-8 jajuk-1.9.6.orig/.settings/org.eclipse.core.runtime.prefs0000644000175000017500000000022211720500104023252 0ustar drazzibdrazzib#Thu Dec 13 00:45:30 CET 2007 eclipse.preferences.version=1 instance/org.eclipse.core.net/org.eclipse.core.net.hasMigrated=true line.separator=\n jajuk-1.9.6.orig/.settings/net.sf.jautodoc.prefs0000644000175000017500000000405211720500104021440 0ustar drazzibdrazzib#Sun Nov 15 23:16:31 CET 2009 add_header=true add_todo=false eclipse.preferences.version=1 header_text=/*\n * Jajuk\n * Copyright (C) 2003-${year} The Jajuk Team\n * http\://jajuk.info\n *\n * This program is free software; you can redistribute it and/or\n * modify it under the terms of the GNU General Public License\n * as published by the Free Software Foundation; either version 2\n * of the License, or any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.\n * \\$Revision\\$\n */ package_doc_text=<\!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">\n\n\n\n DOCUMENT_ME\n\n project_specific_settings=true replace_header=true replacements=\n\n\nGets the\nSets the\nAdds the\nEdits the\nRemoves the\nInits the\nParses the\nCreates the\nBuilds the\nChecks if is\nPrints the\nChecks for\n\n\n