trabucco1.2/0000755000175000017500000000000014157420215012134 5ustar salvosalvotrabucco1.2/CHANGELOG0000644000175000017500000000034514157420215013350 0ustar salvosalvo1.2 * Find more icons * Merge with ynew and add support to run ynew from trabucco 1.1 * Find more icons * Show UI to select a different shortcut, if the default one is taken * Able to reload configuration 1.0 * Initial release trabucco1.2/qml.qrc0000644000175000017500000000012714157420215013434 0ustar salvosalvo main.qml trabucco1.2/ynew/0000755000175000017500000000000014157420215013116 5ustar salvosalvotrabucco1.2/ynew/ynew.10000644000175000017500000000116614157420215014166 0ustar salvosalvo.TH "ynew" "1" .SH "NAME" ynew \(em yakuake tab launcher. .SH "SYNOPSIS" .PP \fBynew\fR COMMAND .SH "DESCRIPTION" .PP ynew launches a new tab in yakuake, setting a name for it. .br For example, we can ssh into a server called "alfio" and have the session into a yakuake tab named "alfio". Or we can have "top" running in a tab named "top". .br When calling ynew with a command name that doesn't exist yet, an editor is opened to write the script. For example "exec ssh alfio". .br The successive times a new yakuake tab is created and the command is executed into that tab. .SH "Files" Commands are stored under $HOME/.ynew trabucco1.2/ynew/ynew0000755000175000017500000000133714157420215014032 0ustar salvosalvo#!/bin/bash if [ -z "$1" ]; then echo Usage: $0 scriptname exit 1 fi title=$1 script=~/.ynew/$1 if ! test -e $script then echo command does not exist read -p "add a new command? [Y/n]" a if test -z "$a" then a="y" fi if [ "$a" = "y" ] || [ "$a" = "Y" ] then mkdir -p ~/.ynew echo "#!/bin/sh" > $script chmod u+x $script ED=${EDITOR:-editor} if command -v $ED > /dev/null; then $ED $script else vi $script fi fi exit 0 fi newsession=$(qdbus org.kde.yakuake /yakuake/sessions org.kde.yakuake.addSession) qdbus org.kde.yakuake /yakuake/tabs org.kde.yakuake.setTabTitle $newsession $title qdbus org.kde.yakuake /yakuake/sessions org.kde.yakuake.runCommandInTerminal $newsession "$script ; exit" trabucco1.2/ynew/README.md0000644000175000017500000000075414157420215014403 0ustar salvosalvoynew ==== This is a rather simple script to open a new tab in yakuake, set the name of the tab, run a script, and close the tab when the script terminates. For example, if you want to ssh to a server called `alfio`, you can run `ynew alfio`. An editor will open, and you can type your command, for example `ssh alfio`. After saving the script, running `ynew alfio` again, will open a new tab named *alfio* which will contain the ssh session. Script for bash completion is also provided. trabucco1.2/ynew/autocomplete/0000755000175000017500000000000014157420215015617 5ustar salvosalvotrabucco1.2/ynew/autocomplete/ynew0000644000175000017500000000046414157420215016530 0ustar salvosalvo_ynew_tab_complete () { local cur prev opts COMPREPLY=() cur="${COMP_WORDS[COMP_CWORD]}" words='' if [ -d ~/.ynew ] && [ $COMP_CWORD -le 1 ] ; then words=$(ls ~/.ynew) fi COMPREPLY=( $(compgen -W "${words}" -- ${cur}) ) return 0 } complete -F _ynew_tab_complete ynew trabucco1.2/settings.ui0000644000175000017500000001376714157420215014351 0ustar salvosalvo Settings 0 0 480 302 Dialog 0 Sources <html><head/><body><p>Select the kind of content you want to search.</p></body></html> .desktop files Bookmarks Web shortcuts (KDE) ynew Qt::Vertical 20 459 Shortcut Modifier cmbModifier Key UI Opacity spnOpacity 0.100000000000000 1.000000000000000 0.100000000000000 Duration (ms) spnDuration 15000 100 Qt::Horizontal QDialogButtonBox::Cancel|QDialogButtonBox::Ok tabWidget chkDesktop chkBookmarks chkSearch chkYnew cmbModifier cmbKey spnOpacity spnDuration buttonBox accepted() Settings accept() 260 295 157 274 buttonBox rejected() Settings reject() 328 295 286 274 trabucco1.2/CODE_OF_CONDUCT.md0000644000175000017500000000634214157420215014740 0ustar salvosalvoInternational code of conduct ============================= No USA cultural imperialism allowed ----------------------------------- This project welcomes every contributor from any background. For this reason we can't let the USA and USA influenced politically correct culture dictate conduct for everyone. Diversity is beautiful, let's not ask of people to forgo their culture to contribute. Achieving social justice is important. Being superficial about it only to feel morally superior is not the way to achieve it and is not tolerated here. The code of conduct only pertains this project ---------------------------------------------- This document only applies to the project and the communication channels. It does not apply to anything any contributor might say or do outside of project channels. It only applies to contributors. People whose only contribution is a code of conduct complaint are not contributors. Language -------- Try to be nice and constructive. Harassing and intentionally offending other people is not allowed. Foul language is allowed. People often contribute to this project in their own time and are not paid, for this reason asking contributors to behave "professionally" makes no sense. Hobbies do not require professionality. Jokes are allowed. It can happen to unintentionally offend someone. Do not reiterate the offensive behaviour, provided that the request is reasonable. People who are easily offended by things not intended to be offensive must try to become more tolerant towards other people, other cultures and their ways of expressing themselves. For example, a person might consider offensive the sight of a woman with or without a headscarf. This person needs to try to become more tolerant to other people's culture. It is not allowed to be offended on behalf of others. Please do not presume to know what others are thinking. Examples of allowed language: * This software is retarded * This program runs like shit * This bug is annoying Examples of disallowed language: * You are retarded * You are shitty and so is your program Skill discrimination is absolutely fine --------------------------------------- Unlike other code of conducts, this allows skill discrimination. Everyone is welcome to contribute according to their skill level and more experienced contributors are encouraged to act as mentors. It is nice if they have time and patience to mentor potential contributors, but since time is a limited resource, it is also fine to turn down low quality and low effort contributions with little explaination. New contributors are expected to respond to comments and be willing to improve the quality of their contribution. Conflict resolution ------------------- This code of conduct is inevitably vague. Follow the intention rather than the letter. The final word rests with the project owners or their delegates. Changes to license ------------------ It is not allowed to ask for license change and complain about copyleft. If you disagree with the license, feel free to start your own project from scratch without getting in touch and never look at the source code, to avoid copyright issues. See also -------- * International code of conduct: https://github.com/ltworf/international_code_of_conduct trabucco1.2/extras/0000755000175000017500000000000014157420215013442 5ustar salvosalvotrabucco1.2/extras/trabucco.png0000644000175000017500000060130714157420215015761 0ustar salvosalvoPNG  IHDRx pHYs+ IDATxwe}9 $A;@hծmi]jײLEdJ-.AEJ*VkSYٮ^ tI[ Hsxw_f5" Xׅ9s~;(((((((((((((((((((((((((((((((((( ~EQv/Vr^MsBq^R^[WEQa=R?@G %@*PEyC$l2 Y- ƫpk EQ^@K>\z8G4)Nh EQ^g~CAi?)%i#S"ZPNP(į=@}HBP)$(=(i7 q4[t<5! |=B *PEyZ;6.#vm)b1A-HuWyQ(ky)5 )y19~M*+)% |ǯ-@Q5Wޗ/j⇁wKIq2kSX n)%k\-aD EQ^e%)? ~C>]ט(" t˦0Dfr'hz(JLCjǐ|c\zyu:U +vs}Rʁ.UEQ  ҅ T"@ 1n@%ks;J`F$3 %(duh_UI?L('@Q6l@!N R΅ V ꥧ鷛M#;5Can FȽb`ؾ T( B)x$]ghB`hH~j^&7Jg(/ =ߣI~t4AgQr EQ^!kIdh|)"n7T)BF0ULSY>aZԯ]jf)/pHYA{ع0ֽ/38E(/KVKG#}n1;Y` +fNNT߼"l*f2E0 X6Ņe|qs$P'*P(sӘw  Cg~̙4O3phAa~4Q\:Q FTJi;ax컩6x*PEy>>[H!+|`2 f&Kܵ:C*wۤKd&qkt D6Oqqò.QbG2e2I4$z.f"A~vduR2t:8(̅8n'=|3)qk\t"ЈT 2 EQ y8[6u#H~ ~ܱĻҸ,%;=GTƭW [ tT4%xuQEFteM7};8=!KB(/hsF4dlR!IgoN0qPzΞ!kvq{3x!NLS_H${=fdOs:~?$C!h(c@Qy}_rl R4j@K=pz%|Vip#4]  tl:G7t CDgnerVHx}gk0)C3  : B)-Jv;]N͖O׋N 7A,j@K)H'[]Sgx-Κ7/{X 3Dsy{L!M7s3ׯf.v b(il\5$?@nf!4j[<{.a@F _2K7"(ي4Oߏkƽw.qYՋ{]-Oޠ[-?JS^D.v]y+rYKGl9t~׾46IW OΉmr EyX;2J3I+zCŅag"J]ؿrQ3 rsAxii[$/ 4֯ЭS_7x3 _DB7 |˕73(ģHd>>&2w-NviuZIa~TL{o~Q\XAʈ<<F`g V:IGkkS\X&4|<}qv=5NE"Esq˖Ey*P _=*>$#oC䧵NդLP"]HFvz4ť*^ޤrN$!2\?,MEa=hf-_Ԥxks-Up6iwQTBk{^%]J 84V"ETۼ|{V)/Wimc3L}?aںN0ٞL/seᩯ5]HdSDb o>'E9jYV(okbE2Bo{T삔~^Kkk=N,,csz]INQ{}vλ>~;jz4_iLgmvfDzHE.sg4j@Q7ķ日"R|ym{"K$~cyLNte,~X4B gw}s=ab~Gh-;^ё_D)w-:vבRƅw+= hٻm^!31Ѝ FBn-4Aqv{M)%v]Nף!9| }ǭMR({/kB@xr0tr+M\C s JeWv;񖽙}jW/LBîS_#1sDa'|N+HE~n<^?y!#W/08#v٥A^s_6TH.}{u]|\ Iqt_*is4 AEnz;N0P_&U,ѭYmKqj`{`xpOqmg luEܿ( v(H?A럞(p$  f }ڻ[ؙdXBEdxn:M+n<1sin@ys|NN~zo#)'9)Q+n|s.?/n0n:os ;xQ4ogr|$;8;+v`H˔V1IZ[tvH 6B)@ygJ/3xQ+}!a}Rjk9u|`~KeS%<@,).kqvI*56! ,v~>aWI'tZԯ]**W/Zt pS?'KP*P5>%$Jܳ<Ť:(Bl3M[D7Mۛ;MReF~ieKg@{g^%Y(SXXB! z֐unȓH)ⳃF׾Bߤ(/(R.> ,kt9=a'n#\"[*Nk5n!4Cǡn$% vud[$]ĭ}7v{\ix8ыKA ~j^(<(󙇳wX N*ٖɽct$syWA+hAe6R+}&+W45+SBи~QcTqcOqB|("(cgJ?/(fai^k4{O+t{Htwhlb 2S \HQ\\!]9أy M)%+T㯹!p#44!zHaR@Go0/yoeER(5s%)@Xǯɤ1Wd^-"eFl s~#Y,c6t2S!hl\etH'-͍t u.'4a H 4gLCߓz0ϟn8Q(>RkR#uMcl9A"#!4"٩Yv v&CnY|ץjUl^JkgM7(.`gs5t\mu5-]G')'mzVͻ[0ѯ#/~*D?UEQ^-dH> )ٻfăa'il` Z=ҕ) ƭz Li DA@c*naf>A׋z'dt]5LsEkMoǾ?JE@QV"puM&sQ1 U{wkx]f"AeF"IvrAIJe(.ymװJgHw7imy\{s($4LMP퇧[H|%}o};wY߮a UEy"Ey@Q'͝fz 73atIdZѩ{b0׿O0sim^M 47m6\k>O"zwcD?H]d{.QkvX Kk#SZ~)<(r[||" IuMcL ! 1?}3HN°xnA;0ۢ{i'(,`38wp>j^xj?okatqYzn}rj|˝ Y^k\i'RR7 _nl U#WEyc[C?(47'%,ɰSƳ~ݴ(.,q1S s *W}R2Bnu킔rEԮ\l|!+a50;ZP>o/rIr)Wsx! iAH2avz tX] CBLū_o@QS)yQǁ"D~5 ,FtyFӡ|go\D\eZd)-پ1svv|OŚOwRRGp;=0p]n D6ikId,B0'Hj~~¨@Q~z>]MZ$!2 pvH&2ȈTyӲqvG4$73GnjӡvY(.c:]:nvrf~ICKhѩ{{ xzʝ+3$ur}g. ]`0@F۟fE=<(zԵ#B : f )=8'31MDA~~ '}Dtsi7 3As:nJ"a'mޤpSuñ ! -CҠGϙ|Jg #z׫]vI%8} 88!C?~FW^I*PeaH靚'~I&wNXTlD<-݃=2S$uF,/U`IFutrfo7]NN]m6lq:`bB3<ޅZ{v=Z! O.%GRwό> $CZ! m[xԠ6*P%[{(Wʤ) uuM-M,pTBafnm0(9أzY @l3 :%EJKIEFtBqiN^Ilͣ?}_)wO[, ]jfr&xx:[wV3'a;`qiT(K!x*K-[m&&Sg@2S(dS v(UF{QE~nLert<w.M0tmwY?/e rFk1O,slsZi fgl\…*;\ܮC8&uA&RgMg&{EaOrT(ʋSLGR<3YբOF=b[lb")_3%I*0z^p/b&Ӹ>4)-.Okhm#M&z.lSf  O9[-K%gtG/cH)ѐ$lp.scAJ!sEfiaKS(/ڬĻ IDATCR4~ ~ !X, <6B";1۬c3fiooT@Jt&Sn,(# enuZ;7h|.Y8t" сrb`N!B_IBܨ!nwHuXw3N| BH_Wŀ+N< fX|T l;*ń@;(d22 [f鷚> ?U`X6@Z*mưLu/b^As=zcڢ7mid,A2PI+Yd|4f~( F;û~7T)#dFG419*f0#M7Q"CUT( =2 ~MBdh#2S 6F&G"zC'fFLR\X!<:OnjBhn\Cl5>g (5S;JpQsk;:>KysS yR _}*O?{w&|ۥwJ IwGFH !qBB\٤Fr+0']ߥ{87):;AH$(-Jil=Jgm,vK]-j ތ4!+8u]$%wr:RDH{ s,OmF-}eq1 p]}l-)4RW E"&Na`3êx]';9CP$X,`xa'H>tҕ x.>If).E!W⮀΀Ku#{M /\BdQ~q9e)Z)SP.Qɟ>]D``PgHX,Q{~*-ftBOk x*@`Nfƕs2Nj@=T(o2@^ HookżB_3 ӤDAa'跛!eƹ,NKH)).F+pjTaM-.@zx }f__;_(xDY,im# DABB=N )%NBm}Gq!`qyRyj ݺP_mT(o_xd*'fA<-7ۙ,4DhnXBݼѻD68R vx֟SZZL47;\m8a0!>'ͯڻKdV<P%w!o%+$b ôHKQb N( d8.{݀Nt!lHGTN-R( MW--R>?eꇹb!.ćDf"IghV+t4~G`mF Bvr)#.Tw=zOJ}IwLZr ^2_ȃ7tSYK9S)1S)"G C0NV eْqDhZEq5.D2n<:߾RDdi'f ]f[u]g)Z(! CtM 8|A @> U @}T(oL(ݣ1$"HJb6k` RhF{gn<u&/ tv@}Sd&VpwNyҥ aPvnݎǕ~Kn~Wzy8[4QC>:6޺|Zry#40!2Dnk .]NcQΧO=7?G`e4*\c0_Ҿ(  fݥ\*GqRRlɤ(覅4_Xfr8lG,R(TKEys>)N?/0k+=GvD(#]>:տe!gjbF,eN }d$1 ,f `0 ;@RJ^`韘i-ESJyD)+W4z.~nY e#T)BB'M q-+A!஻%Jگ=g$2<,$<왠( Mq`薧9yPO\8u?&Q/\R> o v&o i~eBϣzYLy F"Iՠuwcs4N˶vɈn'E*NgHAX4z(D3-~`w-ў7ѿeQ #=.#R96R)5A/tX-ZѬVhŅ2hRz unXTQ7?0)-.MY[ǰVIJH)i^SXR 8Èv5RJ,39m yK+r°hzܐ(>~4 ;a : i6lyr : j$q7C!Fu팸À}d0<\8x}GC:{ɒ,&'Ɲi/sdDi V*My4֯9N^n`*)-]v*!31a'546 Tg)&4L]rx@O>w ϧ]EK ! ( v4J?}Vvga K!_ [`>gū 2 wÔ0@Jz=3b#Ey@Q^!>#|ύ쭒Ld*s_l sd&4opt:ݴHJGgoH$.bgs47XŅl( ]ynvZ?5ן8<"r)#-)H&b6sR)d9öBױs9 St$h6[l rs>BӤ$F&mǥǁ]l ]Ĺ}%!;R!JVKϥHG M (0, Чh' 侌-$k|e)<ǖ^g. 7Z)(Qq[N8>ѾEJSFf?{P #~u{ 1/Z( (kڃ$d]39WH7sRetڞԯ_F->O2SV7=UdgT&}[8 5id PѰu˥ht;A ;mtJg 70ll9BoBǾ|}7 Ƥn ?!A] (<@uTn(kȇA#KO#xh,ݰL!w64 Tip8E0[$ry2QspVϥ؟4F{1wo%-1XJjlZiN 0I`0L En㗃@o\t+^n:q?. !%.ޠǠ㹌ՠ T(OTUwN;Jzw禩4L];UISA^Ot`RcJƅ:DGt|iʠ(*^w5oxC|͑u/$aXX'(  pu^K.Ӣ\xeyzx9=zo;Z(uk`Cєx&J D:e.Zʹ0)T]iWhXd1[qð Y({?>^KbmZH?J)iƾ}6 JB\:㙤,Ỳ?,y#-& A!u&3xuX>8>Eӱ3Ydோ$Hf㸭&V*Co3"O~VL|1ICtX>F"CQ5@&ЩUt;Ew;Rt"?c]tX_MMې:* 5n3_b`{5==G+̇̍ M ^0V E!+VNw7昍x#[w;(FxvD8ET͊\.R/Qmu9R6"HL {rqRB[3,n7QTDxB\aˮNK_#_|'N\(W_-\3VRX?kOqWeӪP~ 7@|y/ciYSןVE}a2#JiWKݨ?32Frp T][1b19jJΆ/Jr+0Ux!N2E;]:2ec&mӭw#)-F,#g|+s߫}jhU n/Fll6.)~NĀ=.?=Gg`&jyyp0S_e?@,iY>{n}ūo =J*q RC#ؙZ+K(Nzx3A7LK ԋ4Ε]*s9%Rr낚_\uFrq ;2T@3,ng}:jq TuʕQ?\H9-?ӸqUbYUX n,Wtn IDATr.K "fc^ࡢHJ"'oD"6R=z<=.3'asB[' A޾(odq[ML4ϐGgO;]t;Jnj5&Uos CZ/V7ڤөH]PnNj覉jvdMM?r)g\o9JmPcK$ Z+j5Iع3+g9_\s]AG_p\S\9= =G2> }BX+4g HɍQHSϹnǰR ^C!/-[1R,F"IuvvxW+g-M0/$1dV[nn{-'j J%.u/(U-\sQ?zE~gm*p7JL2$Opx!`|WMq9=z\fWoRM<lYg,C9#';X6Ose S J 29$2RLV>\;Jg-]ZU骿D/DшPxA$;OaYﭮ-n@lL$~=Q×n(' 'QOefֺV3bIv؟չ}亂24pVg4B#K.sME||z=?_ާV )MX+xC].$H!\ ݷJK[W8f<ӨuhEzxfrudon  aF.'K.Mg\RqJ+ &C8X4Oa;]v 00S]hv(kT,6sg}/_:%1k?o0SjG tb,ak .?6#i[[ *"I_wB,z@OwbJ} n'p0ߎۇ*-Qn'5Rr]/͓X>汒)tqX>Ftc|k= =W8g1ۄGF>ez e^R_lz~Ǔs/y@yYi CNjܹ⺼ bJچ<]wl6h7ya}:_9aGi qavû/V$9SKIqMqszx|_~OJ ؛ `_vm!ן&;: CN?FZaXltn>73;<5ARˆIf5ks)}NԝsY[% 7doVg|0endU]w]v #Dմ(m8.iw}VLV]>nI=}p_+=S_J0k SbS%++Lt nődC<)4hJkS]:Ђ|}Cr˳'?ޣXe=v^x700]vR8R0Hs}1q Tg[(2y$v@OzdnBe< TxNBe$KhJ'皾H3Zr G-l=ʹ7ݐoviLB*!d,ddOM'ys2A9_ ci^pxnfk8nOk\$y=z@G^^*˸1TXZc4cV+FoN$FmKn٘Ͳuks3tt;bo,t(ԝqCa,k1cYEE \'7M43 h!㴚T-f*\lAY({ \#9 7>W!G}1Ǹ a^f<`aHn#6:i?P|Z&f3T|ζ隧$J|(Q@[9=~X˛>-NJeިH} o^ V+iKY7I{EcvgUT(x(F,R,V"ᴚTgh5L\CH cY|EM#p]h(~ݢZk0[uds Ͽթ>[9Ͼ2Yof9fc˹5d v 0=nYTө1)xxSJԊK`t`]UQ=Phuz@JT붩UjB9JXϼS}n7nOk_>[k>m m~h&n;,NFJbAO}kH"@4No|S'yѭcVl ]'{K?=}w߽'ܠxNrNq-K r/}o$_>9/*oHnBLP>a&SY6s4WP39P B}dFi,Ϡ*V:LѮ)ON:L=f;/Җxbl i8aF|BQ0q4FJI:Q;a4*ufkQ?U4[p7~ ]ǮsӠI6#c$cFRnjä݁o554&H)K[ :]L2P!ms7wTRtT*si;J:g]n"4/dm>яo}k9u= >|gf4BpmVJ?rcnr#)m}PTRCFhWJTf& \g%T$+k&#7~E(ONXF,A<߇jTf\Ybsf՟4,FBwv!Dd34 E+NZ+[~4_;^k=n)ꛌ&U9I.sX\=|;ށ<d?9 q[l6XtXi Bb?MO* .Ї~k+ sz\D q6C8vhrƙ*Z?~+m#}1C VddܾC 2}v-BQ4BQy3Q!`2LIvN[{ij޾8{R %^7J(ӨG9XZkram)U<9Cȏu*ă\F~ygs:o!A6q񃌏[L-Ĺe<>r E/0ݿ벧 S9vf|SNKFKwu<Ke|[ 18LTR)[3 dcxfEL wj.aHg$ů| :贚-VYxH=+ޛMH)>6WYK5yH4=5ljc"]H!$t8:BQ-;һ\KL.[ *TaߡA,[m7qud}0j]N>3 &BlJ*s9 :mnUՈ'  $4B6gnR+ &t֪X,R2qLYCE| y./Taiߓh.}݊a8:b&X GCzi6X\*qؐgK[N]x*߾򚒂U/ Iix/w}7è1w|+c#}?" 6KKZuxٮ#€̞$ 4-̠j:Lxx" &\LP#{U | Fcx`&iEc{]EQ趚,-8ԒeS ߯}_:[^ z!2L9.!7388n N'yb'&u;ر'm{&B3X4'ayiA"]DŠQ^oUuW:tGDZ%v82&D="=5Ɏ,BgKMV L$NzN$H%KSH{4pCn\IC6LO4X4v*Kr`E)?CmqيѪ?S96htة euZxf*p;m9ؒgʎWj;_t>~hDO 7 7|3 ?^Bf(gѤ o:Jcgz!?S$ByV߯aiL=JRGŧ/ ׳\:?XuXEowhˈ^E`|3 {\ujz\\j 2ۓc0e!=s#\F5M4mNN-2WuvX;O"'Q0Cqrť * dl%𽨆@QiWJF"ժtUV*Mfjņ/}RʏNr-Ѐ_~4oロG^X__9YG'9~dcCj:^tyqW ǿ]zQX\ZGp|~/IʼnZ_җ'sp~qM97ck/ ',,TZ(J*DnA{(i3O[F:dtq:s穯,1Sqyl%f8H[Hbētk|׉FfhI8*\TB׭u jw5{W,[n{Uz[ C.C/fd0vSYuﻙKߊqRJsgXZkE\]&zT;y ѣ/P,wF4Cu9`^49GqM_ɛH:Z%KujM7HEQU$Jq<.$Ncz~jO'F3` $F,jw;X v*nDNb3-9QڵnOA{lǁ}jqs~;o}[y_N__߆ coy7?GTaರTaȏRx;-Z(= P|`X1j2AA|t:7́X^^\.2(0^Md& &4r{J Bpbbj$Z`u^"dtj[7XJ։bvm5YL#wdiqSŖ(J'~voڹ[^._A&ᮻMoz/~r ~9P{y$a)Tku(m؃7lh~Zߣ^.A3>6±0W\8OMoDz,fffL<(@( =5vu-PI8Go8B,Rk^ )VZL.Q t]]ZS>x>SgqUv+&?fD~)֫W8Ylqr ހgʕwWkXv$׼⦛n"Ln !B&$f5mWP 1 /9tp*>Inzo) IDATTŘɱcxOdfffhH+4'@rw )#x*{.r8{w(W/wsICX\!b1Vƙ"zrQ놦 PຜLD3u!SXbשu6y?v{p9Հ Vi򗿜{cǎaQn~c!As7>tnoTnXqѲgC3 ԧTKԚoydn311A AqMsz\3|ܨ~z `B#jrUFFODGF6/?4T[..&BTlCB@#$}8~mEr6+n5}?Os*:| üo; ]֣_{8BdvWLr/z F~tsnw!fn@m~0DTXZ nynr^UUy{jb (ѫ 9=zN܉W ?R?"n0a Wa ,vuiI؋Y'NJjmo(SUPT5n8wߥlX\kNA ߩ˿>~ \*o~n ###s=>|EQ59?+Ծ9l-dYtw$7msvQ43;D{1j*p!G8?]ĩIՌ=k!HRr-ə3gvP"U3l{h2lZAIAe1Nj!;Ή5UXZ[ y K[]*&tV#)Ԫ j> _poݟ|-&[.6-oaϞ R |d|HM/(AQq7 o9.׼A@\X,200@_(ů|HHep.{LQ}^hqFGG?Zm#6~(Ox6Ez\o!#PL^/n&4@!UPHLh.1ItAivA .e*vC?XmRi Y!K%(8[z7|P'?8OizDS6p뭷rw^$k{)%b/)H8J2^Al-t??@j5)˄aHƶm㸥9s("@>˕6J{ z2( ###:tzh.85Cz\}Wܞ\"[1YLS@WE) $Q u~xEQ邂;Dme vBzn2Tm9JMe,w'D|!nl\( ŵK @E axRjIi;*dmW~KZ($ ~~+ x-=z]nl6~~w  Tu&gQ$/> ݵƕ}*v mΝ;G0CcH&- |ʃ_4Mu{;~z\Qz@g+?a(? )-CӦ­ LMim'%V/踒pWYZ'!cxg`'`Ӫ_W`oFyYKA( V*7bƷԒm$*3 )~l'۶I"e瘄j!6-}ـ=*£щgNq*H|n6X={hw'̟$hCSTY(X)mxw3以BlfttEygq(ky0s2snl,^Rޗ&%P!B,NeKKKO1F\BϿ2ť(?|z~ 멋mFu( _v  }=^7IE|)*Z i3RL8AKE* yPmt(d 撬ZW<ڵG4$ːEU K3k#:iB۷N[)qcPnTh胇 αR]) !(BX3x#_8t\#3͝䷾K,#aYeaS~.i򶷽 ۶g?Sb"^*WCzOI =q Up(sӠERQTD GoJY>83dBf Ԛmfؖ 1M, έ+D!b=*.o+ͺIq2FA naT*EPضo.XF4MKMsyms}j=(B?###A').W_jҗ1QmաA5T*=i?c?ƛ NCz\z7 "8rKZARP@lc3YSxݧVdBN&fџI )ZT] Oͅ|4["+%%R, ng럑DQ! l R)2'oNg $6l<;޿ǰAn)Jt:1 㪉@ ,..;)[w'&ga*T*bdK*4 4yHX$ =(UI*;JT} O댯WU2c@JV&N*mBR Naj m0<C+b3OrnjC#huJOT7+ϯ̀ĝ{ i۸9%v5}"m9f; P(H$X\\Rlzr X2|q |,Z/gxxxveY 333?~m @er^ eĝh+P ܃[ځG, tU`& ]T=J!}189[ B!Tŕi0R!4b{-V~m)U')[X^yT4yR5/ C:333LMMl67loIe1>>ѣGҒ'8~@tU|+cy,C.ff o;.{\6z@˅;7Ĵ_7,;?-5ʽVwl j- c#83ylxc2vw7cK!~ 6yf&@2f1VW_+u+@% ZV(u[(-ti{+x&qZQ OX5kͷػ75 `ucG g@`*gq|8 )%Pt:yKXDAeZ$Z4~F60=BPJ|D@ܵ50n]0"t=AvO!%aR\8tvo\^*Bx\׶\g:B&$="OXJ.ӎ;HM>^4s^X]yp)mvq*Y0EP`g/0,鋾9CbFJ%oİg/a։[Mf'a~kğ Ǿf(K4bL |"1qd|ݱ %ӿ%%]ؤɛg,"2q1.=_[} O^xZ1կ`7Sh9f@o{y0, 2y|7_8Clҹ$@w8<o LOO{yY읟uzTr~jL 9!!8F3lf8w1.eƟʤy/L*0$Bʿ8jz) iM4B4ɅshjY> VҬ1PNp{{c# lJf&Y}鳮M9N`t >#ǀv挛:j,+w) 0(drE7s<['P(f>8o84C!%ϒPu(Jtt{wh深O4"RT| <'c`Q >\Ii/fjp6idwa ZQV$J!)l#u`2E #<1jQ/F8@A@(yY^ȃ73epw\a244iS)U* uJv_aiϽ/$E -14D`s?Gm*mS*~'J' c`,p*Jj)fGϐ_F +(OL&rW_Y&0a"ŝ wnҨWtptrFVFHh 5N0x`Zɠ {h4#XڠGQ2%qu*" 5ri~~LMMusU RABI׳as{tLÒ-PV^"o<&gpb1VeֻcyP^1 s)37Ñ.oT"{u7[7ABI RI.Mqk# <1Y)}eʹ;z 4&wH,$-W]z۱gDAzdc17LDE ܗ"MDtbgH-*۾4A(ƌDhV.O/4IpHz =$J~J_@6x-;~wֿ^G;6N~h7?m;e #M`<hP,Wzzڳ0%}"20 n=}懌N )w߉t.+ğC M 7?v`"Er,V8J\$s:baxz n!Fba*.z Hh*M 'HӬVz(l\6ih8t]TuP8<qx6|<4g DXC4BIRKЭBE]ʹL̀㠙xM,V$c)W1Scf;~x*V@FzL2:yq{U&/a&ШS*[ur=8` ,~c<8S=.g]X ["D96՛6>9^jXD0\CuQ ;0zq|U! | E:~Fv QEB3L& CY!?PO }1Kr!e0ҐNlz"0߾N_&4@hr bqx+V*rrjJ#ÆkWl|TKCU Ftk' ^J bW??m=ew\CJ4jBH H ^c^{FA&!ϳ@(t^`M, tZJdaǟx[BUJu[(RS|JE/+!~V0ɰ2ӤΡPdWo}?O[D7b Z*;W_ը:C8=Ilz= v^fk/7\TPbh+tKQtlD7Fy0w>)ճ)xOͽ(P&?BcG ͤe ~u\HL54 25Cbv0 dWWskH 29n1]E#Oa#IHsb.Z# D@d+T?Bs Z#AH{@@{ 8pu$`  0}U^7 O^WɹNբ\S,UAHD 60a^v?Jş庉i L-߾A6W  rZ3Q,-?bc CKd oj,)`!s6ab3%|@< ʵk(ۇD'e+\E3LSg"1B4BHrkm-7 ­뷕b'UQV.o+uxtkKʁ{I*Jqʔ[+7\vèb{3TݠRRֺ ȉhZ{ 4!К\D!aD&R@}oBtxX&GLQpVxa,&D y2BJj- `ʫUV$J0 doߠT(p3N?1aC4RTOe_%m9nZ9N7c.Pt*>x(lllp˾@h VZ%ݨU(Kԛ6ӿW^U*.FUZ0H3@P&fh+5EёL&Rz]>S]s#wQ eNEnͭw|8h4cBw(l9p`"r7(lo_qeA-u Fح؃Z߼b?&1*:q}=r\7=-[vxõo*̹sz_ @5k`7%T%&fة䨔m0Þa^$8rW&; x`hiX*9ʥ&K׶Tؕzz(^Ƹo#Sn >ϸYf_%6H5t 6@lfM7ߺ>Oj:H Wijv? R/ܾA1VZޟ/l B槠&Siԏ}P6 ^Azd 5tJtq=͛233sȼ:-TLLM3372` ^׌z/@jZQqd B%=9"WVsruVZ~8?I0? V_K ICXqm[s( ]@3M@6;%S8"z*R~LE4mjev2⇿L^Wn<eBvn{NP_rB|>ϕ+WCV&T/Oe#^^~1JM"2 Qִ,A@H +yZ~Hפo^~=<|}΁8O^}T"Wp AO.9jZ`0xd/vB)"rv68jf0QVjfgh4 31R\D@6pB@3}s[uXPƸo aN|?&ɀnf#5Z1Ov~M#"B,*7h5D&1e(r4Y+4=-zA;ou &Q?ßʾ̽JI!3^oo =6ߑsS כpx@vpRJos^`r?G(>-D&R٠ըKA94M;, p1#X8a$#?I;# Ss3SK"1]yoCg"QnPXƊD1#QPBas[_5FV=bJ)J8?UifXv˷m,^?"<lmaa^VjTc7T5vQ{ouG\Ɏ% "T9K5v({?,,,2W+'cs-w4e3^פ',Deb3s [oDgN͠&J׿@lv3%O"ujvu4X/4bH^[uO}'spEv_*,h [Op !X^^yo8=릮)5CQ (x-J N`SFC Dj )"ŮqpN@`P2M#٬g(O¨Tc|51V<Ͻ' v*K,&tc. %$b#58CJpP"V$J_Cio`Og磺'!dy $"xVBxlj RMBo7jfy:ֿ׽fƟ$Pql@pN vB\=r^򕯰5mt*cN"  &ӑi\JD-fZ$NAI%!s!uAdbY4ä'sg!1apM)gvܺAX~BHv^o_5Fݩ?Up\{m(tpq޿<\+apő':׫j܅q7ì#^fo34BrpUmfm0 chG|3~(7扯ʹmك&8281tI8=Ir,F0l[Cq{ 2vލ+T9B4f0ni5d﬐`F?oiX@Rm: ed@y71sv~w7d6 :U9a-^by|ϘrJVIm+$AjQr8ԀeYz#z*!MKlUjJƆ/eY :W^[v` [>gJƥA0An_A5%zZ_HI(9Aj,iQ]ɅeP#BHJvϭWgǢ&UAWڕ7?µ}V !G2~=0Xc 850;;;ePl 4Mܞ2GOvqRJ n87J)ЂBf;p'&%vD\:R~~oO Wޓ|i!hf & cn?pNi_&:}diB4F0npZ-27Qd3ߐdPRm*=9PV߽uG ]C5g#&r0*VJRAjB!JŖ[(fsh =aBR` HcZr<.ke*9=%5cVs2cdžU?TJ))L"v]4+YrSϡ[J{;dn8{# E@*}o]Ppc[% ?[7U'"˿{^\]c=ʘV#O6`y;6J945ዯAbe0/@R` a E_m@Za*bj&^S)@GÏqcccӌ'cqd]鯕EoB 4?uv]*u7nY$旉LЪعBشGhI ~W4| 肘%)5^~ݗq`e+WhSz 6]П ?%a-jQwo?Wݟ\|IP;`pa@zh4d7~U Xk<MC Ej ERD9-qmBw>}LEܺ.1gL n]4J{cI&])l[0uMR3s\k+R(~UZTx@ `XgʪE8Ue6??bnn7v|~%x(*F0QBvմQ2avv BϽw,RqU Dl;_ CLa?~;'c> N eOL54M!1o]Eqgsկ&Ebӳ5_fJlvpri)[Mwmnq#4 52/^~B zn6y{t(:C_"Zu6#x2ց/ſ8t"OK\98R.ӬW9xm۞yz p]X4fffR^N@yiw[/@*"H7<1V?I2{D_7뿐2 3"1D8=E?{& @0$x#C~f8A|-2gqS-]\.G0$`Fu _/h4ujڡzBRPC$@qRb Ւv;Ѿh]6C?þ-^5t 1VFǾ0Af.s>i4\ S BWi'bqRK"1 n'yi44En^#ӎ!SS}RUOx1O7AHG{7$p0Aoy.tiO nHķjJH4M7)K)Z|z>`e* 奔= WņR qmW d2pag=DѸ_ضb(+Z /IRJZ97 p.?&Q A=`8aSp1e24KΣ[׿ޮwdk:Eb3s4kU^{Y'}"Xprmop;Sg%,$C"ŋÏ 6A?o;|wv8GJ9T'v*ׁ_.( *1x!8%V bF&\m%9Qv,cbbx_5Mf-بTV Yi: D"CSҗ7cc+ |]鹀(F%]LTlpcOM"͐]I4XMJ;[X( 뎮 ddok{٦p9]}mP^(z|їw5[v6 %:u)=x졓XRC52@Znr$ur $ C?? _q(;w-_\Z115?Wq#իWY]]\=.c@\~2ߤ)3 7V7Era]$J~k5s43s-vlXX"HݑAfc;*rM>zPwbW |V SOf>}/s莚اlK#xty&O=ԡy=z/#Un!dw>DF0 RhKn8T*ۨ\zI_, L?yPm3aXGBgX@-IPW c}*#?\b>ugXhS?.l{=|> /w~w-P ˴ZM_}_!a`fo+u] ]=9/@sGߏ^oP>(A9S[E^z%//1Na^7 Xq7% |PjV̳wVW)no&>jk8{+W/puox"a;LWDžg}S,Yyh,&w ܪ0.r:ˡV_e9oR| _ L}xU8r%4ڤ5ح#GKذp}WTyb2H0t/^/@NJg>5'Jo]?% RBwce7/N{[ԋV#&p+NeύGARFhz;7smNΣ/9F+jU8lәMN/P.;9pyFC!:BM8N@e;VOp5/b>vZZ,zh];\1zF? 8# 0 N:[LX>Ba8KAܾ}W 9'BHOOO ?B t"3$ڝZoS\iׄ{n s.ݨjFq{UVcaC2$_c sPxiO.pOڠݙD0#!x7dgE`q\bf /g}ֳ嬒QUV1Ms;l=vIdYN2$N ZJ:Zq>PzqԽ8YxKdֲ~Jw@RB|z @j|s_'sp|4I/_$HRڠF|vHIXtmlfxmAdXa+_?PYmkϟXAA,  K !R!_>|~x7r"iC?ܩj|f4jT% 08aނ8;;;C\LNN211FATIX__ _!#bR#?,P^߾d@ri$n,e4[P\Z/p/(zH]g橯 iV+8z H~6{k׹k$b{?uǾa"*P<]tSv@;Aa%R:oNӲ~:G[O?GYQJ_=(aüack)Z?W7lla?Thgj6)Tʝቬ?<^C62h(* C0uĐ0Xpc Ɠ!ߺNTgC$D7֨fL: a-_2Yg}~CB< iذUeo^~уv>-)ǶU }q=$@z"JM~9^-b1P Kjw{R#hn?eZ -WiJ)>O"o}]%@AjVJPЪu'GM,~H)J%] B$hNxr"F vZ=VHI(5Ib~ `ɋc:v4 ;쮭ss̝|Ӣ@p3s5AQUR]|2Sį a|;g_xv/_~k~0 %l7? w3O522#`H*hWڡm[u}ZQ v+VQl; X hRg~GK7 R.~V!>V!~M.ph27邙LQ:pT "86 Oa7w. јHBnt$(jb SXXsvb]q +<4$oR6P/e@SїmcmNν7 /ߎS]B*k0v%<=WgmK Cߒ/x.zDHoc@8,x 333(MǶݍЇ<W/}Vu;~۩؏i{jx>cGvC)ũS8qvv= \S Y,}ȯ#ڦиm8F&֏>9j!;2Nq cK_ J1vۋ0)^1IZs,_ēȝk$ j*ϟډX1/[%?ѧ ~]%6}:+ 0u,2LT`ҡ:}ァנ>yv|#(IMv{t;mn'(z4ݯdw^?| lwmJ+7_ptq&P֣jfɇ>|xlq%kpD~d+1 3\g,@Y~B)֟JQ9Jќl"3< Bf# NdnΓ+]o1M T_ g+Z}kCT;co&Mȕ)i蘦u/+w mO6{.(ް;+:1r4gիSI *mk!y /_w~^Y9Y|S|#qwB:64:s,}[}l{9vm~;avUܬv-/'9{v:M$ %N2i=3Q/tn*0Ȏƈ'PA4o.PDc~b϶<}=gmRi^00 +,_.mA)BT/n( ·O<u]wGcZA/ .3Υ ˽s;rul>l ؏@Enotժ$ ESdGh,ҫWTi.iv=~Կ3f`2uPcg?YFx gbzZ }ӯ&ov;u~N2Cߺ3u @zPMEx+D7pz#kJ/7"\ohp`2S01 nKWtD#$2y V)L$3< JѫW1ID`.T9S~֯ uz^R ._y{^Ed4ᧀmbBTݣŧtMFyxQ"{h lPQe }ne^Ju̍MҚ[[aTwNde8ҡ* Fma?s~˫|:/( -u|ɗ9u$x-BImw[oV{P)=NDD`vvv!yy~iTfp*; _FN-5DɍMRYKk-Ҙs>M#32Ni0va&RL2x$}<͹K,^,$4⺰ ; C4g@gyzo:_4 m3#1X5OwȍO+GV ƮWFl(Ҳ˥ρpZtVTH'gOZ[Yb;bJsfSkn("dV;SF?P\D-dh5f j S!*"no`oI l~~{Rɓo$4@Xw]xx`;VQzuA@А&d210u!R>xD"؝Oc;vCgqӤ#GVL$QaǸPlͥͬ?C.c!M{P@=]=?wݛ7wh4n74NLFƧvAy] T/X'~5t`4m`(EVjIdG'ȍNZ[0G j!.Tz7h@bzBX wr' h9!JA" *x& 77~1v:W .#/86Mprab_r#w= \ }wb(~Uz[(%uM1 4}ucCXɍNuY~f<0HyKgyrbXPN: taW]D}I]w%'cZMzal|SpP,ɠ vrIX&71MftT+;|U1 ܲm}@eBDZNȩeT`(e^lɍMSYW[a8(Ũ\X46ai ߌR;>qkuU,*$cEE|<'z~J O۫/܋`5h ²^U?Tȡn "R1R9s|3~| #y>'mURC[t8\13X*CaRuܫ]SyoӫUuR2ٱ #Gˆ14$8_ivs])92xszǮȭlW/m7t e6x'hzQ\ IDATvA׹ݺ0 D~_Dz"{fP(9w1j'm|NL?$7pM' 6R' 2q 4Q^^~aS_'?1En|bH bXQ# ϟ} C*-{5?vm]3y.2O]6z 1PV@!17Mh%:eݤ_ڠԿv\NbD'Q(4\vCY* V+$sǧi-ѩ,3bxLXq\;TB)oӕ3^R]'b1.=ߞ#u0DFoԹ{ 1 K;u}o>N^/6ɓ|sn'4׫ _٘F*(&ُ;K5j;9Kq:-JN~Y^$ɂp\qblcPHhgJ~B7)3q{%~Ugt "22H!"Ԭ7P(A+`%E*~O.;xn(ku{v*@dHݯ0${Dɣ(҈:RR@U̵"HF' Q)"͑$]W][]9FL86KkeJ~VDc- [ z嫒mt;mB i(>7RyFa^v7MsR!a?} ˊ?u3g ܍Wܘ?/pMKX4sMųt+K31Is[ SIʄO{yx:7Y>$./tTчȘS:7\sMnF/*ĺRt{[[A`|?dp )I1N\gGIR3ERCX{U;n;D[7Lcq> m?*=)`QsIP*D\vпvWt; *@!xG5bߺ|5^/)ƷN;sHGc[dVZ5m ys I,?eAdDq0aP9{u(dg[t*u,F<_\sU諾@*ay gY?|WzA}|m BQ̬*(~wj~yCiJ<ۼ?.uf#=4Lef):@rc?IPc@]EQkvmt.U6d^ .gqSd:opy,?"A݅iED.5O/Q?g׳EԷd3>ګ>7wSœĆ2qɉmV7cgQ:RxX*Md YǷ,V3gx|Mo8>k1_q?PJ!AKw|9:y$ez+C4OD"H c0QL/yLح&#U()r! p:*]HJC Ok#PJXc F<$ry%TbㄾO<ڢVW %l^Ѳy0j_B<EmO]ln_<xM$bz?m(%+_lGn%ӘDBqщ{u #H\<3BJރ? i1=phmd Moլ|k|O - 2.Ln)Le54G<"7>O* }wҥaҥ2cD`(ePNE55%BN /HD.r@>D&aXL,&YYF!zl  ٫]%D Y'^ it3QZ~ ~U@Sk "QgDVH PӦICV-ҥ!hA`Hj#iBS:9<>hk>z8yĜuM^Uɤrs sM_f fdw2[?n0t|qX^^{^4&&&b۞cy6S"!Ga[=.UhN\j?PxG\t&7~VJ锷(5Ӥ4sӘCo&Щ,Z]C8e=_bcY Q?qu=qֱ$t٘/GҐ(Q%n294#N*p:mz 38s#ij{ \fϱɎ.C$ՖS:ca!"7(>?osӲR'f2M<pJAwTI 1I蓞`tq5b4d 1utJR#(9/ex}B;L6#!U*S:h#B:N :My#29{WN,<. x?rY77?fɩS0 ] u[^"RVr70 JSSSR*Bצ"X.K =)yGö%o5O^wkl qg)br҅Ti ј=%;<شg+s<6۶s߮P)C#ꃳ5&`/s(#|l'IQXDK$b$F'@)3묶* A\QAɍ #bӇ1qoBŢ#]n58{ p_]^90|'?h?wInڴb'GYn rU4 ]F뢛14}?48)ds !nn`&S{0g-4H ah8AE rN"&*hѵzaMY%.ӊMF4=3N&Du U."B㇓9) =zߗe6 DRٳqu}W#qv=^hn4T*0d2{َP<Ν;__WIBeP|n ? \$ԓ[kJ`ēpZMr$s<ۢ[Y&KgXx8_sgu/?ǯr;>RwGPc"m88=dZm&͓ v^*(2F';MN=_sCka^Bfxq:mZsitF8^,@I5p whk ٤m?jQyBmJ#p]KUaʇҫ`5ꄁ4b;rˋf""PF(*8+—@}=m_qL Fd ng}z"E4sZ!~oqWxHޕ}?3n՟姺Wtw*JrE^q4ڷ>aH!R,Iӻv\-8jSN/~'xvHJЊz&*,7o5OB%6 㓌r+nS|^^$\rcU?qMjUK)pH?PK-=xkRD⇀bCxxI09wjֱu1Ct*K爥3'qeD-|Ǧ1{qn{VFkqa7&|ϣ0Nu6UۼRW3V(MPf/R^ߩG͌f.Kx:1qCt+tkך045&r mKMoCC*) QXJgq )7K-{G:t c)^?ҥ+(?KDJ{<yyToAu344)?\mA1]nM}8u&"0P y SM32 EN kYhF'ejWA0QL# $(AȁHRK#@Pk) 3F๘PRc(mD DFVdÉ_XHQ'qzٳgi6LMM%L4'O?0?8O?4j5l^3"" C|nu9ypph߽pmG³-ZKk9ޕyӜlpPAQ ҵ\g/x38?|J%3 Q %A6D:1G^%rcC(6qHJejM#34.i4(Eބdlu<a5hA*{!Lne 4@TT(j@&I9ѿ\cf" CQ$rBߋȏETDzh0MC A:D@0BDxL!AAOVУbar;~vEF9m4 7]Qc?~$<~~Ug]WL+  JuÐ9.\@*"ϯxF|7㾛oKKK|Z~@]nUc?p}{7?\ޛ/eMӸЮ:d& \'\dy/"$Ԣ"TC^{&$~V> DJ;/YAhlrb>4tMֈ@ɍM%=<"pF ώ XfhuVtikЍf2 /%Dw]bJg06K`膁=^nuu I:}"{dF xަ&:K ^%!8p$d!7ߨH2D5Y\a4{%d8%314n8&" *e|[PҼk2vvh < 6׎؈Vɓ'|2322ocuWh6/^|FcXF$y-iyT_hw5OJ7. 0TGGH \<=×:QM=ԅ0CH}{Rt/hGq.L R:֦zI:^dg~|Wd"72R >ҭi4iGc GFNeX2Mqo=FnHenQaH,~ \$*Ѧz9 IDATMsO`ז=F"iB4M#I\ Db-BG3p*u<9% 'JPJQ8y$T*8M5uӧO?p*q>CISA>p͋*! ?*<;N8[oL &Qz@ԯӊRGȎ^Zjms S3xE{yM7ɏO;F YBwj^^ ;:NQ =?H6l >ⲅ郸nDBDȎNz.VApKt+X:PD&i-E},ljEfxT9jtZk]`^P1,Q!qʇoi7i/ͣ-%ɬ\'`e Eԯ}9V3|:Q+m7nKKot::x[5b<Er\Ri4M%/iCQJd]/`2 |^qIIqkuAݓ^(okMPݛ/*Gdq9n&7@T:MA'T|f sgibC~0w@$`tML ұ^jIfȍO\%i̵֘<. A"JykLd LbDj԰u"IS4/ѭUz].F"IvxحEX4ZC4X* Jp--Q&ۼП|@Ae?4g/dG(j55 7: K (DV Q9Lnܥ0KZ2M<Bߧ0gKta,k0Y\jx4Py/Rw r"|g39XGʳz.Ñqn 9r{.|ZކAEELmX9郯)z:ҹ}cO8S:𽛁 APTT*޷27Mã|rf[t=F X28[]( z'pFpk9WD^gJ)%\%{ߕ.o,5SxܒRݓ+|?YM_tcHTuvq]8:Y^`P;E%76EntBOB {m#"bTC!-/!kb2_#"01 D4Zut+M~r3}"SJi,G, Wz$€d@V! =k\߱%SApk|+_ak|դ[[!ʐLUKg sY ']Z &Y(6449bR' G@.(ԗ\2(*f[>m'$KC}5 Gm|&|篿0aIXu R9 J׏2F`=x> |q㇓o@UoB3BOY?]ro󎴙qx|4i2X\vA_㿻S_ GSoGuWEHL֡C Q:]vtty0 \g*|ǎ*9VTȧ<a@ZKkt\uEyP.< aꑼ`)*r. 3!ej ?g=# "yT)|A周iTS,w}}"ӣ* [ F3$?15r]Zgt #o$ hǎFH.U=,W "3"hF-wdCiR2ˡm,8T0cS|Á d #(a CPJ0bQFhG?p,V6uۜ~LO\7'N||[@ <#O)Ki`d\"K  P$uY-f$S,ϣi9,N8_U_:zտ/ڵ1D]{#dDz p1'b:^&= Zu 9Ua{>QP'Egs7@ CSIL<`8a"Q fh նh;EX`#p]DBT,rBrTUp;-U1aD:BI|ar`׽3>7Zmm`cj>Pyەwi6~bEOr{1LCo-RX ⃀@߳&h{meyT5F o`ZF0ˣJ#! \yU>M/zU?Bw}",o}ggwmi0ex R*AY-> J,JMOZg[,h6lT6UZD !b͑ªdivp6mZ[,ħc=Q22Q$,BiZi˔/x3fPFqDmO(:[/e'3^DG׺/boܶW}o?˗`?.}kCGb9>ÜPoo⌶HK&lCP9i9Zj[s`Q)l[DeGU%}kQ3ϟ5{yќwKoylg øzc(q8<.Wwa}z|7~<>O>v]S1ec~)T].UUbZۤ:|G1zT$1tB׷u\]-)b"Ⱥ_Gkj .#9J\,l1wt`e5<OR&[7 LziqV @5&:{Xz0FQ8lNȶ!u6@z.])TEN-H lJ8# z},HbL=*Kn?$P ea:i'G5:~tL6? Q$ ۫2PhhYZIR-#]}WJ= rWJ'GNӌ߾gbZ9щm^AG̏n#qu 6Cèų|f] J2IKl^E/|# XZ3 eT~G&oZiX_=(]>4gvsf= efN?`0-.4}Ӗu1f޷S7?G?=~%[퍀vۦ( Nτ,S'_ˏur/ouc6MNs=nueHϦ̏nS$ abn3"嗫.˕MkaqEyMtGJ4MS&OoȦ(Wi hJifY$.cuQ詁85#`g1ou]a=Ӷ= @)Lۡ* ,]2JBhКyThk5m|ekgx6I Hhol-ٔt1#$#LLϦXK0XO-V˦ӥ?i/{|`eL%>5`Cc)0@(P.*fY#f"7GwSf]s5 aqyq|8|[ݳ}s/ߏ}] p qB]joGsnl>#WCյѠ_̝ <֛6h@:=42n,rɏ?÷eǎ?KtW2kvFﱍ1kQ0 enO~(+ =e GQI֔F3Nē n E6;c~xs5Zf{>^Oǔiڴ )_j\UZB_0=^"khquW>@+`mӶh9sFAx_n:>.TQh *r1tB3,N%0/,%klF4DxAG˹ECvβ 4t=k#,i|բ~pg)uӌ8>D)h F}I,tv4e F:(&_ x.ea9`mXq  O̾x ?t_6GTUPpz\]6ɣ~R,ZGsZ z`K]Nx=Q`yCqխȰ]"$;IV01Zkќ,5 ธ$Jr DYJ_{W5Bo7G0ގ[@:PB)z܊e˹1NFtwuzI蠩Lq6bFG5Zu ivy4_5[Km:èKlS.׼ ߨlYt\қsQJvF +BTweRFQL'`\z b;.48~aY_2`7i;wJ@6O@sB'-#0MklC)zjBNpPkaWD #Ŝd:4(2fxИb.n\ L ܂|CѧZ`R+H44,7B$OIJa2[B[ݭ+ݾ0( zղp-8o?]'+nZOkR^"5lcvpУ @bR=rٻ粃}#x7.ìgൻ9az/ܕ(ɹӣ'hV +ss~ uWz/t}~O;^%c&Q\%O~苫zؓؿ ݷF1/5T/1є >%J- XK=.oo@:byEF(<5]`+S<^P)`H{cl> IDATp)HҜYvUM%7yF`֬@@lQ&"J+L-D͙"g?y.Z]E!"̂d:!P庂8=;}`]6y(0&JAZ5@@l6}% *%`+Z^o!@@յ2gluUAυ³MҲ4Mw\ n=b&'4/i ׉0;x`"#ŒPnwe wl|.4/]Aل*ITgR_%W77\}SU2R~C_'ci!N;k =e Q>9p (%T Yji-kwLǥeզ#LJW q[E:?#_ rɣNhNK#gIf !C%ltL^6ku*"ˀd90W\u]MnyLW3w2'a p]|J) Fd3 VSeILK|z{:i/K2'cXŜt6i #+dL-}'lkIآHc) ;律f8 Xѯ4@@A>r0@)S!@:,sFB&j&{ʱ BQԗț~YV>aӪx ` ݾ/:](l1JP$1ey5.yQ{6mKWZ2q}Vl$&ΧZE1 v#q(cogpW%{_66<$}NJ?~+~-"֏ý5xѫyC,m}l題/[t1BޜnsZ3_f_4Eclϣe?2GTx>^K:;%9;]Q.{( IIL{0d>j;K ZUDy6 twj9 -j[t]f3, "HB$)ԥN˾0MP_Xy\.$yZhR*ErA3d#r#jm)ą`^rq:߾G#,gp:n@'&2њ}s'DŽ!ZCt@ ZXb7cx2!vt],D#P ,8+oBŜ!eӿr ӌ@G; Zy ߦ A;YV@8Z pۗpNx.ViL65 eU(:=$*{~!t53 Qf$ 8^9 9~N{g[Iir Ի;R/kսǞĶ[^Xd}];t3S<3K?T?OG7>CĽ׶aЦoWtimPTymlma\񕨶(Q UoKĸ(ҳ)Ӳm_%QɑNk67iw3ݥse[_(҄xr[d5Lcye _A͈/eSQҥ4eu!^-] RJ;愬_p/5 2 &kI E%5z<+L<<{?[̈ǘMw*~ yF$1Y4'll NC{ckeE)b#c'hmҒt4cYYvij@K'4nئE&z[@do G(@G@SA.`̡(8zCwG@#V^6(ӅnLSZ DDF^lu4`B"v)Ҙ> ;nBBjY)<צeZFHb4qmi|)(+-*vFT&n-Geig?lkjW}O=vVO80}JRf?ӟ>}]w?~l+˂9i\E ydC]'Xޘ)E6UEYCRr Q*%BX"K8.Y4%-f YjOOthx3jl-:`0":90 Zݾ?PUh6@ :lgNW3/>zuGV?%j~U$$l#׊zW}˒ pE,pg?QW|(՟??{çb?,[wq~.# hoP$olqS [b|D.bhNҳ)pDgkCH\`-jQSkR^ޥ4p :g߼,Aw*B)]`mwb-%[aY1B! ѧ~'^aw<n?,"Zqm 7xYx.嫯yF{}Sԕ ehZyUye _o=|qJ4Ev3W[~q|Z(K 8ZuVl`q|t`!* $&eÝ]_JN3^֮&R<6ZPR=ރGwX 7]{x+=&X5#Z NZ"j_/J/`ō^1uUޥ=D24s:!N=ۻiBtrHgYژ )Ew `Z6^ҳ&*p7#9 Mˋ3m¿T0]6jA4!uUnKT0NU89h@[/\XJn(nkbLÀZ;i@Iwÿ!Jf5P)ˤk=?f"€OXY6gStxrNyg=^k+k}wqLLC v] l㚢}yo>DZC˛ FtCU>,Wjѣ>JNTEFk@u![OhP2g޲ !T'"`#tDqe"b*gYmr,ħcholWNx|L֘‚;WzuN9^ƕ+!*)!LɣAD8ZuEgZjRf, }}aYz4!tbE2>B-Po%U~@K!B| Q )ZQqH99S% m@k3 L> jZkagsƴ. V{%A&yB:;#7(dAS !Y1ЬXC4UEIO)]}:M0QU5/,V@7kwܤ.OĚHp[mꪤ*pْCoqVPfKz.^  yZE87#*.uZ-DLv( 1L((*/䔈(dםdח,[@~Ϳ$7ZѦ( nޚ1{'?cO~vd[EGd,{l 66ڍ~:}i(P tEp UٲRҳ J):;禝R}*w,!^1K@ebRpEtu<@므@trDD ,HO ƕ]$grvJ(+ rytwz+vcʂT F @%,Dy}i j :A 4=%6 i(ӄűU5gU 詁obȅP7"F-E)K5\qQ3WIŰ,ML} XGNEP lҀqZ֣t1C ӊ+Y]z(:8ҩY`%W-05RRl7#4Kk{ȁ{Il]$kضEY[>,QJɝ#oo|7țNl[Th Y4'lBVyx2JpHO'U`9>KmD@u]@< A{} ' 4Pi7xխ)d'}mEP6k 4zlxYCq7ȺE8X%ŧ'$SlOGz]xzY P@\*F|Ogg$S=ƥ 􃵺 lX &7@ZI=Z.4l1 R +O?GgA} I(.0HJd~~EYa;ҌQin#YᢸP*(n|u~ᵢEo? |+A ovz)HЧ.aq]7هz1cG ܼUY|G'Gގ V9pq>UĠep4Ձ7e -n=C?4`H{} 4cݵ˲fqvb6#=aMO[[7LgS ˦帔Me4@?E7 颤B8C!mLJѢfAɂh0ħZSnkS_]WM"]>[L-)Ulà}ۿT / IDAT:L%!*Z Ĵ:&''TE@ќO>?e<.hkȓQ`svl'~`0s# Ӣs;./5*7&yCtuP/A9f΁~Nt]@)*T{Rg3,m9;holk6,Z "!>E ;@L-"Ik3 M۔sƨ!% D>YpԌ㊬:O\1^{oiez(U̢@D''2N4WJ2u`.1Up]#$ƴl|p^bz,Ct spvAv\hO~.+q}<  }7666.X__穧GA)1fY@gm>MhǮ"G ~mE]\[fOV|۔|jy\)g֐s*u.8KTj<9R!(Q_'(ҔdAc>"4S)⅓["amkqoWR5EL8~@w RJ=%$E}J ,DƢ鲄G(mC*0>=f{m?BraSӠ{M'"e#-\~e;dǯt-&gzq|W9rEyE.v(kv'l8:h4uT]1ylϧu(R30<0."{ =ȳ"l58yO3NXj=:;en|NdaZEiv ߓ&61 [/P Fz\%2qL()W㒄\5PȯtD[d oqB.Sp1OOû=%{$"*~'yC]XO?G}?GtCh}&т"+jX1}ŢV+_psv Գ^|k|m|)34t:>aE z)m<<䓼momo{o| |73ްfo/g{yWD늴 猧eՇ?gI?w#`7}4K` Zza BIRsk^`u#P= ӤHb GIB{mp0jt>@0`6-.'$ǔݭmT(tuB^-ץifN&*KDB ͦ4ps斡Kify+btBj nP,fd /A!O)ӄuU2?a nx>etq]wA!ԾAF.'\VVUuXE'Ǹ*X"B]Uoc.M-fuyd9iȣEZln@ 0T~aЌNƱ/dP'J _Rs.5s.`8mu vWKpUfRͮn')l[jxs1|լ_x6u4 zqaZCӔ}۷w0 )/-b0#<ƒː5Ӑwpi]ouܻT<(@ßy޻~ }9k!pɒ*Wjh$TĔ S Pt҄ n`4)EOY쪮$*h{KKY̓1uitj~. qDrvt6tmB,@,cY) 8d,kjk+xE64RL@Ӝ<3j K]5VQiml8.`^qe\(Pp ~=eeqZ5 3Ч&!\ޛZ}k聃Dѐdڲ9D[|C`Hc8@8'Al'"E!%S;ysnuW :nݳ{ir# CSjc mHNBJ!DQ|gfȂȷ6mJ3 QFUnAup>SLˡ9tzdDJfqn*/ȒPu](VTeyM2 5 Pi, HSt ]u6tqqx4 _<B:$+U>eUqhH@&Of4XӀF"Ri_}~T?Ab#b/~w ^{5:& om m/+74Ml0,:ys _O&tkBBip7~ݦ+c9mcq;3.cB?Jl6 eX;Uyu4NJ0šjׁ+~oQyg5)$O g3duiU ~3?iU"W ڎrՀ@v[IJ(%;!!9٧9bdP>% X%% qjc6e){CH{qOFug0\v(Lnoiu|+ WU`04np0LpeK)ű©UnOU)Qe St=g`]s !B Hff^V\?տx-MGǨo!'% V$ $ia(e\4@^^`ܤ`;8gEr,8ߗB<@:rzRM¤T BhtO2au2[$yL)KxTڶƫ.Gu f34FK%B([ַ3lCBA_ F&Rj Z^L+΂T^^R˂x9'].[mkZy 3zF -3z7UZJ΃Gg3(d MPZvz[M[]oVJ$_xG ,T qRlOQɴ(wuU0T(Ӏf У9!h *8W&@0+𣳐]g2?go5n0-{u'WY"tY>9 t KT/Bd'hiBSq Y0=@)9x9' C$`6~i;30iuTd|JWû;34 ,]SYY-ܗSJp^Ң& vC Ȳ1(?))T}m~ U?[&iМ(/TYy@PiI+2noy Q"IO$"nqM&w9J 4, cte?8Q$1a>=_kwUppHU;7I8 g]w=(Bmݴ0)OA9VQ>&p (-yW1 u <ڏS*9(b> ?KVA̓9Q"cik/u Z@Tjv'*'6'RjiJߛe=YZ5G3k@ RqHX"TiJ DB@Yea׋D%"gܴi$yEV( سU*k,,IV $ti TE;5AVmɂVDHRb uO]G*6Qc*jSɖ37@Z{uplcjضMp\uI`@QV mzK,7$_/qHYpT\%S+Ɣ2hUILFUNX>G!zI&TUXNMvKun2P24e n"ZLϧ1)j7nv略܍5wf}x{o7;Uqtw6q%4UFny4wgO]= Jkv-~~/| c x ÎDkch<9Gyo}32հyyO4'vLǡƷ1RSo@ۍ1# rhb:i[ vt)v-wp ġBC!D)|P"iiPzj4P; 6NE29]f#. nOV9e1վWU_i F]]U{ REz5 1 "h!U7f!8:D w+-$m2JN/|?[N ; 7U%uaf}כ媶')3˜_:!]\X>y`:VquҢb|t4 Si4{[tԜ?Y-h W#(i%NM{+'by +k,x %!|7E|1R={j2L2i ǴB(0 ^xnDK4M{t~֤e-Sn1a8N`{4(IӠ?y P&Sst{prwr=<G8=Wz>yVV}h~m?tf RNTo!WǪd_jҦt=:&wȘfꃾϿc<99[ {m?.@UU, ]{=s8lɔ?|߰ᵗXY4 " ֘n[2MkɕH=XI6eQ$ foX-ԮP ?]H <\Ĺ6T \鮣P=:qS|k@%H^tKp`<=Pmـ(hpA*v~#h"DWJ l g tM0tfq ~<oRIIcnOWQVI!- ׻ K1Nq'g7+4 1rAٜj}X{L<ӄpzBԜٲIWKLϧ{x qu.XijK55`7QډkA3A# jՀ$H*, Rn95Hb˳0ReS$ j i&X^ Mz'9rhG8|Jpyayj A6N OJ:h4>_OY_ 1]pLkc]nz[­ :/8(΃T?vKn;ÆYKlaN^%a11M7-< 0YZɺցR|wg,?z}o !_5޽i{ r~~0v|G|c&T4oC/qmBhDM-eUּS,9ƂZG`a)["*JYS3sW[!t #Bv*o)@K,z4o,X~VV (78Jd{A9^NFh G20RM#euuk^Tn j#h#-k$KQ^˴Bxfn/$0'PXAM(s\?0=7$^(YKd2fEI^D3,קw9=%na;ޟ(Rs2pZm#5B /Ϸi+zĤi \qC̷>R)C!hRG.Sse:;c]pJZ`7[<2H IDATKIS34]9S#<EfxN -/g F2Oɳӝ0 PٜO. KȭrW1(y鶻X챣//p- }pW0TEk\rQIޗo\^x{M!PA*\ᵻjئ΃Y2]YVXR-:"Ȯu|z^/ӹ/v'{_i4Ϝ_t9%b.YGi+__:v|8Xq/~{ vEYa:Æ5!%͆e%W](2EhnS݆HHK;;,k }l@fr,Ek|OxoRī$1ҚYgRi͞V,PɒŜ"Mh FKZjM"MȪ59iPfxsU"Tp534h@1FrK | *lV*4f-Y0^( `MǷ0LEMV8}@!9]&<>!Mրh-j`$˒PUx0ICebKbJvt?K.S >68h̓0141Z)QʣYm'5 uKw(nK4J#$Agej ޼YvLPieD4;ߺjAU%fA@׎9Vг:{L\`8iQn[=BSV'bT*85!&B;@WdujrX yN<*T99 1lwk9<IL\(SXa>hv~B7tn9M [JTRG{ܮb5qxJ 2 6)T4Z|uu*!P ,t~7g3o‰HҜa͖M "CYB%vrL:~}АEGS( >ꫯ/Y}U;dߛ< y:C_jUhz;N6I9N?9yay~ tLGM pzNtOhTek5:JJ[ݙyۮp[}!)hѺ TGWMG ^4[t`:S|ek7*yJ5pYb8?(߄RhE &]Wu|3CBx?Ϳiip2ue>TI8a64k{6mDB=^, *>ȋML &<s2\Mp^D֖~w$,@($3^#.N1l-ɩJʼn\G,]wnhvIe"Z&|1멱I0x'_9at#XJ4*ywQVG|Z9.N?K8}LCÀ,1H"fPFm]:|A=!%~7Ekޣv|ŻP 浢d4MyJfN wȪQwzi),lR]q/^]?h !R1gggf3z sdqD6{Box3= ү9nqM{,Mh>#5]L @AUi5=E;i"Y-TaW$[  JjH' gRHQfj)X%Ֆ#7x>t}yF`| q+XgdJ^ ]b#oUUYҚ`7E QBY!|Ja?Ź܉f UZ>VĴ,&c~S zaM/X=ކ$ߠ1aM,i h&TڞX(gG ^b0ue)b"R9 *u~y2 ̆hx_Td,q,Oq;=dQlu^(h5(^՗4]8!Ng:e%yr6'3A n6o%Vhv߉pM .K 2_N(W'9o=B0jN4,w_mY(qFr5#J2Wzح6Dm,Vi;S;1 !ԩJQIsEXdW@@ 7W ,As5U |n#-!+ߛ#;K$љPdͨ$^<(@.*x.^h6^W6UkZ-1Ԙ5G@6+oDky fEZvJe\i~T2Mu ްM:=gL?} gfGyA\!;9CL%)Ebyʗ l_9陵1ݐӥ5G7MRB:=iZ^%I9qHo1DBL$Bwjy 2yȯ!0:aM,xG ^.Ulaخt 0i$X/f[idc0j4Hh:mC4}r@' q?R^aI\TM6da8ʌo7$Q.^j~20BҸ8TEl)45~flR} D_х_vt4\^&N+XJLZ5MrZ Qv'f%v !%vI^!fXY.ӫ !S:7>Q98F/"_dYjuevlMP ^߳63#bD,\u Kl2h' #okqtE*b/4sRiC~=6q(ӵ\Z1 ;gH!d Y87'-G`$۠sxK%%q(,ZCFẸK0d7V@AƵݫ"醡 KD$Yɟ77%gq{Pݜ0SrM}Р踦 3&@Y uzog~%| F'L~j5ci`HwL<ڪ=nxq XØHXg|G|')tDliNV(@3 +2lydqX|Dkrϟ(ĚfX^wP $Sڃݨ0 +cҦ4-M2^u@AHĻBu|Q^]uk xxDKIjc:UiͽlȆk?)҄\:|;Є:sPVT,4a<)YWXC޹3⛂ ^8nH zbb۔ڔA.~Hq^Lݟ8s秬B4c:'*o>eyby>vEMsQcxNC ^X@D Z$%!`jwE:}O/Y!H^>2yE7GAsr[€ il:֪OV}/dJ%Qn3bwz8Iӧ4}|{C<Ə@ճaC ́o+B1+: _q"U!^z&{؍&j,\c6( ek%jhcMՂT=ߖ:mN&;>)Q=sU%G+N/g5afmU\yLYNCRrbYք0i J:fIПBM; m4lō/@YI3jXb }0XW,/r, \sQ{gmwȢ*W@)5ٯuyQ rNededB`  :UG@З;q; rlUQ.9 Ղubr$99<(W+4 ZM)OWVs<:' #F{(>*-5D׵ hUE^E%I٤gCQeZ A2Q @ZDfeipe3?QPaYmN]4"L ʧZQYPHJg>!ָit9i9OWZF)9󾄿:moYu\^۳PEEj4 yVvF|p>Ǯuʧ|(D7-tӦSto ".p׶DHɭKyRT R }w_5Ww)* `chsqyW;D@@=ʒXs)cjvXYUZ݃yx)wH& jߨpz(]Z't~o>8~C/Bh<_ȱ{PY/I#r^О ?<ǰm:'xy0{Þ IDATYF7- [uLp;*:hз !cGRH"I6,5vF1Y- .ULh"IX>$O'*][]0]b8.cNx`!i°l :9eFf/yt c|!|̕H"Rfa@pyN%5icW=&O7tcVaIg-c*JMDB,7JFV<^'@׾?[Qm`0 ~~F!~ъo7i:`G:Y&.*ʚp\r$ƪ  i1[ǩ]|0-B;]gRk=|UT^f/kٜ.VKTUay>s|W4eñM[Շy9‰笕*so  +d fUJQ1<ʁôX8,I|#h=+( =˺dTlEFxUYzB2.|\ʂ,Zב2kڤH뎂.''G4lP$"_Du$.1[Oȋ&:4z-)\C\ il? ]-hvڤy|ȋ79kOH X{L{0(Hpɿz9пa_UUi/Ih6A)h[tk5&䑎t6 &c#nO&y 5[ivfnk`jॅ sR0Ȧ#}jA<`HkbCJLmwG->?xw-RvQ1p}4240Lskϼ*0m?X@I(luJf4,P|h]ҿ^K-1O'ѯoQ?:Q+c´,,j8 .v:{~8ȴOm"@ FS |BMTH88ǴmVk^%Տo*~J.9oY|~pҴ1=?)a1Qi#wNҥp_D&TmJ q^,|޵˫:[<#TY1d1r4W ft jzt.kh@[ ?䆟|P,tP%}Fӟer1B&iQ%^(bԃ4²w1r<@tzH4,}y}>aLiQS~"³O~Gׄ/{t=i]վ<CO?Pp%%Ft@BcCUߜS1 Aӣ`)|p AF^pU>m8ԌyZa;BlS~} {7q-V7W\?1^_f4Ǩ܈2-v=)Etȹ6,ۤ%(F#o1#Dv [ +vT8^,1)W,Jiw|d]8,w4 .!oMN6(FIv D*lN9eD*)+E<x ~mM!尻w)yusU G`cӶ5G@ l'mx:f==0w?|䵒}j 3t$u3KD (Hַd^K# e =ƭ@X)&VnAtg>mp Zd9#t@%fdvCi2?>w;Ld2[ցa!]%L>3/<6%w)5),FvAouJҲN*enFn-XL [z|UfKGօ@4S$ a+Ѥq4R~o5J ohHXɘ,ֿ%c G(P@RHt(TD(ZJ7S JUtd}:ݾ&רQ˧B 8h4TUaxA@78 ]e84Q|2I4GH pHVFq- qڶ8ԋ"XݘS8H0,sSs~lEKr58;4\0,Kc57QyHӦ̓M7)}"6!ZRDhDzE%J yfl{tnNǯi+2:_h5~ , "78yOh]*ju _*%KѡC6j v/҄VߛaH뱺y[7 m 1}赸lk N yt@uժؿ7:KcmjݣѲ+fЪ;Ns,i F$bM>u½>E*ހx6actH4j"@g;/ge@z( o%/%|KڱK7ꖕbTL^ KˮpnijD0xHдJXvtrٶ uɤnfTn'^CQtN"S-Q%Y0N,VU{zI4 ֡?!GA`2,`;\ Pu'X (q$1qKi`Wij1O5s, W*I?*!zk'QUUa 8PZ^wʹZI]8iq v.ESM´ضEˁ/HY'Lg'`:g=ng;ՓRg9i`Y @TLR7,ਆ~JLWpg=#+EPԺP\-K^DxIγYRߦZ6;0~ˀ#$+$ik^IMpU2qb0 r:>n1 ..ӲڛR"@aEGuB`yc:61nz|Swc03hq>$wܫ7eK|ulA|oQAwKJH<%ߠ!ʣfиv-) H^WJ!E7(l$O"B5mxZ)\ g48o4/<ɿny@OX|f]{\,Ҋ) #Y;Tl?HW6$hhHNՌW)RܮV/cg-fM*3OuxPwzQDpb\Li4q"M4Yik("KM!pXb# H[R0hٜ(&'(ِVD F7LqUdxL}:\!mi20LPUiYA@Ӯ8żƝɒq}ӴDm2,>9-[ C7XongX1gyݤLW2 .-hyb8s5Y&iNBLskFc9F&qO3,'81H]DŲv ޖ-E;d/ 48;/s(\C;6!]Ρ6멊r[(%TMnɣ^Cf#ktlutD|Fj/糥Iʚ󒖘RCĴJFt8S(( !_b{A(휿;'yPJWʽapcf(0)s| GtSG1烂 8-^.J&&z# UO6 O&{ q^2jk`D^bA@%'flIlJU8~`+$ص%v7x;?R~6~cCo୷⭷~uc {,OAG֯~,ӊ; P$U il,>e˓ݥ{?h9CWOQ+]רc !uB`=r:ZmVk#ַWxurF(4&ZwF ɍ.2 D0h*x|w6÷rP8a-SM\.:፳d:r= Ĩrʢb޽d[')zIFoOGPod* Gnde Z _}z=Yk7dWўsV/(7}r&2ѫ?X)ư~Ga53z8/D@&"?W0hgAx" YV&?G||r^EX54t&YakF5ǐ QB1C:A!E 9pJ d&* @{cU EXV eXBjh:&lwdJ?iG+£VլuP= ÁP· ?,p8~WœaGJ״]\Zq2'Η7BD/*ZŹ:\,{&Q0rK|[HK0݃ނdGr sljk4ꍱOYeMǤ%AGf^!3 /,TEԊx>jݠj&N'D0k2ʹh8mj~G\Gh*w&(RBbU /JՁH~oO?|qH|rhUK|kNeDrl8i贾UKLaQY<ĤM^8^@IiXl d+O**ܐ[q=]ʖ~ő%-ߡ|2h7Cg.@Vi7Ӷ1,d6 X,*.@W\<z:KbۙeIZ!p$pU dt݂iŬ_ M)8EPa{>e!Sl?bP,kܰE䜰UwX6Уݡ{0ZG.8"P ҧ뒪0!p'f~^eV2s#c.p1h%K)Wi=T9Wh2PJ?"\!_^jhl`-VUkh}leudI;7v<>q3pL'$jwW ^LVК(FQw>tl& ww pO+@ҕƶ66*(L*7:phhrK^۴Q0p*BGH_,"ro#Ms Wms9:!4y.4))ȉ&ڄe0B ]noNNFsKNcLˡ5:C,ݞ¤nڦ B] A,AVp+\>"RT0JnJg ); tT%XH2u4HJ7r/@ G^\<=eWXdqUiq\_Ucm3跹IIX:i7Z7˸EqrJaE6[<Di¨ }(<%E@NwvDk8B)mɒЅ@CyB/BR4gz"u -~k__D$)N`6bPѨe|!̣].p𘰧Ctԫ7̖.;>% C:fAѤƴP၈؈kXj~R1Ja5 H Ǐhs_}˫~Cwm:r9 ,UMc.@QfY]f1 ߆LBW V vh8]b"+C(DRV WDCbxW(@&_ۈ5nôxv)+E%&'m"#aXvnt{ WC7;dk>KKۿ۸{; lz?%R^DŽˎ=ahaKcU\GfB2ki F؞_cwY +UNn79:|3pOUl J;]4dz V,kh .*Lcݦ*lӅ|JZ`:.nyU^,ċ):9!Gi4UP4d1֟VԽm' v X/e` u6@'qV)`NWa4$0,L6hq\ϣij1uƌ'q I2q,%OTezBexǻUVqܴ05k?;|*fNnãEtZ/X >=H.<3^pW{U@e[fzU$E}"YRnNȈƋJFtׂ E IDAT[xsxoӴ*{~홬o_.瘮vV MFpİlG#-?F5~Xo~ AwEZl9c8h.m#) _B%2DPt@s^7 x:~vU1;Սe}xp5$[/G6ͣ8GgcҜҠ,LRDd1v}'4]VA.DÓB@KDL%/c盗zXd{eq ⌓6F&ɣ5UUl5|9~Lx:Hfq ,FV+"( ⟍0T)%'''} YŰ) 68.1D'y3VΤ}vTGgf"x.3dI[&88uG EeYBe h( _bW'|[oկ|) .^ X.׼q9BşAajHU`֝mkUrҽ犁[-fzNݥܔOD?0s)Ƙhy,^ '焽'ѝPHg[gB{Dݦm &PN.RAlUI [~LPIBx4"_v:؎'Ws+(ap.jHn9 B@޹Gt?a et]F)y~DSDU i?t vuE@W\^-l`m~v3 {ZY-c.oHWK#:pzC-dt/QY57.9;|ߣqtʚ01^E>e~u C ]ɓBLx>%O4~8X "D׬'7؞OWOVheaB`1J[P,I/$QɳeAU[3E~$/*Ba4m =j+CT}!5l~o6mUY`:)^CU{kT^ƺ"Ej( /[^c!{z}ZV)qL D{ x I\t؆ޛQ355AGiBvtQJ5D[$kt;\PoYfςc_c߻t^Nź~s> G69Oeַ\B/wٜ_^WW%l(jB]< dfiEܒG>9))車_Py7o|1D>ֺ\չG#m+wjj1(ӶH ,q<Ŕl>0Lv&NnkHgbXDaA;υ;*DDJmaoo[4]UVX:f'yk؞dPwy"0LK,4 bJl bU'fc ؾGY4 \SV7Ggx7>g?`)U*q S.NPy&}$bAL鲴GXYպ8Q׾ENsn GUYn M'17 d_ ""8 2CP>Z9KĦo>aΛC翺h']Ϩ2PZ-4\kU.Ct%e Z2B6e'fyolPeAILh)`ð,4EU:& nB"%">D3^H^0G`j`Z<9XLplKke,TQRf:HD'9ARk@`,R,(%W$1NeX''ij)?` Eak2uy4JځM+p0M)m6s6,Ya}}>ቂygh:om<5}ggt=c=0CeuKG7G?kQU7[Y]hGJ~qG ^p@ #m!Pl y P^ }PM%xcl%yɠbe~Cњh@ї{Y\rQ6cDqRTo{!ZsZz%[?UQI:2Ϋ\q^Y-^ o5 3lSha].^[ȥ@)%0k>7]:qJLާJI "#$m4)U4#6ϲz&AstBstuVyN</8~޽Ga@#WWiEAxyVei?taӛ6JsL[2/pA%Oޒ#|Y<?aEVP`^PlPUoJvT<_Z#O;vM$ BlqE@jxyUUxS]i9˧ E+c:LOz*<I{6@.wCJK:g O\/ѹOU,c݋g9Pa9.|FZwۮMc6˫DZ_@$yd#pѶqCGq)" g OЖ3di4zTBÆuZJKWsDUHzdmzؖ>5M*י!,ӊf9ic1=loN~}| +i6E D(͙+ 2 ,ǩ S]پ'DYrT)"a}{*%q4e *A=SAO[p"u*"%bjotAygBz8mtxd1:{I-L?)e6{u%fj F.ce6LS%{9JdD%A僠y/V1r1ĐێhWxf9,q-8̳-o2 rr5@ڬQUϧ,A`H;/7+FfO[nqP(6BkFIQu0BZ01],Vnާ9^J"KɣjYV^L1ͣfy9,/Z?oٚOl7׶?֏i򹇧O"ؾƯ\' &TUXGnZkR{IzrCG# #ȃgՆB'}Q_(jz]R*UtMeMWK^L 될 k L'#[Ȣ&cy~MLp-N( nò&cNerDtpO3mzDCAu^(ƆHVVtMZ~i[;`rME߇oÀeRl|ahzE1j|s43:sYW)< FWL`*L|N l+JKQ`mүe|U8ɸwAj||vXb.OH6ڿ,0LKN/V}G|"].coڝmB^OTEAsx\g9 Djvmh2F»ՙJC(qEԏܠCH\֙סR25YqxL,G+LB)+Bc!򀔪(e:>aYEV? 6]-F4G'4 fmt 6"H`Z߿E(V>o#C4au2*1H~Cc0D̝,r Y3ݥ}rVwv)˚K4ڧ;?CɕЀ!uG ۟BYz l\MQZp9lr6o,"@aWe||:(%o|<7g<̽j?Y[cNo6S~(σ`PJ(fCI*l!zCʂ2M {Qg'@O tLfviטl"MhOh X9Ddi -~,ۨTl `kW> R#.$e"갏ӭC^r]2m UNi٬nHW 슥}V6j,YBkDx՛[C<œ@mad& 6\7GM 6"8X.#]]osUU^TgY!,V0d$W&{N;^gwdEI3h8IN968et]]UV=,,3qvZ)Ҍa,u>R:8nCdѪ^EsC<;7>=`j_M! 9?.l#QeEsxB88sѻ^aXRb3zGqHɍou*en5OǔYBc?&Y68ej =q@}65eâZ(cl7!}oO ~NXRE5[5>aFY-7QZ'n ۂ(M`Y_xsxFc"'m2ݒlnNpUگOq,f"%uzO6X Lfqt:9Eͣ8hhd4-c?st}fi 8]0- ö1-7lb;nq0 uɗλXؖ٠E˳3f^@&$GVcJveb@3X(*-]W%Y8iXq>:i:n 5o\m<<8 ㌳QRm'Uͦ[]ܼߚA;#mlX&&l8~@U$ i>=Wu|ɂGXn'J,D32u!jȒ ꡪ%j|* ڧ?>Yx3"\mjޏN˴jYKf&1i)y8yTmF tCTnj 7^XV/鍽7X^Xmm [ꂢ(jg)"c"2"[.%pW5܌s2}Wv\Q媊2M{t>+n4}T,TG & m2rt<0m^2KT) Rcɲ:.lY~iE+>EL qLuISpjJU׸ɯ=.#&wIoDU#1|)Lx>eZaH,קK'߭ge݀XKӨ.:(Ȥ&KfL~?@.Ck90Թ4`pzb 2[#O&&ϡp`JBWlۜ6u撦,08{JSWmn 鸽>;g IDAT(=\B  ϟa6,81?^%{.V)}ESH>.8/*:VaGa ċhSps I=?|>l~>zsoe5?o\C>k{k)3y0\׾Ha5U.Ã%B&seb&:5'ƛNZ3/!ߺx($^nQrJHn}_jDеc3W^5[3ƢV{b*<ݶ"W6$B`y>eK !M-?Bw)|?ڣ{x o tmC y %t=(X]st@f`HFby{.UU38dMr*M48Sbx~9%CӐ\(z /|_0Is=g#ŌR!I/_jMfXTYJs=K]i^rt0B&+U v) K+Is2fU0UaWXnmt X-_TwlݣNͮ^&͉PB6Kh}[۸Jnh_s1$"=Yy]!)7Xw*ף4@l5Rh$*g5d9knHg#&Q"^av#L[6 yT؈؅uC%o>[4$JSaJ0k丫Ox#ZTiUn$봮m:s=]-ZNmP9E.Tz98t\$VFn\l6*p:=L%ܐpO.ktM&}iRoǍ0+1 CHVU*wįLe4 f^SaL0̖$Yy>_TۤT'9_Q548I6*9!4oo^1Kau̺-ʝs&lz&[r}8ql* j1 h*ٱӝM dL&A+-∺0lݴJYm/@mƒ¥zh:c4ծt.|殐+H"҅V]{k #LUq!0tu}[gRw{|iG{ttNezK|w V@jbw{I.B2۵Y!rO$rǃC2"%& Qq؊_G \@~!RHXp5E%-mTY7;Qd~膡J~d9 n.5!WC no8*1Q$^o@\٠56&c'I)5Nz6e ~5G))yRVr= v4#oi,Қt–Rt^*B+S2S$Vx8y\S[c:_~~'Rn 7QɫUӵ$tm]#}s:(EwIȫe04ZX[_{o50<҄degt )RCHJΞ'H0!T1l;2h?ia?}fd%e`aK>TʲhI\Q5QѰ)U0CVr5.gBr|sz4ZU14lCWrCZ F jN›K577 K-6ےɭ*^\6sƻ ZG{ N/pm뻐|&%~4 +M`276/*NYfd˹^6^(R^vA@ M N_~~_|T/Y6[;_۲ʏv PrKܹnZ"3YXXna6(hn:V]ຉx<|oy}3,?[ UYdQSb".%7qoi<y-oA ߛlB@t" U!9B~)z# z^hGZ(K])^ke74]O!t@M]-D[?lҷ<Ც*kr]ቊC_ǷG`U63ؗ '%n*o+Rnľe$3խp:]{FY45Nj(tǛ.$wS\Pd1#t#l?=OJ(8 ;Pĺ?syRlgpEFZ0Uw2T.v¯$xZ% FReɗz毜/Er? ?yN\k!=z+$Z y5Zq&N(pY}j~\TGd!Gܮ$҂>7޻ՂyPoh3| :, ,zmhAFyjTJ踔}ӮAըz7oLM0V,^bq;JZPnZ ?sp!jAILn!eG!`ylB{1UQ{?|8$wI"Ъ M( tt)iV2zH)yrENU75/G CҢB~5x}mfakh؝5|"Ι'[Fr56ƇKJbFҋ,|\<j)X)6_w4,ϧI xgZ߱Лl$[MkEESf)n`.jIDl&6CP|Wtm@14\B"qi+]k6'M~<둵N2ILͰp=LG^dSZ܎3ZA-H:{h(%eg #Yz^;iB#!7MUDh~R>.y9H\|7uS\W;lRh;&,c P^04 uR˦&B-߄|[.RuL2YG{&6p(Xś׏IĂNѩECףB)׾uk&Jת@듎gd(!P$wvM2 %O`y>EM;R`DĤ9nL//9ߺ\q'}sQiFZU.Y35 C Yꦤ xgk:pzxĨ')Q^c&RwH}+/89@ ۑ޺Y 7QERw˖E؝e8[MuwtȣMY*zK9|SU(dm݃ ~`)CW׌ǼtaOYL]}\Wf2'^WJSZfgł:BWƯ}m3{a֏T u)X;3ѝ{ʭ`Q zCGJ NV _͊хT߰^AcJdfW:,1Qө$-׀phժ"o-R 9sp5weNn)%M mB_9 zՃ%y=C[i{deͫE"Ѫ4En;{댟g\^O ~zF!jku~^!QkBui^RWM,BB|CbYI4QڔXm<|KgҚxe#] _oT%Kх ZF*^YX~@_.d!l0  uCW%ݴ^ `u{tMTe6ysM73?P -N-8]{r3!yʫEpVd}a$)r>yZ-?? Wa]*lu45iƣ+ n(p1TȶX`jm gަF{J# MS,[^@.Y]L:<ހl3aQHdu{R?wrfZ;Eh7Q銳(f\O?ȺLHS,SD%j^OV /TE8t dz-~ԴK\N#/N\+u pEpJHΨPXN~-󆫰"*%/?nsoVR&=O^>ћy͘9sLY⚂=Og4ROy$zx(YKW{|ϓ6o`D aQySL1Miq*`)I^w|I>m$8cw&c! vJq*Kj4Y1ek5MMDklUx:j&ťq~~"M2¼E & 2ö Wpk"khPf5+"Kc^x5Y|(xr40L<2]f[k֪E<HGȺF-tQZnuNUt<,[}ftMKz@DAxl<ɣp3o0İ#`ysJXbaQ>sCHD q$R1uk=%.36'ۣHc+ :iAGec h_յri{ټOuQ(љBq9M)d6EӴTVstmr'CDhHy"R) A@h MTj4`oSU“FQ it젃QEm`' =$vK]x1sV) T.@QI.U8k!\t8x(Tҩ!4<\[6e"Tuj6vKQ-yzqu8nOן/lɏg+^_7~7TLK@-x*nX*^ DLB!Gu-gѳ*hj/c@]DJE3s2$NAV_[̗[3N3 v] (HyCd:Ncf|JxñFlFX!Me>Mi *Ą@` )P9)$@}}o+tUE\.M IDAT$ !ibNС3,PZuj>J 3,j]@Z^.%ik~ݲ LRzgd%yJǨΖtitOp:]-8<9?~$Ѐ!B2Bw}|GV\K~V}_e3wf~7>je*eְR5'lc _??H9m텄B2>ѣ:o;yqalKL]l槎!(ke t|l;ۗeC1|6'@Zp{,_}DG*{f'^aru=h0:{_hUm4F@ *\S$m)qt蟞c&ɥ} 0GYw-,M3rTaP5\*B, .v2v8hSCDQH: yY4ZaEVo$(|#ip7eKN*W p$aExCVq{N)(fB$NKM#WCV%bN3U"Ifw]{p5ɍb8.yQD!Ҏdr 07t\ r4M]d[]G P@NS; $"BH!jXwJNemk$XtEFh`,1iGdmU,i͖st˦rTygH'  ľSץA Pjb׈uG [.6?hrKq:jT$ *Up{C|7. r.e@{Tӡ!zuUR {,ɋ9JGhyBSXqnM*&b\[5rF\`8. ,'_-VSN]NOtUn `!oXo{/i:W-k*ş_iQDžt=oay&KbB=:C7M?*+hȑtTSHt}5N2kmjW ⁽4պF%@EcZUÿ˲x5Iy>U?/H x AJ޸l'U1Wq#YTjNy׈CXAі@hCY]>G+›K$PHT?Ւb".LCfj^lvhu {=R^sO24릥쇚@Pd)Q9 45MӐWC_Y?AM )VMP?MB xh*JxzUXq[uί)V%nJ8&L62p=n_1#-wtJx{޳V_)5v]%H۾L4Ӣw?SW)%BC#l$Ҕprvu: $#0X^HżeNaw,.)gԼ\ӭWJ9w9 Psvn*sOWחK>t= M)X ]hzC2P4NOqB̚Bx |Xͩ'RGH\Iɻany3z+R|bч n: IM|7!M8{ [/wOyY&[@4?cq @3}]ϿpM[C=_߱Eg`O]^"߄|zB= } j`'˃/H)T EW^=!Til2q="l8 *5.e |%]>gt{=dS߻zu_ϿOϒfm{yE) Y]R ^}_{g2n']~~`cu*V'.|n8JһLS5g|:vХJ(t]K 1nڎi_ޥ5/%˼H"/$غX{tOι +Os:?$P&1gb8|4FB= ]uSz}yB3-%ďe ?TM?~z6\]#Om臫" O+z__zGB/鵑 ,K=3oyo_ !^еcLMʤcw&giIPcRvw]Be˫yȠs;ڻ[RJaב&E\3tۦ2,0utb2k(1U0Kޛ3tSOWTᒪ0lGc&qn0e0 3ƃ.*x3 ݣ*2-׀ljhEU4!h׀_WFAz? #gR0 B"Խ6YbA ZtOیnB2V#^ yNt{t6vu1#h#mj`L W9{G܅$[*J8?;B/VX=:QA|ヲ~CWU87Q*o5}3]BS9uS''G#l#-@ 5<},__?gy? %EbU)뢙&E#膥JqXB<ߧhzɆy#$+jĦR/j4, p=Obm%BK_OouC.ڂ~~; k9']q. &ؚdCBR|?BU`#Q70xۧY]~. m8bN:R$⌛b3S,EBwz.4QC =f͞LԄ-D7uiY4R=;.`IS7wthyYl?SU 8Iʾhc\/ҝx$8;S,tI l0L1|ڮ5'rEo]` Ξ.Hý zo^t`TvT?YIUAwt'|x=JB`v?hrug{TYB90t!뱊vIB_t[ϼ/]2w&S!OxvWҷ$^٩=>+DSg{|˻a/m%* ưt3"%W]>ؗ'BXm{tRT][ s|kٔhrM(*Ⱥ&jSUUh]xZQB>.\->^4#ߪVQ[OVex|)||kk%HHn [y-5BPN " dU/gO(̄O״3+Ϝy?_o]|mDOD{>LC)ZiMT&FcY&eQ*#۰ڴD9KȈJIn#;4qefx1o+kRF+&t3/Y C~IY&uc0t<<)yywx7`<\bF&P;Bo4k8}EZL)aio4"ʲF)1m˲ےiJPK(km\3JTAt]S_az438;eEVTj^e-MTyiϵ%;]0xvG.G{+5[7lG4%x@TnHbymND\H27,`BW2*2#,?P亢wQ jw4 o0T ;]uNH?^;Pݛ6Y}'km"R"LFpEJ[m_M@!َmI6M hf0Ku3_SV, sK L BS6L#i R~"b!21"\k*}[7Fk"7?3# : uE1%]aYͻ-ucV_En>Sk0g Đ@^&5QMzooh꠼\w*("+ "Wɷ ^~Qvvo\y2[%|pأYLC!p,mb,MIfu{8OVczqE,bLc i\Bz8d:[g J7єɳΏi?fT,SU Nǘ2hgɷ}XuYIÖ@R}ϸx/.=PǏpPOWn1`ۢ3FZw#O,ҊUa=VNߋ}Bw@6Pl˗.5ۂ*Kp u_,-t|(xƼ2ǬWIK.PˀeɽTP*okV = lA_kƸݽ#m@CZ0pN}NMJIO {{ΏQ<5֋WO96_y6eI1ff]a8|t~ZҍbSzxaiԢ1(VDؖFЦipL; Qѝ0~>S4q(kap||ʛ[VJሟ,EMo6D EŷeO bk ?789BVc^!,5iԋlL\xF4cS3 a4n0\te9ݾUIlqA7|]r۸- Qj])o|x|~vw{PU":Ysguc^缺Mo \Ǣ$x)"kc45~~Unp):]emHܖxQF p`xuUiVlq8Ben6+_?oV\OY2MlxzDl ~CυQi7`zvJq?ˍQ%y#5>Ti7i-*6:e0}Sє"ٲzxx, t;2 m&&eݏ:`N@9t;uzniƱP6*ԇC3o16dtow7aT_~ڏ^-rʦa +D(FF1U N^yGQЃ%`"bYWH.m- 9-;yZ* BK",:h)N [L]dFguIڨTłj90!r}V AS, Sgl0[ ʙkD L?yDw~DS7J \]-pۗnmﭼM(5;rs<։G]5JwHgzfgR!Gpcd,p"1 wNEhceZO= u¼Ȗl.H8G4V|?yDg4QZ V-psc>2<{-N]G'S@&p2@MgG$[6iBw:gpDqdLGU $7,o={/?|+>w^_?>ڤi1TY@ ~bINV< Y[AZ?hmi)Yq}ĺo-^ sMr*Ӻp83;ޛWmNWp w7t%HCzz Zl7D1\9[Ĵ1 WIo(wԵom[Ɍ(X_&Ybշl[m~a`$]Ն-w)8.`T7",hml[9idu '=M:eAWeGSƾ4Tu@mfSr~6۬|Mِ&Y dbY8^'5mgIo ΁Z5b͙w@)[~{ywwD&خ Cހ| :Y{.5]0P9e㆑G)ktN<^ԀӖ5rP"Rcwcg}utj$wWd; M⸵jp4CS{JOE}R_o~J# oedKrePeY.9*횼Mkh4,+";;&i(?hł Lr@"nk w7*֬2jyݴ3xo\oU&q"ٴBg< BmU=Pڊd 3Asߡ`ykɌp휦k "`@OŐ"|̯5w2M^Ѵ6J\x8QOYei͏Lc )'El M_2PIJ%{G'X:K\1CqX_!"E |n]@,lłRoWtxtHr1""tDEwz0>[O@ïMz'-h7(XE€ n8t*-EIxUؾOjhwp[ZYc>!h0 ")V:og=ݟ*e4n/AщZ񝻀W"|@xOۚ۬Ƶ0 vv+=:5w@vxe!1]ldC;afrsry`] vz-?<_n?t0i]nG]:8 Z3meلY(t(OJـf fw,6i\汃k6VTFdtww[(g4R kDob/( z]bS(cDGZT>0k4epuTݲZj`d1p'|G$c k ;''sL].:U KlSDdCq{óѾa<#ԕV}SU4vG-52y|WND#y@|H 2W{hb V#'s^2O^]Sf#fCgr  '>O;๶j>G\uiՂgp,*(T%¶x=<1H DD5; p0:VYBQRMYGQ'fUQZ 5AK_&kZk^zAMJ:S B.K44F $(~`-"Dn3$*)˽2R,ŲwhH9}׋5jk5|\+d?lFM/`/>Y`bn KǦl e'Ŧj*б`ڢ=]1zau,GeFIҌwO2Ɛ ˬrn2fSpfdϻ0m{FvQű}/^3&_)خA%nQl׈`YA[l9_aS+7<o0 |6]DLJЉu"kp,3p?Y_tGt▰?$M7k"3ӥiʖ F!iDlYR8&,uCәQE+$58ͬtǙr$3i Ix*Q ׼uY;V͊V#ϧ;?t A5ZÅOv®apQ){SjPR0lN 9siK!FnD;f.6 2M\tČ'ts˶ΎChitƓ")aX_o]tg N`he$ހ(8ؖDcLHެ* ژTV pIZnj?UU[:t☬Ϝ/"ݷG_g7?^~o@ ogҪކ6*3|‹) 0LӊlihN ˬb]NrR9Y=iŸAƧX wCjmk-F;ӖL3%{tՆiu!Vlo5S<svda74b ,ag"{0 6,6QKf߇;e%AoQQLlyף}L̗}E~/|{?^?G |o>smr!p|]7ksp=Ua;nbYv[6!׿ 묤jTXЪ2< PN* " ,? LcaꑞC{;c ^yٍ;= hWwdr)AG%mvj|L]Ӵ4R[^C)7p͎tsuZbx.k5AS9+gΞ3oNv:;;rytKED }>hhnCqM] &s@KdKҝYR89ٲ׼A1<1#b~a{"R6 n|!&KyϧۉJEr{HAǗ,'U}Yz/^Vh_\xR/fcH+cRy|<啫4. 0 c>VT/"vUٟ5yl˒mR)ca2Mȉd?~^ Ρ^;ᇏ1z%]pvrmկЛNU=!wޝ#l",:G] B zQT%- [nM>?cİH{:8ն:V;@]hhʎK>Ƌ:lo.yꂫiϪm&._|2g$]D)z'OuQ64FC4%ۢ+aޏӋ2nyq?0MMGd̓)A >/;OK ryBX n*n #LbEHcDlc! '?m9^x?y"dnΛkdt*CD@YTMawNgRI B:9XsLc:wvb! >~{vEdCN#Cb/<~?~-W>;|Y>oX𵓀qVM}-KV BnQqF WݾEe~8C 5DZ6>=[>\lHpMMSHeZ:PJjB9D" W?> <ׅ>ʪ(?l]՚k4%O=ōpцP:Tjh\;f傞(ަJ/ )z@$y29{|ʤ!c;<| |_BPlO=U cN!HhB^ԅ<d8Ɨ ct:WCtbqP#~6?ԍa5|tW5j[>HhKKX%v쪼aL!c Ceg͉ͦ܇@%/) =}KV篴/ [\ijєDkΩң|BwvL]| {}Fo~Bk͛^G`KK 6k:O!߮I/p04}ޥD1Q<2i2KU#pLh|Misslc1_!1PZj'V:WWxQLՖC^'h4= _z}›_{~G|y4h:`0 lʐT mMr!Ecv3,'pHEerG`wBﬣrA0>Ys-ي|~F6_<_f{ <-z`[$]-xkO>N!@'hB^E8@n NG!&mM.Z;ZφLݪq8bƁ82 py}eNXe[uIS'R9?tha``Tֻ6'g]'w7dK:]d ݭ]`L4w0 v^1b.tcK}>~KpzE4?9òI[!14Y;cw\o=̏[7Ev@ Ԥ;&mtC]}P{ݒ#S` ȟq޿wjm!]zǧ> A1m2=5Ђ/ k;o_p}=ϖ膚G zF خCo9*t|>7aݭvm B.TLBlS_›Ī2i鬦z=%n IDAT ޺1EPRl,- jo]ˊgϟ006u)6%Mq\20ÉNS[?Pt.l[cMu4Uud@iv@݉6iЍ-Rl8ϹZ? Y?;;)+6WS6UU*VK,&)n/*JލpN! [- ;lq | Hj'6r-bڏwk<=AČ|lD^lB 9onA*OUQop16~@VWlָQ@+坊uX"N#lЛ G2WoYҙ{} WI0y <*#ܴDۤF,3Ǵ[3Ή'30 "R@Kvt)&eIwv^lJq`!|^mYr }NYAcxMQǦӆlUپ\Vlΰ\m@\&!O?픻wQM9AoV/ts:9Pكl7R\?['S&w7mreܬjD~&o+6Ij5)l l /x|tէy?hǀ{!ɜ|n zXhHJVys_2y>WoGw\lkb 1|31AASVݭ1ٮ+Bxb>Wi>cMTo$j' ꗞ ]9!t01d/eѻbAXin3n"ٲ|1fv ?G,e)a@lYۑ@t/{C %(pN# "} 4ȿ9NTvbj_Ԗ3)U,؝ph-`tzPłCGM;U@ei9pWq}ׂgx8E[{Af`< @0v'L|ދA1tfmdQ,nhʂ׈k}뽢23M,@k"'mCȺ¡jv.A`sԱh$B8EcT05\Zq_lk`)v%Mx' >Sj-*2olr]:Jp^_NOT@͗lXuAHw~D^)h h4HӲ`X%d%zB4)}[' y,s |ІN;T딧glvq1 p]7Bۉ9‹q7xg=355~5Ҧ@dת7ak!$5uE߮] v+dΎ)Ӕ\_b;^cY&.И6XC fGkuhTDo~ͅ@`rɗFG[N{CHu=;e+f⹷}}1`s1~8!5B @& Nڮz(1&`=uB .Ǵ]m}2Ni.a}FbiAD!bYɖ KcePl֤w7TEc^F؎h=([!VAa[V; `lyж9kl zR!g]1F/#ꄩ]m)p,\{'T ~) &gqe#աFOg"# [70ψoZ}h@^L;.)/a ']fN/pA`q6 cN=ʲzP8.?|#}O5@`Θ\|1t"_9i cɃr^g9 =YՏYhnY/צ`Y fyy ^;6Rnx݊ߪ)ʵH=rfմ:9?}j,,¦bwP_|G(?m0;A՛dy4UEP֎^lwpy;nr׿p24L܊Ѭ] F&F3Ҋv? c3XۂNseUOg5"Y"mM_%=7\1- *\ t_ymjECXBDn[g~PS{x%ēH dx>Nlߵ0|?>"[#C48ܼ~u`]VG=y'?96pfNZ_}̎NUlq]yFC4a9y~v2 )-`*rcr@83z>e;*hih`n\є%hu`( =(ϯ?"t"iTY6:OqXs(Z=4r5cfD$@8!FNηYi\ *hlb5M)wlzGn,9xXij_g7ßto >_}EKW@OuUs6!me;OXX>@'S\Q74-K9m]Z=xp.O>_PꂛRlU&ugo}F؟)Jd:K #j'P!F01#f J*QH(L,H*ui;_Ob9}3sYd߈{w^wBUt;|˶)[ͪaDovQע p8nUvXHYJpvH?`=ɞ҃р6`0bx˶ɷ[4D#qYUS%,gg @zK,]v]zg֌sJd uM4?,xXl8zcbWmr0xBo2k%WZ{B/3ֹtGK@#|C| N::H7o:z 8p◐8GdmXǐ=^ xxeySB]>y=W$ýQ7(F㩽Ep(il2~ʶY]b}˲$>ۘt5RO/蟜oc/>!ߣu{} ?{;֬wzPDi3O AD>o_%@#BK޿xb<oڮH8ݍXS,KĂJYYl9AÑ+wNUjyƸ7Q 4eE+#{*k7sh< cO=O:<$&2$8Mh!s# ]- 11.`0p2t`o&tv&?ޣ,KxgaN@P9);n߯)EG)F"-pa[q7'׹}|z N/=[ЭFrhr8ɖd!ߺ*;>3V7}u>r;y h@oJU~GH 'ҢT{؉ɲh2re@$)񌺪>Sheh]s6xH tkN3)Z׀o%;=F%+6ڟӞOXQϕ|(T}zS`5r33O2= If?W7$~Z*Rl]z/- X2W?| &C.5 MEQոug).P]QR`xj,_`I*7zT 7wF(0Ća_l[]2M[^Y]:$ۇ;, ! B5%^cpz&@<;4I6lvJQeYze3+S.)\[zGPf)eW֢g@t=O1;MWx[Kh4"T&r!/5|JNsq4l+Zx"ޫJs: C^p2 "7V\:#b NpCiG&gvBn0v+.deM^5#ޢx^vЇ^bX'Y(_Q>"W|e2DaBxGBخ\%jEe/$ 42}84}}K}2RJ4/EIMn[;Rjt"4B`(Y!x 2M]|E=є(Y1$tNRt}D<)z6/ԱVNqZ:%q!k -sW,م8ΙKeORoAWI}* 寿jx)Y&%L eOSmMfb3\:I ((467liPˬƭK6TNJI+/+9yeatHЗ]>6P&Xg^;>C66nVlcnh,2HYu Cl݁BUKfLLl&>74)`9vָOAVQ̺2Sb}mG6YUtg4OUh ՖaϹwj 3~bg!SYlD4Yq*g0uҬ`8푭W%G]"zQiy{ tSnh]ӝ;: 3ň[t韜џy6;JujwZBfy齙Vベ^u9W q`H4`9./W֬47%); ʿ Ո[⪚8)5)ԅJcv,:ffhzlN66AT)dflUA8~ IDATb̸َ@~]Dc ]j@3,NLc2'9 SP( NERJ Ŝ,t Ο`.eHiBg02p%m>tmF!lF%f%?B jJ22Y}8i %3f#Cksѫ)|ֹt ѕ\]\wyB@) ,||R(x4_{$ѷ?م\߸J]+)Ӡպ>6bfN~~OEte6x2+ ^Ji+O_5?ԢAY*n("^=8/|~|\o[tַהYFPl8? J]UmEg0‹"Nu ͎`X{@nGAwN-n#֛Ÿ{m ~!yi;+?9R(f:W &7ԕEYz+!/+$_YEÇW3(I!ds{t(8 *|簌SMYLxwxm$9ON%xj"[D>j"8Nr> Ϥ,sІ.E]#QWbۢdm,k2L "W1u IkTPN)h4]FE)i|{ܑ^@]ONIVs77@Qk>]{?zS|1j| ,[|8x19 [zg]ji~YR.5?(.]33/4D`p>m )"DcΕWx5EYe{(W6 & l&d+z$,7Ԍ$K_bx,ތYMQp'6gtCk 6mY(d&)Yƻ#/+ng-Fk?:"9:IƠ1 ]'}k&vtѿHɜ̈thmNq-Nȗu@)rBV+ D#.zSQ[pls5Q[vӝP/^/Ϗ>~FjFFܤ=+'BiwL{A[1>pqR0q;8QgJzRAKAZT7YUۖnx$]ΉFXKsB5A@ovF)T G_'$Ѻ6%D,XWT)6.r 3B1dI\(J} jb|+sdՋ6AI8&%AOq%!E#FXb@R_ove[mGŞ b,+ϱq.Fj9CQF#5U&xF`p<酌aZY,w!9UoVB sۘJR|4rj>%VCc!_\$Mvze'l o\x\eN9ȋ8^ey\/(klۦjv z,~aݝp9gfʍEFI|Z9)[Iγ!vC"̉=ɖ &ru6}\4"dn֣os~G@wr"dt{5RV]\@33ojjuB<jAYG]#e c!EL$6"Z I1>:iGŕ&t-f (k|;5ը kmB@\hb)|[:>^!,(ˢ3;zK6?'5RH)N?Qn 4O1 g=&s88A ˤ26B>'c)ͽj 66ς)G.exgIQ֚rvzKUzGUx>}J4y8ɢx;WO*CTk)Z@ho[PX2ًvvOYt[ jͪJ=>nh4՞O겔 c4iȡd {]rP ΋;`+!ཱི_ʚ?QQAk@sWd{xw]FRd[ڈ7c&U2\-+](+(g˩wt"3N t29$YA` p@6,v%Q3n&y?|Ng0BC_mZ N/鎧f}ƃS"Z+J m7>X<<][lVOؾs7W~I߳Yȿ׾ʇ}H:Ey&][lU@-P(^>b0;fL`)k?F=`vSc{f\c;EB`17 42 GI Ll :*5U!(蚱BCkbG,KK~GJ)}#J;QxAٟfvl-PI[d'aYv \ %P (*xMn4?xɟﰧ UZ(n.׷>'=}UΏL\ꊇucY\%*pXbbmnǥ{d1:>mB ͆E"VXT<'[8EU|=`k MϷ>C=?euGaS7Iu`G' ίB4͉vaNUJ '~8@Aq'X0MF-,^6@lhʪn?yfXYm(=GOs!EJ`[R~#tBWH%F#?].Az{xIwvLZ>^oVMVr1S1~Ov#,wtDs9dTˣR$[꒭؎RںB#dnL!Л[01'hx,%XyRC#~{?$ZJbTLB.x0 l 'mW$&NQd2`y~ 5ke18dxr 8g \PHit^Nyn[l&j҄2MGf1m =4K 3NH  nŀE;>3EN"^4< "*AQg3ԟ)֣fk^Kc@d4@\wNΰlx~/<t:,̉_H gȂFgZDgE`NB2lzyQRx uB5f4=|,I:67վ5Ps[|o<,Q;, ,✡lEgwd޸N NqX+ ;p%?,%룧k&c^sBc˳#FdouzS'"%b|}翵'^]ϖ5lv2Kގ֚|J''xfLB)rWLWVP#jX/W%7o'%k^#i[5dtPr\"?Hܽݚldsw5#Gv=+:RRB])ԙV7Qj)S33}wz,,Eٖ!¹hlNLeQ CeӞ(+HNĩtVGͳ/3)}_r!)nG6"MZ7׉ ~Cx ۬ z}Gi "*7 !zn\"Ÿ"i:JAǑ,)5/D?V+ Q&Ƙ m!H싺oNKѽ.~$Ӟ97lY+w,>f*wXlTU>`|txx5R8TE6n㊻8'M2a^'k}yO7'}/5ZiujX@wx{?o%tj™< q3~&?P$ 蠔m< 'Y9^':a4)A @))f(/452a"ŮJ,6 &x}<ҁ!wCV%m;b*2F%UTY۬tG%k̄bKӢx*Sm;d5nС.Kј:^q>}͒P8H*MEq mbbeBl:B>LdGحwB@Y  "GqPZ{(ZZEL <_߿ =aӏPu|x˦;=;=WtM숮k1vK"9 WiNQz iwmfL%q+d~GB"2VIYvB qHTyJ?0]#;])Tc@Mײg8~ ~%.nS͚|7e864d&Jy#wԱjv&JJOP6E;Wn8_M/ ʿ][9TVیY?3q"FDZV)9|e8e{'}\2ܰG8e,)3SeO1Ӟ.KYeeҲ{edfo>O?mo揳ŷ',m=jx_ۊXL%_iOΰiYj~sl#mGi(\NO)b;SCI \?h3v)'d1Dz,'xQ97D+_h>ZXnxH`rnÓ٨R{O?$uu<ί.z},?SiG{'d2E\5qb9u|t?5])/*NӔڕIQ(:|fWVuz|uB#[,Ltysfװ##A49rp+^0Ҳ=8enWR܁r49_).2p@ƩZM (0)42KD#݅5%ɔL݊Еg.c:ѨϕAuA;e14CO6tsvL!0 }4U%_v$HydGcRnX Rs9;q> (eZl;T']?g|Ƕe(>`/:ޔTM0ǾF M${Mwɖ*Zm . 6+/jAlns /}m;.E*K,׆^oJ$-͚eRĠ:eptE`0z`斛k9sl%7A<պ:p┫ $bLs' \)Ş>a\̆o=/ Hd]D1V!a_,{ţvXY`;ј|LSzGDŽ[ E,A)Kđ1n3* FCPC:PPр6[EByGί_fPiBY \ n}Au4EO|Z#-I]H`6't'3N[^q G= Y Mo϶踲/5xa%&"ۃOS̅$"MPJaNwWñ,ɝ]s\,xJi# EǸJ~Br!~դcՉLJ[J$hM3+d!eŲl mFR,Y'5UI*2C!*q;(K59R׵ %-8;p6p[g1~I>˷8~+4(5k~I_+& 怽0pl܁N)-LMZp~vBPf^#:ñP oڜ;> C|]rhd2cLF4K<9p'gȶNH2`ڮ^ORhM`F\e'gD)Y,QE`{myp̍U30|z <Ї 2'6[r#Lp.7Uح6 WF]*P@Ct>۬A`1ز1&k;gy%fxadF[ ow{tgGXJ6$! T;fv~3Zn é8frAA`8(Cɨ4i ᪫<^7rm7@f8(ek.R D\QR =q,!JϣzPIy].(ˢwttt-`HYh C@~6ʍw|툦J2LJVpW|łwXۋ`lu0㷕}ut _y?N/"^.꿚A*OsAtu%3 :U%(dՆnnuNlױA넒m(]/p\-߬ܛ|7?N?/q7T)Rze+Joq2{<41Q"V'tNlstLpc{rp;j /KqVsWȂy`Tʟ~ >x|e1,d}|8|3zDQ7& όO{Bg0.K/6ďw&q_5ڲ8:5^(VGk즵nʤ nV-ሪ ,s{AA`fm6]e ίCd5e&eY,( ߊ_:O_yjlR좩l^'hy{k!Zk?z8U׌B2}G6Fgvkfk9&8^R]D[RyEn"ƸaxQDwz,^G@0*T'g`d\&9Jb#U2%] g483K\M!P78 4E㔮W؞E# %ۍŸ*rzcQ+iͦ9uvy$iwW_5_=cyh1tZqv<t|;SO<\:r[.XtLhш&k`@lm*/|zA]>76Qf ‚)2y+8hַ?ɿB!ONXL^OuM=QWӉBvqda)2imJ8~nK}HFQErY~/[ϓƱ?| aW^KQ})&.ȥp'6sk"Qܺ(v@XjpĨw\$x~`XLCRGY_>, WltJ)BGDK7fxeUpȈ˲}1Ex4!Qy g}wMg^.8JF=v)jRd7-zsq<*2tvH]U ׋NX*\Kz \q;,aph<#cV/ ,D e*e{YfswC焣)'b|⵱.wXy8" i7c1L~z*$2DU.VԥE{,CS˖F2Mp3RjeuhXn! )Zk?>omc}E|yGgJ3yC#|ѝX- ?ܑ ëخPĪ"7!0N Xl$菤m&; |&HSY"٨4fidS\ r ^ˌ1F߷X[8Vl8xGJYL2yAȊ #Y>؎ú}u%ILwrDe?8xLs9̲Jsdn}QR9Wm"qsMQwdp8fx'2? _u[ssPJOuкPh_TDE߲_,jnE>$Yk;p벾0 7pÈd : (!AS$ ҥg׵~;K"۬Y],X1ə(i yJZ ye3E[6 j| /< lXM蔠bNg41h uۑksoۘ +OGa @JIruEtZW LS%MA1Bs1@|:.(2pzG2YH8Z4RW%EDZbG/7|r='ɾ%>~KI׏|\"ݬ2I6>ڹ":ym_۠&u;RTyYs8"Pvi+?˲x<ߣ¬#msJy,ITJ/%, +K/2?I~y{~e{(mY,EljE0 .֓j* #_wPiEeY&S!ܒ(KfϹvhÏ>0ڌC ?ϰWds+IX |[bkkt4GnSr K vFU"~X54ۊ2G:cMX^DGTeA|KXyQt97#S7L{韘RYL55,dtzʌ'c G)Rﰻ E_I7FI5'dׄX?7`prďq]#lKpّe9՛tLMp)ɑQH8 Qs8nW32N ,i.ln]Fg[hƳijWoDs$|!Y>M:$U0(MIkB(oՂY"{e|hG~Fj)PJC"Bܿie;/uOﯽVcY$kvbȌȵr.3&Q M0d~ 0 ˶d lX  F&!9rݷZr_"3'"*rM쪌ȈwŎQӦj˽:8qqc?D?"?:|~H|~5BPJf oPadI,ib:+9\.2&l0&州}h_ךykONq|?NP>*E! Uv * [-ܠX=ׄ (#w܋q<;$QW)_v"+ɑp X* xNBﭠRxMimf(EUv4BGV'"#l"ARrZ mcYI%s2l3MHա3n䉀v'D&JBؚ<_L󊞛'zE[ Op IPQ.N: ]>xzW?|a +D>jqwQހO1]f>Ǘe_Dޓɿ -\(ǥWHKaW9+vB󨩘C_u8#NExk1c26_zo'5'\>M3?6;8ܡ}Jgw,? lH\Ta|vXB.k5-'c;/zG'LKQQH $-QhppUv23=4f9b5uqrqQ.f1L͚Z&{bvG;:^7{86שcR GbT- 63.n*\W*D<RDF|t/c$fq}IZ-[?FdSQ" wy`u{f5ǭ9^&{4놹{1SNEѫXbJi@y97cP`M>J\/r}.wf1ڏt!˛K Ӓ]ob^]#*~=g'#af~eMJvh?zJnU2q(R n YŚEl\F`3α3׫2XoeL嬽hSm'۫bdhOx[A%,ެ;}^4ދ^R\:-M"&-JNbbX\wA]ZR jw][Ooy>Zf/{߭vˡ/ [m f6cܾx,*zOx9'r4 k>a<׆ rU㖬J,3(0ZtKg_Z+JoRl=7uZP h X@ g677+7 P`-MY!}"ɍۿ gӲR$ᾨH5 Q <^Ba5𺘇 ^&_ӄwH:XnXJzX\T<'p+.fpq=Bhcys%jI,Dl\~L}:φ\/sU ?(@WJ^gVd!<>CYް@g2kW<:r+4pk-Pz5#j.Y*Й@,ioh:㺍k W[hm(6(!S c?^yzYx]Z*h Rbxap|2z++*5[u<-ε0׹2 EbJ"s=kg|p>e5ƮTh?z' H!:M}9Cb= _m"6H+0-u4Od*.=K4ӆ(%ϣ^d}}V3P-7h^nVy)Zt9B&CO|لE(ݗROX?CAߗQu8:gqp>e^>C1OM{🻪?=#隋U,sY@c{U%FeaeZCLt)h&k?~;}Dk?{f}mT#K.vf%J>[\$Y *E⍔(k{y;%Oupׯ aU4%Y^M;*5vEE8bA-ɂ_v4@ae |$\ߊZo@;0 ^lB ©V6h-e38>{NML`a>&cꍀ:f{@-nK-ӑ w-F}1?Ҩ TJ4x3] )hJ!b5-6lp2L֓1P0ݶT-Lb=a9AqђG_I(tSct@7qL{EqN+ AccrS{o.)},BύL*aHYN>Ȭx(:>APѮ0lG j>vr2:IZʥPQ)F5Rba sxT^ &e;yϼciQkw-͚p:$yKp%]Ұ͹q1~oĥ_ :eY *4yw_+3*w@ekhPE%6׼S(Ք/+ FJ??HW3YƳ>|gvRB?{Bo:yL'|M $[?֘]PE$Ֆ0c4[ZHǯ ja YŚK>yra?)G(U|n=Whޓk~`EYh,:G2(*\E륈GMpdL h6YnSmnt+PLjGyoƒ\gY9<4h9{UmgiqDi+sVK&;FlD%iqؤ!ǷxOūr Cm$̧hѽNd6z~?R_(m 4.J´b)L& A`&dvX$Jl3e ΩAv7TJgI{9صpZ#6+eXTq>5 #)X GtnJLGY9W۽obȵ R!k*.T"<;_sMM'쾻d( GV+Z%@A0*Qh6! aRQ5J"2 IDAT,w $OEIj,g'c:]lH&2ZxУ9K{ T+( +EJ jU$̘m3NcԯM/MrWdBL>ǯv.na.QʫM1ӗX\ 2Vӗ3zMYj=~xQYv=E~y9߯J7 _kߗkoc+ީxrlSȃyu{f>ӭQjQ3huzԺ}]gP앟fx>K~DEVʨ{GgKJ4mǏ0,%K4cJ@ G_]ضL;tE-k2>Əg(G~4y._.ׯ*Wm(2  pw_I椾~xy,/_U񴊷!54d18'_^w(jM+#u =_g9)6q24&i<Tr5lZȖU?f3|I8*3oWYsx?QMmV Κ6wewCՒ3i5eaƩXoYO؞a٤dA&Ai_x myR|4Ci=+q]5lã|T}mB)P?<9 Z-`=0J /e%M=σt?1 szxBѼG?i`V/9O?_ o5lDx4-V[W{p7<>ðl6)tŗ^ ͥ>vۮ p5G"6Z\_zXEf1u&jisXwLyT[O,ϙ__F[;?1p0 ? m ~[r>OexxL%h7>}|"=G UǕ35lkA]Ȃ~KOl$b."+ͷ.SK~#Iibx&$,|z&#=v_mU 5m- Ao ;笧#lף>8ĪTlv\ՃרRJpǸ@ 2"#WW[q$oYl%/4R B9]GM^mzVS?<&ڬY\I]N?Oc.'?1[a _}JQ7h h«7IK^EJv1czp*Zôtq~}J՛+?{f]m_SPՓ:ʀ_4o~w?${I?wTpQb |W,% p6ibW<8*P뱔FO<=j Z D̆[PaYΈX Fwx^QNդWC&߃Fw8+/97q>dqxa%f35(5ls= ]ncH5~/ 6OǦ'Qw朕-%V_SJh4UJlE\f7aJˍ.UXgi*F4M*=b22zWa<)^E08QhKÁoYF)͏D&`+5Zmk߂)yV#C5;=hr(߭2M+[쌇FFYAAvݸN!q5GF]-Xsu4R/k'408Lg@^QmiO;ٮaaLx&^^NF$ID=ku^1RHkRzU ξM^Iݦb^ܧLjC=Di1|ZS4NH v{}A o(kM}7r9/A+}OJt:x<>|yIS/do*MO+UZ[(>i!C!eo@NXLE&cMHbUxv5}řll,-͇Rls]Wv5_yL':bNKTB &w=,e\fGRJ"0'>0ӚT j&Y,&;ӲGcJФ>ɟv=]/ZZ= %3z7+4 d7}lJ)m@6X'nݗԽ"=~M*Mk2, ٦][\OKY+GiY+LұQ)E|w 1~ʟmVYZ'VM%HHin4 ~=zwR6a X0LnAj J,]y\."D}+b(wSaqsQI24.;=EhnOz慃ai;4Nqu!PmQQg{5,WS RT-g8p:fvxqAJ5YR^.~«ѠG+~RɤDyunqT0M)I-e !N&-^%1 *vl ˤvУ߭E@(?WQm{W/8ռǜϓW܏{+j}԰iV>ǯ 4KUݼy.U8~@ ۗFk_寳}7&?3W+هh\LE9}tj_d8Y̓}<~[R 1}њh#d"aRwD%{ R}pLݰ Zj2Wbs1OOJ8mXmA0V7P|xe(=._ΞQ_u39 ^Lq>͓G|F*&7/^𹯽؃(}:VRΊJ_([v_ YC_u2:`=H\`URpɒhxT_o1ioʞXʮOmSz@v9Tb;BS"0zF@su J9`Qk&3^ܸc ѐ4@kYG7dii٢hAC8cia Q[j-v/(ԛd(e`MW4s%>+oiTMi(5CL^Dh- tܟ[$q$e& ~W2Le]z_6JvY6|p>\r5Ywks1HnI#bۘl3*nPgy}z:4hWo+/]$^\۟iˑϕ/חL^>0MZoL<( o7XG{~>BtGi+Ct=@1O+75uGszԥ>(p:xYc3f _J!byL'ҫcWk"q*%fIܜQ'E *q=Qh-|Fۼ̭h4jE?ps0hm (XoSNuې#ɘ4bW8ItwS"5EmP_)J 30N'wXmid.2ߴD},DSȧl" O1Qk=~@We;_w1$cxf1=`9n:i~W7$ۈZc :g1iL4 hTLg+ &g4i(,z>:+UY#ZgFCV7Ii5Z,#vڦlH|BU'Mt#wŴLѫ O5|-/|}q]"KB5s%MRmn<.AYKlFiBY.OGkdm[ aE_} 5 ;#Z'ɒg'#PW<H! htKa(C,]` &y lB w0͈<7kM&į$y= O}QZJ`D#ܣ6RЮZ= 'B-%M?V㊢XdIR*^sB<b;.mSߡH- S{m(Y@T%^p% Ur=N2boB֓[G[!wNԛ9N7Y&wR7JCG9+B$QDo1u M@C+*J[$P&KQ* **O0Cutz40,p>aysMZ"Xⵤ>8Ʃp5{D~k`=owO"Z*>'SXACkuk^)7Dn'lX$ۍǐka8. WE|5_sn ._ca`=7OZF(róZf1gÒ+RmYaH'H a}qjj5؞GGΟ1Cp-.A)0xIG4V;!JƷYo*o~|'gt:BAi;\Gy>l)Q@]ɰPm`:'#L? rRB3)Y^?<<&DW^=6RL:UU=4Bp*Ǫp7ȯJkQ#e4 .G=`M86Q&HawVru=3 J58nօ -y5@Өtk&U۸K&UZ)ECiuQVhE jqR6bئEE~3btOmq ,wj>vRŻ(k[,xAXDsALPISjAfR6Q,+T+eOVNĭ {er"^`=@!׺N9iNP h^)OG}MhUg2D-PLJT `>'BW IDAT}"oCnZ (bgC~+.F˽N?<7- Ӣh:{b=1;A}-z pxܤ)^/Ke帟2WE)LD^Ri?jSfˉI5 '-M773ߋS7NFTǯ[2붦͈s>`^,hlmU*RD0L۫ ,Md[ ^L$R[KaDjZ|*55W@rˡg<8δD:ut rng*@TS1rv+Fq>Z}a,B1KPěP=$ JCqRO| hxT&zM4U6w4pkՒp>a=jưL6Ӊ$~ +)[BZGCGndUc cJf ,%p 歁"1*aҗb:E)CfsśhH'Rp^aX6l)o z6"w=E3JD; Ȓ`@%YBbxuƧRgmU-P*`'I\B.[I<o)t)v;~ːg5=~ jYnX0{dw{T;]IQp|lB!z2L.! 7P(?f>X[k4Y\]0~!rmlV整Oyozi03wI`T;xv9zrt#fj_\aX&dwVf' f9x0MPmuXnY"ּ'|{B&DMw?HpwY &?d!09x3,g'T[m(_-nݯ'xK7WLZK08j,nd8gi&糘\hl]z88m[յs|| #dFqtNF̮^#Ŝ'ل._|3I{Nj,Umi~o=ׯf~d͍rY݊RoGB>PrUrxBa_̯.J(ќ/b^̒_K52?3MD3$buį4y` 8 ,N6zaT;]chlaY9=B8Зp6,t taZ##D-ǥvEαT[my8|{LK,fx: 2>^cЩ4-…-c]V,BXAT9i i@^9ӓqhS|7i;+%U6{=w5Pj`gjuqnR;=!>py{gΒeRNhCQY>5Q==2lja.`*!YM>A/C0c^*44@7@i \-VRsZ/-p6au{CZ\8::Md+0I,~y_q9"ߏ5H*'=/&l4+I&8^UXPD :S r`Tݰɨh<},ՂdaTVӲX\F[H$;v:.90! N0Lk\X_/AP)+-)d5@Ѽ@)On;>8٤|4)Oanc=AP<R:}aL^>e~u2ntddQV8 ZkA_|:HEkUL?e =t AOH0 H2Y5x>{d8Ko7'г_VC"Vq4(wriN8^-7IbA&l36)RjcafGfZӴ,fn.Ŧ vKzӶ rE[TRu z5f J9^e"ɯL6J%QoDٮ ?%h ^2T=w{:=@\zey3/]-pL+58o}6LpG#4 _VM&~^|_tkjCJGŃ ,S|*Hm3lOfu/sI,=L9"}'`Pv1Eg7wNFl3,`MN*#6jA)B2eCi&ȫTH!p VT!x v3#Fg)VdLZp]via.NbpM,JUq{-L4͊g-ebA)溓(|kMc$,|GT(K(9L3, T66T*u>-ҫ T-jΧXGtaA8^#Y7!Yr4 ۭVĒ]5Ǡ+I*c%PH`:F ŭ,XPzdjR'I pJ_TmfKv<8>@IR!)dwR;֥яRJA]cꔆgЯ֎UABuZNo2C.G>E%~xLW7h-FYN,I0L7h!U.iP"[-Ks+twkvˏ.C-Z㏘ﴉv122ۈg_Nr}=o>'/IhĿ7~i~_T͊r0f1IaYb8: F7BkvKח(خש>J+SyZn`pDo0;O.pSlj'+T,(͸'$Ò!:*줊ކ&G 9;u,a̮d:I]h߽;^,%QiXȜ~P_6ҝ^~SQ7ZS/+Duڰh  Gl;wD].X8kv=xf-{ep=(w>adVw{̽y~ő4Ul?4yX R@:&8A`T~4C&Gl/TNY%X%7edZ<U,vF,{fw7x8N37MIE,wC)B[qThT(:Պ nG3zӄin0Yoȵ{_o5ynLsD,MY#w;}GQwF0S ̵nb/iͲ8)%9 jF &Kr*)r܃}خ/NL=z!]l<׳)AMD "_uٽ=K0x l`FN=SqZ]WQ>z7&caJDH仮io80,XN υJG,{5Kt?ipB&h![v<7r 5Y§2HcNI/cPzE\?/wV9iȃWrC!#w賶 H<]dqA\60(:2Mo٤ٞG4#,WYG .VW\*LVbF} -\v7@5L\wa8[fWDŽ*XϦ4] =ymw[t6LӒm^Ŷ,(b0ڽt, udcLȫXdw˰l#VdiB-ܳT6 jN \WڠN#>j͞}PNsǧs_~uRzD)labXv~<canrw l]< ʔ;rNJk|۠4$yv/ eA >7%MJ8M{xw,I+5F e,,Vǯ5\.&j=T%Qtx~T|rgݝxt=>r94+5O^+Włh:0-zK$–-/ec\%cRҘH9E(EE&Wܽ|S:\{T.Yr8o2p C?5Oׯ?kҏ<!H!p=Osx9a;stYJOsyI+UhYt6IR$ nufR $ī%V-B?v  |7-w4˸[3IBu!/{ߛfd!8ZQD ^,˻|&03Z*NP .(D)y[Ifc#d5a9OdL0 23_+Baju_)~Nk@ȂB@qob 1mG*UhE4 2mDWbZ9 f4$pEӴ%q5RH! MI5MG@)3U.kA ]&[!4^)nBt3ސ弑[B6mrNl9d%*LkQg.箸F/;3~DŽK(5=) _]2Mq|,ہ,c:d~{i;=gS C O^Cklp%ʈ)2:gr%Rޤm&K^|!'߿Yظ7'b4S'k{'p]8ğX`#A1xZ8*YEG`I:9!O\Ǖa:]t1mbqW K$ K>Z\=D6')l`>(f.8 8;jHÓg,{.iίHAI{B3's 7k*V[3i k1FGz^vO꒮#W/EM#ӚEʋqlHR?נO+עGoZxGuXPOۧ(V<~Űm'5˗,'c`!@gW$W,s3 V~iY$lJiyԎeV>z&xseNa'gY;MiG_|YJC2<&&dZbq6`Zd\$+Z9΃{檵ƫ/b]:QJ s|R*7PLV-Zn! HL18 M֋ 른ZGX/$%jRIh2_> [Ks$h|wﶨ5uQLޟ5Z+CP͉rg!mmϗdy7dڿb{lSJ#7 l"Q‹{'Lakw+U]hsi-Vm\z-[Fx.!Jq1L ?f(S Wp'1un2D:"nIrwj:.^[R=>-W zL;If}#(}5G/w~o _xcX]Mh+e:/JCSrLGbj1_va 9BgZ<'#,ï5DX -".U(<4,.Gühe3_m%>Kw_| M7 'Kj1J|zd8~x0әr7z\+Z;ij5Bk$ӌW)/' t99PPVPMUmj' v,n6d? lu+uHhhj1'Ńòk Fxdv#a1۰Ri;oYMFL3[g,\ S: vCIlܐOg\_|Ƥwz1jJqri,u $V,܎&bt'jE{|?)[,חJMom74DډKhHw\6ӖRcHX&l$'rPrɨH:q䱨pM2Ͻ2Boկ° ߧBem0,#luv]77 '5%@E)wC;_ْhO\On8Px됮#T2kP \rtZgXy›9 Pp=l4曾6g{ѶB|k6Wr(JA˲ RtlDI#G6ƠĭTY,G;)]hB!՚2Qj:~ ^yMS844|}Sd4Ц:*,b7>Sju-[I$T]0bW+hx!PoΣGNXbX{c"2' yJ@4΂m]S-LJ zS|xC&X5%e6t2FwAH}Ne_{tzEqx90V?}ggx]Pp#sP\i~?m𬈮G IDATfq\~0,rw<ԕaE Ն%f$Z2]b9I/f2)ul$X/nzy+Q ѩ+= 틁Z<ޅ xVyR<[<6'<$oO&MGŜ4N Tk,'#f]aRju V  2ktZkR%ZQ|[sg}j֎4lZ“ɯi;DŽIm|ƫpÒHH Q ̧<rVzh5﷒@-RLRl%fkQc1ZߠXFvj?okfh(>H˯51]%'?Nj*;e|o!1nXbvg~Q{]P}xf/Bך&#f7}tɒo\ޏi;TORjuX&/^ܐm㣹9Zh[-Cp`R}j*ͷo)Tm5NcrC*wY|j Ja@o,GC ۡ9""f=qq0o%\-tZ#*TOL2~,q^<o) CWv\%sI&ly:3œG=?<{e-*CϽ2LzLG'+Vzъx{Z#GWTOY/ROF[GsL{j2b|k"Ajzc? wJ.K_ZϽ~_ PpGŸAwh=Jlγ! >ob'zH[,M#0+]4aò -8v},e~ xV uo';Jxܥ Ťw3؆ҾYx}2UnaCPo)xp%-R\Ư5 ]xp\fnFZr @ULFk+,'c)6,s8,TQkJCA5xViyTfuJ.:䳐jLۑ.FIǒ ZbNkj1qeF$3RNRjT+t٦xtSPsU:h1`5v: U|Gc7d~[[)Fguh>-rtz#)St$;Z E^_4ےwr6Ͽ^MY񽿳(ɸ^ɸG\_R@n?+CF-ŷns@N'eI5۵u ,I_ܹ(įs#w7XGM=(t,דSr j)qY"fER~F{*ӿ*n~al(fm4j*z{ &%n:x+g i㕫d3Tx9ߑSMPo&w5k*,1ȴfe-ww :9QJ{6XNUlZ) G3_mAUl&,X Bż  R%5I5Rx(4eֿ, 3.& ^! z;4|,½J6X<|pg%vs'㒅Ȍ߰lZ!Ŗ{5ܟMRvsKˢoڶ~ܔ"l*5;Tiȉ|wێt\oqb qδ1~P_?Ų-|eͷOۛrA&a Az$ZMz|zor{C* YG A}5"-VH$ҔuhQ>ś7x3ʷlv] LT-Z-1LRGBoV| (ףz|FzSB]Ji3\DqU PɄWB ҝ^*9J| b40$N顆(WiZg0ڄJ|jsZ~ELK"i>7*LWLWr°,DITa99c8=%αn{: K,no<߬8fڿ,Z~^ wRH|"ckE%+Ȃ"]pԸyC{Pq W<'핻'$QN]y;v~3 ^.u d9Wȷ^~k̓Fmov}6Nrt=zd# dRg^T7AIPФ|$It t[. m6`n *U i:=H1iJ~G1(1"1ߋpj,*Nd)wqwW&g/|ܓM30w6Fò -f]lU &6[<_~D\!NX"NW .6KFMjuNYhSeZt瓄~hnh)knu"iu|̲7a3^ؔr4d=a!nB8HюU2/"lIV+" \Mwvx[ O>љj }TS@b:q,_bMq\ o>(įJfI޶5ī-l?d9%^-%$2; a%n plJ^_jG?1¡8_9ojTdڊizp3,!"5%~ƻa8wh2fv3t\F,I 2˴<e(~) z,源9&Ŝjǩmq.Sc&w;U k5;3/z3t֒w*Aj<"YGA^扎e]Q l|wFA^~a!1e29G"ef*d0 F;(s<za9r|a|0*k"4bOgnoj"}W{PpM'k|+tA,%gUX7>+$c_-UU̇7W+3uB"FYaZl9lw ju,M1L̀uA]ʹ8{īd(E"4<'5NhL|W<6fKټZnv#NXf9/#Ɏaٔ]zxbpdLPRcec.gɾ֊ Ϣ(lKƖJbTS=>CgBvQ 8A Re=gt;#W R'}f26" Ҵ >g ]S82' H^֠=+%~N q\d>EoRP֒,7,'c\]m81|fsXl_^bfŐT)~$I028/!*7MC6 ۄCKfE-ӠJLzeG:`SƏFqR3{Cp_boWZ~ "΂>Gېlc>ܚY+'mHa(m Nb6I$Kf\44YG&ĝye./ye*#i\ 0 Oe oqB=G v/ %iբ̋, ֤%)Uo&nJuY@c{>^j:a=`XY ?AVg=2{}V@:[j5Xs<|gVu~RJFEb-fOc @.]T!sve, *5jI}Bܒ2\e2֌ 'D+;]~_v'e \¯X/LQ׆WfӢK 0lbi+^_S@6ŴHp9]wU*ffېk*SğMe^9Y~ܷG%{\|tL7}{ t,8)A˖6 7ԙi?/[0a;cǰټ1(c @^hY@V-ZnÆWjwɒ$|YZ+6r|z> 9Yp,< (r<}A40ɨ6;L3Υh[kf # \3߈;08)[Lܭ2LjM:=WxG(C 3,דb!-~[mps;ⓟ}"yu,BARvYo3 r%/d[q9TxE^ <w2lJn,wRPU0m[,owx ZkTӛ\NKZ]iP*{wߏop(8WHηc~5'~A)0D=C*cVݐiÖ,.X& 8b9f:/#.G׿o+Ci^kV)nylYp[9:+Uڻ^NC1/縥2^Y_Vӱ+c'Dtʝ u1:$JMɚ%IӄI,֊kEm!˝wqT9:0 W, J.i3ͧ~WD0,XI,ce'\/RWsMk[d od)έtN=sc= ѱöI5qᛱ^qUJ6a2Xl(CpLΙrr3ߗHZæ6OϾblq(8WV M۴T)K&KC@PLK!N_ȽOP d$ʸ\oWA-Rlųy9Nc) R|P~}%#yӧػh>vKe*Ggb4d5#ms[fgo̒>[n8{m!3,UGգy" bnl`!cVܑud-(C͌%c6؟kI>'U'w~bxeCpРc妶?~h1dqZ)9RnYT3fvq+,וzx1gz'JRff9-]Wvm@30SG;7&….tO*61W~[kBӿ~Gj2"M\Z'MYMG(e t.+q(wOD.X0Ǽ*-U(N:5|&{KiT)3h| WZ=o.wO\iȴ=}RӶ%qqx81x1zX毐IY^h&[p_XocqԛJXVay_jYHfMۑHx[jȺlM&}}kz󔗣UpGU?Vp(8ŷ48W.ĺ;Y&t[YR=rЕ4Fo?(6|XMa~j1df?LG7)NPb~;`tyx$lk)Ҋ~,-4U`.'Hd)kr"w:(e}FU}"8'dq$7[ڐܒ΄=> Mq ާ4-> yTN#ƹmcL{;I~8Jcs<⸜r_h;Ŝ٠PG.k MZ[H$GV̫ܰD`ضnG?rAy/w7kp1S:Өko,k]m[(B}'%'Uk>y7, ~>[pZyS4b"4@'4p!N5/ y{~YBzs)0_dyw[t \DY V'^,0m^R[,ץ|tJ},d}BKmɒ]<$!IԘ\k~R쫶8˳'}%4^L&q{{m_(ܘ@BcjHN39;ANS$@O֑[]i23O(6YOQw@øuy0./;Z_8?V&ۀN)$=Ӛ7b^w Aga"R|,Wpˡ/F 󷐟CY4J3lXw7FU a،l_-'MXG%;9]'bnm3Zxd;g9 /!luXτph Nrs9I8 >()1U>7qm|rؾG%^ǘ){ []JM1߆}9wUe1I17m[,{AHK[YSX&8E IDAT3CgJ`|ozGZ¡8_CG|B}{is lqH]%ؿj ]-XGvTO;'}R|) L$/25˲>Y &SϵvZπM#=^Yܰ|xͤI<$8VQJx:VCs:&8[o>%φ@}VÏ$/_'WPp{oSʾo']SRV (°m ib&bh|f ZMGgJGNTY!t\j | dTjϹLkQ$. a G,x쾥ga;AUʝ#٠,F;2RKFjeX*z-Yb.dIeins[*D,1-YMF_i)/[.Yl6@t,:2'ۜ7TɈi_&((/$pHG*A,7̇7T'H'˻{19_3(Qُo#KC c~]S>ԡY IEƬl6eG&鄻I"P S)Tu>- _|7u]hW[I`.ȂjI!sPx,H$|B>B4j o5HBLܰDsswE>麔Z]Rg[wª (O-G~Oxx?_ VoLW;ț=?'b޿wPZ},2;Ic1y;!AsAkٲKCp|G[e#Ȟ?Vr >ܴCJ $Q'} $Y] D)<< Ηe<[̳h˙8XƖ0, 瓥)k kъ/n2k=Cm㘋id<g5{7iWonX Azd~-a-9bD)")uqr!3biҿZ}5NsGLzop|_ܲZ ܦ]HHP4ioF #RKfLz½{8`2h}^?g׏#]W2?frR8]NţTouFX^#$Za{>e# Drl Cjo~e;'NhKX)yCY oXP"KSVq눋}(Mɳh mlubQ?(? $(}C!ˀc#3$lfò [z,I]YBEP<l?@)C?^q,.r}fWīŃ'1mG4hfh[* kiZ6AS›un7'oOȋl:i-Y?_V[Pp{͍ 2HTB $X *e@% 灆,HVK80-[LndIzd\rh|3fog f$Zqrz1/$\4C>9 k?Hrw}p dZ3_k.1YH{3-ה,'U1 ˔:G^ f7[-tvmz4Y oЙƫi|xCE#>5 ɂUB{^Cmbmd#Xh6Zdiʴwj6يy%\d\<8[[*}&k IJ%~7"ۄ*AE%K+ףfկ5RC)3{N_zozٳSh-,E)G<ڴkARir]i%1r0r2ÞEB{<,va0M|"L|^\PjOԧd3P >G#dI̴y hǚc)ޱj@~:C:4;$Td[NX=TIb(iZ'MFWL#0/7YWleiͦئtJ#f8Z1_Mhȉ0 [*0]i/ȴ킹oY"ŌnP"h1-[Bxr}?OhSjwYxğ&H{G,{czN/oٟxKzG/1W4t+-/qv%5^-IHaY6 Y̢ͦ;L˂p*5OijIqtJe*G6h/HVKQO_EY?=rtB/_0J(Qd5ѫN,CVdmoJ NmV1s<6b]x Ưձ H5>hWԛX&'ˢHSIR4.X=̨XsJu#ߟC.~Pp{_hTV1?׿YUI֫<4/c\X R`6iqUʳMR7e' :YǸR t&OYS^zL+bGXS6+ɀ䴜ӂF_z\c e3]2:g1}% តTX8["}C!SI!pV;,ϣrt_]q.S3[ uJ&3 d1e|lc'~RǯT ٠2~xݻ;dt"y\>J)_Ԩ_طÖ b:`guIVӌjt!deFjX8j׊MPTdX^24Ʋg}I%km%al3ٌ`̆A,kiv"'1Na'ǐHJ-[0%dګn޳·sI2%5}Tչ;2Mn=(R?CwN G2u *E gI븇+sp2w5ӤPΖXA@JSMcCa(q1hopQog,Y&20f{ ;{+ƅZ~L\~a>'BFuqT=j ]\PPcExVF M7zg[ wl!ݭ4^ eIʻ—ŒYp}l*-;B eF0 ȃMJJV, 8ڑzr\L7Mev e,%|鄭Q̳wFl]Ez9/k`=q_GUzoaxA7-Xn G Ep{>i8li#{<OU]\BK$Aݧn-呃^#3tbka0WgLҩ7.PG 6ogVjmbpY`K Kqp:幍/WO!;f΀YBo}*oy|e hf&I=fRg13րBa^4f\4 .Pl,.a> ;BPթ-`A&~Y/-bɐig0pm n02>n0"PJ$cvmF&'4|LOߡܥƿ7-kJy6[6aG]&IiI ?MScPs1b@ZA:Y[iĆS@`9BdYܤ3SPxnp (˛@̱M~]V"4 ermyU,蝭\#Hvy5 Ffӣg!d~MWPwrρZ8&Y+{.ZFR˝Jbpk`48D'9^Tawp+5L;G-R_PMv7  #$"{W(7k~LHA4t&, k 馅麤aoy#Wk1͗$~@O@kkАĉĵUb)o+$aasi{S4D/\gyf~h] |5,~BhLM?O0KhSAFF,;?;W UfѤດqj 0`=?l xZ#}F;G N,f(Tҡn0(Tj8Bi߿;Mnjw vBHr{ә&%OTB5!Iᵂm!34fo61㢙h*58" :fŶ *z|IGfAi ti($ YhA8 eSa@$.^ x]ԏvG:%.S;B-\4ʘрȟ6Rى%Ԗ/`Gg! GgLcyė8?h87-jZ4Uk4/\$ m{0 K!4 oSߣ[ I0ظE&@\eݧ{E{)EHvrcL뽘3$[J|37cU* ¯ ]9Z 8 r󚕪RŠj#f%`4% |8.U4miTG(5X,MJj B4DބD .[;} U׵%nL:{L:|{/W\Gi!9,7i^^( '\#p I#4xdqc6Gn a8N&uթ/TL{v6 'tryV>gudsP_Ԟ?jvr{qB0>gq٥J[L{;wm#7T"^+W9;Rj@x@+Mh^[T )۳C"R3T薕k°lF`f+t M#)A<?ETΗF S=~)G"?t5ݻsT @xǪ1X}"˭2I4M&lb4Yޓ^,Mʵ 6zO2(Rȝu^SytB?{fP2(Zg7z<~*ru~x>Sx/vp4_M7|~$ GB7|)ͬ5Emu<< n3|)/#4h2@}Vy@ }ߘkɉd8b&+!v(YVcrpg랮}n9Js dqxƙ?Bp-K}iX2CnmlBeaBƤhg pag/Kǽ'|/TP<@\y#Vq4B[Wv 49y Ao\!bHT` J1 b sTEY{(#)\ ACKcet/ K ^N}du+mK)*H$Y&doe󹁍2{;LH)))0l']2#lkgr]'8EK>h^C)*;7m1%󋔚sɻw>Bpklc\X5 3oTv׽iQ[^No^g(rJAAy1B)u[ޤz2t>9s{s1 O~d*_CdZ>`ݷ^Fkq dbY H0 ZBIR`uB5}C[\0b8eE[Y.WCdYZe3e4Ix97&DLI0uAg&UZ#0ܸN;=R(Z,]\t~vM+iy.)/a:NЛjNeb8߆[6vLnwA]ZfL05UGfT/0wZ4so?:J7V/S(@FE,2#|[onI)/ xBn x6q̐ߟ/27Hy~vxݴ->gM]pfG&;v-2֛4kv6B_. ]*ϖ< w6n>fmc?eqb/f; ?'?|j{'+~`P BnYe27#$x~DQiۤqD;MDQV7dmctS ݪQ. K}[ RfILfg؋@bD6DR+WYYlak(S@cE.v-scwۀv%BJyJŷK82! 2scE6[$p7聀r{bkL= 3 g-tMZ3O\ "͋)6$a@ =\.UCb42\'} ͋Qj Fz7%wkQ(O >o~j6AB% cYHO$ 0C0-,IBarӟX0JRn8K -.xq#ƥRPG}:"o˲9Э &HB0% OZ`G-$"bvzg!=N\[t`$p 1m`8`E4%}!tX ( <y6dC\l9͵)/% [n Nn˝[k+TJ%8!Kc'<^L0ҽ"^ɝqf'D"dH0ޯ|z?Ш@x@yzs [e?l c L|tarU|UJțPuvY3NuN\C$e3cv' (csfNhƮOoϖ7 ;Q(W)F}^.:;#V)cWJP5OLH{S&{NA*r%í NM .}],Q[r](" 2stЅ`nQn/о:* @J78xx (T4/>]$~F@G[ #J֥QY\& ^IgD_=/cd:%3O!W_{_M5x 0P(21N%C {Rħڸx5 f凤7orҔ4 -s*aE %;ㄝq=^&G\ޢuͤbԖWXV0xqkޭ?z Tr{P6p `8 J%˴& F[R]^Pi:B[sf`g4̓w)0lϧo| NJѩ!jihIuy$ũ7.(8?v>VIHgׇ1]/=c3@~.w~Wr{* ̓׃.9U>\k`]\ 0A=4ArǸ[4[Mm!E8a;ao2#L]GbZtQ CIo0hLfff^)p2nwLIV)NAF;I$8FA$iv"nIYhkLsI.s ExgMM1ߡwz^<4RCDL?{Ȍp2fN0by5G8ӿ}Bxqsp/B0EϊL~(|ORP B-S[X`b\I馱dgF CM6{;=Qďzle9Bs  8MQdӟ |{@{puLDž4Ih8کF&15,IHB^T=M'n_ϫ ? 7{B҆dS7{/ P<@xz<5gC:4&%?u/L0Ӏ#hd,\[0BZ<׬Үێc2Qu)AQrm,% #Z)ɰ6':%= k]Duyݴ}. 4`4xo]u2ѽu֝q>  ݘ<N?R~6@5oDG|ME]Ʉ$V?bIיog }#IĴ! "VBRJl0mxMܱn:iBp0 y?D~`sJo2?H!W@~*y\Š`C4]PkP_.WAfPϾ u,(B3 0cB7b*,P`<:RAALOO-!<_@߶SBqUP(^CW6O_GO.ڐZCBR=IOLR4I=ү{=*cKt;; 0t^q ˶Ru;Q햘tn:͋Q;8ݺp{$ ~8\:w > 4O|&xOU_qTP7F D&秔MAA( .mG,$c$E$HgkC&Кe/#3IRéI' Jy !&ބjv-˜ItK#S_'8ףS7/؊/MMt,mq502 q ]`wZB,_SmyK}t`GHL{ й2G2n`اq4i^BO9<-c{i&9R$w%,߽?yT_Ҩ@x .&ӷ{sVIf@K |S5FF 403gV*4!Xm(UD1 q!NÐg/$/ۃD_J`(O '>dp]-Q|'@x rub.B$`Ъ)0"Ktn4vIˆ' 5AwI&B|b(TjXn)3A,Ibh:FD7z-k{_}9ѓ7/?, VAVG% A4%L%RpcݐJ!{[u.W;9fB06Ý {2)DO'ꃏ'Z^+A% knU)C i(Zv*!H|}M,IkӶS*\ 02,]&ap,Y 4+4#)nxa8xBu_|gɓ7/!N \S'; lbQ(hD$ō}qvr`EVvp=t1e 8:&sяNGR&BYOoׯ>NWJ0|[-KhTKXn C". fXn6h$mW#Lr_K}[8`Xgj u{\'LCף+O]n_y{ !Bo ÌaBowˤʹg&iw05ű$*R Lҙ|s? KNI$cR~?x;E*g574 y;~@ф[aA>2Xp r\lSaKN^?'L2t #dbWjX7:Sv(v 5'G~wP(;˩s8:,]^PRб"A$I^5 #N'AOXx),lEAV-,8/Dg> k_oR;u{h4xRJAí$)lu ncAv? R~ʷx%oB@Pq]J%bV(X/7XkȒ-bXtB/L/Sbc&Q\ 5F{;+yPJ /}Uԫ?ozgh[3͓A^LSN^TP(NpQ8kCk 4li],Y&Q2R)%2 %?%LA$/._2=OW'Oi?#|'O 8_5y)3I)>)cOUB% .<B.skv:A-_>B̂4 h:!=&a0fT"RJ>A_:=ۀU>ZnIx/ Ļ8x)$t$']P(NBqO~ڪnMШ8,7J̕LLQ4=41B&dRg{pk!6)@C}o}OVYO ?2>oMϨ{J }(kJ > YFPRejDT$$QDCg0ao/_"#7~~+R* wqK>x%O_ⵃJ 7l>!?-WWn"? 3pQY?y¤ i)@PlVۍGtE#wWx 7'u?x6Xq_W2ysO*P B(FAި;)9/WrR^%w_]~mAJYIDAT9AL` TP(JڻuQ=$8ܥ{.ѕ]]dϼPQ BߔV$, R"{Bkv"/>J P|OP Bkg/c/ 24\Żn BP( BP( BP( BP( BP( BP( BP( BP( BP( BP( BP( BP( BP( BP( BP( BP( BP( BP( BP( BP( BP( BP( BP( BP( BP( BP( BP(^kB YNIENDB`trabucco1.2/extras/trabucco.desktop0000644000175000017500000000033214157420215016635 0ustar salvosalvo[Desktop Entry] Name=Trabucco GenericName=Trabucco desktop launcher Comment=Launches applications and bookmarks Exec=trabucco Icon=trabucco Terminal=0 Type=Application Categories=Utility; Keywords=launcher;application trabucco1.2/extras/trabucco.10000644000175000017500000000060114157420215015323 0ustar salvosalvo.TH "trabucco" "1" .SH "NAME" trabucco \(em Desktop launcher. .SH "SYNOPSIS" .PP \fBtrabucco\fR .SH "DESCRIPTION" .PP Trabucco means trebuchet in Italian, which is a siege weapon, like a catapult. When KDE4 was released, katapult was replaced by krunner, which has several drawbacks. Trabucco is meant to overcome these drawbacks. Mostly by having a deterministic behaviour. trabucco1.2/README.md0000644000175000017500000000247414157420215013422 0ustar salvosalvoTrabucco ======== Can launch your 90kg applications for 300m (It's a launcher, like katapult, but better). This is a launcher for people that are nostalgic about katapult. ![Screenshot](http://i.imgur.com/sh166aS.jpg) It is licensed under GPLv3. It uses Qt5.5 and QML. Supported actions ================= Right now it can search: * Installed applications * Bookmarks * Web shortcuts (Those KDE things to search on google by typing gg:string) Build ===== Requires Qt5.5 and libx11. ``` mkdir build cd build qmake .. make ./trabucco ``` Why === I got a bit nostalgic of katapult, because it was much better than krunner. Trabucco means trebuchet in Italian, which is a siege weapon, like a catapult. When KDE4 was released, katapult was replaced by krunner, which has several drawbacks. * It sometimes crashes. * Uses a timeout to show suggestions. This means that if the system is under heavy load, no suggestion is shown. * Fuzzy. A certain sequence of letters doesn't always result in the same suggestions. * Most plugins don't work, or trigger heavy CPU load. Trabucco aims to solve these problems by showing only one suggestion per search string, and being deterministic about it. I will add plugins for things that I need. Debug ===== To compile with debug symbols, ``` qmake CONFIG+=debug .. make ``` trabucco1.2/main.qml0000644000175000017500000001503414157420215013576 0ustar salvosalvo/* This file is part of Trabucco. Trabucco is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Trabucco is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Trabucco. If not, see . Copyright (C) 2016 Salvo "LtWorf" Tomaselli Copyright (C) 2016 Giuseppe Bilotta */ import QtQuick 2.7 import QtQuick.Window 2.2 import QtQuick.Controls 1.3 import Qt.labs.settings 1.0 ApplicationWindow { MouseArea { acceptedButtons: Qt.MiddleButton anchors.fill: parent onClicked: { search.insert(search.length, clipboard.getSelection()) } } function appear() { fadeIn.start() window.show() window.raise() window.requestActivate() } function disappear() { fadeOut.start(); } function reset() { icon.source = settings.defaultimg search.text = "" name.text = "Trabucco!" cornerIcon.visible = false } function startsWith(long_string, header){ return long_string.substr(0, header.length) == header } SystemPalette { id: activePalette; colorGroup: SystemPalette.Active } Settings { id: settings; property int duration: 250; property double opacity: 0.8; property string defaultimg: trabucco_icon; property color selected_color: activePalette.highlight; property color text_color: activePalette.windowText; property color background_color: activePalette.dark; property int corner_factor: 15 property int size_factor: 6 property int text_size: 40 } Connections { target: ShortcutX11 onActivated: { if (window.visible) disappear(); else appear(); } } onActiveChanged: { if (!active) disappear(); } id: window visible: false title: "Trabucco!" width: Screen.width / settings.size_factor > 300 ? Screen.width / settings.size_factor: 300 height: width + name.height Component.onCompleted: { setX(Screen.width / 2 - width / 2); setY(Screen.height / 2 - height / 2); } flags: Qt.WindowStaysOnTopHint | Qt.X11BypassWindowManagerHint color: "transparent" Rectangle { NumberAnimation on opacity { id: fadeIn from: 0 to: settings.opacity; duration: settings.duration; } NumberAnimation on opacity { id: fadeOut from: settings.opacity; to: 0 duration: settings.duration; onStopped: { window.setVisible(false); reset(); } } smooth: true radius: width / settings.corner_factor color: settings.background_color anchors.fill: parent Image { id: icon opacity: 1 source: settings.defaultimg //Make the icon area slightly smaller than the window width: parent.width * 0.95 height: parent.width * 0.95 x: (parent.width / 2 - width / 2) y: parent.width - width Image { id: cornerIcon visible: false opacity: 1 width: parent.width / 4 height: parent.height / 4 anchors.bottom: parent.bottom anchors.right: parent.right } } Text { id: name anchors.top: icon.bottom width: parent.width font.pointSize: settings.text_size fontSizeMode: Text.HorizontalFit text: "Trabucco!" color: settings.text_color horizontalAlignment: Text.AlignHCenter } TextInput { id: search focus: true visible: false text: '' Shortcut { sequence: "Esc" onActivated: { disappear(); } } onAccepted: { tree.runAction() disappear(); } onTextChanged: { if (!search.text.length) { reset() return } var a = tree.search(search.text) var action_name = '' var is_prefix = false if (a !== null) { action_name = a.getName() is_prefix = a.isPrefix() } if (startsWith(action_name.toLowerCase(),text.toLowerCase())) { name.text = '' + action_name.substr(0,search.text.length) + '' name.text += action_name.substr(text.length, action_name.length) } else if (is_prefix) { name.text = '' + search.text + '' } else { name.text = '' + search.text + '' icon.source = settings.defaultimg cornerIcon.visible = false return } var icon_path = a.getIcon() if (icon_path) { icon.source = 'file://' + icon_path //Some magic to make svg images show with the proper resolution icon.sourceSize.width = icon.width icon.sourceSize.height = icon.height } else icon.source = settings.defaultimg if (a.hasCornerIcon() && a.getCornerIcon()) { cornerIcon.visible = true cornerIcon.source = 'file://' + a.getCornerIcon() cornerIcon.sourceSize.width = cornerIcon.width cornerIcon.sourceSize.height = cornerIcon.height } else { cornerIcon.visible = false } } onCursorVisibleChanged: cursorVisible = false } } } trabucco1.2/COPYING0000644000175000017500000010451314157420215013173 0ustar salvosalvo GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. 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 them 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 prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. 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. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey 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; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If 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 convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU 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 that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. 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. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 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. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. 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 state 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 3 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, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Copyright (C) This program 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, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU 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. But first, please read . trabucco1.2/trabucco.pro0000644000175000017500000000350214157420215014460 0ustar salvosalvoTEMPLATE = app VERSION = 1.2 QT += qml widgets gui sql network CONFIG += c++11 strict_c++ LIBS += -lX11 QMAKE_LFLAGS += -Wl,--as-needed QMAKE_CXXFLAGS += -Wextra RESOURCES += qml.qrc HEADERS += \ src/settings.h \ src/singleinstance.h \ src/action.h \ src/desktopaction.h \ src/tree.h \ src/node.h \ src/iconfinder.h \ src/shortcutactivator.h \ src/btree.h \ src/btreeiterator.h \ src/bookmarkaction.h \ src/cache.h \ src/downloader.h \ src/searchaction.h \ src/clipboard.h \ src/ynewaction.h SOURCES += \ src/main.cpp \ src/settings.cpp \ src/singleinstance.cpp \ src/action.cpp \ src/desktopaction.cpp \ src/tree.cpp \ src/node.cpp \ src/iconfinder.cpp \ src/shortcutactivator.cpp \ src/btree.cpp \ src/btreeiterator.cpp \ src/bookmarkaction.cpp \ src/cache.cpp \ src/downloader.cpp \ src/searchaction.cpp \ src/clipboard.cpp \ src/ynewaction.cpp FORMS += \ settings.ui INSTALL += searchshortcuts DISTFILES += main.qml extras/* \ CHANGELOG \ README.md \ CODE_OF_CONDUCT.md \ COPYING \ # searchproviders/* \ ynew/ynew \ ynew/autocomplete/ynew \ ynew/README.md \ ynew/ynew.1 isEmpty(target.path) { target.path = $${DESTDIR}/usr/bin export(target.path) } INSTALLS += target searchproviders.path = $${DESTDIR}/usr/share/kservices5/searchproviders/ searchproviders.files = searchproviders/* INSTALLS += searchproviders launcher.path = $${DESTDIR}/usr/share/applications/ launcher.files = extras/trabucco.desktop INSTALLS += launcher manpage.path = $${DESTDIR}/usr/share/man/man1/ manpage.files = extras/trabucco.1 INSTALLS += manpage icon.path = $${DESTDIR}/usr/share/icons/hicolor/512x512/apps icon.files = extras/trabucco.png INSTALLS += icon export(INSTALLS) trabucco1.2/src/0000755000175000017500000000000014157420215012723 5ustar salvosalvotrabucco1.2/src/btreeiterator.h0000644000175000017500000000217714157420215015756 0ustar salvosalvo/* This file is part of Trabucco. Trabucco is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Trabucco is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Trabucco. If not, see . Copyright (C) 2016 Salvo "LtWorf" Tomaselli */ #ifndef BTREEITERATOR_H #define BTREEITERATOR_H #include #include #include "btree.h" typedef enum { LEFT, SELF, } iter_state; typedef struct { BTree* ptr; iter_state state; } stack_item; class BTreeIterator : public QObject { Q_OBJECT public: BTreeIterator(BTree*, QObject* parent=NULL); Action* next(); bool hasNext(); private: QStack stack; bool can_iterate; }; #endif // BTREEITERATOR_H trabucco1.2/src/clipboard.h0000644000175000017500000000156214157420215015037 0ustar salvosalvo/* This file is part of Trabucco. Trabucco is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Trabucco is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Trabucco. If not, see . Copyright (C) 2016 Salvo "LtWorf" Tomaselli */ #ifndef CLIPBOARD_H #define CLIPBOARD_H #include #include class Clipboard : public QObject { Q_OBJECT public slots: QString getSelection(); }; #endif // CLIPBOARD_H trabucco1.2/src/shortcutactivator.h0000644000175000017500000000224214157420215016664 0ustar salvosalvo/* This file is part of Trabucco. Trabucco is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Trabucco is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Trabucco. If not, see . Copyright (C) 2016 Salvo "LtWorf" Tomaselli Copyright (C) 2016 Giuseppe Bilotta */ #ifndef SHORTCUTACTIVATOR_H #define SHORTCUTACTIVATOR_H #include #include class ShortcutActivator : public QThread { Q_OBJECT public: explicit ShortcutActivator(QObject *parent = 0); void run(); signals: void activated(); void grab_failed(); public slots: void end(); QString shortcut_name(); private: bool terminate = false; unsigned char key; unsigned int modifier; }; #endif // SHORTCUTACTIVATOR_H trabucco1.2/src/iconfinder.cpp0000644000175000017500000001532014157420215015550 0ustar salvosalvo/* This file is part of Trabucco. Trabucco is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Trabucco is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Trabucco. If not, see . Copyright (C) 2016 Salvo "LtWorf" Tomaselli Copyright (C) 2016 Giuseppe Bilotta */ #include "iconfinder.h" #include #include #include #include #include static QStringList* search_paths() { static bool init = false; static QStringList dirs; if (!init) { init = true; QStringList themes; QStringList themes_paths = QIcon::themeSearchPaths(); /* icons and pixmaps under XDG_DATA_HOME (~/.local/share/) seem to be missing from Qt's default * search paths, while XDG_DATA_DIR ones are present. Add the HOME ones */ { QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); QString home_local_share = env.value("XDG_DATA_HOME", QDir::homePath() + "/.local/share/"); QString home_icons = QDir::cleanPath(home_local_share + "/icons"); QString home_pixmaps = QDir::cleanPath(home_local_share + "/pixmaps"); qDebug() << home_local_share; qDebug() << home_icons; qDebug() << home_pixmaps; QFileInfo info(home_icons); if (info.exists() && info.isDir()) { themes_paths.prepend(home_icons); } info = QFileInfo(home_pixmaps); if (info.exists() && info.isDir()) { themes_paths.prepend(home_pixmaps); } themes_paths.append("/usr/share/pixmaps"); themes_paths.removeDuplicates(); QIcon::setThemeSearchPaths(themes_paths); } qDebug() << themes_paths; for (int i=0; i 2) { qDebug() << "Adding" << dir << "to icon search path"; dirs.append(dir); } } } qDebug() << dirs << "\n"; } return &dirs; } QString IconFinder::FindIcon(QString icon) { static const char * formats[]= { ".svg", ".svgz", ".png", }; qDebug() << "finding " << icon; qDebug() << "discoverable as theme icon: " << QIcon::hasThemeIcon(icon); //In case a full path is provided QFileInfo i(icon); if (icon.startsWith('/') && i.exists() && i.isReadable()) { return icon; } //Strip format from icon field, if it has one for (unsigned int f=0; flength(); d++) { for (unsigned int f=0; fat(d) + icon + QString(formats[f]); QFileInfo i(attempt); qDebug() << "Attempting icon" << attempt; if (i.exists() && i.isReadable()) { return attempt; } } } qDebug() << icon << " not found" << "\n"; return ""; } trabucco1.2/src/clipboard.cpp0000644000175000017500000000156614157420215015376 0ustar salvosalvo/* This file is part of Trabucco. Trabucco is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Trabucco is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Trabucco. If not, see . Copyright (C) 2016 Salvo "LtWorf" Tomaselli */ #include "clipboard.h" #include #include QString Clipboard::getSelection() { QClipboard* cl = QApplication::clipboard(); return cl->text(QClipboard::Selection); } trabucco1.2/src/iconfinder.h0000644000175000017500000000151514157420215015216 0ustar salvosalvo/* This file is part of Trabucco. Trabucco is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Trabucco is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Trabucco. If not, see . Copyright (C) 2016 Salvo "LtWorf" Tomaselli */ #ifndef ICONFINDER_H #define ICONFINDER_H #include class IconFinder { public: static QString FindIcon(QString icon); }; #endif // ICONFINDER_H trabucco1.2/src/ynewaction.cpp0000644000175000017500000000464014157420215015613 0ustar salvosalvo/* This file is part of Trabucco. Trabucco is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Trabucco is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Trabucco. If not, see . Copyright (C) 2017-2021 Salvo "LtWorf" Tomaselli */ #include #include #include #include #include #include "iconfinder.h" #include "ynewaction.h" static QString separator; YnewAction::YnewAction(QString script, QString prefix, QObject *parent) : Action(parent) { this->script = script; this->name = prefix + separator + script; } QString YnewAction::getIcon() { return this->cached_icon_path; } void YnewAction::runAction() { QStringList arguments; arguments << script; QProcess::startDetached("ynew", arguments); } void YnewAction::LoadYnewActions(BTree* tree, QObject* parent) { if (!YnewAction::isYnewInstalled()) { return; } QStringList* dirs = YnewAction::GetPaths(); QString dir = dirs->at(0); QSettings settings; QStringList prefixes = settings.value("YnewAction/prefixes", "ynew").toStringList(); separator = settings.value("YnewAction/separator", " ").toString(); QString yakuake_icon = IconFinder::FindIcon("yakuake"); QDirIterator i(dir, QDirIterator::FollowSymlinks); while (i.hasNext()) { QFileInfo file(i.next()); if (file.isDir() || (! file.isExecutable())) continue; for (int i = 0; i < prefixes.size(); i++) { YnewAction* ynew_action = new YnewAction(file.fileName(), prefixes.at(i), parent); ynew_action->cached_icon_path = yakuake_icon; tree->add(ynew_action); } } } QStringList* YnewAction::GetPaths() { static QStringList* result = NULL; if (result) return result; result = new QStringList(); result->append(QDir::homePath() + "/.ynew/"); return result; } bool YnewAction::isYnewInstalled() { QFile ynew("/usr/bin/ynew"); return ynew.exists(); } trabucco1.2/src/downloader.cpp0000644000175000017500000000334014157420215015565 0ustar salvosalvo/* This file is part of Trabucco. Trabucco is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Trabucco is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Trabucco. If not, see . Copyright (C) 2016 Salvo "LtWorf" Tomaselli */ #include "downloader.h" #include #include Downloader::Downloader(QStringList sources, QString destination, QObject *parent) : QObject(parent) { this->sources = sources; this->destination = destination; //this->dest_file = QFile(destination); connect( &this->nam, &QNetworkAccessManager::finished, this, &Downloader::finished ); this->download(); //TODO place a lock on the destination file } void Downloader::finished(QNetworkReply* reply) { if (reply->error() != QNetworkReply::NoError) { this->download(); return; } QString tmp = destination + "_temp"; QFile dest(tmp); dest.open(QIODevice::WriteOnly); dest.write(reply->readAll()); dest.close(); QDir d; d.remove(destination); d.rename(tmp, destination); } void Downloader::download() { if (this->sources.isEmpty()) return; QUrl url(this->sources.at(0)); this->sources.removeFirst(); QNetworkRequest request(url); this->nam.get(request); } trabucco1.2/src/settings.cpp0000644000175000017500000000626314157420215015276 0ustar salvosalvo/* This file is part of Trabucco. Trabucco is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Trabucco is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Trabucco. If not, see . Copyright (C) 2016 Salvo "LtWorf" Tomaselli */ #include "settings.h" #include "ui_settings.h" #include #include #include static void selectData(QComboBox* box, QVariant data) { int id = box->findData(data); if (id == -1) id = 0; box->setCurrentIndex(id); } static void addModifiers(QComboBox* box, unsigned int modifier) { box->addItem("Alt", Mod1Mask); box->addItem("Ctrl", ControlMask); selectData(box, modifier); } static void addKeys(QComboBox* box, QString key) { /* * When adding new keys, make sure that the "data" is * supported by XStringToKeysym */ for (char i = 'A'; i <= 'Z'; i++) box->addItem(QString(i), QString(i)); box->addItem("Space","space"); selectData(box, key); } Settings::Settings(QWidget *parent) : QDialog(parent), ui(new Ui::Settings) { ui->setupUi(this); QSettings settings; ui->chkBookmarks->setChecked(settings.value("Source/Bookmarks", true).toBool()); ui->chkDesktop->setChecked(settings.value("Source/Desktop", true).toBool()); ui->chkSearch->setChecked(settings.value("Source/SearchProvider", true).toBool()); ui->chkYnew->setChecked(settings.value("Source/YnewProvider", true).toBool()); ui->spnDuration->setValue(settings.value("duration", 250).toInt()); ui->spnOpacity->setValue(settings.value("opacity", 0.8).toDouble()); unsigned int modifier = settings.value("Shortcut/modifier", Mod1Mask).toUInt(); QString key = settings.value("Shortcut/keycode", "space").toString(); addModifiers(this->ui->cmbModifier, modifier); addKeys(this->ui->cmbKey, key); } void Settings::accept() { QSettings settings; settings.setValue("Source/Bookmarks", this->ui->chkBookmarks->isChecked()); settings.setValue("Source/Desktop", this->ui->chkDesktop->isChecked()); settings.setValue("Source/SearchProvider", this->ui->chkSearch->isChecked()); settings.setValue("Source/YnewProvider", this->ui->chkYnew->isChecked()); settings.setValue("Shortcut/modifier", this->ui->cmbModifier->currentData()); settings.setValue("Shortcut/keycode", this->ui->cmbKey->currentData()); settings.setValue("duration", this->ui->spnDuration->value()); settings.setValue("opacity", this->ui->spnOpacity->value()); QDialog::accept(); QApplication::exit(CONFIG_RELOAD); } Settings::~Settings() { delete ui; } void Settings::grab_error() { this->ui->tabWidget->setCurrentIndex(1); this->ui->lblGrabError->setText("Shortcut already in use. Select a different one"); this->show(); } trabucco1.2/src/btreeiterator.cpp0000644000175000017500000000335414157420215016307 0ustar salvosalvo/* This file is part of Trabucco. Trabucco is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Trabucco is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Trabucco. If not, see . Copyright (C) 2016 Salvo "LtWorf" Tomaselli */ #include "btreeiterator.h" BTreeIterator::BTreeIterator(BTree *tree, QObject* parent) : QObject(parent) { can_iterate = tree != NULL; stack_item root; root.ptr = tree; root.state = LEFT; stack.push(root); } bool BTreeIterator::hasNext() { return can_iterate; } Action* BTreeIterator::next() { while (true) { stack_item item = stack.pop(); switch (item.state) { case LEFT: { item.state = SELF; stack.push(item); if (item.ptr->getLeft()) { stack_item n; n.ptr = item.ptr->getLeft(); n.state = LEFT; stack.push(n); } break; } case SELF: { if (item.ptr->getRight()!=NULL) { stack_item n; n.ptr = item.ptr->getRight(); n.state = LEFT; stack.push(n); } else if (!stack.size()) can_iterate = false; return item.ptr->getAction(); break; } } } } trabucco1.2/src/tree.cpp0000644000175000017500000000616514157420215014376 0ustar salvosalvo/* This file is part of Trabucco. Trabucco is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Trabucco is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Trabucco. If not, see . Copyright (C) 2017 Salvo "LtWorf" Tomaselli */ #include "tree.h" #include #include "btree.h" #include "btreeiterator.h" #include "bookmarkaction.h" #include "searchaction.h" #include "ynewaction.h" Tree::Tree(QObject *parent) : QObject(parent) { QSettings settings; this->bookmarks = settings.value("Source/Bookmarks", true).toBool(); this->desktop = settings.value("Source/Desktop", true).toBool(); this->searchprovider = settings.value("Source/SearchProvider", true).toBool(); this->ynew = settings.value("Source/YnewProvider", true).toBool(); if(this->desktop) this->watcher.addPaths(*DesktopAction::GetPaths()); if(this->searchprovider) this->watcher.addPaths(*SearchAction::GetPaths()); if(this->bookmarks) this->watcher.addPaths(*BookmarkAction::GetPaths()); if(this->ynew) this->watcher.addPaths(*YnewAction::GetPaths()); connect( &this->watcher, &QFileSystemWatcher::directoryChanged, this, &Tree::rescan ); connect( &this->watcher, &QFileSystemWatcher::fileChanged, this, &Tree::rescan ); rescan(); } void Tree::rescan() { this->ready = false; printf("Rescan triggered\n"); { delete this->action_parent; delete this->node; } { this->action_parent = new QObject(this); this->node = new Node(); BTree sorted_tree; if (this->desktop) DesktopAction::LoadDesktopActions(&sorted_tree, this->action_parent); if (this->bookmarks) BookmarkAction::LoadBookmarkActions(&sorted_tree, this->action_parent); if (this->searchprovider) SearchAction::LoadSearchActions(&sorted_tree, this->action_parent); if (this->ynew) YnewAction::LoadYnewActions(&sorted_tree, this->action_parent); BTreeIterator i(&sorted_tree); while (i.hasNext()) { Action* a = i.next(); node->add(a); } } this->ready = true; } void Tree::runAction() { if (this->last == NULL || !this->ready) return; if (last->isPrefix()) { QString query = this->last_prefix.mid(last->getName().size()); last->runAction(query); } else last->runAction(); } Action * Tree::search(QString prefix) { if (!this->ready) return NULL; printf("Searching %s\n", prefix.toStdString().c_str()); this->last_prefix = prefix; return this->last = this->node->search(prefix); } trabucco1.2/src/ynewaction.h0000644000175000017500000000234214157420215015255 0ustar salvosalvo/* This file is part of Trabucco. Trabucco is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Trabucco is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Trabucco. If not, see . Copyright (C) 2017-2021 Salvo "LtWorf" Tomaselli */ #ifndef YNEWACTION_H #define YNEWACTION_H #include #include #include "action.h" #include "btree.h" class YnewAction: public Action { public: YnewAction(QString script, QString prefix, QObject * parent=NULL); static void LoadYnewActions(BTree*, QObject* parent=NULL); static QStringList* GetPaths(); static bool isYnewInstalled(); public slots: virtual void runAction(); virtual QString getIcon(); // bool mustShow(); private: QString script; QString cached_icon_path; }; #endif // DESKTOPACTION_H trabucco1.2/src/settings.h0000644000175000017500000000201114157420215014726 0ustar salvosalvo/* This file is part of Trabucco. Trabucco is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Trabucco is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Trabucco. If not, see . Copyright (C) 2016 Salvo "LtWorf" Tomaselli */ #ifndef SETTINGS_H #define SETTINGS_H #include #define CONFIG_RELOAD 23 namespace Ui { class Settings; } class Settings : public QDialog { Q_OBJECT public: explicit Settings(QWidget *parent = 0); ~Settings(); public slots: void accept(); void grab_error(); private: Ui::Settings *ui; }; #endif // SETTINGS_H trabucco1.2/src/btree.h0000644000175000017500000000206314157420215014176 0ustar salvosalvo/* This file is part of Trabucco. Trabucco is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Trabucco is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Trabucco. If not, see . Copyright (C) 2016 Salvo "LtWorf" Tomaselli */ #ifndef BTREE_H #define BTREE_H #include #include "action.h" class BTree : public QObject { Q_OBJECT public: explicit BTree(QObject * parent=NULL); public slots: bool add(Action* action); Action* getAction(); BTree* getLeft(); BTree* getRight(); private: Action* action = NULL; BTree* left = NULL; BTree* right = NULL; }; #endif // BTREE_H trabucco1.2/src/downloader.h0000644000175000017500000000235614157420215015240 0ustar salvosalvo/* This file is part of Trabucco. Trabucco is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Trabucco is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Trabucco. If not, see . Copyright (C) 2016 Salvo "LtWorf" Tomaselli Copyright (C) 2016 Giuseppe Bilotta */ #ifndef DOWNLOADER_H #define DOWNLOADER_H #include #include #include #include #include #include class Downloader : public QObject { Q_OBJECT public: explicit Downloader(QStringList sources, QString destination, QObject *parent = 0); private slots: void download(); void finished(QNetworkReply* reply); private: QStringList sources; QString destination; QFile dest_file; QNetworkAccessManager nam; }; #endif // DOWNLOADER_H trabucco1.2/src/shortcutactivator.cpp0000644000175000017500000000616614157420215017230 0ustar salvosalvo/* This file is part of Trabucco. Trabucco is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Trabucco is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Trabucco. If not, see . Copyright (C) 2016 Salvo "LtWorf" Tomaselli Copyright (C) 2016 Giuseppe Bilotta */ #include "shortcutactivator.h" #include #include #include #include #include bool grab_error = False; int xerrorhandler(Display *, XErrorEvent * ev) { if (ev->error_code == BadAccess) { qDebug() << "Unable to grab global shortcut"; grab_error = True; } return 0; } ShortcutActivator::ShortcutActivator(QObject *parent) : QThread(parent) { QSettings settings; const char* k = settings.value("Shortcut/keycode","space").toString().toStdString().c_str(); this->key = XStringToKeysym(k); this->modifier = settings.value("Shortcut/modifier",Mod1Mask).toUInt(); } void ShortcutActivator::end() { this->terminate = true; } QString ShortcutActivator::shortcut_name() { QSettings settings; QString r; switch (this->modifier) { case Mod1Mask: r = "Alt"; break; case ControlMask: r = "Ctrl"; break; default: break; } r += "+" + settings.value("Shortcut/keycode","space").toString(); return r; } void ShortcutActivator::run() { XSetErrorHandler(xerrorhandler); Display* dpy = XOpenDisplay(getenv("DISPLAY")); Window root_window = DefaultRootWindow(dpy); XEvent ev; unsigned int keycode = XKeysymToKeycode(dpy, this->key); { /* * Caps lock and num lock count as modifiers, * so different masks are needed for all their * statuses. */ unsigned int mods[] = { modifier, modifier | Mod2Mask, //Num lock modifier | LockMask, // caps lock modifier | Mod2Mask | LockMask, }; Bool owner_events = False; int pointer_mode = GrabModeAsync; int keyboard_mode = GrabModeAsync; for (unsigned int i=0; i<(sizeof(mods)/sizeof(int)); i++) { XGrabKey( dpy, keycode, mods[i], root_window, owner_events, pointer_mode, keyboard_mode ); } } XSync(dpy, false); if (grab_error) { grab_error = false; emit grab_failed(); } while(true) { XNextEvent(dpy, &ev); if (ev.type == KeyPress) { printf("Key pressed\n"); emit this->activated(); } if(this->terminate) break; } XCloseDisplay(dpy); } trabucco1.2/src/cache.h0000644000175000017500000000170714157420215014144 0ustar salvosalvo/* This file is part of Trabucco. Trabucco is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Trabucco is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Trabucco. If not, see . Copyright (C) 2016 Salvo "LtWorf" Tomaselli */ #ifndef CACHE_H #define CACHE_H #include #include class Cache { public: static void create_cache_dir(); static QString cached_icon(QUrl); static void download_favicon(QUrl, QString, QObject* parent, QString default_icon = NULL); }; #endif // CACHE_H trabucco1.2/src/singleinstance.cpp0000644000175000017500000000227314157420215016441 0ustar salvosalvo#include #include #include "singleinstance.h" /** * @brief filename * @param key * @param scope * @return a fully qualified filename * * Generates an appropriate filename for the lock */ static QString filename(QString key, scope_t scope) { QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); QString tmp = env.value("TEMP", "/tmp") + "/"; QString user = env.value("USER", "alfio"); QString r; switch (scope) { case SYSTEM: r = tmp; break; case SESSION: //TODO this will prevent trabucco to run in multiple sessions r = env.value("XDG_RUNTIME_DIR", tmp + user) + "/"; break; } return r + key + ".lock"; } /** * @brief SingleInstance::unique * @param key the unique name of the program * @param scope wether it needs to be system-wide or session-wide * @return true if this is the only instance * * Make sure that this instance is unique. */ bool SingleInstance::unique(QString key, scope_t scope) { QLockFile* lock = new QLockFile(filename(key, scope)); bool r = lock->tryLock(); if (!r) delete lock; return r; } trabucco1.2/src/desktopaction.h0000644000175000017500000000244014157420215015743 0ustar salvosalvo/* This file is part of Trabucco. Trabucco is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Trabucco is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Trabucco. If not, see . Copyright (C) 2016 Salvo "LtWorf" Tomaselli Copyright (C) 2016 Giuseppe Bilotta */ #ifndef DESKTOPACTION_H #define DESKTOPACTION_H #include #include #include "action.h" #include "btree.h" class DesktopAction: public Action { public: DesktopAction(QString file,QObject * parent=NULL); static void LoadDesktopActions(BTree*, QObject* parent=NULL); static QStringList* GetPaths(); public slots: virtual void runAction(); virtual QString getIcon(); bool mustShow(); private: bool show; bool terminal; bool cached_icon = false; QString cached_icon_path; void clear_action(); }; #endif // DESKTOPACTION_H trabucco1.2/src/bookmarkaction.cpp0000644000175000017500000002436114157420215016440 0ustar salvosalvo/* This file is part of Trabucco. Trabucco is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Trabucco is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Trabucco. If not, see . Copyright (C) 2016 Salvo "LtWorf" Tomaselli Copyright (C) 2016 Giuseppe Bilotta */ #include "bookmarkaction.h" #include #include #include #include #include #include #include #include #include #include "cache.h" #include "downloader.h" #include "iconfinder.h" /** * @brief load_from_chromium * @param tree: add the Actions to this tree * @param value * * Recursively load bookmarks from chromium json file. * * The json has many levels, some can be done with objects * and some can be done with arrays. * * This function iterates the entire document until it finds * actual bookmarks and adds them. */ static void load_from_chromium(BTree *tree, QJsonValue *value, QObject* parent) { if (value->isUndefined()) return; QJsonObject obj; if (value->isObject()) { obj = value->toObject(); QJsonValue type = obj.value("type"); if (type.toString() == "url") { //Found a URL. QString name = obj.value("name").toString(); QString url = obj.value("url").toString(); if (name.length()!=0 && url.length() != 0) { BookmarkAction* bookmark = new BookmarkAction(name,url,"", parent); if (!tree->add(bookmark)) delete bookmark; } } else { QStringList keys = obj.keys(); for (int i = 0; i < keys.length(); i++) { QJsonValue tmp = obj.value(keys[i]); load_from_chromium(tree, &tmp, parent); } } } else if (value->isArray()) { QJsonArray array = value->toArray(); for (int i=0; i< array.size(); i++) { QJsonValue tmp = array.at(i); load_from_chromium(tree, &tmp, parent); } } } /** * @brief load_from_chromium * @param tree * @param chromium_bookmarks * * Load bookmarks actions from a chromium-like json file into the tree. */ static void load_from_chromium(BTree* tree, QFileInfo chromium_bookmarks, QObject* parent) { if (chromium_bookmarks.exists() && chromium_bookmarks.isReadable()) { QFile bookmarks(chromium_bookmarks.absoluteFilePath()); bookmarks.open(QIODevice::ReadOnly); QByteArray content = bookmarks.readAll(); QJsonDocument document = QJsonDocument::fromJson(content); if (document.isObject()) { QJsonValue obj = document.object(); load_from_chromium(tree, &obj, parent); } } } /** * @brief load_from_firefox_places * * Load bookmark actions from a Firefox-like `places` SQLite database */ static void load_from_firefox_places( BTree *tree, //< [out] action tree to add actions to QString dbfile, //< path to a Firefox places database QObject* parent ) { QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE"); db.setDatabaseName(dbfile); if (!db.open()) { qDebug() << "Failed to open Firefox bookmarks @ " << dbfile << "\n"; } qDebug() << "Loading Firefox bookmarks @ " << dbfile << "\n"; QSqlQuery query( "select moz_bookmarks.title, moz_places.url, moz_favicons.url " "from moz_bookmarks, moz_places left join moz_favicons " "on moz_places.favicon_id = moz_favicons.id " "where moz_bookmarks.fk = moz_places.id;", db); while (query.next()) { QString title = query.value(0).toString(); QString url = query.value(1).toString(); // skip entry if it has no title or it's a special place or a bookmarklet if (title.isEmpty() || url.startsWith("place:") || url.startsWith("javascript:")) continue; QString icon_url = query.value(2).toString(); BookmarkAction* bookmark = new BookmarkAction(title, url, icon_url, parent); if (!tree->add(bookmark)) delete bookmark; } db.close(); } /** * @brief load_from_firefox * * Load bookmark actions from the default Firefox profile found in a given directory */ static void load_from_firefox( BTree *tree, //< [out] action tree to add actions to QString path,//< path to a Firefox configuration directory QObject* parent ) { QSettings profiles(path + "profiles.ini", QSettings::IniFormat); QStringList groups(profiles.childGroups()); groups.removeAll("General"); QStringListIterator group(groups); QString section; // If there are multiple profiles defined, then we want the one with // Default=1; otherwise, we just want the first one. We could do conditionals // based on the number of elements in groups, but it's simpler to just // over the whole list, break if we meet one with Default=1, and // just leave the last one selected. while (group.hasNext()) { section = group.next(); if (profiles.value(section + "/Default").toInt() == 1) break; } if (section.isEmpty()) { qDebug() << "No Firefox profile found\n"; return; } profiles.beginGroup(section); qDebug() << "Loading from profile " << profiles.value("Name").toString() << "\n"; // TODO FIXME handle IsRelative QString places_path = path + profiles.value("Path").toString() + "/places.sqlite"; load_from_firefox_places(tree, places_path, parent); profiles.endGroup(); } /** * Load bookmarks from an Opera bookmark list (pre-Blink versions) */ static void load_from_opera12( BTree* tree, //< [out] action tree to add actions to QString path, //< path to the old Opera bookmark file QObject* parent ) { QFile bookmarks(path); if (!bookmarks.exists()) return; bookmarks.open(QIODevice::ReadOnly); // file is UTF-8 encoded, and QString reads a QByteArray assuming // that encoding, so we're good QString content(bookmarks.readAll()); int section_begin = 0; int section_end = 0; // delete the Trash folder from the content section_begin = content.indexOf("TRASH FOLDER=YES"); section_end = content.indexOf("\n\n-\n\n", section_begin); content.remove(section_begin, section_end - section_begin); // bookmarks are stored in sections that begin with #URL and end with double-newlines while ((section_begin = content.indexOf("#URL\n", section_end)) >= 0) { section_end = content.indexOf("\n\n", section_begin); if (section_end < 0) section_end = content.length(); QStringRef section(&content, section_begin, section_end - section_begin); // skip 'partner' bookmarks if (section.contains("\tPARTNERID=")) continue; int name_idx = section.indexOf("\tNAME="); int url_idx = section.indexOf("\tURL="); if (name_idx < 0 || url_idx < 0) continue; name_idx += 6; url_idx += 5; int name_end = section.indexOf("\n", name_idx); int url_end = section.indexOf("\n", url_idx); QString name(section.mid(name_idx, name_end - name_idx).toString()); QString url(section.mid(url_idx, url_end - url_idx).toString()); BookmarkAction* bookmark = new BookmarkAction(name, url, QString(), parent); if (!tree->add(bookmark)) delete bookmark; } } /** * @brief BookmarkAction::LoadBookmarkActions * @param tree * * Loads bookmarks actions inside the tree */ void BookmarkAction::LoadBookmarkActions(BTree* tree, QObject *parent) { QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); QString config_root = env.value("XDG_CONFIG_HOME", env.value("HOME") + "/.config"); QFileInfo chromium_bookmarks(config_root + "/chromium/Default/Bookmarks"); load_from_chromium(tree, chromium_bookmarks, parent); QFileInfo opera_bookmarks(config_root + "/opera/Bookmarks"); load_from_chromium(tree, opera_bookmarks, parent); QFileInfo google_chrome(config_root + "/google-chrome/Default/Bookmarks"); load_from_chromium(tree, google_chrome, parent); QString ff_config_root = env.value("HOME") + "/.mozilla/firefox/"; load_from_firefox(tree, ff_config_root, parent); load_from_opera12(tree, env.value("HOME") + "/.opera/bookmarks.adr", parent); } QStringList* BookmarkAction::GetPaths() { static QStringList* result = NULL; if (result) return result; result = new QStringList(); QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); QString config_root = env.value("XDG_CONFIG_HOME", env.value("HOME") + "/.config"); result->append(config_root + "/chromium/Default/Bookmarks"); result->append(config_root + "/opera/Bookmarks"); result->append(config_root + "/google-chrome/Default/Bookmarks"); result->append(env.value("HOME") + "/.opera/bookmarks.adr"); //TODO firefox path for bookmarks return result; } bool BookmarkAction::hasCornerIcon() { return true; } BookmarkAction::BookmarkAction(QString name, QUrl url, QString icon, QObject* parent): Action(parent) { this->name = name; this->url = url; this->icon = Cache::cached_icon(url); QFileInfo cached_icon(this->icon); if (!cached_icon.exists()) Cache::download_favicon(url, this->icon, this, icon); } void BookmarkAction::runAction() { QDesktopServices::openUrl(url); } QString BookmarkAction::getIcon() { static QString browser = IconFinder::FindIcon("internet-web-browser"); return browser; } QString BookmarkAction::getCornerIcon() { QFileInfo cached_icon(this->icon); //If the downloader managed to get an icon return it if (cached_icon.size() != 0) return this->icon; //Return the default icon return ""; } trabucco1.2/src/bookmarkaction.h0000644000175000017500000000236014157420215016100 0ustar salvosalvo/* This file is part of Trabucco. Trabucco is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Trabucco is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Trabucco. If not, see . Copyright (C) 2016 Salvo "LtWorf" Tomaselli */ #ifndef BOOKMARKACTION_H #define BOOKMARKACTION_H #include #include #include #include "action.h" #include "btree.h" class BookmarkAction: public Action { public: BookmarkAction(QString name, QUrl url, QString icon, QObject* parent=NULL); static void LoadBookmarkActions(BTree*, QObject* parent=NULL); static QStringList* GetPaths(); public slots: virtual void runAction(); virtual QString getIcon(); virtual bool hasCornerIcon(); virtual QString getCornerIcon(); private: QUrl url; }; #endif // BOOKMARKACTION_H trabucco1.2/src/cache.cpp0000644000175000017500000000444014157420215014474 0ustar salvosalvo/* This file is part of Trabucco. Trabucco is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Trabucco is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Trabucco. If not, see . Copyright (C) 2016 Salvo "LtWorf" Tomaselli */ #include #include #include #include #include #include "cache.h" #include "downloader.h" /** * @brief Cache::create_cache_dir * * Make sure that the cache directory exists. */ void Cache::create_cache_dir() { QString cache_path = QStandardPaths::writableLocation(QStandardPaths::CacheLocation); QDir dir; if (!dir.exists(cache_path)) { dir.mkdir(cache_path); } } /** * @brief Create an hash path to store the favicon of a website * @param favicon * @return */ QString Cache::cached_icon(QUrl url) { url.setPath("/favicon.ico"); url.setQuery(""); QByteArray hash = QCryptographicHash::hash( url.toString().toLatin1(), QCryptographicHash::Md5 ); QString cache_dir = QStandardPaths::writableLocation(QStandardPaths::CacheLocation); return cache_dir + "/" + hash.toHex(); } void Cache::download_favicon(QUrl url, QString destination, QObject* parent, QString default_icon) { url.setQuery(""); //Create empty destination file QFile cache(destination); cache.open(QIODevice::WriteOnly); cache.close(); QStringList icons; //The icon indicated in the bookmark if (default_icon.size() != 0 && ! default_icon.startsWith("blob:")) { icons.append(default_icon); } url.setPath("//apple-touch-icon.png"); icons.append(url.toString()); url.setPath("/favicon.ico"); icons.append(url.toString()); //Setting this as parent to free the memory of it new Downloader(icons, destination, parent); } trabucco1.2/src/searchaction.h0000644000175000017500000000263114157420215015541 0ustar salvosalvo/* This file is part of Trabucco. Trabucco is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Trabucco is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Trabucco. If not, see . Copyright (C) 2016 Salvo "LtWorf" Tomaselli */ #ifndef SEARCHACTION_H #define SEARCHACTION_H #include #include #include #include "action.h" #include "btree.h" class SearchAction: public Action { public: static QList LoadFile(QString file, QObject* parent=NULL); static void LoadSearchActions(BTree*, QObject* parent=NULL); static QStringList* GetPaths(); bool mustShow(); public slots: virtual bool isPrefix(); virtual QString getIcon(); virtual void runAction(QString); virtual bool hasCornerIcon(); virtual QString getCornerIcon(); private: SearchAction(QString name, QString query, bool hidden, QObject* parent=NULL); QString query; QString hidden; bool show; }; #endif // SEARCHACTION_H trabucco1.2/src/desktopaction.cpp0000644000175000017500000001362614157420215016306 0ustar salvosalvo/* This file is part of Trabucco. Trabucco is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Trabucco is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Trabucco. If not, see . Copyright (C) 2016 Salvo "LtWorf" Tomaselli Copyright (C) 2016 Giuseppe Bilotta */ #include #include #include #include #include #include #include "desktopaction.h" #include "iconfinder.h" /** * @brief DesktopAction::clear_action * * Removes the placeholders for the command line parameters. */ void DesktopAction::clear_action() { static const char * substitutions[] = { "%f", "%F", "%u", "%U", "%d", "%D", "%n", "%N", "%i", "%k", "%v", "%m", }; this->action = this->action.replace("%c", this->name); for (unsigned int i=0; i< sizeof(substitutions)/sizeof(int*); i++) { this->action = this->action.replace(substitutions[i],""); } } DesktopAction::DesktopAction(QString file, QObject *parent): Action(parent) { QSettings settings(file, QSettings::IniFormat); settings.setIniCodec("UTF-8"); this->name = settings.value("Desktop Entry/Name","").toString(); this->icon = settings.value("Desktop Entry/Icon","").toString(); this->action = settings.value("Desktop Entry/Exec","").toString(); this->terminal = settings.value("Desktop Entry/Terminal","false").toBool(); this->clear_action(); this->show = true; //Determine wheter to show it if (settings.value("Desktop Entry/NoDisplay","false").toBool()) { this->show = false; } //Show/hide depending on the DE being used QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); QStringList xdg_current_desktop = env.value("XDG_CURRENT_DESKTOP","").split(":"); QSet desktop_environments = QSet( xdg_current_desktop.begin(), xdg_current_desktop.end() ); QStringList not_show_list = settings.value("Desktop Entry/NotShowIn","").toString().split(":"); QSet not_show = QSet( not_show_list.begin(), not_show_list.end() ); QStringList show_list = settings.value("Desktop Entry/OnlyShowIn","").toString().split(":"); QSet show_in = QSet( show_list.begin(), show_list.end() ); desktop_environments.remove(""); not_show.remove(""); show_in.remove(""); int show_in_c = show_in.size(); if (not_show.size()) { not_show.intersect(desktop_environments); if (not_show.size() != 0) { this->show = false; } } if (show_in_c) { show_in.subtract(desktop_environments); if (show_in_c == show_in.size()) { this->show = false; } } if (settings.value("Desktop Entry/Hidden", "false").toBool()) { this->show = false; } } bool DesktopAction::mustShow() { return this->show; } void DesktopAction::runAction() { printf("%s\n", this->action.toStdString().c_str()); if (!this->terminal) { QProcess::startDetached(this->action); } else { QProcess::startDetached("x-terminal-emulator -e " + this->action); } } QString DesktopAction::getIcon() { if (!this->cached_icon) { this->cached_icon_path = IconFinder::FindIcon(this->icon); this->cached_icon = true; } return this->cached_icon_path; } static void iterate_dir(BTree* tree, QString dir, QObject* parent) { // Include subdirectories and follow links QDirIterator i(dir, QDirIterator::Subdirectories | QDirIterator::FollowSymlinks); while (i.hasNext()) { QString path = i.next(); if (!path.endsWith(".desktop")) { continue; } QFileInfo info(path); if (info.isFile() && info.isReadable()) { DesktopAction * action = new DesktopAction(path, parent); if (!action->mustShow() || !tree->add(action)) delete action; } } } // Following the freedesktop.org specification, we look for applications in the // `applications` subdirectory of: // $XDG_DATA_HOME (which defaults to `$HOME/.local/share`), // and all components of $XDG_DATA_DIRS (a colon-separated list of paths // that defaults to `/usr/local/share/:/usr/share/`) static const QString xdg_data_dirs_default = "/usr/local/share/:/usr/share/"; /** * @brief DesktopAction::GetPaths * @return the list of paths containing .desktop files */ QStringList* DesktopAction::GetPaths() { static QStringList* result = NULL; if (result) return result; QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); QStringList xdg_data_dirs = env.value("XDG_DATA_DIRS", xdg_data_dirs_default).split(":"); // put user's data dir before the system ones xdg_data_dirs.prepend(env.value("XDG_DATA_HOME", QDir::homePath() + "/.local/share/")); result = new QStringList(); QStringListIterator i(xdg_data_dirs); while (i.hasNext()) { result->append(i.next() + "/applications"); } result->removeDuplicates(); return result; } /** * @brief DesktopAction::LoadDesktopActions * @return a stack containing Action for all the .desktop files */ void DesktopAction::LoadDesktopActions(BTree* tree, QObject *parent) { QStringListIterator i(*DesktopAction::GetPaths()); while (i.hasNext()) { iterate_dir(tree, i.next(), parent); } } trabucco1.2/src/singleinstance.h0000644000175000017500000000033114157420215016077 0ustar salvosalvo#ifndef SINGLEINSTANCE_H #define SINGLEINSTANCE_H typedef enum { SYSTEM, SESSION, } scope_t; class SingleInstance { public: static bool unique(QString key, scope_t scope); }; #endif // SINGLEINSTANCE_H trabucco1.2/src/searchaction.cpp0000644000175000017500000001124414157420215016074 0ustar salvosalvo/* This file is part of Trabucco. Trabucco is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Trabucco is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Trabucco. If not, see . Copyright (C) 2016 Salvo "LtWorf" Tomaselli */ #include "searchaction.h" #include #include #include #include #include #include #include "cache.h" #include "iconfinder.h" static QString get_url(QString action, QString query) { action.replace("\\{@}", QUrl::toPercentEncoding(query)); return action; } SearchAction::SearchAction(QString name, QString query, bool hidden, QObject *parent): Action(parent) { this->name = name + ":"; this->action = query; this->show = ! hidden; //Hide invalid entries if (!name.size() || !query.size()) this->show = false; if (this->show == false) return; QUrl url = get_url(this->action, ""); this->icon = Cache::cached_icon(url); QFileInfo cached_icon(this->icon); if (!cached_icon.exists()) Cache::download_favicon(url, this->icon, this); } QList SearchAction::LoadFile(QString file, QObject* parent) { QList r; QSettings settings(file, QSettings::IniFormat); QString charset = settings.value("Desktop Entry/Charset", "").toString(); if (charset == "") charset = "UTF-8"; settings.setIniCodec(charset.toStdString().c_str()); //Some validation { QString type = settings.value("Desktop Entry/Type","").toString(); if (type != "Service") return r; } QString query = settings.value("Desktop Entry/Query","").toString(); bool hidden = settings.value("Desktop Entry/Hidden","").toBool(); QStringList keys = settings.value("Desktop Entry/Keys","").toStringList(); for (int i = 0; i < keys.size(); i++) { SearchAction* action = new SearchAction(keys.at(i), query, hidden, parent); r.append(action); } return r; } QStringList* SearchAction::GetPaths() { static QStringList* result = NULL; if (result) return result; QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); result = new QStringList(); result->append("/usr/share/kservices5/searchproviders/"); if (env.contains("HOME")) { QString home = env.value("HOME"); QString xdg_data_home = env.value("XDG_DATA_HOME", home + "/.local/share/"); result->append(home + "/.kde/share/kde4/services/searchproviders"); result->append(xdg_data_home + "/kservices5/searchproviders"); } return result; } //TODO de-duplicate this code with the one in desktopaction.cpp static void iterate_dir(BTree* tree, QString dir, QObject* parent) { // Include subdirectories and follow links QDirIterator i(dir, QDirIterator::Subdirectories | QDirIterator::FollowSymlinks); while (i.hasNext()) { QString path = i.next(); if (!path.endsWith(".desktop")) { continue; } QFileInfo info(path); if (info.isFile() && info.isReadable()) { QList actions = SearchAction::LoadFile(path, parent); for (int i=0; i < actions.size(); i++) { SearchAction* action = actions.at(i); if (!action->mustShow() || !tree->add(action)) delete action; } } } } bool SearchAction::mustShow() { return this->show; } void SearchAction::LoadSearchActions(BTree* tree, QObject *parent) { QStringListIterator i(*SearchAction::GetPaths()); while (i.hasNext()) { iterate_dir(tree, i.next(), parent); } } bool SearchAction::isPrefix() { return true; } bool SearchAction::hasCornerIcon() { return true; } QString SearchAction::getCornerIcon() { QFileInfo cached_icon(this->icon); //If the downloader managed to get an icon return it if (cached_icon.size() != 0) return this->icon; //Return the default icon return ""; } QString SearchAction::getIcon() { static QString browser = IconFinder::FindIcon("internet-web-browser"); return browser; } void SearchAction::runAction(QString query) { QDesktopServices::openUrl(get_url(this->action, query)); } trabucco1.2/src/main.cpp0000644000175000017500000000614214157420215014356 0ustar salvosalvo/* This file is part of Trabucco. Trabucco is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Trabucco is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Trabucco. If not, see . Copyright (C) 2016 Salvo "LtWorf" Tomaselli Copyright (C) 2016 Giuseppe Bilotta */ #include #include #include #include #include #include #include "cache.h" #include "clipboard.h" #include "iconfinder.h" #include "tree.h" #include "shortcutactivator.h" #include "settings.h" #include "singleinstance.h" int main(int argc, char *argv[]) { QApplication app(argc, argv); app.setApplicationName("Trabucco"); app.setOrganizationDomain("SiegeSoftware"); bool wait = argc == 2 && QString(argv[1]) == "--wait"; QString icon_path = IconFinder::FindIcon("trabucco"); QSystemTrayIcon tray; tray.setIcon(QIcon(icon_path)); tray.show(); //Ensure unique instance, but allow for previous self to die if (!SingleInstance::unique("trabucco", SESSION)) { int retry = wait ? 30 : 0; while (retry > 0) { qDebug() << "wait.."; if (SingleInstance::unique("trabucco", SESSION)) { goto is_unique; } retry--; sleep(1); } qDebug() << "Already running"; tray.showMessage("Trabucco","Trabucco is already running.", QSystemTrayIcon::Warning, 4000); return 1; } is_unique: Cache::create_cache_dir(); Tree t; ShortcutActivator shortcut; Settings settings; Clipboard clipboard; QQmlApplicationEngine engine; engine.rootContext()->setContextProperty("clipboard", &clipboard); engine.rootContext()->setContextProperty("tree", &t); engine.rootContext()->setContextProperty("ShortcutX11", &shortcut); engine.rootContext()->setContextProperty("trabucco_icon", QVariant::fromValue("file://" + icon_path)); qmlRegisterType("trabucco.siegesoftware", 1, 0, "Action"); engine.load(QUrl(QStringLiteral("qrc:/main.qml"))); Settings::connect( &tray, &QSystemTrayIcon::activated, &settings, &Settings::show ); Settings::connect( &shortcut, &ShortcutActivator::grab_failed, &settings, &Settings::grab_error ); shortcut.start(); tray.showMessage("Trabucco","Trabucco is running. Press " + shortcut.shortcut_name(), QSystemTrayIcon::Information, 2000); int r = app.exec(); if (r == CONFIG_RELOAD) { QStringList args; args.append("--wait"); QProcess::startDetached(QApplication::applicationFilePath(), args); } return r; } trabucco1.2/src/node.h0000644000175000017500000000211414157420215014017 0ustar salvosalvo/* This file is part of Trabucco. Trabucco is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Trabucco is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Trabucco. If not, see . Copyright (C) 2016 Salvo "LtWorf" Tomaselli */ #ifndef NODE_H #define NODE_H #include #include #include #include "action.h" class Node { public: Node(); Node(Action* action); ~Node(); void add(Action* action); Action * search(QString prefix); private: QHash hash; Action * action=NULL; void add(Action* action, QString name); Action * _search(QString prefix); }; #endif // NODE_H trabucco1.2/src/tree.h0000644000175000017500000000250114157420215014031 0ustar salvosalvo/* This file is part of Trabucco. Trabucco is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Trabucco is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Trabucco. If not, see . Copyright (C) 2016 Salvo "LtWorf" Tomaselli Copyright (C) 2016 Giuseppe Bilotta */ #ifndef TREE_H #define TREE_H #include #include #include #include "desktopaction.h" #include "action.h" #include "node.h" class Tree : public QObject { Q_OBJECT public: explicit Tree(QObject *parent = 0); public slots: Action * search(QString prefix); void runAction(); void rescan(); private: bool ready = false; bool bookmarks; bool desktop; bool searchprovider; bool ynew; QObject* action_parent = NULL; Action * last = NULL; QString last_prefix; Node * node = NULL; QFileSystemWatcher watcher; }; #endif // TREE_H trabucco1.2/src/btree.cpp0000644000175000017500000000265314157420215014536 0ustar salvosalvo/* This file is part of Trabucco. Trabucco is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Trabucco is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Trabucco. If not, see . Copyright (C) 2016 Salvo "LtWorf" Tomaselli */ #include "btree.h" BTree::BTree(QObject *parent) : QObject(parent) {} Action* BTree::getAction() { return action; } BTree* BTree::getLeft() { return left; } BTree* BTree::getRight() { return right; } bool BTree::add(Action* action) { if (!this->action) { this->action = action; return true; } else if (this->action->getName() == action->getName()) { //Avoid duplicates return false; } bool go_left = action->getName().compare(this->action->getName(), Qt::CaseInsensitive) < 0; if (go_left && !left) left = new BTree(this); else if (!go_left && !right) right = new BTree(this); if (go_left) return left->add(action); else return right->add(action); } trabucco1.2/src/action.h0000644000175000017500000000247614157420215014362 0ustar salvosalvo/* This file is part of Trabucco. Trabucco is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Trabucco is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Trabucco. If not, see . Copyright (C) 2016 Salvo "LtWorf" Tomaselli Copyright (C) 2016 Giuseppe Bilotta */ #ifndef ACTION_H #define ACTION_H #include #include class Action : public QObject { Q_OBJECT public: explicit Action(QObject * parent=NULL); explicit Action(QString name, QString action, QString icon, QObject * parent=NULL); signals: public slots: QString getName(); QString getAction(); virtual QString getIcon(); virtual void runAction(); virtual void runAction(QString); virtual bool hasCornerIcon(); virtual bool isPrefix(); virtual QString getCornerIcon(); protected: QString name; QString action; QString icon; }; #endif // ACTION_H trabucco1.2/src/action.cpp0000644000175000017500000000303214157420215014702 0ustar salvosalvo/* This file is part of Trabucco. Trabucco is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Trabucco is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Trabucco. If not, see . Copyright (C) 2016 Salvo "LtWorf" Tomaselli Copyright (C) 2016 Giuseppe Bilotta */ #include "action.h" #include Action::Action(QObject *parent) : QObject(parent) { QQmlEngine::setObjectOwnership( this, QQmlEngine::CppOwnership ); } Action::Action(QString name, QString action, QString icon, QObject *parent): QObject(parent) { QQmlEngine::setObjectOwnership( this, QQmlEngine::CppOwnership ); this->name = name; this->action = action; this->icon = icon; } QString Action::getName() { return this->name; } QString Action::getAction() { return this->action; } QString Action::getIcon() { return this->icon; } QString Action::getCornerIcon() { return ""; } bool Action::hasCornerIcon() { return false; } bool Action::isPrefix() { return false; } void Action::runAction() {} void Action::runAction(QString /* unused */) {} trabucco1.2/src/node.cpp0000644000175000017500000000370514157420215014361 0ustar salvosalvo/* This file is part of Trabucco. Trabucco is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Trabucco is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Trabucco. If not, see . Copyright (C) 2016 Salvo "LtWorf" Tomaselli */ #include "node.h" #include Node::Node() { this->action = NULL; } Node::Node(Action* action) { this->action = action; } void Node::add(Action *action) { this->add(action,action->getName().toLower()); } Node::~Node() { QHashIterator i(this->hash); while (i.hasNext()) { i.next(); delete i.value(); } } void Node::add(Action *action, QString name) { if (name.length()==0) { return; } Node * n; if (this->hash.contains(name[0])) { n = hash[name[0]]; } else { n = new Node(action->isPrefix() && name.size()!=1? NULL:action); hash.insert(name[0], n); } if (!this->action && !action->isPrefix()) this->action = action; n->add(action,name.right(name.length() - 1)); } Action * Node::search(QString prefix) { return this->_search(prefix.toLower()); } Action * Node::_search(QString prefix) { Action * result = this->action; if (result && result->isPrefix() && prefix.length()) return result; if (prefix.length() && hash.contains(prefix[0])) { Node * n = hash.value(prefix[0]); result = n->_search(prefix.right(prefix.length() - 1)); } else if (prefix.length()) { result = NULL; } return result; }