ukui-notebook/0000755000175000017500000000000014201141222012256 5ustar fengfengukui-notebook/AUTHORS0000644000175000017500000000014314201140431013325 0ustar fengfengukui-notebook authors ------------------ lixin yueshuai ukui-notebook/.gitignore0000644000175000017500000000161614201136534014264 0ustar fengfeng# C++ objects and libs *.slo *.lo *.o *.a *.la *.lai *.so *.so.* *.dll *.dylib # Qt-es object_script.*.Release object_script.*.Debug *_plugin_import.cpp /.qmake.cache /.qmake.stash *.pro.user *.pro.user.* *.qbs.user *.qbs.user.* *.moc moc_*.cpp moc_*.h qrc_*.cpp ui_*.h *.qmlc *.jsc Makefile* *build-* *.qm *.prl # Qt unit tests target_wrapper.* # QtCreator *.autosave # QtCreator Qml *.qmlproject.user *.qmlproject.user.* # QtCreator CMake CMakeLists.txt.user* # QtCreator 4.8< compilation database compile_commands.json # QtCreator local machine specific files for imported projects *creator.user* # VSCode .vscode .VSCode* # build build build-* #doc doc #vscode .vscode #debian debian/files debian/.debhelper debian/ukui-notebook debian/*.debhelper.log debian/*.substvars /src/ukui-notebook /uNoteDbusServer/note_adaptor.* /uNoteDbusServer/note_interface.* /uNoteDbusServer/ukui-notebook-serverukui-notebook/data/0000755000175000017500000000000014201140431013170 5ustar fengfengukui-notebook/data/org.ukui.note.conf0000644000175000017500000000124314174170620016562 0ustar fengfeng ukui-notebook/data/ukui-notebook/0000755000175000017500000000000014201136534015774 5ustar fengfengukui-notebook/data/ukui-notebook/en_US/0000755000175000017500000000000014201136534017005 5ustar fengfengukui-notebook/data/ukui-notebook/en_US/image/0000755000175000017500000000000014201136534020067 5ustar fengfengukui-notebook/data/ukui-notebook/en_US/image/2.png0000644000175000017500000025015414201136534020745 0ustar fengfengPNG  IHDR]usBITO pHYs+ IDATx{mUcε{jn!6$DA , #DH(BF8"Ze*PA(PZ TlTN<@ H Iyךs1dugz17_bdD?fbd"孲?W/[o2wpA$-ѝs_1פۣ9tۙ,JPѓ"mm%LE袟F,Ih q/z6mq';YqJvwCIwn&s͐$R-V\#+|8LqCzGĉV?Y^/B)sat @h&#2 6p5Q' 2et@bՐb lLX#NVNDSW40[p2h-%'(%-pzB^??Zz׮ 8# 5pP@i`JVDTC#!pBDbu4|$$]?׳jhuר5G @y+/pQ#HٕW7@\hxճ|ߩ54cqWP"]4DtIJ:>aT/Fj9h4fAcgZI#p..K}C#Zx={7gr&8dLLug". DaR,N+%C4:E&B^A$B ttApSzaI^BvSQFp:CW54Da MdCK/5唔X|jRb\eZ@S1mA0E,,qXN zj b_6`)7GK.䖆\h( z!V+N6$z5xLFrHw{U;. 5|q=p]"{WxBLDkvK׈v;3Owe͞.!c *4KF=8I'y"5 訸ty %"& 긥27qb"bã8$d`e%.9HpP &`!Y!J0 2cw՟dS]{zPĊpCd'2 ʎ JNj .Qʔ^Cif! qbWx";$E ZT@x1(L&,:JP9~_m6|qB @_c6F !'vq.[ vś;hݔ9JFW9J h@ "-5Ϫpwژckj5 Z]ܸX8p tU4aDT#O\޻BPHَ W\g!R pGUe逘+ QBz!⎃+PY h 2J\nn>u-D VKIW4_01q8qC2t,aɲc^`r&8bF_.mmdA#}bQkg;0w@T&,-*Sk8CNx X (3cUA38L,Lc% tìZӸRkFᕓ/.`(l_`欌Kev>\_4,m.+P׼l}P4o&P !"%}1P2t Xڶ7 sq_;)}dAfj6ٴw6V׈%x \V9L]ɝID4#n!#à|6MQe08%Ocld0m\wH!dQQ\50 rbcIȒyLYA✥DA2QmɁY]B3PϻcX u(L" qGJ+D ː(:n ܥ26Up`}q 4s2 T{+YNCμekÒ jZ_֞\YVZjj'm-؊[xV/5!wHk"~Y-0^xG(B/t4-iirjBCNݗ0; 9T@0 Bww\+ʽsrH]Mp[ǘ >ԠD+@=Gtfu1mvwiTvy*phd9С]ݹ$JHC=b~{`cM[518pc`тK6 \0#RV7Mv Έ*{'IrtDEqQ0qbd"{KQ7&^hbS &`!GCx>zGxʶ.A*'삇(\*V /P eQ&. dRPCWbXLK +W2ҵh3 LW29BobP!;)T9\ wԐ"a-KuC8Bya&cr Aƅiw`Z6U d%9AP". Dža(*rhRNX:t )4 R"!׵A?EHDJI(~aAw9"MV"~eXdͥZ'K#YsXX|ӗ1WPzÕfĂ*S ̒ZRz$l8ԍEF{T_̣ɩ1H^%ӣ̀P'As!c1I@U螃`!dh#ʰ& u)g`fFJt,3}nAu򰖰+NSWer  pYT@׉z,9!u O |P0anth|& b;3\8Yhͣ ZV j L*pB #,l3ЪerZ#xb[I}~a-`]+MW?R㚦-&"JBj+r< ~ RB!9Tf}/x|PQJ]WU:"{[g^3yf,"哊3C&p-lrB`h1 +ԝYN7*{a޹"rN>rLG[_pM0V!kD$n \ѥEY.PKU^HzO"ydg =sǬeVޱ$ *jf- PnbfT5Sh&!a;)!| U2I DZgl%V[d+RSHꎽfX(ZHp܅p.3;*x B0PmͰx5skiiqZ]x-# 6կ6ʉU'G:ŋdԶ,H=҇[ne-~9ś^iie4]\MbFbܽk>Nr@ dǂ9#,K!Ft`WwYo̜b#n SIQUV#Z;3D$bwBt,62+X)BpjdI-SUM[& C:d0Q:EaZ U*$&K4+RSr`;"8|e᝵;hAXLƳ!!MP*݈ x(L(ǪrnXW"6\Q& % 6􀙵#KMT7.:G2" cGi5(|U ֓5vJn3! =ZpUX[žb>/Xڢn>4A0@*)N^T/*ອoq-,CED5N/<0yOv[V(߱2ܙ"N&Fr|ڙmIsU`>ElMIqk|qٳĢd /ԫ-xDdH1,FbF"~$\vYwT:&k I}?4#R@}p8KgQ+٧ۋ>@>b{: J1R,o2b)5|UJLEU $?TPB-[J Ƃ7*1qEK ˾@_q_\ȨKTy.-F|Á3RʨXHPPBVþU=,J4^W} I1oFzݻ!u}{Eţtv]|i?@ube.# .'-n_q¼9ҥ`pDgGuxZ.c"} CJJzV3  &xW)1C'!!lpOd0/Eõxp)b;0LUeAP"05'솽E؉EDPj+dddR%*G#5 `A #@c##&uR =֨Gړb޺z%w.*oOִM^'v* {2M4E&H ˞OZk~au 9٫cQ#n5nnrBa,wv:JWlc{i7k8[}f4uiQ/_o_$C+1I=0ǴLHED Y 1SzuSvwDrͳe;xܧ<9Aqk:?- Ĭ5Y.AW $e(dG *ޟ*seFX ȇX|fnC`PxXWmnfĆȅ>5u&^ Z&uSd;>3a$ڭ%NM[M+I*9B. IWA% 9TH5VXV7ۖ*̜V3Or `)5xk*P8klx^&{:JULJզcC˶ -p㆏|]oyx>{ 8r}s#=ۧ>P|g^ Ư;LIS\+{g.?{.Hx˃sϯ~>ug߾=>5K_ܳ"AQ!3W|v~nx؟ ,r]>xL;A,&)˔XvgpM,NOWe)7N|~7TZ'b4@Vl3呣y >Ů"Ґ.BΈ {=S%V'*a|Át+`—iEp:Ў-\iZϱL M9@tpzsΜv2ܔpnH_:ҙ*`NVF3*&&Xt$4U Jd!hET= )&iu-\#*A~Vx~qL +ۏšeI,K+d*&2(@S{\1T &0~ L؀,z: nG)788 o3u}w6?vašCݵ7N--#{{z믖;&7}|7㓏??Ur'#O\uwO8s䡓?>w"SC+v#߿UG;yU/?'wƪ#@shUṬ] xfZIyّ`{+\Mm׻ZW% FԪ $AMXZ@ cU7w%=@d8:aXOudV[{:Q "t 4-隴AUSmN g5AJA0d*dMxHMd+i }ɞJ hhQj.6S3sm=Ea_,뭂eP#(Թbd)p#pXx&iVҹR.Ճ;i*Pe}fVOOHj___ho%RX|qc8sΟ^?Wn'>ɧ}(?#lnoƗLG$.w_P])ïog]}#;,'6^M.5ARO^o~Whjc~(rx GްeX;6w҈Hy>=n+N*a"cwF0zG0#G9:&Xܯв>].e}AYx+;/~⿩oyy1~ϟkk뾙_}_|._03od3^tnuz2,=0ZkF~7@1s$ܙW##C[%+ *tSǍ c ̖³bNLe3Db#LaHSUF֎;J0Ɇ*c#bbTG܉`l- te Ɠp4sc׉X. .0$U.eeZT"#;{4G*ȁ0TjPv3@end$"΋/[g_z'2M wq9zo{+>ƛ(~;e+G:~xKn567ÏmOS~P]PMw?q~BD_n}*'$v9Q5it,_}{C^gQ;Vνޡw6Ltƍ6]%S;V^2 Of1xĕ #2^WV q|sL[J*V"z#YI0rO` ![ ^)B蔙3i8"e7VLIhf"/ ]bpdD&;tKHXFzHj l@AٱI%sW!Е$+` #\I;IH@eB4d:J! tP:AbKҾm_xVSl>[)Z_k l#/]I\c ]K}||O>qo>]67/<} ?Ox]|<.V~#g.gU蒢cr4.Ԋ&US]ё0>91Ve%#97d~ț;2Kɵu?}s}@`b{6W2CֆfB6锡6MLle6腹sq. \Yq,Zq|6~ Ya0;}(}z j [b ֋qk+%0ﱹ}/;pI_ï.~M{vW]Ç?^|9oGN"'_1_~SS-pwA#xw #ɰ%+$U[z-Z7կ/mzȹ/nʣۚ-pa P 'jbBM`ۡm0~6XMf ]M!J+W e`+G:,.QRej P.3l GG66aޱLƎsŹ6pe`gBH~D5INs=|l[6|9B@GB,S{=.aK,a DNxŒhM}a ʍBFf#L>iF Uaku 4~"J^ `XEYJ=ܤxCH6%i__x=t~?84y/[-n KRp oox[y1~aiט>МQNt}~םu'/^M?P Ȼx'.Oş0"y |X^aȣW""d.3O"tWeLA$WɅ{u[; UcZ <7"Ꭵi:a(~  SЕ>K12 tiᯍ2 5 ,@[܄ybK9Yq[fLal8%.-H2&SlVV9qvڝDZ-tzR 5dL?Zovm|_er"Y\^A; V+wHh M887&`Rb *.($ֳ֕#ZuɅD]^8#.t$ c]S:;dte]C]֙EՔ`{g9˿| zg>{_OM'&^=ʇ{Y!nGx#Os*+0RDM9" UH:U؃ %G("3P(J(ܓQY90*s*¡ZU4"G'.n^3|~^CVx,ڵ^ZyfJĖA{zUB_:$UTE8Ptrd2r^jD+NN(QtfU`/[@rzuVh(dRTp]]83x2lEQPUy?B W[& ^7/IMXw8{eo5}y;{`|\?zw>2y/?#||۷ֿC_?:Bn@G鄍ÎmW7Wm4dC64y"4$ك?Tj`eeE0#$,b3,˼:Fxw'_Ev4XZtj!fŽlKG8!AeK:+bLd%_NIeY@T* kNEB1xqWd!rų|JsY8tig gWёX3@#(appp0CZE3!0ePVBߌ I"t B c` ,lmŷ3 Rg1\oyefok-쁷*uz }Ŗ% CUvKE:A6n@oƋqk(g2>kgz[;y/f>yO栿N$&m|jpӟ<;|mSοuvy[yyc<1N)z~{OFZ=4.bY !)A,<꼞~O\R{˻_7;""ZE{eRWYfE.bz)6;0hDan8%d$N y'h D<4aJ\|ڑDp@͈2> gjx2DĴGJDف=gLj׸dBPHxG J)Gl4L(.la2Yȵ *^HRh+N@( K0PƦҖ)N6RuEXedX N!#|֙;'`u,F-6&t$vl5[xL9~nS3)M(Kҍ~A bbnH OCyוje/>܁Z>+yp /הs~k7"KK0Y_?.~oW^q78rN?^T;ٌ;ZOc62]1X%|@:e*RJJuQvwB#h! )S~KH0Tס7ermD:983ea!V-HYB~qR3#Q#% 1Eʛ5 gT,֏aKߪ׮_^J_-AJƵ3}ݷvM0a>_dwȻn7y)^v~ѷgw!;M'_ϾGyK~]~[ӇX\%*2W E" ,ϸ!J`i!9w,Ldtxȴ/L#˰m 8cGrll?H阐 ޟVaӰX:g{?{F鄔U&\&8J0b&?`e>NP`dUmutμ;ܹjLsgfH&jbPM2MK2?Kw2`lD00:ydsKu)wр_١2퐲~H'Un@vB A$L֪jS1><0z]~|u4\{K%B+? 0+?X̮^myvhˏ瞿[Gt4Ut#QG+7?UOw?<.on8;bs?x{yOn߿+&E*?:{6Վ^{H(2wxO\©+a .^zWͮҗy+VPYROŀ*6F[uoݪ۟f֜1\9{s"Ss>\s5{1G9`1TuvkUh0a3:L{ nLO(7J yn^$m74Hjbr]$*IYi >[Bj-Z%sIPj- /PB%k:rA~**()'7dG085&V/'S)P4<=ܫ( ;K^M|S޼ZVMeO=OX'g?S\~y ~{7|с?OݯnU):Eټ^Wk%Q@#EIq =q_RBwI)V\<l{޶&/y/y%_xm/Go;KW~ݼPx{𶻸jo|\?kWXri=O}3$;{߸<׮Kn=p":$ I M hHhΪ_8LQUɛ=qF6l] jD=.PoPs$%:#I% 70-1+0dxNbU\֐#Uu=GkWCNӻYAɘ'6oQ*f,Lā* Gy$$*g5 4:@n97Gl'JhZ ekڍ55lcxx0~T[IۮL9QmHH3>"Y-2r;ޑКF ig+H1P{>h*a&a' RMap@DgB.kL3rG[(Ukee< * D4*aI3~nz4Ͽ_w< ?#Ν Oo/y}{νD`3oyύ͗޾'-?K~^r 'Mu-gO|]nGV1 }mAVn9lcB5@uѦD"[U:(U9wU]NkxotS $a%Sބ$ǚVGwBC/'Bm$9R[Ӏ 5cIWqޜ||L/w}9bwV?"-^@5!Fh` O9Eh[DڣcN^Xv̥5qmRk)KDz*ӎўHV PgܕL Hd u3B AaV;P !|~hqwE+DGtV<Ɗbgju1 Nqx穛]0;ۿwhK-;\?~}]V^>~_r|< y#?-3`4bۿ?G]˻= G"13{yl'N2*@c DR*"4σʺnVU2G7q'TXGT9Cr;V(ll~*~@#5pu:pCs+R2i4h< G 䁩8c$Fa.xC6+lĄzygܕV8˜amPx}̝;gI;[щKKo[䇳V_>ǭk{.'jZ߽GwkWT~s _|lo{o <&>oΣ6O=DIFF_>1|?1#M.W $ TV6y'{ X.bG<04<i 6P4hy@ZBd4r kl"1-KبY˔$WmНOs3Φ96jTH%4Ψ`΢!+!% T h[-iĝP XF#kdā1njH"F\kIvCi-5~DB8oa qLe¢pjx| k6G|, "CX@FE%3j"JT"P$X  əsY|1A#㲼W=:ݕrFEsC$gܾƓOғ\N" Ol>7zg#woğ ?/4wb>p;?ÿ>x^Nfo3O:"x:jekcM̳D4U| yķQ:Hã~|ZE:C3J ~aG3>ƒΊjU#Zٵ%uiN}M|Aہg'T4=j4\;ɾԢIj } 1vɀ\9&%ЊT*z*@Uc@OK99 TC21Z <[OGs9w3gз/h"xt5+ԑ4I'cO6k.%EAQOe8>WYVҲ Jmsf?1e~Nvni"sI5!=0:rxG#ciİꙔ% HO 4"#J;Bi %4-_x⎨D[8m ߩq&U ԘIb8cyu a?UEvgs\plJg?潧F;o~l]fINVlSe q8m]jetk-4昦 ɒ a42~Qa\L [je܈ ]MeWĀ SX` NR,zŽfk" OH.~$M,v|i-8{'ȑw^<&>f2! '}D#}͚[ xBh=#{*0pFӀ*3bf< "UBaFclE@*5Ѳcݖxma9H^W8d$}~кER s)RgѐPy"q < U$lϥI]g_>I!_QkLQU*=+[Xz_[Rlhч aS&ͭ"30D- ډtfv3^־mTȅ+ s sun[CbE.v* S-:fJ/?x_8p iDSRxwNo/H> nY MFG]ME=ZPzFeS9\ zבJ j䊔U;HI:#> 3PVԻ MKң;ID؉= O%o33BB"^O6qlzcbL4"BbvHjBUL!LȐuNឬq5ܟ t`+ ѹE`ODtx!6 P/ʅu(i+&J=-r9I+%w1׿KN}؊}_t=cm gDA+hH*H{Rd{~~LX$ێͪ6􈙪0o>2sJcxkβC{S&H6:m{6eyd%lÀFV辖Ad-+V=U P:2oN5^!8-PX{#t8ƣF|)>5?5w_." #yDѼⷩJNp  T*m!V9/'CnINc֢hZkp'#ݑR1VUr!ggITԹP-ן˙˚K.rbUIf3z}!|7FjP*yrGZ@ c@f0&FF雮9V )˨*#R.&7Oe\I;1̈6/u-JPbx-j5X6$֝V[P'uV/@[hJYpJRRyW*}BS˩j+yqTcB2*0wܙQyPIhkg3Dg!KȲDc6SYEpB8ƓC-E1څ:AE( 8ed?R.\ PKJm Z:@4̺rx2\HArE\Ro+'o^{ T~R 94AM"ؗCȩ=MGVӼq$֛helgJx4';  uGb)Z'*Q cY)JhvˆX-'Q _;ʑD3j2dM>bi+gLS[pT[uY#ŷ!DFEw+'SSڀt*sh;TD.h^i%5eϜ;59݁ "n\RD[~%vl7{ ӱ,r$OAP8 B>꒓$R|fLg1wKEdL<o<|Q+7货ݶ8o-Ԫ &k+"r IȺ!pCBPf=(hy)JȺ+Ohmo5GoNa0"4}Sg-P)+lKq)"O۶r`g4\A+}gE8 -P*ghJƤa:sd͔V'd\gJWr RMv(Y;s*&s\9]*rQ ǔqS!5+:Z#eF ++!ɪc2gabP_3fj`hYqfEK ]F(e")es&CFfgO(/gC'"9 ^?=)W h @qkf!{JLi=UH e{GJ;o8lUO+'8|p8>.RC=N6sy>=\&&z\0&l7eyV9f1!ĢkfhYR21l(Džo@d2w 8?O n;eraw\ :IӲiʏ8ѣD%j>ڼ D^6ݭw'ӷDI}$FH2 e$(iH쪬p86| `ć:Zcjs78E[fYjkq\>3x#&JXeN݊KDEfXIhFV3< ɃCZl(XAԔ0(JN4U<J!(xr4LI"&5h8WylW9G 3͙:8,C.t[c%T rDO'r3Qn/_(,ʠHRQD\z5[c=:lEHkPGR)"XAN̉C"+,҂1VD@x $j@bi)G \b2`A6Fy#J릗 ~R9鐃y-vTWʬ\U(0YvUzd24R9Mq0+vͩΒBrɉB #/Ts6p-q5ğL7¶ؒ T1n} 9?gWX3 *xS53#r0!APXXQhUAk L[S3'8Cz }:֊|6rUWD.GEeGtN] %(8RYF3* '81r'̎p=^j꡻1E$QE[ mG)2eX.'(U]6λ1Q/Z*1+ c+r&b=`VJ2N%rK0y[XT´ޅ:S~ۧpɞ]!k"It' M"޹NPE/*8IH B -. Ҷ`R"9X楃8-| JCG*Pd4BF4d\Ɯ =yDVUǶFV5= L%*Ȕj>cnJ!uEyɔo$EěJR[-/2KVJq\H\81R7uDC<^b XT|9)G41sf @w]&l"MTKME.aF_X(t攅}c)ldA."IRNF _u̦UʒTOilIk&!fb "3JQW&'XT-Ϟ,i-l 4 "I;V\JHI ԰h-f[ t?i2subԏb=d[r%͈S1NPvW1WTQ{#DFvgٓ|..Üф>`Kg|E 7m WMhEFaOsP1y"WSzpa/s3rvg%bM$LɅbiԂ%-%Bg]UܽiDH$QS޲M+H),iwH:ey2c*:/=̷b bN>8 Y I[ɘ\Vfh /A +Ss5&qԒWy*j^M;%siz$CN[5,EER+c̅tZ1ldhWpՔA-t/ Axia=rPh2tQXj6b!ju+?: s2f8:demJSDdao=17~g.٬q.3qW!vklR/|uC\آvݶ&xY#}cRcFM$H=@ 'tHFeWɶCWm)Ue!woOL iaTy +!lSWf>LY|(T-)(ZXl'bb+BEũָE8nC*Esңk z!4`|x\0^kKzD:Mu>jֹEJa*kRrdY6@,J쌙LW.u)2,MadbaB!˓vFqꓨs[O=k 6K)4 ԭq $ӽr h35&2>) S37fʎ;4f"@(RyzB%%$!8a0$)$ȥגVhW6*@d F'@/4(ApxRgVGLV-[3@%Ծ8q ʳZOkDICRH%1$ib ɪPewoFV*RN+TJ =gBt9EưV2rV4L|)`{TI OyKҁg¤~bKm)]?:z(mBaAƉ>X_?w B՘FHYq F>mrm5x4| UMdj1ϕt h bTŖ8̈>ωc+{[~Y _/'H[tk=CIpψzDRa9b؆ӒT\m" {j˜ssQ"1X].$!z[9 z28Y'*REpF7Y#W`n2 R.̸1,Y)^8)8P .xLf~Jϭ *?oj׀`-I1>sx@4A=ib>T@v\PmV;?{hJhA2%H ٹ gx wzLM~1'Dhm%G8C&+"l|bLaNJK$oaq؜h#9݌ u< q*IB`Ч q}b,fh%n\O' %@)85CXKR NUZ܄9,R QSz5˭0&3K2&rœ삃~(rAEթL_L.,d5iɰ>5Χ C]+=jsC[?z#lY.jء,cyD *e>U-}4.db6k;GZY+ȅ*ѷZ\?N*F5VAL.lHz:#6xlpP+uO`,NvJeRdaZWAQH{z^V|^K - 3.aO}a{z`:.(]$ 1eKTA\I+}%wg{#RT䠆 9j}Mnh j6xKkXJK3/U'm# qkhh!KnQ H eꄀFF ~H}b6ǝKH,.%|NXHF[zElVBcEDsw$?̅Ϋ1DžPaG/oCҘgqʌ< YnJ h ҈rȄ1"k5ǔguHT9U,"wOsѲ,"dsM"*:HVJ7t1A1 吚K,g 縉a2bZ8$x̃;u :il #/}RP0A$3b%],s&]}"= U˜9c$c0]=a9T-t[% {VwontB;ev' (373[ڑ)0eۓKOH͌]s33pDoyq6ympA.؈P(Edl=D4t͕jKZr)$&{*iޛ D/Oy9mnϜ=6,cg,JEda9 o7#n?W:kp̹-owq9gri3"jqӫ}z.3!LEqMbW,vhe_b~-a(,s٩}ϒ3i,}ݓR9W_B4\)cT9 %se,vfL+KnApUSj sF]U@Y]ְl[d;%QQ<ai١TѰP[eXmyE1)A=6H.&W0',0}HDuy*kc|2xW& s֕=v9Z.ݑvu/XkXG敿Ń,41qSO4w{ٻhN/r,GְGͅjK,l9'̱YYhFD&3w~ \r],2Y#y;S|lR_whvan,bAyv{x| 2&{Y޾dVeX!nCu,su۫= !_p}\B@H*ps%-zb<bGv2N~^u'ޏw`gsk-]6:ڂ'>ӠL.Sv*:2̝h]`~ռ߃C.05>{^aG+IJвZs,SK8 ͥ[ext_HMa K꼯& 8Y,sW?m~};'=~{}rEîm޶X5v*>&j7Hq;w+LCJ](tO4,T->eKn;2{=y yDSw]&A|,.e!s}{U!Rv OT\f/"F=!_AZ`D]}]0uU:4>NYlMm;1/8jfh)J3Slal˘wn0_b˪l=8pM1 Lʂ%y3˙_BesgP~pw~™;;LvٕT^,z"UorWѰ۠C4'! u}8f߃J\k0g^;kŵp/~H~?M4,~NԼrL.<ɀάI7]Zi5aW[]e/߿""BD+B'/-_ st`Z(M, +)~o[w7緽%_o|qo=W~'?ُ~﷽%߳ٹ}K/{Y?/|㷾Ӄ[/{S擞y7{3pϸڣZF~xx˟M?#~>[W՜hx;~7>ݒcy|Ӟre.u̵ۮ7U(/n?_~ g; pQW?O=__|/^'j.8 >g8r|<Y,\t73s;M_pdz_M<{rL_vޝ?֟w3gξ>;_|r{^\t¹|';{a7|[K>i4piϡ9s3{~(aFpIqi3/Y4ﵷ|o~RRx~C?mq]c&?z {}7AIytƣOMUG4G^ۺ7 ? !%"A@@,0@~@')*;P۹Hj vwT}Tڵ,+Jy+(,/+>FϘ|^A!{/z)1N9J|&nǟ<6^: esyub649r٢ޅZ&p8CG%%2_{s M{p8Ɓo_0.].UW5m=}9O9wGN))/G͜ oo~>zt(8rhvf.(vml҅Ky0-[zk[߬/)qG `÷+ uc\ߑyϯtOnrfMml! gAÆlXnśҳ1Ϝt:[L9Ѕ:юpkϿ -Z uCCfk"  0X4  8 0|`NB y32s=7?ur2>1ݳrOrMN;B||Lnīvt^~n.ק-]΋sgWTJ}mVVNTtԈa6MՋ7mڃ7駟?v$lZ={t0k=ztzaVI%%?8v/@y2go'o~T|L1GW~\Stt[M6jXZNxw-r( 3Ek~S_Ykնu||%4>Cl>a6OU j͊ klU?Hi;Inm>(( l-^bll̪o6p> (K~*+m䐕}ٕ^zYqŪu0!S}A;(Ki|koqGᄒwz޻ngx_??nŀ!op8b/=#2"b;3;@ؘz:uy.뫯WWTTN`dddll+]8?|C*G~ْޮM6:屇澴ȼp<3;>._?޽S5cߜ9Sa~y0N+c74jvȉ>Y //wy}gĎW|RM].|+1g<ک?S4w\6{У7ߤd};ȴ{q\ Ot:wn١cWw)_rnt\vȟw2%iBOh4Hސ W %3z!Ta{1! ^@ 8DIPi &[GBLU{kФwT i@n\ЇI+0v0 `N^|wu NZFuLm?wI1W_>;'DEGww{ &?6a w54? '+/?נQů.`yyGQ_|LVX^]x#7yVmRJ gx侖SJ/еw[,]zu>szxVdvϜ7mܔ'EJ{_U|uׁLzŅ#o/y/-n4`Ƕ2ګۮm;V1O>?ߨtկO<.8_@~}? iS_BWoI@9(a ׈PX  Z$")7 ^GzmDph9͚&<|][ԻYB ~tS9]Y[jN/4a݆{򱣙YNK t/r9$r& 1׫ r|orqdtnpظxI&=|QqIx?:3-_)} o,{g)d:]ˆhzFa xh 4q%< gjo-}ٯ^i{ڟʏk~" NL9i߶0b;vc0q'6ݤ.e%%% {;tL}z3O_wƮZqdz_x|&G 1ԉ,Uݔ#~Z%߻ygz냥?ظɣ6 IOAB)aD^*ٷ PP ( "B 58$TXFULb(1<=2"1~esbc^^ ?G^1&Ι9L{X8~l|7ѓgSfvpK?9W? 1Ͼm}mG,ݹkC6-Ktx{N_|/_,u\izo#7%f֓;F=46++qwsybm{￷e3dI`I?fǶ:8&yqzYn1Rm;1yo_ 4Gg?t蘪)UjGNTvOe1+E0B5^X$,D @) ,"$ w"4 N0IDxfV-gyCs5}{ɋ=W缿dKc-zift:/7@ΉSe啑QNs̨!\AG6U$ΏCgfqN)VLЧ[jќ&kh-[w*ʅ18EjҢ$**U_ `_n2y[36O=5}\umJJ.FGEl1=} _{_0{//_ã%9/,Zq}hfzzƫ g͈>|֭N:҉;3gW_3}z"e|>˵H~ޑ)) ^|esOwyז=i,{MEF5^ &>&PmI7vJi2`&-:߿|*gG6jDxAÆ;vɬ\+Z|S\|Oۇu\t&E/q=ŘQCzuܯOQ pPRrqϊ b;%4A򢬬@v-JJf_#3s 7lȈ^^^nOIWYO=n㦵Xg8tp-[=7hР?8Gu=s?5͵-= cAbg׾ 28˯;ϟ-͚%̟ڱ#'<2oÏߞ8Аss;0nmǏkn87b% ^ys^yk#2y_ gA?ed:YY,:wt~2v޳已K8gǮ#l|ې{Ə-߾i i fr <,~ojݮ̀!dsS޷yZ/ WsZW #$+_Hu#^-ifyE6񀗴~m)0$OuS5 l qØ3.B!Μ)$#*-;CiTu\[e6y( {݆-|z1_I4hG;͠>9VUO*e ;u㚟"o}Y>s ֪]ʰQù4-ۥ 5Y nRR@Wohtۤ~ovo7NQ\ VS݌AdHihZ T `60;^\@D e`< m6j3qSO6 ?TveF W%Ce,A]j"*=40UufHG ϴY7z@!kocAˠASzhR5 avD hdkjQ "D$)J  aQ5W5 4H!*%[f 1 œ!qO P5 Œb :#cu32D纆WQIjiA)R ɉҿS-\Tc^P/, V Z D=<;GiJ%1z0;3Q4j Tб&iQ55 Jn4Ymr]qy\TƨCL&Bk %_{R@E'n#@ #$&B`(H2mۨ;"})44A 2g:2Be0-ːAjB)UvVH-Gs4jjE`Q/ a'7,.XDXW'- %M)Zm#!Gob""F%!x%tSPPb̡R< h9 /j6/ 5P *z  k5lհXDI4u _ѭ+lB`9J6<C 4-=!je!,4!kB-tK,+(B<`AE7W @\aV倫`!F Խv'WصyMۃ~R)\+):0N2@ X@!3hքfD2]K]r_e( n HAE*NP' /0x}+]P)4(ȍCgA6 FeFt-!hiLzLPh0 BK$!&׈" `!TV/L` vBAH!~Foh_ ! FS<AX3mq*[h˯561L1gATE^]94:6xʠA[%A  TPB,"P,m[pNv0Je hUpuҚ.YcXMDj A.YԨk0Jn54ondRX@`8Vv/7Hlհy`o{ B>ZY=D'z%o& MÈ?&j*7;y6/}Ea凯5'(拷̜4}}PϮ=Dү}df4Y̘zyiyY`X[ykLC K~#=x!@9ד 27!B SQ',% 's yeX `cHEB@SIS, VDv'l?K@$սRB@CoT?`g|ȸf M*Av\m;~+fdtKmk٭ pr&Y= ؗqHlnVuYmÏ0Oi|E&x1 '6>C8Sٌ!E;zj:l iPrnFZ:g(.r}PG*)UDr ~jQNo' 2:A"@$pw/60 BJ2&KB@H)#B ۃQ5zշkș3);=c p\SW|7) w9]7މ,'7@f2̠AMF:LΡM`fZ \f h &@T}G6 xX51X GaQRDZ6_ WZJ96xfۆWȯ|s}"ck&=3bƭ'όp8V}kK5>uejP?~~wl۫{Wt|N)#"栠 c {oݭԧ^H1,ǰq=oA5sΫ@*4rR+k$mQ[:h5A57`D_f#"J=LK$'$BQ OO X `6:( _Iv}-~{ƭc&LE/h:1бuߟzܘQNK,zgk4٩eR"oӍQ"rt#S;zWNpݓΜ/Ah+fB(>P.Ч;޵ >PWr)>0jh =ѯzo?5> uנ\ .IxD c\`V B 7PQ*JD 3hgX/:v_I3Kf_`Cy$Cg Ns};.yYe?ǘ;wҸawk65kdws U+>>xBQyyŷk>$%9`2jx Њ$T!pT3#H}j F`nqPLsZ9uN0FA|nJ@ qDj@a@M½wnܸ!V)-"+8:Ji/eP\=궡#n{_Wʹ^ǩKͨ\è5 wul_.6jWPxH檯5ip۵Jiq5W7KKpl߱>?#䗡r f1pgDM1BIUA̧8PΕACpCa4X2DCuJþR  &shW?+Y_/e`AC%8:Rg?;܊C@Sk!p kf@2 2$[JF΂ '0b$k4/_ l]f4 Cq D x0 )$ L(GM@aH K^ Be{G(,:3j]~QQ9VK+Z&q2 6nYBE݆-72FFDT m)3+V دO!%Gcj9f?;uw޿ckt}5_.߿c/)D;DW3KGu1d V&ikDHWCj}(a-|d/4qA u @xs[ 07  HeM$IA$B K5,D Bh94ڴSq\O?1??Sx0}w w8r$@½w ޱ鋟0h@ Y/-iP? "q?<%wffɯx}澴ؗqH]nّ`iv<]͝3ީ-xb|jib!#2G74v] +u uqCb(@(V7!y 1JPRG@Ͼt޽|/Sv+5 mڴo4jp=[꛵iLI5@DBQ1i4a㦭ЅCLNڛq@9s">_6r͞D(;#%QYBGO>[=궡^asqftQO =JRITk(Md^ ĺ A n Bm"JX$HH P0@` F% Zr!DF J0Gm8w'Y0;G1 $OX{̟۵im^~-W-r3>R5kYӄCpSum;~ս~iəs۷N4w>=̜.w:u+({O>[=aV5@# ۍ$h7u2shlMMei+OB9$h0(B >4<P+(%`Ր. nlV ! )MYul5s{]8]~a9F64p j. 4&a~z%XF_鉏[0 IDAT,1H kn( 4 qBh@(5J(,6+ PAT "K!Z!i7O\R`Unx}Ց`2aݽLЧ[e6n|M-k,MP|AJM^spjh""Eh2]0 4N.}dCܟ>P7R:UOOCdXS35`U~Xt.nONuaIX$X%TՄ7a<׏cd,YhЎL_5\C 1Jg!@C"Ce AwNѤA dToz6 qЀ!hЧiz0` {8Hh$/l"(GɻP-2F}!GSPfh¹ݴQ @(# HP*@a;SP4gfg"EPB}kPU0A3%0e˻q vE\t$n >NJ\+QFm fdAfv0 BT00/ [w (Q&%FdP0Rq 7 r әf `btD"4ht+nag"$ b+,WX@@XENPH /@EJ$0 IL_" *"D0V~ Y3"Sl]!o|o`:h4ʠb JߚH@DM=xc 9ൃA,, X5 :Q] RDdAY%("c#I @/$d dzJSD'6!1ECHZ i`ҩ!|<IF:&#4ke љ<׌.@- t Ps>=2's]5`aXHxHѫ䫻DH^+$H7|V1fF G*m+J@Dh6:R_r 1F4dAčO~YV͸kYyA.AkwfxM ׂk">fP1ƂECr@  "$B@)j0'- J^945^G 3p䱄 @v 0.pL9v}vY!E 1H@ ӧTPx ,vPϳC` V"ur,e"%J 1")(РiYd 4@7l/4 vg \? ,Ҙ@& Z ]1brFFV$~/`a!T[@ADx-@U:k-"<G!%  Cy= Po$0fA,pX`˄mwyO}>^$o ,@Du .kYQZ"Jny֛'>}pݻS=ի͝o۞ѨalRR s:3'S>Α7?9k)Mޛqa?J(oXnd^ '9rҷ?/,P'*OԔkץe\MztK[~{!ztKPH4uYf5 ۰r-ov=1p ,p5(51>cvTAT&f\ "QQ"zq\ e`"  0H" PJ8pV(ęyQ۠T")sWh孶R1B栙izhѣouUU9š7o#׏S' II{tK3:yOpLQfu|I^{q;6'[/޸`6/>?w蛖5Ohпoi-'fsыym(a}7}7mimd巛C狕zu۴NھsҥVIMǏ'=Nnؼ7*-p u UlݾOhJlyժ3dWNQQ ))7JIǫr:]n-\k $#hP $4` Pgt:4Zr* yDRtc(@10/DzVN=6>Be/w#a 2@)$A6$ `kk/V.ר4А=}O Kh҈G=]xLѺە_7%}7C5DGH߹^:׶Nڱsͯ&tޙuD98aVvMKmsSQ;T ^{A^F rް#hX!ُYnz֮,Y1;/9zEbWj!USXxn߁l_ZW鬺eH͛wf߯sW|+/Mc@Jrγ`?N1c! G;œeJ ӭu>Z<3s^9IBGj'?PR Ux$vGĂسDT8A Z^"$b`zЩ+-L~BBJ"@{@, Jsj@b h!Э[zzvڱs/ҎrDJr<15אr\,!NdtTdAdAXwU5HLCZniNxN~4ѾMٜZRbmR Yl+ڸ`vZ#o6k);;tpVIMd<*gt~_߷?Mգ^?H߹76aO=Y8!g] n=daii3.zҷٽȳO?\r+̕9,;+O᠕Q`̯COB|#BC'uF kF ]aX؋`epX!0AA{W{wM%̐P-%H^"dfojd`X Wիۼy& 5lo((<[N#.],B/ Ξ-7K w+Yn;WI{_wHlֱM@@گ"&jhhԴKZwu}Qg3g@7+(hd[- &箮p`νkק4jX@fy6o|oY[cmms-n~&?wGAOW|W^Zˡ0j9 fmphm8H}^>҇; D fz "Eax!`6tPXJLB]aPH(h. ^@x? PwM7$50& %IB/PO°~W|MBF @νGd}1)IM [7%nwuni͛5iެnkڤ~6EЁLKmvWŤOW>HHkmZ'wrSf<Gаf-]Ff-UȚ g->k /0}֒ @Y>]ĖڴN.+g--9'_sPu-s5~ݵ;'JNn>*g xClStegfL|KM5u: 姶"#귆MЪs@ʯJ`A(ՑH 50JJ,q@(H Cp>*QQe I Y@#@mAZwlzd6FIdLU}fmҪ!˾| @ݺ׶NfAo9x87pV-#\: uFmb:nP.bVw-\`sސֿo}`ʭyE0!(S89rН#qUahѷ]wg-ؾP~=OזV8YN{]j:7>)j\Yy ^zS.2Zq ƌM|-֊kFA^TyOW(;J4 B@!܎b2.:#@ vA,ÂH t={=pA&bC.7 nǤ@&|<[  :O~kYs>|$m]/*XPXHs#m׾c{ A9wQL'3dVN^N0Q/rcfΝh{m}y.>)czCzOMk[ۺnMEby=+--ٲmwQlZ-rĉ*,wG:wy)GfiJ Ecf|v/V#Ah *=:Mh >OaD̟Ѽ7 y"hPfB<Ȫ`@0X`EpYBuPWbp U6 6MeH8GiUue H :,6n NʕkƍyX#cLzG =%5/0+f-}9*|/aa}(*rFu\*^oyj{rG]{רCȱnV*u?o}c{v`o8ga67pG~3͈eo2}Ž}zt@Yy]eeʹ/+t~7ゥo {3ulif>̩ѧgGmiY;&v2G޾w.nw6lR,`4d}wp P{ҧ1@q0aBB 63D 2 Vn/Qώ~ 8]f)980G)b!V]uh/,UMS0Ta W]ݨ짟--phOLf wNu@JR?mޱgﱱwݒֱO I鳖*^Zů,TJPrACe_+ݬFiF vh_KK׮uCZ%56ac۴N*(8zCg[V^q͛5ٴwJ}'@iYui6[ABN&q-;;ltۘ1'Z \yuimiHz#&#AsZBai1sA0 ,3yjΔڑk8qI9:.q@CdvhxlΧ)4fS:rLd 4ӯbjS^\hC@B2R_@/oLSn+ee@#`H!A7׌'Z ^q%jj9 /{;PB{\#pgR[4Y7OCHӧ5d(_Iٽ0Kl52Z5(>YHd"3KLgZSi_]̛p gR\ynhf`@S +1,`IL.gLy+`X`j8ޱp`(.G"{Nܭi )T:75iAxv(t/4mNZOdH{ k5;ҟ\/.f#mv=* SU- @Ie3 s=Quޅ<[.?J (U/<mЩ "NФ!i 2B@Wr="' ^>yhג[CCHz*А75Drsk7O4ԙuqCCxBδ,XM&=k($r#/ \ AQ(:F^:rQ jWv$sƣ?fYYւ![DBe뾠OʘE#[ȒgͪzNlJ_C>m v>l_Cwf0*IZs(@QS%LfyY*:ž2}nbH.Gcnoo\ܣ8`? mX;>ǝjvo_L|跋_4Xc2D7zDXB8iKZ"i#E%x!$dH鄆hZh "^j>ǡuhUGqЀW+@ U)h BfŜv*  v1j2(DŽJӬcDG+ۈiJF|vҸhN)ҾTEDȲ$rH4(|(s$ oD,8bEH`Y d/i+- V6irkW. UTfP4VB3rdY;9TAsW%qƍ,Ve2&ioTWbǔI\?¥j*\`/`־oO9A 1upTtfzLe޽ )IyZCrf&ZCt-"?|t2iu%XiI]Vf R`H4KNf-8i .hAC2 hZ#M$ k!- lc,g0eKJvFW I/ۣE̙/HiZ0(2B0x7X:sq'_i Cs"hZ4(⛚}@D MYǺɒ?2a{c͢FߢA-_ڌl[m&Q.Tю@.(jL4em`ewEYFWphQԒښ:-qLm*^ɯe: M?13_}eom۞144 ,YvѕW^bfϞeK㠤k]mǎ Ƌ\xI{5pe}3'yvw\ kn_ʍ?Yǟ7-S * y٥eOm{fp(tB!o-Szg& ][_{Vn+]xA^v7.{#IWX̛OIjirӒ@<~ZC&ݙZC&Z@Zp^kE&hlN6%B[B(! !4(Lm.&mf01pݘ%rp)DF(ow( lpfB {s?񑝟(Ѹ@-x S;wNRyhb;ĖrS=c_߬._{_xNi˷}kWS&7>˿*v-o\* ?|ʕI=kՏz7Ǟ;oyMK]_ _x~0ˣۿ~Gڟ=|_?zW{/n|_4V*S}[0DUf1iP\ Z5B<4D~ʫNTa9-TPAD`xOCb\i&57 ncqڿyM(DJ EJl;Չ1(3OYBwǰ%\]Y]Jڶ%è%E.݆3) v~e]4hވ˼=ʗ_{}}}grsΞ֕_%VXtr{.[b%7oW;9sf{l#?oyŽGΝ3OܵqaWwzޱ\W_`y^ks$ W\eع+y3tʞ{8BgRGjx7Z'@171h?g='7y1Y@cB(;'5&/=Ɩ.`AVE@ Jcn0 ä0/5zc\]SP.:S"7{ݜ?{Zؗ473Ϝtem{vlKVf-^|O;sߴu붾޳sm{|ח3&~a _e@wg]?w=lڱk~+z/c[l ВzMÁ hE"h4"ë 4D"2Hqw߁^zл5nYTVp[Xῼsf+vZ_u儞=8@CÞPӦN=ȿ\uW\tppmܼW]=yJD߸={Jn{n>;K_]^)U+-oVAz֮tuWL2}^91yJu^C o㸾p۪<]U73` 6o[dѕWn>w{GZWWGgG{qP/&O-[8wkj޿7Lԓ3gNڽ>{ڽ?_ 2ݑ]{N?-4@[4D Q 5PB /hESQ}Xʈ̳TIB*YcQu:-DhC.q4EH,@;Nц,a(DbE40P.j ibv <8g2bup|TPZˠǏV?zy>^/oխ+CW~ZcŊ?w͚V\VTr O;_/m H ߺ7TX;zsΙ;sKW^jPϲ.7Xzy_Ƿ>De/]y9̸x ݝW(+\7G_ek҆=^b @A.8Ih$4}UŁ1lm"T&P -j[rVAtMC-mFGZhhQ3 9UiJ<.TcvT8ڞ)i PL8 692TT"oK~?DFG\U;" 4K #TU .HIlC 18D8y1tclG}-.bȁF#AQ%!xӕW,Y\'j~{z߲͘9k?7|044=ndTToq ):CW{+^-|dl,|Bo>*4G`_Ə +|@bqoSy}3/?o_'F/Fww_۶c/+RyR wF^,W*/6#dB)2D #S҄!ZäA%4xm E zC#ㆆz yxɨ@ZɋmnQF^ywxc8exPWq 5qs 4ӑ(m"-hC &ssF-СƷtt._h<&{rP8F7\_n&(i(dZnC![ku֤" ZM^_Ml>L,bL C ZCgeǖ ҡ)6} @!FFT8"& 9&DBJZRKe&邋)0\"J FVBn 4c'?܇IQ qMZ>X_aQZd%V E8K  I~ѡEhG?_@$$ಡc[#pT {vLp5JHG[ e a%nUZڭ 8YZj-R(ݟ,$bOSG4$DMw&jSZMrc#3hC"o^`h5Pɪ'CD4;N> X2ecZ+ p@iC9LQ &XrBw/pLp )E8rm1pP=k*ա1_q")9:7F2&)^6f{Z= &F3fBCS2+ȑ*5۔᷻zK# Haڔꔲ ܊9`kt3f;GdT !eN% ۸A')Dh5F~tTIZTG!ƩI sq5&B?hc!N҂"|j:'4N# &<Y$2aDR;UZ!lt !c]3kb(;T@8-_DPr"ڕim"(T3?c%%׌2O&ᐭ2dG!RPuR̅BVAɕIjpS4iDhh n0,\t03eЖyCX1cp S:(!J4|/+ps:0p h/Cj|Aс-"־b CB`HN?]ӤEfҿС%(xq +5B];,[e˧<&pYRhۍk=U9+,-~jY5_M\Rga8bk-*y(KթJwK&G9'M7jC(*q'jzו(tj159 ]0B)Tw5(}Ȝ#>II儙-sϞn*i 1@vjuzbh )m5ZN҈<2%KXԫ3?peh ohNQFH#ap,W̲9fN('DQ (kY kBA+ QEtDhh} wX1!qjhF0{Q8h1!aR?YhHԡ֠!B@:4Z 9識-@iK.8#ߵj\\p%σ8BSHԺj3N9̂ xb:h1HoSS1$!x'2e<^pURu14bX=4@}C 4d5=> ;Z_I {;&N1z ݣRT mZjyCI1Su8A.Զ-yI֮B!8n GhwHzkt7")s:)oPHjz/Ph q?@0F'Jӂ'2oOjS 6E & "AAHH@" o{NhS˕܎#Uv~vP$M:tM) l]XvTq\_]A!*r_|?t_}֬~럀ڲ߅rrם_Ξs%;{%Kuww>m/ }cݸi]glW{%]=f//|~W?}gs+=@,iNmh9P$k#4_Y2$8hdb)ziOzuhYԥ˙ ꢑ%x5Y2EG ΤhyQcJ9fAj35BjST1}g| 1P9tQE9ЎQe 6Ytҷ*O8'kA>d7m'KܰO#,v vڷs۞mŋ.Vfkg//gݷwy7͏.zXpIU+N={֌|f͚L209R~+ظyǡCC ǎ;q3Ι=84<80-۾?΃OcȀvp$KC }262UOT{]?nBDBY蓝ieD_ *Vt;擃Gq4#FRvQtݜ--6#_taB2 r"9LM ohQwM ??O_+\%}v.;oγXsÊ_Lk/꥟=ww<޽oɒESwɧ9Vϟlٲ-oW}?ްyg8x>/?w)=6?ERxiBC,-( FiNֵ'A!ȤqbĨ"4ԋJi pIdH$LMx b36;OU-]S.jB+ӗ:gvV[U eal"PVTQ?OH/6K;[w(|T*GhzӝTϿ<̮<;ww_N:Ryӆ'rӻ =|w .魗xeW^\p~޻5yGBG".4jn^/@h0i*(9L;zNX+D =oξ}:2kh@'~C?;&0eu~leSNں;?^ǚ%K{Na;gߺjŭGFǀիpݺꆿnqYgG{Wgq`p48[umNŠBTS!LB"4nS큊FrVM:v-]KU = /eԥ葿-S`^Sm$Ոn;Ǵm͞ ĮRvJm RD#Kw= &F+(!rBC]A I_~BIoon 0446 myez&c=ٕ ]_b+݇/ .h {챍IPصtɢY- nڼXŋkZx&OC#9::VT:]x^DRˮ\{^ qy #޻tIgϚ̘qh#^Y- 7N2q/Yp_oMw`7aEζtݝŋ]aٻvtrRuN 4CCTNbꓡ!Vh*Ø?HMN"u dvoNE?svhǁ8\?6 H(uiqL8Q(ϿP7t ~ibXBU҂69Eu dtբ9r[_vnɚwn_~;-SNpGrʿg=Y k&X|AaǶa볷\lܰeɒE۶?CV.[q>goܣ6?>pʫ֛gKϘ:iΜJephxE?r 9G6\{͒=lc_;vJH焆NNRB3jD&Y,h5&\-"yKȢVx|sD#Ŏ:zh{6UX:UFTۜ3|]f;tph7xV`d9dԕ3Lh`\$$Q cňF`!P)L5Q2o  :ca;0=86i+2#,L-&9* S'Q0{ ӟ8`o7z9;zVAkAa a9,#0ٿ7,k a AK(Wx$rEpnX|/7 )AζW^f8 QOe1㦡osxu>1Kb2"Wkbj'&G N< @"?<9ƪed*JE1G/IM}ahe X6dB>)%+1)X۰7PҋRZ ZS[MJ!w}[4B_X7HK A\F' a&:4 >'-fSB !Q9VѶ4U˝F#c}:!ǣ g! pq\ Jdߥ8xJ0D PÈHN,)4CR4Ry\TZQN:KYH)}0.D5VM iN,u4D[66*F*9RF7 WIfuЮUrʆ}|q##ӏln㷣<U VZ?sQ290GhNzCe1'vFg$`B&:[bM^$e3 i%CCV#RǸ ̂fA-&&@HTdJP udx2i9sҜ͜Q-I`<8489~ Ϝ(%4P7\P]eJ *Cy 6ڪD855TxBƥ,4FdUƠAR&xBFZj D ;(0;zrӹnYfU;ZX9~šʴ1Z< F)U.ZՏiҁ;J\_0@ZhP@Iȣ-6n]MHPIq\M["݈hnds=!DlhHmqy"iyYVJd͎;ǤD8Aw Ui~pBRUNEG.0ϟ`ST~ _j( tf*e}8>"RNR>Ikb\C4* U`4MLy:<$4ƼEܶ",瑃U2R!ltRО͖Pq Y:O`0OL=heVߴI F۟=[$DD i>H@J@ &*wZWW2c$' Bo'h'IgҴ&Kyʭx!AhqJ qtHWk^: _h[C7P T )`RT1ta(j эYB*S]Ot;82-<1$}!b;۩@a*~'#$ s $uHP5ɕrBx1夭.-0<6Eh"iybCMn)6E Z,Ș!4͢oAT-Cvg4G٪]cHEqw J =GWϓ cǮ>Pi/-/um=kgM~)%Qkr'AhG$ IDATaL0Kn&!b$'ߚ٭^Hᴲk M)<~c^V݊ !FPS|PjAA!o9Uô+.+ܩe)LqgljܲqzL\"nNVN %Hh Eh % T8c/ܸa")'\RƷ1iRO)N1?8lh m:4d Aܢ1[ {FoY&3AL\-2\"0Š)2Um؀%BZXgb:*疥RjG(4ؚnڂ2 ӚHx_D&2OHN4;V o5d OqM#DR!垻hqNC=\I` IƎ:: Feբl`R.2 HUƌ5\}ZdjGFn̢yEZvK0t,fxm4Qt.zL0Azh+sߪD0qs˯Kkʕ[7OZzLgw"V8 K Y_)>!D24ct Z|tCCp"gŁ6:V-! (6 Tc*#R*2rZp.e4`ЁsU -$/9WF&Toj憗5wX~W,lߞnU%yny'$ֈΙq?YʕˁS'O2\gW#N b}p:иo&7/-VΆ wq'>ŗb !d^E:?KA8Y4WWF3.*'QZ9uv`jguptj1lѥEqjwei(' -.Z m?8c @r6ePW"O 4g`}vR b‹,N~~Q9gM#cO;w%[һ\lWqj%un0Aud'*$Ȅ|&WF8P'Db ;wE|}E жqTإnՎ[VaLYrb܊EAXEaJƮt3}T` Z4@ 8_LR`*L6Zf $swt̓/~:^UpБ<psݾ[u {|T*w~>V&vc65J! BZ_?b %E#( e qY&twtu<)%N2O\z`+\5n?qzŊ._k|X̿nʻ>z#=;"Ծy x H>!2HFSv4 Z.}dtzSn^zsZ5%18Jc\UYeakGvquQ? M-y.G)Q)v6|}+i:tm?-m#OXi0DgΘpmǁB!_'{pZ@Rygkw>riƓ(E`l,h^|Mc*@ZyF~!dܔ.B[QP@qiBCi#_JNSEcTI" e;'\ls]a]h*iV5!:p```i:  ʈߓmM[;:?-V-;1>n;N_:`; C$ xOHP(B11`ld9868I%14};}/{W9\UjUkUվ眡Ukۺo1c_im|u_\.?Zo^{@AO<5~7^/}图~;_!#&'48S X*v {bA@Cgݝe*ܔ[ j%GqAjڌ&jf,u:˯*]`y9bUZUaarHph~Wj+٬a,0BuivPcqx'X)魯W_/ۿ?[o棗~w|+/mCd.g?OovҚǏ~S_?zk#_gF;x)vt"Ùct:S`_hI S` W22BJ}vn̺p].C"@ znʁĐpC慗]emcw,`xJ&&*G4~&8ѷo'ʗӟCK_~3#Bqsz7~SǏ~6zG?O<O#_zO}~??'?ZG0UAhcZ,WVCdΈWNuf]0F)0Vb"[8;V2Jz9rx`,ph퍸V,`ϲ<1K@%xeX&Ԃ@0WiOkc$w |KγwS#?__+nNǾ/~K?~5K>G?~kwNA0y",2*r`B-@h8h06XlS 8i.P%chA`@if _s|#-_]/s\Ei.*",:6ڄ5I+P`@0Xfy7~7ʏ>yן _${γ~٣?˿?۾G>ɓR_|wO1>]_W N;~n_dαؘ.ex4# E}a 4Lfr+5oI H K.X[9B6ĒҬzj5I:.?5&*< T>1f@NxLuk{ͦްVs{O7?$m|`CGuY`SNq۳hls~?@o{z@'?jeHYlV-gcVF2#\^C%3!xkt0:(=bFa&\kFTvXu๲:q6CcsxHeTai$j\fA%a28$shDc)e?ᗿ~V,d‚IvM.Q]WX̑*)Ckߟ/*2\<3ҜLb3 s07fHy#u=Wh 1|Tx&:G &^D]i }ݸcư]#pM@VаUnvXoS-^{92$®Suez~|I WE\`B@TEd.KԵ;r}De91?鼧F {-kg4tFa*l^[Tk"&Z7Jav]oСi6w;t X?={'~$(GcLrUՏL,SG$߻0_BR~E( efx2L0!N\HlpQE]whBoԠyTQ}U9R76&8m:=;©QgSJOOo_xƳ]WYǤ| ym!= "x(U Vea+AC 6qpfa=`S í]fjө5ЀGB(aCx4``/LSLt</O;s4:ZYr `1yYvzG˕RI_ d ];!w *jI־S me*] 7 7 ǚ0Jq:9!8l-KAJY/?#??g_KbBe!,,`W3Kry󌜑 9R3)/_*(˧"p!$2 R諿zL CLx9/& 4` :a44}ŧ;Ӊj4G%3ۇ?Ocl`^X)\Ӟ!Es$a,qd݂?oB?Xx;BEhz6tܚf4q@s|rjS*(`g #,?pCӕ{`3a)DEvKS^<g^|3,͗P22k5I&L ɘ#u˯-#K$rH>3e#8 uX,,D8UR0>`3i&Å~L{;`kبUO'2c~߄*qsKЀ.<@:EvG{Ō#WIJDϫGңܝ94ʤrD3=W8!7%da>`K}"Ýv SlWma037Q 9^WV:l:Y/~o>u-ɂjLAF7(+yeCBnvX@MSA+/2|_lcD)'ZN64 sE[~h}71|o S Ǩ';B L檯_?ۿ`_ߌD(FC`tҘd~IwњKbA@MQ5%Nku*6X<#jMuQF 45"6s@v: T@èN\[9L^eW=Gs>l~%(#YT 2r,ϑ/{%Ao\Y1ȷذp5b0T };Da]v:4it65LT`u̡j5īoȿ0> T2T ʘg|^иBk&)#|S-v;Vnp P7Dn5sCx: a5m ,` jӌ/o ܐsP$HDb~Y7hb7enhUn7 : 0Zp8Xll'cU?sCxm2CJA;cobdgTs#g8~]sA8Qbܖ"eFS r* ) N!эN\&[ ,`K1o;ڮ{"{jȰ-lJ{/02HXCùY==5)+Gz1эnl.CC6zJD ԥKk^bkX.//}8zAЄŁ5 vcu9h2`1(SCk%QXӯKdQnr2GBos rj;Sroj~$LfQ7NgW%){ #8:u^0 ;_ I@18,wR*CL0rIYȧo{j)+2, t 7wv4i\q-NL9D _5TkH$bh$ >r#^'P2j=b00V#.v{"h Aiabii}S["rq4Ex e-E 2(!/.){3 '3<S-(W,HMBC1T<w8])44!y/_{,;?֯b=Z $*$8N \@ r!r\+K(Z6"ٸl fglǦ kڝ#Fٮn=QxaҺ6#Kp8NcA_rc<9`Q-=gR) enpgtay-P@K"g:7Z}8M7u֎AZ3(c :L_0_0_(?B܂&u{1S4{a ca4onoЀ:aV{]kS@u:p?")#(rlHD(Rw4m!.jlZ:5\T{@"0w^t8Vv#A+V"T3 z} +7aP("%'斊3 $c蓮F_ȒmYv4fk^k|kmD03-OP]YCβE*CDc>_}`bga- #:3ځ$()%xr;=`9!Kh2S bЈp 5{U28b0ǵ< c{1𫴓E-#bk=B)_ݦ\S3C-M.O,IeZq=iM IDAT́rd)ut0휍cKzOݹ*q nu6@arl5;ha#v!6*( M Glg3As*f[阙=c0jSGj`T|}Q/Tk-hw^Ou_CCǘ;[8UXD1 ނ-EI Re+ $BbQrfs#sH4%xM;羌W5|]źl{._IՏ=U(F mj&| m !+StCvǾJka{bb% )9P6_;`R2Du͊]/9qL-a77[Qe'pf SF7N~MǹjG;AQ#Pp&dP&dA{@1Hhlc֍b#])p[Dp0ܰ*a>j nCc|p="4K+P.pIA%,9"G$c yE'ԒwԤIfoA'tW9jOME[[B+X#ýS:p`ACTr,hKBNd3 ɐ+`)R1W =PR^Y7rp ׊q~nwtpp^a9r @Z(kmB, #Iz0ʘ"RT^/=ib;a}W^/$4!8L,}QtP>N*~" Pe_;%:lvC`sd-zdI%ʶ!> U?ybxlgaF^iEs Kv*?KWI5FR !)ɡ,4 H^rRLF<G;6#!A 7OM v˓_tstv'x0- `ާ7SҬĀ3hiSsX>& GJ zwh ]u8 t 8\GO#th St[X $Y= @ԕ٠l9c;/JM:7Ji긎lWttXs Z0 2#k  ˂GL2z=P`CJYprlq\G#:=@Ц[?yІwZSO%k,1μMd#a$elME9(SZ6Pn`'2\ohLmˁwaS6=;Ujzs)O&AR%9唂8(BF;K8Ǵ1l;K$tnd9&U?A(g{ [?; P~\rA5HWN̕eCJ&Kl#^f[OV%zK|TA4ejG,8FOW3j҅ $7wWnr,G 1E53E˕1ɴ#[wy%8υɭZOfV|B{9Ognv7Wϒtb}vS";O5"W"s$ He PBNkiɍg0Emw$jvmod/[Uzt4&i\i#TCņ ΦS}UG: `(˔ped)[$ 9.'A:LL:2)x 5llUu.u&[_id=Rۿ:^\1,~ƴ4p6NcJR$ fn>k"A9.&JrwwoA2kٚ d4Eŕ^A[G7ށnPձ3 ϧV;=ã? t_k1r69,3,Bja!<3, eHD46Rɔ'Wo,M~,ަ|E7C=CZUDOroVRe1=bId2K0(g 'ܐ %~|aPdO4U]L"kvw]N' nnTp8@gDkgS$ o,ui>4PVBP*I5f9`6y6֦@4D4Mѭ,mi#<`f~)/ B7(bzc:9H4!X jz`ȑ&ie,Q!l՗ڜvkŎ֍V_nu H:N8Sn):om})5 3F;= m*Ifr%%79^G4ʟ|v{?B fx!H)\7CCpN!ɏ jZp""VN)A,4G6qz;Z8$(5Io`ov9n 8pCYwg)Z,6#%n NIɈ`r&jz.CY]1`U15\!Uj om8m*h8>Խg#tB:bP+$Fp9! Ȋ ́E0XmHV\nZe{ie7 u)p'`d.yHrnIv5񰔰OS#G.!5nnͦ.I+i^8pP&w8Ltq*0x@ * ХOL2 p37?%;=Z?띦6=9ljxs5~.t8qs<%X3\d%Ü y19!Y:Nkm)gC&6%w3p^tPS#3=isjb2" E0ەB-H5TYHTh C++b³|||;OGЭ- &3⤅#ht5h$D)f50EgQ(P__(xz<4R/sn143ÄJ|8SEbE$V'Tb$ZrI; ,NH\ww&Y)Pz޹RpV)}dNv> :Kp(Ԉ~#sLa_)4mDg NytIdd1< c/_ N;f<FC0ݹt.tPx;!kͲQN:$@82fQ'N:NpT&-.߹W֜RevtO\ksjr6T-sa1+CN)DDܶ)z#SE4ib[zF>G,}ǁŝ ;t":fvylWkÚm и6rqX (9d j+a_uлt;lMН( 3VA) `yUDpDdvd(id+2; b=AF) %^SYbrMefEȍUwm*G.)PX#86`+ex#Ft MxѰ$ &`Kqq_' #}ϭM58t- kŗp%/ѡX"6KxM[ |[Hb%:,Ep̥$(H1{/hς#xVwx7 'v ojc:G޸.{)?.Ǘx8+Р2%" Y,^@6=Q2nb8(aL9}M܃p67/8.BP20H`AțF% LU"RI)e qo29I z&v~=Xg-s!t{47gi H` Jp#$iȂ Ak ug)Ew[C*':v? ' &MzD;;W0ӭlR6lN rg*uuٯUY 32m̀ 4f=/rZkOϕ_ZsYDT!3<^.= ,$>{bNX.x[9× @~9_!}E3fݑt-;{c ;K"dMr @fxQGVU,wl5{hF)=$S؄sv1uݙvj3bxA3ưW۲8-:r@9*?"uHPFUymgϑ o~/=X?/B|xWK,!w8KJa/QɗI/-uC6H딮_-UeCN3:{ b3***S̺!9Rkx4*ŧ|E9r^ūzz=ji\`BHD92%3f| 8’<Q;rqn>:T5^ ^/`plXTlIDAT28(`af*FI. +\XC՞Z&TBo1^̛~*o}3F"fDž1Ķ=ZgCźJtbV `2XA0KlpH!Yy9ga̗`zIF T&r{& JDC̪ g./8{//BfaǖZ_s=& ιyElE@gB[rkZ%T)ECE JY|^"* ̑jXS3h >);QNxZ w\$<@$J<[QEWz#HTe^vQ̢̍" Z&(`kr53','}V QuACঅ2&`AP'fXρ =pVɽsS{ܾ9m#Ka |McFN2g. -w< ]7Q\#2HNIrC6d3g䠜$S ?2.5\ 433~ln$mҙ%Vr1aRi%n0BHk:ֳ\6zjrg+Hoyjh_Ph@ag 뿥<rS Mw)]Umuk06i`IL-[U]ll4t_BR{.[N_-4@f|΋9s"~@IiOfo``2;B7t+z;B, OIڬ y9}MUw-vEZMj`$MxRÂ7TԤh(b,0iTkeh\[##qaX#X9bk50"f r\[giژ;Zބ ]l}!C۟M.@|٣k"NNa=[6! dʘW#jR~JfA h2j ZryPq*X2JY{XzV_ +61 ![ͦ6W'ȁLM_|ۗD,9<Kn%,}3:=i5#nNi-2lV!bzM7<0p&Y}5}vݲ2^[:02͋^E| sY$)\KMIL]/Z{n?{d'lv)ƈ '0u'58UF3Z9ryz$d'>jDD73'-sE2hfeh]T#l/4 3( 1OF27EPTC r$ xVR1sɋ"WGZ7ׇ. -ET9lηEk.R@j}|~Z}Y3 '$t!㥛#8Ծp#^]^π|IώJ%epBt#TE!wӥLPAd(hfr!: 1TnU&B0SR@ 46Ų.;P(( tcd4&c#3 1ӯ)D%P`WYȯBURj/VJ@cz~H#kPzyƻx. (n 2 `:VrN[XyskZ~K( k֣jK AS7[(uƂ~h[S1zpMPaL =ؘM߇*5#װd4c ]2 phJ]yjf7 I";lc7v?Sb13#2klU!@/@o@$Z(X/0AuӷfMЀnW3ksjmYMscPnn\]ʬ_6Eu @,- f=iث(+ "+/q+8UQIeLY۩*Uvn2x_h wmg&nue,eZM`k3|*f7.疮5eEzfwyZlxǘw͕D;jeיV=-ib#wkTEV .55Hi KHbD*u\r4-sKiltALD,ˢP@cҚCm)4B-v+d TE n~rWNK!{=*~#l8H. um KpkC3(2744Ώ`'ް۷vhzR (U0~s0 & f9Hw W} ,N +2a]]o6YJ&h}q}(P4MÒ#Y,<]jL1ux ; Erf eB>[ 9Yb[n=amHuusU r?CÓk] zhsa<>蛋NX]j?7ͫB-NgyebiUJXv?)$iߟ|um qGԒs+Ake[9[>v.{1_ "C&Tko+[3FL`0H+2|1 Y <KoN0(8acIMo_3|RA0_򐧁P4֐K&c`B VO3>}A+s|A^@op^5SQB`9fp wuKywp9t8=3TYӼDȜ&ED(,^$EBF"JdfbRB@BΓY!em 'XVkL/0bpI΢(K1 b_߈ Di;@XH tWp,Y795NVca 7b-?tC- t"x/cРr/v. 2")C?Bv/jG/4"=n]l^G PGjݗ;䞍\UWAZu"z_9}}XPAՃG !^>`.LT h 4j@5jzDA w#i H(2j#+kY5Y1o\o:w({VGY)DG9"Έ~e?AUZ'bsy/b 1F iP^i!Q4B>h:q+:ܥ [U]Pڐd﷣;=NU`_նIENDB`ukui-notebook/data/ukui-notebook/en_US/image/1.png0000644000175000017500000065101214201136534020742 0ustar fengfengPNG  IHDR{XLsBITO pHYs+ IDATxkevcGWN>~\'("$P)q((SK$$X $7N @Ce 1a~Tk10U]Uէk9k暏;J'>WW\+\Im?5K ?Hi/Tx5_b2?U 6JrT9aM04L?į?"wЊ`|zv`qjê\0P@a]v i(k~cYiY~ާy-_5M;`&x #s.;H`z$Sa^d=2TjR)Q`@faN_6P[̲ta1d -;/P3dJ@RԳ*P$D鄨PGTSVK,zɊT13*LQLb x*˭aօ$i"Li`1z,Y(J$0*dYE'  0wrLo, PD8iJAE([ą EkЕgMhQ1J^O^zK\3]tݘQWɘDue䄔&V[ b* \2V'4<+YɇC>ylP@8%le UB#Qsu Irqx-2aTiI0v xįqIPD:%1AG_1ѵ;$ +F2р*Xb`Wؾyv nҟ^h^t>W̳3=n  y):̗?O$j p2 /ܜqdOy1#GQc/ru±/H$]PvVm |߀QUѵܕu"uҽ/_לE{ދ޿0/>%ܼ(C"g>r=o礼?1cI)r}y&6#MebMSD[5, _PQ̦Q I[xBqRH*2q# 89r"tr!UD ;TQa nkMMh Wq|f*&s3K}7N^TQVrH"Qb$P ˠvi#N (Տ( pNmYH $JF%%Ck/BIKdmek]=׎GoKEE>n|,D*:LH RNEN O0)-MyiY{pb$%Jy{^;5׈ ts =dwۖ՗%¢}Xwݻwn_|zȯp֒N&$m*x`kH3 L :#JZErM=d҅r"˖}iYٞ]K"R>ջlgVJ59<._4bty*k\TQun}ȏ~GoM`I]RD1zj͵5ˁEK ;wF\e͟?G֔B,~u޽ua~v +.,v8؛흇lFjw, .0;@g*ٸa>^q1(rtRZY @b*m8j((6-Nfl‘JlX818nd۝4E7dBBDX0i "!dcT!GLIf= SQ.m~M%<݊haj(TU$zB}fiY #jIkJ1lcH9>r ̨'&zF\ F|b#mP@`3޵a/ h^ |SS3K<.PIW#O]4v*i'ͅe>7~mSQ;Cο7~黟_>b2zh*X]:f5sN!@=- jTNww3ԟylnT[.nqtw_5Vo<u`ec{{] w;xxDV7d90XGWji*0S_}bw8l :p }IQt;%53֢a; ]VeCnQ}۔h^;G)33S!R$ #2QۻT+O퐆P㮊~n2:k 9]0c"T=jc I '=SDSEr"< lP۳mr4 FP[ kj&oTXN5nn3JpU9& NiYx^| Jێfѥ-҉8quK uDX.Pz%3LtE+]]B?B:DgXҨ<$u szL% 92Ci oND4ӪO;T}ظI:Sgfo\_E~+;X!Y霎\ȼxN|Cn& Gk,Ű#ZM}_i1Y+˃2[\FctAw9d7:y"f8zȦU|S󁛗adۮr uvD%ňwaڹ+HnoY`Av=jj*(v0U ۳{kݮu2OevwWƖ_᫼u󗱿цkK}z~wVCxc"'uDKc0VJ GF)z`m'e4%0InC^weϺɲ;;f`wYvx[㸱(N6 3:Nh{F(gB(uj5`!4& <634Yv]Dy[Z$^!w-w:VDEere3 6y\d(5 O:32t9T-vHۦ/(Ȇd$dq$m"}24lidcŒ"b.`f7έݰ7~! {ix)F'L3jک U|!P#6L倛yup[𗗮Dl1S]\+1U*ʳ҅TA\uNO6H~ii9JujXWfAMp<;P(7ȟ7*;w8.Xإ;E4!b`5\XˁTgZ-ƾˌ4H٣}?qw-8(vyp{&71o׾Jx8p,]| Do{GlɜUyo/P(6m3ļse)brŏP0dTކw9 > p/ǰlXm LgҹczjKv ;=BI 0P K\whǕB$Q9ʏMaY-lR\ֵ`M`fSH댒`R+dOgR2Mf`ڠ1,=j2xM466B*֔?{~v :Nu0`t0dluf9(UNROkDO -Ӿ̆Uo#o՝RW]tN22׵GqFTK ECAvJW ;x3]El <5Z+NJ͂T`/3tkۂ Ŵ4[|'#Qt=semvî߿?|cC`Fq 4&$Bkl9RFr*JZGoZc7,7SIMW7vqf9W7}n.<p<tܜW!tɒONT0$:Mo~5p'1}Td_&%YTV,7؈NeUtײTʮ֎^Xog~oࢰzP78-ߥ:CGn 8Nb׮ŷݰ<8ýCONa^_&2#6E+N񂉹M\Ĕ}SuSE:Թ=L6Gp̗F>' X΅Yǰ]w"0w\8YŽq`wYHdH'b6Q;4ND,!bHIn ФJbt13sMfKeܝgC36PYMt1XT%"LEF4ZTB#*^-6id6ʗGvM}Yn``=(XÚ{Nەn)PMNUa>iB:\ &cY1 x(HZ ]BOARkkˍ|8avB&mDI:ӪKI ,IS%yk qq?j{ll&fjYZMiFl@vPi\9,\;UgSg(r~?*?_r(~2@ 0P5k'_Hh HVZo0q%_6dzUsfZlǗ$a/,Ҟ_۔v Nhmo,Z2ɶGْ߮(O`D?0-RPN/|2 A/CL`|u#?ȧa l X07},?e{v­=7V ; ,X}נLZNt@pTaՒQ.Qcf&Ӊ,JN̕"ҰΣ]q(&Ur\0,\pO ,jJSZ2h1ctP| Gutk/i`whf)GO97Z" @ӟ84Gmf;E!6\mknmqӾ υ粄(^kƁ5VhꈞJfV)7MnٛzM=-G#]me E489[JNge57 3İ$oN,M{%e.Yn*u;±hRl̝l3N'mE#uW ܼ99vp);P2|ps nuBZoBtWwf-' {7WAE珮<ý,#;pdPrmWV8^h3e4q4Tb&k9qE40T' =Ϧhhx?} }7/e"qgd1佁7G>s?9'8ji[Ơv؜!Vxոֳqwޒ[`wccfREm2eVRF!9vՎj"=̻mp"Pq%ȍ琝;)YbfBOyVGSB(V7`3CڑFfIXc08QH#f)NpU]I9-uj $:BZP$`81y#QfaA[BA{6z%3뺯Qb ʞP[]zweo#Tg"m>F?١디2d9E,`vOfx[J>% k퀛1b}ƃo'}o)d5)I4G*dS5e@# k֋ꅂ_IUU0=i.9E\ 7els;L[.OeE:ul ;;? e]ch.>YaQRE5nاtj7VZϭ>~u/&ڰp{r.׸v{d8i5uf+u`#"A$ro;fM=56']b 5E1&7joa#)dX,xۺk-8:\L+ٲcV槎1<ԯm5 ,kɢgcpʒފNac D ӖzL4$$Fhs1JY%,N) d)gѕi 4Bd lӥ,5,F:-cTVbTՍeJGDDstgcavI9?LrTgtjQ,SȜIq\vUymliw W6r,@f;P k+ߜtVy7,W5TGruXm ב e@”Rz#iEuYٸʔl4%Z{ {{WY#ȘSXm,WdM0[{kf `c Z[5NVY]Ӡ?w9asw,imU| > m|fOeW.TcJN|W]u%NoTi5e49Gs?mmQ6D&Ja>s.67}Dz);r=s#_䚿{`A?7[MK[l>epQ(ɍz펛 n.Xv ga'bA5'؉ IDAT qM@C\ < w'=ŠWPs*!"pơ*=+1X(+uCD栬}CᛴA-JwwZ1h;A7MX9kY'EΩ驑xitiJQL{i,X#"'؋ls>U-|]"]a _b_O)qK7՘.l.,l' EFgn꒥Dc_2rj!`,qq~3?woWeaRgП:\Ij1˪Mz.Jۗ< ͽg gev{-8:K_|${kdYU(GT;6QXܭ&Ak;pI-AJg=흴X Zl45Ŵb4SKj>I6L˔V6IU;3ԕ\utŻ2Z]vخ+n5:6o9ȹ9ktheA;ŹQ8puPﴷ`QraU%Ԕ NI䲹)mH#>mLeN3[ob2K0ǮblUk9fp2jVZVj9ؘҘ1xlTMM:{cvctogN8ё +# +T[C"fxi24I`ge~ jcdSBXظkes22c,yIpL3:O[xva2-:-{w-b1sG;Fq{komIEXKz?1'=~+>[뤱2u_u/v;X~Gg٩6VdaaKd3J8UY#Y 2 aΤԘ7LCaY0鼋@2JDxf*q5jF&լZʇq#{ON]"1q*ү-hPܚiFNgs01LNE4fB9 2iȻ^wTKQ\cg[FWbcزZTv-C=rXƙnفS2B|}٣fN:oZ8Itv%bQ]+VhTch1X=x`Yn*+@ Z$ehlH;8 Y=AtdgL;-_<s$T]wanWb}֙ww:/:>>,ŷY&p3q^}&>1RVX'>ÿ`Q-$KHyxz_6ZVD8/w33 8X{%?X^a_|pw^Foo\HXmS-dMH4GJ5LScMԙμ,ZB)bUXv{pSj3ZGpT؛P0ICS9hr.PeV f'ZIcn=Ϋ{vV{*yXĚjqdU|@Iuha JZL͊X:aR-,4 dNY{GBӹ3RM,&;2̭[JŸx o[sPU28lxޚ/ѱ79ܜ07¦V yUb2Dp^y[in.ؓlIwS8gs.iZBcπ{9ed~R k[ ]l^^|ؙ4响)YZ[ivwHTȕWFօb y5L.Jjo劾+yZwo}oO5`g.e/ak-򻷨ZjL'7un'lgi-f]E&Eٌy#o6aυO mRmh3Kq}eB7yg8s"-Bmm*cP6 , k7Oi'a0\vOak4$|Luz%isY^7;0'[0SoNѢӱrvrur00]#RU(s Gpz=R dنI fF;&qS&*Af;Gah('G!봱ZKU}PD9S76nPBN@2uZ`(DB۴^IмNj'W s&y -< *,zһ !\( ##GqWN:Ӿ#LQo9ȍiyيo.vcLÕyLImژ vb'mxӿ+}tk_οuĝ@ &?'Էz fl$"l6r}O0o|ot븤5r?\Wr;!Ω3y3?2ZSٞ؏g0v~4DN=Yg_:ayWmy2Bɴwg'_{gy*e~#~sivjxQ6ϋOg{1}^^M2"?O3 V7tп֗=:stC㿋8x7Ivm|Z{s&֝jnNl78^s͇o?/}l.?G <0oK8==Y p 7,y<udsƛ3)¢έc;/|/t:Kۻ/SKm:=Q=3N7tG8v\^ï ޻//XAIT_ 9%z{'zȰa_Ʈ2 nȦ=տ\ȆlNyYdsVM<2 slLW@64Oy>c7:ËO zk.狮N5-װ>ت8Y~Au{v qe]/>v~lc7ŷ~??o~O&!S0Ϗ{^&%=yXAD0 wB6vEXl}K4E=#\5=m\eN9>d f'{N㞳ldsV'[+#3:puF;ѹ_ٜ9lI^Pw:ht_ĹJ:~A- \ą%X`m_X7^qp|w~]#+TL:7ST9\;St+%ʹ頟$Q_y_@檘fkl>E؜!. dXi8S _Nx5d g|dxut&y2Nx,y֠;y8W}4o4MUZK?hUkZ^xv!M\'\&=U['2dCG;cc= BEj:Ss&vٵ]Sr+c:0=7!@LbB63~OqλH9<Fl*tm 8L {smƋѦS_}п^Xʋ8 o$x*(|7\XVe7L2tϾr,eoo]o^G2_:4MW7?} 2eFPO@\55`/dsSEYTdz RW/s`z6yVp {]lK~)Ja{'IQOul w.p(Ȝ$I(HTbzQEAy~fDb@S$4bHB8~+j8Df#4MR |Nd#:0Q4ߩAdc_|"R:e# ߡC(IdͯIpҚƆ:^~W>,J GQ0E4ss1JReH:OX{WI6T G]jgNFUڊd7\gTڇ_O}ldz]v9~G6bܠ`l\:we>r[[dMө9ĤI&uJš_P1LW}aQŢUI(uuud2ʢߗ:m~]F9U@06T״nWARULd.؝R缌3f MU78?pu,Ж?nT*ft 6$c+rO)xFpj RRogxz-IݖIa;,D'?M$dPSO9DYkXL%;_ {4dS5Ql@cw?]nh֥uRٮcDsIY@) xQ >Y 8IB(PE6zT15 bLQrqw f` Ÿ]'vb JXyf)Iod 6 N6 mXG`bhQAo^$ll x X@ca:rv]Sy1cg+~&=oD*)3@@ (*043^fb 0߰,"^L=K4CtULܫřD϶(:f6&Tuj*?<:gw\>隚D^ &lDlT&7#3rE#ُScAl亢ș[֒OSos7A^&6ڞuNE7Z*[rM>35J@+ \jG-M5o.(Ǜ{S#+PAA> @;+(aj IMdګ~˻ Wܔ݊l9Ve+VbݘͿW=-:~䝕?.JxƟޝB|O(ʶ]n**[-^4OLNI7^) IDATtVh"٘HljAGǮV}ejfS 9;114uקR{[k޽ G# 5 Usv8oLf ;\65nk{#TC] P_[ 7Ex.guiB,1B'%bMpت6-W8qN_QPo}ѿ/gaoً !f !̚0Q(tzI$RR֯(&32Zp_y @M-y1Uߗξ.FK{lu0.عGkj i2GQؿoW7xC'YC9tɢg֮ WKC=mP]UL&k&6ҲCã%L'tMMBUAZW*h.cNL37lt4K^HJ&woki=mۍilfs:t4'tkcZOmޑZnkK$Ԇg9MLNNlI"MLMu5}g{Kijl1 >Q|~]Z?ę&DydJ7VT# @q"@$|ax ZG)i;6wkQhw~-^'ˆ7)c,0 T1-Ml֒֝kJzr uqe7 ?&1|q㒏]tM~ћk̍MpJs/}!5=݅Rn VtΡj?V#,?-AQ^xxKSCȈOvsZ[f47564f&rlhP4UQ*ŋc*(ZM+Ed0ڕpЧ-Zoh {Hfm` MnPhPO?k*z5>p6r;gƕ]ܙ3F2-kkjtt}[sS[jΞL@#ZCc׌VfC׻wW++5uhmn۵g+#@++Zo:9ױlmQdTUe@!mmL=z/*L.q,[o``Wo ]SyJM̟ݕpbjm;LNE[@6>J q/6d32lk⮶xM,|"K2|}0m&hlQ |o隍7}~cMߖ]$ !l n[^)$@2QBL:/AW}l57..7N:6z wf]W7o(mwpJ3dQ^qikinb*?1ji燲ٖzJTKC(Ù,dž۰&=2P]]W71ˢ 5Uô$Tu^WԫwT(y]yyY-:;,I{ؼ@Ubr2pN+[NLM5Oi# ZSF 6"@m* ;BgnkN̞zwh6\_``dj\UL6 ¶9s_@V]ni>dI[MFMȆyoP262jO3fj 8PSh.9M6&dAJ@Q KSuubRQ@)@@* H`Pf PK6Y?:#$7Vd}-Tn1`;G\ssã Ov''~_`;>cjEj@fl`ђيP)>BAߣJ&džچxE29#X&H7l"?I=Y]֐t}}>799ɦ ۺG'=IUQnUD_n2N guu57>9Y]YٚN hW^GL) bƯCJO1lp+xTt$ #"ȡTj!7Q2́enbQD ^15G6O6hYP`%%$<MD6ao0{&_0sJpڛkLU1 ݢ`nF ;tPE]g-v~^qW6+Dd*wڭbj*>=J;86jRL蓷-cܖd"zݻ{G8CΜ`Ξ3g|c/x"67< `|bbN{[sC=vզ4M+кTjۮ^஁=\E$386:/P%]W{j*G0՗ڦDbl1t}|rrhd=w;>pf4]mR9>=[7g)`ay Slk§vƕw$g 'Of917>Ubryx+\~s]  flL1@q` PTc)Ece]L@(@"-f`lUύ2G_{ GSiod?ߟ= 6׹$ϝ4G{ *&m=cmM3Mˌ4P\u5ݸaG7\~nfSڂƺ9m35m٣o;Fe*Jw׌d+Sƍ;g6ue,{Ս96TU&N̚\yO={v 5?gH&gx^,=BUEEh6(hY''*+1Lek_UU9@*U 6üd×m'NqM,dc2:l6{ Lb.cEҹQ> 7ᬮqz6ֹq֧b172f̹틏yM{}W}֢|IU]^UQ}TDo-[,cٱln 3f`D~{We2my@׌䤵D2zc{*OԤRUJl&2*XRnژ˼޽<c0MgkF2|bAW'LUٳ6naykM["")L!WeMώ**UU OMr`QƵjml\dS\7y#b+H?abA ΍K{|)bAqoˆ7րND)h.(P0 2 íf^L!e{{V]w-u3wͪ>L W׺#>_M| C^CtD돋}?˼$rc zyq-;_x\A{ u￴2Y_3N=K*DCmmM*LjRUu@хWЏf˖m3wv vTs3:k-SR:g~shFdliUyמThrFsSm*58:mW/1MM RyGwU29m939ow&_ښ U2;"{wKq].!xAޡ OdCg'FWXرɑ("$~S7-r$.1]4)=m`Ξh&9sX7fs-{2S ,*\pkE6e'sy9]C[w**͚5MmO;2mњT|>?훘# NN3太6׏f3= mrj3 k[y_GK.̌eDnAKy*<*@_MRL39bx* E6N wEQFPNkoE¦ K8ot~M~@*ǀbA?%18 uƕG_' uf%qD>EBV|WF6?g UUIT)*V]C`0 s'K'+2]^%l 鍒}joIs34,{ڼ}GP8hႝaź7f^`G-Vx[MLupnwO_4akn111y6owb!x.g`'{dFh'(}lP1/o^YNJ#d'FE_a[8^_W77ā~Jx=g52tDot#VTXXX2PL#~pc*z~qoVJӳͶeo|$ ߜZ$d#^3cWM ;h3oEN6>7, وr?BL'{kEd =j$wS+LEࡱ|f.!\1@ӉejL*oJ (I(d0UPc( AK(P7ƣ(QǦ&r[i? F6VWp7QQW< @1{K\e$ql7Srd3X,VGoUi]-6D/?$ܹޘoCVVq\/P!0 ť7$ 0c}c)K/ ƙ 5ʍ7I2ò`MoX$& ٸ@RA6m NFs\_͞6JC*lLB' 6]OQ tHJ\a )v&Whx#֏r@X W;pT$KڱΙ*R%fd\yxn{UQ@hBH( B3'nSJ1ϨB g&HwB#oA䙃wxH]dOǘ _Kon!q{F sHp# l<@Ȇ+K!,bW,& uCb^H0](=I/X7{|>":@)L! P@ ASI PDaoēgڐNߴg5C]an԰JirM`nm( :|.olÉ暢+"7CA)^oD#"$.~t1+bSc-$iaY=JxeK !/]( A_q7]@\`Z+$GjdĜ-)Hh( MRr_wջ}-Wj~^-~03d槼kT?5Nc=ݲ`|t>x`J. DeE+$rd(.u{O :0 IDAT~DK*z1$dE !AK%G IbccU$"߿ &;i =M*HL5j_L(L1 J;WxˮC-Ojr>[FNPHMtd435UTc=PuR8R&0}5?66FyZ,!)GTA(1ڞPo$L77X9CʽYT>]',%a'3 V<,`߳Cq4FC[!zX<^;kwˁEH1]'%AF8}B˾W$IBFa7D2e?c1lFǎU\d~7"q}C$ڃ(=s+| @ τ2(B 0 /ILD3+ͬFK rk~>l_Ú@0NIdc3.x۟"q`iAC?K&[?՛$Ȇ}D MLX}\!FoDw{ !A|y kӒ|՘0ׅ.:K-0PRE>j&!@=d<5/CXONp1{40D_-Up 5*CZӋ>=L`BFl\ 9l$ӻMo:7wnV'^q{*b^dҝX“M. g8ׂ;ҍ*O H)M,*@R/ hF7>NQf5X€݋QP*CB#%̕plFLٸ#ؾ5L&Yǂ5-JVAdYVgm/sJfHN]i#6O63MPa-s:;&yQʭf0^ڗ+#ߔ9%]dfQǡ ?>Aw,ӷ@@`̙j8S sx ga?d[ 4KXBɤ6iADF_<ن{$!}x_g3%F6Opp\:hqZͭBbX7C\_!*Tkl]@""^I Ysʖ&}x QA QAJ3h`!"5ҙʽg 'wlOWBEA%jH u/H|?8l KjӢQdkDG#"\ ߔFۯ_+Z#8q$y oJCZsp7E(0FC@PPHT e%'Tf{͛kJcYgj;k_$B7.Yf >{1)(^ЊS|qMj1MXigq|Jl8emF`̧` c3N1Aut4!eѤWt!1'rTg9LdϬK܊S$|S٦d#h*œKyKHX; QfoRƕS0&8Gl&ӽ҄|&p;(~~d#z8 2S2o%aE6a{%R (UbSBNvX ϵt|c])eFѷ-xCD_X` H+)*Oq@q) 5E5N4᝜ H 6c!6)^!H҉> u3V %{U<ɦ܂oBi {яx{ԥEp(+6PɅ(l:IF{ 1w<#S OBi(bdLnlWe!%p>5b[5ǁۢa(aP0oe~oj7j?1Ƨ?]K*x\ u- Ql @6IT7uC_uN/|tbIʉ8a{8Tr}I钹L7a Ph(.P EtP_⏘*F!MQeݗɦCn2 y~-0_*X,rX!8adᜂ׉N O d5qeC!#pWjNW}̵))߄+Ex'x=V<7vT C U{.CK!nJG4 ' .o 4!Nn`0@P(5/ S4sabƵ4 ` 4@Kb}=%,@ƒkԂ,g(؈xyȆ*qR_b+ȡWsys5wWg>B-B۳a,{!ZJ2~"#܌ }`2}˸X?!BD.J8"!67=IIJ܃i *.F1@MQ(F@14{J%b |fΈ|>&ed8l0)\fdD(oT;nSPBu[<]:Kr'| f%U6H04\‘/ɏ 86 uy1d$b5z)r q 2g\*"ʣFd!G( (P)40gN!cJ0kt-a-L6ӆ5ј&tB7iEryld#VbAܭl\|!Z׹V#~!'L@tI|{YZTa OjR;0 #&_$OjùY`r^TTgKgxsCK8rɁRchh@TFQ/Q2}=bqr"+Ȃެt@6EȦ؄,XN*90ᰆ܄ɂ6E}L3v,a28x9}؇9.=A/gcN{rS⼘,M=(|!L)JHsaѧ_ƭ^ 9D,{:]yY0S>f>D{Kwzj"4M+LGyC a,G5@GS*,椁fTicnVVJL􎐖K\ dL6NmF|jd'+n,#XNLgi'xw\e<3o{ir]cb㥝~c&\41*k'_>f+Pd}x| 7D! PUurrg?l(_myP3o00FL9aFF6Ӊ5| 0X\$xlxքd!] R;7b67˓;}{\dk$6j 1%aM3Di +W(I.~(`W9,r$HFH&!OD՘M  Qh S1ĜثhXnJ'(="=^l#lz?;ȭ=#B`ld~JɑDp^OĽR|%ld|VrZv)3W+ u"i019c:Ə q$GKXH1DٞSR'TuMDx!iR  F& 4890xfSZq*)V9} "MoC8+k$L4j`)dS<ȓ1\/VNċ̏4^GewF6XqBF zb(%? 6-_ꛯ5RTfyqGq(詂d IQʑx.HE Xy sL$<:i(n i] H6 ܮ-<,pH6zh Ȕ,.3q׽tf!mwZu9 >>E6 ~ t^ihcNyMr+"yEqS轫70TafTePTPPj<ٌ!GA(1^ALct` ldf g}|8x5d#KW]9޼lm$Ml!S&zX+O6V 3t@+Պu$2 8 9e̎~,=z$j{N[n` jFǍcmI .Qn2]kۼȦk ޗK$iq*k K6V;Pח(|V[It'ۈ:6=/ED2xKm%_`?ŵB%wG+< \sqLꄒT\ho|-x)NV)`0`goȠ/G*1)7{HfaFa͊5>kEO9⃱-lm;C6B5S+KС+v({rMy7fJx#JTz[I3p_#?bx)&CstJ?fn*X,i@).2hYR&S [Xgj!iK7؝#*W 8!o Ϡ^)P|GPӳ< s9.T^H6Ӌ5goC@^Nk`2y]2G `(q+&&g>O dDoĴ#nJ`bL(T(06g D5|k#r(Oy;&D;&*ko( Qr =q #p6ę?q` ‧o鿅qAR}Zɦ#yho9I!ǽ"셑ԁ̸|(؂:"/ބy`*C6BhWeB ,fM[*1^'%= 5bi' k{w(xFp_>Z3WCH=Tc4ZC!mw^]&Q0 (F pOxr /JPb&xA& T 0v 'Aoi% ;&~f/a~Kp n3RXct6%秘l pn p׾ j#࣌SJ'I _e1{$̵O?r6:/mA]{u""Jnbw$$qg5"H,&aޓIp%>خ'Թb+ʝP7!)&F"$0Q 5Me/f,.Q3Ֆ)$F0R k X#l. D8le gA1eF~Ė317ZRE{}ol;#̷dh K3WȲÏAdg-=|8^8]B"e P]Q0 E~)T]W 1FC\KEI4=5uC،d$5) qQA&lxEZu-.gb b~ڢ.% 90wR̓G6>X "N 5Ao-ЧRq&t:¡6_UT}ҏ( BWNI'/#ԗTHVᓄusb$ِ%1B$*33!%bEeK*.=CgĚw,_P|l 졞}!xOH&$y<0ȯGV&FR ?\R1~|rl8kb?CD }wﵧH&pzB[QN ! _T$@+$a;hk?aRl]Ҡ194fd#77Yr{lp7^t{q2gvȈsκCJ^9G^ǟ~oo׫Jpg/?zɬYpݹLLt&&\~~p˧S_l}\:{s_b~ӟO~?dzgsh&1uыgzKO=樷/?N켳?vyۊ?=ʊ֖n}?ٵa{~'w}8?>;cH\\u9;wiظ}~~cc/oڬm+.9W#}nPͦ~㫻vC6Kך[t~UXqyg͛3kޜ޲}6 ʫ ANÖ˽>ϯ|M_zYmogm[kC?w~[[j3cc'\pɢK-XpEm۷ls9`wqT-qql8u:-Y$H6C܎$"1Կ+1bk|chV$?T+'0Oݬ!4_;À tsymOQvDR@`4Ø10cOMƙ~VuqMgq[bfX~t}4 IDAT[׾R_n3V^Xq}%V.<֦KWM?-͙LVmWЧ_Zǯgя\~c]荷~'_Zǹsjkjtu1#~ގfXޮy9u5s:o}G?X6WW:깳;/>똣oz{uwچ>卛zV tϽu)Sg{Ej =}ɏ]}eKs+Ot9ڥ͹+/7?~𮻿WX~AuSӊ15nZ`eF:}ˍÿ=4d#|ot?eDsN;+=i㫞oյ-p-yחx'l<~s)cHRk׬]h;>!=zkn?|Id#ق|ZcBeW΅B6|vQ/aS34Gș@._o(bz}^Ѿfh.JU IP@S%@R A`fS @hIJ` 'pi?2<6d%}{}];n?NU~Ϸ37_|=ϻӬ\mKsZ~%?:nRgm-yį.8Z+u瞓JUꏏOɗ=37_7ghe*ᷧRU=sO]ْnZ`ůozg9>J5ԳϿМNyء-o~`hhhteY7_6~w;9uշ^sO>i`p蓟k^/QJd³108Go ?Jw|峟oeŵ_u^y◵55lvWoo]mʓO|؏zA+O>_㫞6?:8;_׾~5wu-IϞ=!>d?-_}Mnim.9zĥm_knSVҷ*]zLC*0&Bwp!Ƨ`b |7ѥJV}6nE$PoB?qǏ~ăZ|ߧ-ԏ8xtr]U4.AK1U$@@cPq hy })s@qD ||moek{ zٰmO~蜳f57=gH7^|Yn|ѭ?/{m-?Ͽ}V#}?ӟ <SV<Һe-[H?h9rÖmG,;Ooԏ{mÁx |e}f=mx/>f[wwkssDW_Ь-hzeynqW^uѻ|~̝s%Y`/y/_?o_xفw|o55m"srG]>wӍzoO?vGbȥ=}?Ad] c9ssC׿>|=O\9OqG}n }j?u JW[G7n]2 >?/~m^4'ѽ[o׾;ܼu%]bƍ֮Yz!Y樣ڹsiůN{ :Xojnkj" .zwSsw5z -ɕ-Xkw|%v^1. ¬\z=Kc !A1$RX>4$C9!SE"~F`"q( dx (7VAZa0Z}Xg3P FoFߋʖ͙<%s9wf3cgGOϚmaM|]~ȡ^]tz[<{/njJ_ek֭%KR> 6Tn䆺ZB8=Ho_ի z~˟~{n'.a yU~^ sm7zh qUJ/$ ~6㏾WXfQ.߱}퟼s}q ҋkn⚡=Ӂfo&!.==d9ZbckBM~g RwQ )?3n+w^ Tki(PLH0$T ,@40 U_)5BK4G3"^+kۓg_yeŵ.^\N:OX9W_?K/>` rk_sz8E ?>o?vcی{c6o?vnІM-Xp @mشi|cX*:31<Ύw_zfXh˯@l&ڳǞRn\ qPd#A5ޙ9$a P ULI?!#ŠP %2':p<E&~UQPo@) P4T B ?TQ;\S#*$,l 1Kl $vS)7 $PP `,w7*eɒsvcO2;{ΑLμ̳;E.?x7F Ч`;+}I賓 ͎]k׶]h!׈1+k_8j|^~{3+WK_/{V7>ԭ;vN;&|˷\{- W^37ޮS2_`쬢c55E6nq-n,蓗7eܘwƛm;n>7ӧ{N45=_Ϯw}?ߏ>@7ljU|隫 nQ6pǷ~w굋w}G?DѣFxz O %:mشy;sƓϿOnv\շd?\mٶŋķǪߥ%%G*+q'~_vV>Wӧ[׬]G4 +/ve.Zx_þ߯XQu_-7lҥ=~'b_@uU={xenpsTV6n?L!bsC6x #sv&/^ ^o.*=wdiaGxVđqu&.4@D9SH.R:gdѣ CDĎ]PT 4D_TdL(u%#B6=w'O-`ʔWV/W7zwMlL8E},֞^.'F|r*[aJѣ0o? =LMө=)?{+KSP'-7޳~S_e+ި>~[:A/Ok?}K tԱpx} '?\r'n #ʇjw_[ޯ7= ~w3gDK}b+׮|ݒ_96_%% ×p{PiIYiIiI z-ò=8r_zrek׮peUUvs8Νw_ͮx!Ⴧ^}뮿nͪ5%1lg_^ңN6ܷwTlZe}+lSM2i]+'ap㕠KʴMJİpo̶ /+Yƞ\>KQ?OxuFC;"PLߔQU/˜9AV @P(>j|r{( Ǝ$Q8~4dǫU\|:U3f0LJ:|>Ԉlٹ3o~wS?`y3g2n~-vj ravXIf^:{fvvc:2zg52}. M'{dO7f߁?dYƎ}7'0~cܖ)ceًOz7-/ZTY[{hw}AScrΟfsA}ry[͙='L{$bmXM|j*vaElۋ Bz{w[i]y%GL!PU]=kmw1<.+\ՆF;U ^!\[w޼bÇ F됸\z׾C:x֭y%yXԷouU՞{F3*avYwE ߍ]4ܹScַu-wݞRG ;KKjPVTbA65==6HvT(1#ZN 8,6"r*FX7 ^v^IK'  Ђ` "~P*@` L BbZ !! @3dA%Xr͚5VY< ee*+a.?=ܱ{6o9g?q݉y6yc~w-eJ9_~/TQ.5OAw3Ƭ9p#;;ŋvŋ }rqvvV8sgV]smwbmݳC\s~zsgL{kK/nv>>}/C<[+gL|ɢuO45-YB᭕07>v po׷ᄋiSvTl9kr?y跈>\Y秒}Px}Wz/tnݹ{\7|T7V 28+7e5 I&dgg:tK.t _[׾?aZ}{OT!޳{y[֯Z{ɕwO3}B\۷m r;Uo9dX%W^^Gnέ[>ٝ^[{7} 8^{JO#~&Δ+<nR'wDŒLْg_Ygn{gP^]Q"1%|C@4W {F%Vus4?">"PuBU "JA4A!`>h dH#y~]} \Ѫ|ẽMM?ꗍ}Sn}WL u/}zi5`csNv ~Dkllj˯sv0nG>ntpÏ?n?TCGV?$7yֹӧ'6G^z|7?{޹q{A-28f G&L"(ÌVBV5͘L)zbeI ?4~A@A5UhP3 jѨW&#/\7hEђGsǏ(/noG|G۷<ږn o\xAq~v]{hѰ8:p%>=8zЛ.p_0gPPPЧTl)ٳl-.w࠾<{؜ [?{a/.5=Q 3d-fڵ~|/-ӓ[9콇yO?|rL IDATڥ{?t˶ͯ),,0rUU=| [T>dp E]`ڔɈorɞ}<\]Sӻw0l໾[Uu%\u<oOK1^_Fd3tȐK/h5jTuu5 ]qiwKi&O,..PRZgnL޷{e/}㫗^y٦6Θ5G|qs?o~szxAN:zLǬ5U՗,^dU5BRmqV@LX=JD上sqmumm[۪kkO57?\ O|ʄ [qG?:r pR۶ ޭ8xΙ=s [n{Okhl'? /Ԇgm&77+.a.lM  *n]39w,P]]?_0믭={ޜ'ۯ1~ʤo}KrpyW]m~Y3m_1]BH 5bqX#⎻\Mﹻq㜯K@LXEҽN˻7Qm# aC0Iuf 1) OE .('н`O^fv yI2V1ZOP3M%j!@>QB4pC4 A?e@_~ >s#OH#! FFphSkOaGѱ rɪ>:s6=v5qg2Y>ϡ4MwHj>)w &F?A1p"[7㸁M, 4 BGOύd刦ĊooH7F@4 ZLcg*$J50@(F"C!.~h&lMz,!'"ja0y/5b"*!9mdmpDdJ+3X"%FYjLXIQ=Q'SF6݇RG?nc|E։QѾ0P 3!@Az?ɬr]NIܾe eP(A%HHu @A(j_WKQ-FceSm!XxwTfzH#b.RId#!D3TE֌K!A5VcwHJtH3F|^(&ay[aH88*?̚F q8,[QQ|c߈/ӊ > uQAB0uR} APH$ e03EFbrƑ t!l Jd֤E. k(@6NRĩPNjK>2`c&yGƹ7t{13و ފ- .t+=c$]FLl4XĆo\$F,:u`Q2էF|+i`Ơh #940E YPЅ!Ƞ10@kz`dIHɱmQ)dCE7K#l19A]%q5!1݀l N?ƖY*KsT;q5U`ݯ=l%3;Yt\(7I-w+;"\%тNb2־[W &_Tx BSj\٬AUt'AYӺBDThG2?Y`~D ADeAS|dx܄בsF椬oѼ 9墴Gl,3h/m^}y v;dpP#GBm}ianA;JyLܯ ;TR¹'(`C> pE+䆲4hgNꗗ_@uNo۵[G6SƏI 5î};:n|&p mXrssO57w+W>QW7|PtD"l=9ȝM.׳AWO Kl!_$]dYLdLྛlq dd^7cdT&1Oq8J ,.A szy y!"BZ(#`L jZiYQEQT1?QUz`?tթ-蓅S\2]g?-zh%{s㦶N g W_ΦMkb B!Kv&ODV}&O|iu"" I:#׮>zyS&j͈Ak/*6fl]Sj5G?ٻ+7yykk[`N7\Sw;vBYA )+ݱg?ҁw>7''ɛ` `lvy@!GYaSu]ͅ aX٠HW[S8y؆Ɠ:ZeCZa#Lla)rEmqU ؑ1D}U?:jxosmmGՔ [M96 ņ'+UX'm۹豪1F翿q]`@ ϟ'я ڥ`as w{᯸H$oKƸuza=M)tisH 7b:m##psSsZ~XbI"Gیc~6T$ (g|c#fP3Ï1 "FTƠhv@Z(]~-PhiLSӐ|]D; A>+I}7AMqlrS'?@ձ+ϝn۶7l;a 9x |B.[n;ven 8;l:ZאtѬ ~ rE}V~艆, g TicM Æm߻#=JO^Z(+0(' e57 "`癲ưҒS'}TX+0mkL2CUU(HYFp<ٰpUҒg}KtS& 7?/JMݰHU5F5깗_ lv;7w̴5 Μqԩ_{޺pG-v}k<邵;~Կ_uuo͕8=×̨({v"L^bg#Sg^R-~c҄M=t¥K%>y|#`Mca'}BX6(J?h2t5UD8ƤKLMsB63rC[V>sEga+]0a„#* y*CJK'.0PИO}F%}7$/[E D#{qĜP΀~EEu'DE]CCPHϢ6=t\y={ݧ}~]-sWI~#ˇ6~oδO)Kllb2< ;rH$cTNv&w&?f9m3g|ɶJ[/8 >e2Ɠ'%W{ﮞ9kUW]gϞm*DwjL:$-hpX/6l֤lvx$h3N([Mwzi9w GڲEP~{ sPy٠cGxpE.S!fA3\T[oA#`#l fpB먢~ɳmm_ [<<8U]{"fDPH/Cyi J8}h{G;.?o[o< _ߪz@ @X?ٳoe N4/_p@VVE "ZiڻgpYيwޝ1q|xFM)/8@NNnm #Gn `:c*5m,**ˌOI۶wuvM?[?>3>ضm(Kf?k!Gva V&Aȋg\ME lR5״N > IDAT[nX0fbP27Ds$#XC0֩I|0cH{Ehi0@QOc)B0USħ(~0$D1> !O8@KnI;<e#K' mcxN0pƴMno6fLWW}EvzytT1_QxC:"khlhڴ^Ћִvv56>sau흝]Y`YS--rzF} #9TyRk/9~x>t(;4o295[^ ZsϞGYh `-OlbΟN|XNvhYG}^n^~eH_oMC*pEY-ԑM:"帓0K%KdgZKノ'zb썙&b%|M)#of3(ȧJjCC4튯 iRh 40 XDUPe-Q.v}U֙fpK[g}'?o]֥Cae6Al޹M-Xr֭Ol޼斕7%k>ںpKϛwe>ڵ{st¦qG'22?ѢrBwpy'ORUQnSG kd3nT>ٱ{sƌA{U8l9b~4L I4PVpa:+wE#͟鳬kO74l߳o⸱ 88|'Mu{]]Fd:gİeGGegZ.aC3:u_n|E)%7\x1Z4]|E2BJT *fE AOqB6b=3m#%L]ime¥xd /T]<8ћbMiVKE'AT0ҮhH@P4MS(aAt2yK.CM=-%W`ձmoy˴SG`ӾdF ۿ+Wu[ZJ}}ZUiU5`am}74F}*U^0?/+u]C_T>9?عȑ gQ>㊝w7mƦ,;:z5wcsˋo}??XU}R`[7\Z2gڔqg)^mm?ں!> ????A?yŋ-ͧ[c>HS7D;;+^>74ԛ/^ GY&Nh붎Ǫ7|X / ;崽D++ƍ"CxuH9K,G(+){xm(뉨'Tne(tVu*<16\ע$  )82YļbWc9ʢ1Vu oX  e b;N4S,US)S( hJAVA8/+iQYm-hj1Ĩź"-#?מ[JـXYߢ+>Fۑ.䰍%޲2,񟤑cE¼8bK9 OG;쬬sF W}'RY>H9əOOO>VYrΟ.nwK1;hv7W5 .g3mnyU |Ośq@aXm9:dbםX uxё&k\ROxw'U#LGRNl佫~3E_wbS!9Y9| h-(-P#YB4 FRAQ#[*l,W$H-1)d=7d#GxD6aB IñM?)I!pʑK8Hj\'FOeHh?%z\͝iIqG6p!o䄟^f5{Q& {.DM mjj'4l+5A*Y :pWF29*FVc EHHnBuJPʂ*A@A_{M:$3m##xfv qh%鄍3qQ`f"Y8NJB8C0@xSqzxOrɌ04) >cY3V SP}Ш´xFL!~% 0kiK?l(P`,{cшXK${E^rǼ0Ell TDR- )7!%̥6,muHӦ84(B $F}>ӈƢUʨFWKU%znF3?=60ΰ:9SG6b%kb*@kj 6=l}D&&U*pEK6S2bsm1M${DEeIHYdwxO(]$( D۬/eERA%*c>QBI0 #t4b_Ӻ 1I%VA4Vd%m/1ӧ)?HGd78 @6 4aVdc'dٸfdd_ADHSNmNRvȏ*^hrM摍m˛o9'j]e"^G )ɵUm'~3yC^N`Jv1@ (qz)$,Bs4-JN|4Qh $ o^LDJs> "ZKQ),Gl𲆳\?B6|%QIrfd"vOtw \ ŽwJ..^sq6Gݎ7XkF[{RHJ.յ3"qFR)<,Y,nӓ"}T13%c6 bT0 m̥u $"MI|c˗neOoJFI))`LLM"P A,@SST %HsX`*Ƙ{ D[yF6vBj zs^CZ\ f%N\UjFrŻOh,8KB'3uB(;{cܑd X?mvtj0ۛ`=pjL1#c8 Ft5B*ک0tՈ.E:@^!G)DS(Ҙ#wp!na;ؓj#RD6TM\""uF662/c=3Qݍlzk\s$]bJQpAKPs(]d Vl.(Qe/eRs&fo$L8&aJr'b85D{R)d#!7϶O8{d^52'h?vݼbL!b.e1yP3$Pc11G?.3ܨ/_u#WEhN/ bB|~l;ٴ~o&6;i8KUg\&6Wf.GR@4;SCo'kbLEFEfUʜ8V>e;9+ind5KǓÚ z7 STPTolPU`{5^(bFІ7Zo?K+n=>2k"p,8/m(G8%x|[„pcR3;[Z&q[~ܽH Kܽݔ˽e&"y$Q@aP@UA/)#Qtu2M*נ*Lo)Im#/&D66k݅lNt%f?EMҺ k)(H5oA?գ!YLqJ,ɛ|z@tڲ&g牝FFČɲ8F #XΓ H Gp4!jNp@ߢ PDI@4DU@dhv׷Tڛ_r1-x &CΘG6Ȇ%EtXԳ?>m-tƴn gDWߝZ Eiq8dH[n d,CSst2Qbmc7' 4sB DggY5υ\(" h(eEݛXDUedS䫔haJP) кXbvKy_%/23P31^xԑMU!Z+=ו9D^>[@źM{AdQ&\֪d`tH &gYqRpe EP[7ED}mfaMxS:'ԘH$]JX 0@^V0 BT%)BrZVB4qZ91TdB%ydO۽Ȇ"L6 `w )@.1gWܜMYW珦Dh2όh%)OoGFS܅7Paw6XB,YBVt !sحXN:7QL4>2hQP!hE&PDAdٸJgq :p6<=ֳp OL8ҡmzF8]7+gA= dlT/%ye2!=(gb& "?A|b*YiI"k/7piW,\ߘt mlBP Րb( Q"RDe9qY73dy 㜉f NC4E1~\l:QI`ڮ(N뤀l<@ۢ 6wDl|^Ffת` bLrr3;mx_uk IDATL`Bxc{YĻs4L_oҲ֚c}X]nl/`br7 喴XQ'ZT[*bpJ,RBkq.19=9*lt+W2dg@U EA?Y*(* H@UEL/aз-v[d K_8>ycD%tPd$@6U#L/L@n3Q igY%31SxfsK땍CTvpQ}&"+XYGб`NQ8@/HVL\d w9@Ah,"^x}*"PXwWWuEQ $p#w823L9G}UO=tuuշOu&v!%,(F vBƹF:%SU)lDEU"BE&Ȇ nusQr;SMoӜ P" " _xK). ֘3, T%{|#H(NoJ@+ hTH m@'A,Lp_d:PA*(ٞX50INvȍQ?#=l GFMOئeLQl)gf9~XShwNo\dEڽ|O/FԊo,g ȊUmMPL"MGY|׏3>2h@ @ba7[QC(a@;!0`Y0,Ιs?A[[omNW9|_A2%+ 4É teݍ '>X 0CJWU2>@ŗ~iZ5 ؑ}V x[4JA܋0- )HwLX-Lchc.f}U4@v +Eˆt2:N,M׉j˔~ 8S8G()nv'>m+Hg}B6s6 /nC68l_m1X _ q3Ka?pp`9*&[I)YFLMq)q8{ʳ#rA;#`Ӑ'Ær;`@ MF8 ء v-@XA Ku߹?A6prd#$G6TQ7:_Q(JFIEO_%ʻeQu -Lɸ!"]>e(JhwRA.!6H+3`̰@pfSXkРCfE%h@`B7ۙo)m#)*B*@~?ѳtOglT.7RXCJ*(ljQx >d7muQ+4H62'ͷ1YBb\|zŀ"+-@Q ԰ha`):5`Bhh@#jnb%LRBT~3(Ul bl?OS"d\Y@EGZP6D6*R7i E=5 &O(xmx#92+iS":B.^E]buQDlvJC;"4`ю2p M0@Ag';@L#i TI*|8"d#xBQJsA3ċj('H{bqŻ JCTUOij(}y}׫ atL`38Y *zSR55KG :al8̠AvZ\D4ߖr HnEk"TlvL3u |(G7ߨ#W~-+ض7ٕy\6~[R2 3y #o(dô#(8e K(@aD:QLhGP B;@CR n+#2.Gf7ūBE(J U WO׃L~l/^]ݨ;`p*OƩ.IRP~֑,#ov oD:hөlYrAF@[@t_&m8 <Z;t6a`avַU*6Pt1{DU d#RQ[MwK;I/2VA ¼VݲoP%]y>6>U JT"bDgn"VJjc=6 z;+3! Xp@PO`P.C1zr $ Q3X3FA3tFjoȮ zRW&v*Iy|V~@&ߋj5r j֑3WS]#*T8\0 h)P ІBOag/&'CIAt`jFka;hUj /Ƒ@"chf/rKҹvH7^.T "D PRHrGA7?'~Ȕ ; v3;vjb9E. Q8E Ng7Ynjp fKG$<43g>B ,]<0%.??HCCc F j'3[[͖7 %yؐAM7k﮿;oʩ'T sf~7ۤNO1o욺r)S[ƓsGXtwoqzG[RQ0__>wci (5wE]tɮ]?8q\jJ SRS* H[ǏojlIkէ**Rŵ[Z+*>.1- .OLLL_]^B_|KKSSsCHͪ8)`9hSdO@\+"My7x#a Ѻd%YWH<-~>D0+]L>ŋ+|Tܕ[[:/)VT2v.Da4JXP:! pmPk5[P,F w}Qֶoi@rJ]WW>YQ]+^]$]E{. nWΈ3)(ಆdekim|wֹ5p{a!mii{{e#G" nHIJJ߿_k[$%%?ph߸8WU7̙n0$'qlko7&Okԇ/{r MW{h2cSEUu;S&,{+sl~]>!=D/7}=rw)00-ty+q`Zݷ-ޛop]vB#SK?)11)!ْ'˒۱X 6tOxپcA]`BB\7uEK(ٻqӇ\csILNLLLLLN8[]0gİ'zp_ᚗ_33<733-_p,oĤVv\7ibޤ aaEEW]=a1[ w,Z~In^zSZqо'5[v= 虊`qc8V,q^Șq ħLҡF.&Oyu̦Zef ؞7֕ot<IJ|O>P{~=zS;|>ڙwSP0(3Ec123߿sFV/u̫"#Ἲ 뷸Gط;o_S&7^?Ơsɨ5Gs5cF1fPffٙ3o~YfA1 zcccF5<SsK { KKNۏ8jZnim DϘ:eێƦn_<-?ߕeB9oڋvkf|kܜYt[ O< ""bSM |H ^~i!Ξej0W)JOK2>OO=ꚵg+\^ёYqۢE7m 7"# x|ʿcsss _[qL`֭[zEEFFYrȚWvҗּg=wݑ`FN0kf^{ ge'N/bYz/ii|ˋi[2?bE3F?포e7ʫ#-$q]O(Dž6A IJƧ7B:a'-R5Mð[cA_b%0VV Xҧgh>|C'**\[֛#I~$8YYyÏ<{f.dg17A=? %O~'EGK6okL{Í\3;Sdgdgr)ӯFgFqy ^zA܏_xx>3kƌvs8ʪX|X[{!CLɉb8~,%1Ty{ gN+?ݷzE g}7ڽ:!/oێ_7Ea9w/]W|cǚOw%rۢOѧ[ t]Ko4qÏ?w3ڽ{?up\)o[5p._~r}i'woSS]>/zY~⸸GWS]&&%zCe9d> w]1qF굥HHAٯzѻ' ^H}}0.\q,PP*O-aE^r٭ -y'`tpz 8{DاI :P `vP NЁi@v(h@֠Ab`n]S٩)ozv7ʚ_1%ZzVԜt}֩yy=rXcLEuեCsQWVrb~? s`\ .6>m%cc'O޵VWdn~S\pjԈs3iܸIYt۲ۖ 7..S+4(+>L?czSÿ>Kjj0gw:% ͙9|Y-..3-?DYwa18TT^U}_{{r~"-',RyꚚD}yU7~eG'M:urϽ;(Vg^}'y//Vwݶ@Kk_׬1>immoF `ܬL_]1cܹӧMf۷ę8~}7/`0rˑA0[>}Nu@s< &[?z<?0{|?p}sc@RVbX_mpbY馆FݭK&̬{@qQyܾ@aGUVT≮vϬ 3oGz.Q>x%Q- < /ewsY"𔂼<>Z̚ǥ<׬mji=FdӧǏLy)S-<B1ߥ?xp̙/_MØQߟxྶ?/*;}&""|֌ɉn,w O29@vf&m;v4< }Ly훝vʕ91!ŋLM;~ŸV~⤋v)\tiWpknnkhCged-[>Wλ6ϙ-.窱߾a_`:y,+#EnkeNϝ[WW{)L&TٸѣF HK-!^w}?u4aM7.N}XXDd8wxn^8eﹷ+D~pہ?0oo0[,]x-[/X:V{]m-cr[|Ru7O sP67,v} ~ElwL2=Bb~݌s" sh Nd?" q䚹/_8"NᎴc3ID V sP;@fz`KF b>w ~Gb1n/pY⢢-Hí;hnmz A9yl݅2X[fw\3E>‹\7S7Pq\g ؿ^l|%,s\1723]}b9SЇc1U55r>L!1#sM7[̟n޾dpcGLMlꓭ_= _:ӧN75WubFHIMu IDATbB<{8Yѧ[rN_'9,Б~C`&.buմ}׷;vL偉W]p|^SeƏ`rػގRbD7468[^__Ə>mrRQYyͬĤr' 2m~H80Az"_}u欙O-'\ʲ]v-_VW?ꙶgxid6{؈ٸ%spPS]sן}?>O?g JH:|0}ء~K 5;y#ԲY>|Aw`}>GwJp[r+B7Z æe`##,(U AYZZA[g2E'`eH6ha@jn +zA}3/eڼ};RnjJM7W!4?,~XuG ͉@q?g}s ``Z.z-F7s׬>m>L 0[>;e pxՐ![xaz.>UUS~8.6O~æƦ% egfn۱vն}]-_v#u?kkS{s1hj08tdsv g@С7`\W>|gkhl &|v|/ uv-I^tb^pbwRb"wɈQ K3ΜX5sLp&m@ZuU`٦ƲI/so=sT='0o?0]e3m'b7(=a͛/iI%J;Y#D3*W9w(};gR-R~< l-,刜_"}O85.|#=0O5 (T3 va`!;ìCEDtm:-ڬŽR,S/) `ҥ][n[09jj`=%fի[x9:p}`\QÇsܓS <7wukNIqu9z}yeeٙ3C JKMHKIpa'Nt&t֑egع0""mdlx˜w.ZtϜVP][W^Uԃ+}'ZSUS6^A-I NW⽪ y%LU{KMm[7\2,#%߻ kr(g'ɇVΔ)/bҤ?AooPS[sL[o\ӱO|~ܹ?{Q=7HO[F7fLZ[۸e.4 Aݰ^f\^^qq1LŜeֹpGΟ;n&ڷg/Dd-Y2 [yslIOw/XpۯoueA9C\>ݸ)ӧ}|wo䉏>ƻZqC+\y_d II5ojbzۡN h|.[ʪ7. G|#0,iSB cSǓKȢ6!57v ,˂j-l + "Z' 7=RL\veR*6vlJb7;wN⊬jbN_1ltIz!{KO0-.2zR K]r4=-s9ykL?nxnԽ86a7۾%Xdj߷|ђ;v{;v:o;v 8b1/iᦏ6quCsN>̘́6oђ/grY_]Yy\^?^Rop pg>S VsqwP.'M̼rά_:'+]mn RӤWF7_#Spu|N* iv-T0M%3TU,Pu DO,.o9:׍D;.R VN (Xh BDDūO^W~0.rUqQK?^v75V~Ѿƾu8kOyyq›-?WQ]at˜K9Gpu&oNV=aCSf=+s?4~ÇO:@ׇ556n|k/̌+.=EM zE.-)%s68|+XswݓX̖u}pSKLJϚĤ$3t"Q56ADaWGcz` sOD1TPX ݲSK6 T-(qDӴ0`l`l`  = m^ tmP?ysgf>z͉qQ}O~ G^~\gZf'./oim7)(H3g9JIwSgfq/;uرgT645umw /FDDIOzޕuԂ}#Y /+vݻݶcNJnÝKwa{.ǎ{1 C˗p"֬-*=6sZAfzv=vlpVLM.echcںm{|~'N|qN`O'Og/~)+=v nhlz}ݻת= )!X `۰cwRΖWHOK+h;9vsO,+:r4=-Fc@vvVUUui鱊*ӧMk>1S/= Mn^'Μ>][[g^0HKIwŲWڜ뮹_>tl[u.gwB6Nq.~a30Mmǹ}!6*0%'G 5k׿8p߹xC?xAo8S^ٷۿ;nǚoxW^USS^Y𧫯/; 0eOjڌNWd޹QL}CE\Ѧ:]^dݼu+U鉓U55." K徱w'CEUsl޺?;r!'.Z0{9[!XLy%q8q… m5u--g+ܟ.13/|`m]gaJ~s8q}˗(++ѦO>ʼn=a6W"l/ `[ϙϓvR M8hIicOKKLH϶oUpx) ⟙td -)*=nGOCGoin8uOLԒCE^gF"ru_(XX͑'蚳Νj sgrj;~;͸N82BƹY+eca8G3AsLbҷա &ʂaa#9n퀹-ac&Ȇ9@6uy͗n^Y8DI8&5A_Aopis77EݕYwU=6_-/'*>@bàp#b- /y?HF%U< I/oX?ERxq;?:e4SU0tA kPS)̥FIKJtfeBLaӣSZ`J)( ;(gHzRՠ3ph-DYS)(6}0}i4%S s | b⌽"}V Vp UR-(nU1(.(Gq[A ̀kle,( (R 26ZQ4j5Fg540@` c; "=K/2LB{B0RmL5隹 g )H݄D&!_U ~3s !70ԗ%GI+. 8fKd]D'2J>3UQUƚBa,t贬!Lc5F ,! `9Y ;1bn`* SH5jKe5!li䍬KJ6m L A:ߢq WȔTt p4pG2|Ź7>)WFhg;!6(@jLxlD 4Z-40h;>i1#-!wq& }}1n(=xgX\V*eUQ+Su۷6^zU|vol., oMR$@{lbJhрpDzN{9K C8; ڇ3~W w\?Yt[Pؖ+x|#dZۑ񘼄}O{9tk(:/}}4EDkQLD ^GەBoD>.EnrF~LJmۅi3%`BlZbah`%`F f4,6@@ ;arRw^r)_D6 d^9(dԚQXEsT6`U&XkH/FC$%Q[$J)}B*ԇ@o]:oyFI !fa\!}O<}O=YöRX RM Ym6" 6zX z0тA`nHF=C#3{$ +E6z@y8 "q>$I?> F+xU y_' fuLBH,*]z>lǧԺM܉({c3h:0Vh `Z`"۞Xmp! }$#0$Kt q}vCZ?BCkАFCʦ)5y5uVW`]$u*Yc,JbRi&CjP,1ձ|}Nd7u" G -U\*`_dAOL?VKluPttBGIA)t[bh01DGV `QHTY]v޴,,$dtw[]՜p"8Y "CRtTĕ_~dqKguWNie|8,R]YE\)2L Uuu)mN_77|Ș8fjP/'8 OӌR"pD \6QL.F9`Qõx̔&R3|]V҂wz?F(Uo7 ,(/KRXhltThH+t  `Xhm8 Ϥl  逽 `UYyrUWL9R}S[뿿~ґ?ƙ=o22$" Xԉ z'ZF V{\Ss+GQ鱰if"/NȃZZtQCtZms\\'28sO@h2;Ye8ؿD+&?u챓eL&&riy f^#>V'7@@Եr Wr)<s ԩ}\FQNȊ7X6N?1#5jF;b8/*ҿvq5ŘKtZå贺Hopܸ~52:*ԔD^ϭ9v $ocIMjrA/*)=wಉ~,4bv  M0C XweJ B#tٍ'TߪFrHxI&7D"䍴ҭHKD7F [8STw8B==nv;;`бY!`585`gIf1@:[ap#l%W K]6fԦ8v 8df@bf?$9 hlm\Ӓ˫9ϓ']:ŶyH@SCcO|ty%qFc457-\AƁXvS2h2mqoDae}cIM--XuΊDFD\6Iyc~iH'f[?Mɛ֣ HRDbHjwkf\$(A4"D=W`^oRQ/B lɆp؉0Z0ՊPODmF&7 6L fu9o2˘ܜvep)) }w2aHVw n/s'-P]HlLc'O&'~Gsga$@r||B??(Aϕiuָ:^.*=Ÿ`DGFt)5NqFNSz$C ʬw?q|s)o! ATF|ܸGM 6؂TUGA`xEDF^O~S2FH%>6԰!, lh% D PP۔8*Ziw>`)m)NijG~ԞcmI'$%ϋpvzKa^. &r2g=cڱJC(ϕNF1n;x^@Xx{މޠ!7߇@']ےXw{Q*ҫ"pmP}]w,q~FXX;@HHA"X`:("'UXf ]W36z+:~>>TXHȤQ'#swvXKΜ%#9e܋Col7B8Chj봻ڈIfJ%CsVC,%gN52gpLt#rc1jϝ?o2˹ܬYiN j$L@4'rde`X4ҊJJi f68+à;__ϭqc'us{8]QYSwn䰜dc\\zsQqFcEU odaNЯA:7 ʽ`2]0xTX##eT? ~ $ Q =A^^LYڹE$PI:Ɋ 1 nC"hV  W#,\=`5 +,h36$k#;l cm)K^TI۸W8#7iun8c55v=jll7\kAqUݹ>ucz_4VV]>aSg; #5%k`zB|s,,$dit[~>T+7֘;dPnWU&'ߐZmܪaА:ÇZ E:S=?dC- (+ILI_A K/jQ<\'ox&7XS k " eKI3 XS, DCebCEmbG8 !PJpV46+,f1v?2jגͮw3 DBUg8RxG?bLl8*~D7,$$;cҢ%tdfIMyH=sT.a4ݯ]#ȳz]=v?x&h|X{~znHw yXIdqa}ޔ2&cK4 {Ք)yG3NI[%"]jwUWcJW0^^dRt yjodG?phs6 PwУVlpk>&:- %`X !`` V 0iVkvtX&x+N@EЀe2P |nqd=\e*ٺTaS-/ ,m*fBڢE6[ P۞l}WCJVZDUt+"hTh/3 Aˢa+QH3EW@w*J60VC0 @YP4 ꭰ 6j(<e6a],CWn.>m#SP%Ph8EW by]iUdR!{%n`:@㪚gzu=,fr.//>^GUS~Cap&dA Bf0^vVP+4f tRh(Bk -q;OC v9a 0 >i/Cd!=Q$os={UpgFvt9"È[(PDkAjS֔S詮MyIO@|# >7İ9 0 L @`g@5р, dfQoa)`g WsSEj }KȆg^ ["O 㩩(U 'u A$Kͺr1 Xq5Rjг, gdCx~Bw7b 6&^) |X eL=tM B&lV0Gh,0T0cX>#A Jq1FA%f#@ǎE|o{)Hޖ-O C(kO!R_ JQ|%oax+Bب:)ǡJ*|= {Y!%5_BoBނΉB4 M'NǗXt6+(,hm"lm HSihY@7|7Ge^wKF/uWVK}f0a 4}#o#?ЩQFUuȘB4穮_sh!P XՂX3 h%VF/j3fH0XEXMT4Ůܲbiq;S5+$P[0862e~=Q/bCdg ['!j, .zaElk DD2WW_ѐArDxjj#!v0Dh0X뀾Z, j<\DNCм ǀT#kWuƟQO#S> E}vEfo"of c+&~rF|1mw*(RNZ7FO*T`k`0@0` X:>I)vP3hi\Rkn8,Q,_>eZ>ʉZ(|MCVL4t)X|CuJ@d=ruxt6+( +F| ,Q+@^:-+^]jdCŏIڤ(nNJl6`ŤU%eI|#XS gJmînBpk YFQ(Z[t&(%\ӎIO3oBd\TPL^d~SYYbƒ;np`),PP7jQ@,JP+anجXapp&*4e2" {k-ax-GNB8DZ6Rg~P[M!/j3[~Rf'w%DVy!}Hq1AF?2Y?U\w6jI2 [#_f 0>ɉ"R U/"7Dv11y>AӎѧF̎@+Q⁑o}#aZlhv<K%S |}GUk܉pP` Z7H]y;6P.a1 `2 dc$D6%5_Z]$K4`'Tt~qs2ND87Vx?e3 n7@ V8UJ`9TK<'#a< (`$ofE b;HtO"Ƣ0>m$nbIf2MXkSz MEg3s1X8Jod*K^ MPd]HUj Q X X] 7p[<+ip9`, 5CaEVš ӟꗐP>N* 6߇^՚Zh}-&V8E539%?ujO,@+.Dqpe6ޘKF|_o of#/4ԟ@. 7`6TRX) HV&>nER'a< <-$B|ۣh8tWȮmI׉岬Tr8eCަ_IZ1¨oevn5L2 e琑96|p ]ec̕I*iEQR*å(NّSMx9979:S8x=ŏlJ:T5V4y IzUbd -eHDXghcdNx@ص O,LX^G KXB]uZ 9F N U]On%ɾcΗ<ρ/6T:+aN2;n jY`q=gE=,7].vGBna[ D/U2VkӳU|(W3ҊdfdUIG[Iਓ`$ 3iKӯsրaZRޣIjֽ:d٣PJRDՂʒ#,h(\M\ 9gpjäHV.rP,5 `%ZA)@Aj W9X+ ?Nztm%#Mu=mH3d AV s Қs}'䝼eŁP+0 Vg']lA̹!692ܤ0Eu:4)3)44-!й0Wǖb`+hÃo_|bbZ10%8`+(p|p8 \@pv}V n ]P7zG|׶ UQΈ|=_@0F&(_}|#j`B͞[ 7 gѕEFfQDϣo\ɫ֯*6 .;;\)Pه.HUUJJ jD+gVy0_` F5|X,U)@7x upV \DOՆ7 /.,58s?t]GTR>bBD7ު6M͑yE 2 `*X#oTj(;PuD7KUlF\vפQ7ijqOUn*@)@@ypy  )ǁFU]v@3m!%E6b!I>pHua7\CX74f4if*&I|mD?+}X17RǷHQչ$GE8+ xC$?h裳K$ѶjHL6M3iϫ}[7fR0(9.;@  lW`ppt↥6%1LHƒ^G[zz դݧyޝT)$Q-~4W yiZb)U7d.5wKc3"M:T UFO)IZDI;_M$b3(77xxr`pQɡC>&^tD )! H,V *pQuA8_6:@AY2 `d^ ̶cuR1 1M}=aKs3R2Vɑ S$:ߓ%Y=o՛)Y]zjή!90̘bX[O^5a|۔(2(4`}!olT-bj'ay Cԩ7>+8 08 " PTzb(XH5P65Cʯo6bL  kB"j ꄼ*_bЗ !"cx#zK/+uaÎtLKckdt7 WA pѴ9eQv-ҶB~X$GY L:PJhi|c`\$P+||X iPUpNX\p@ P'(.V pSX80T% _H%XS>)6Кn!BD3E0aϼ>"aF#$ix2v̵1eBf -x甘DMN]ϒtxRjFKeY:Wo4i>SƀQ3z͛pOgJCb,D|<ۭm8ڨP W.'UܠP \.yjpaBn:b0Eh͙:PXZ!!4`c^y6o~i>vk$!3@Xc@{'w|nS&K=Սo[Ωwi`hB|kiX,ac84sF}*di6ޘtN)61b5 qwsPodʡkԴzpF P)_*P'x*X9P' K!8 0)Ujˍa mpΤgJ5 d6fZ/4:&DH"M3X ];mIkOdjBI (ԄV~  } 9CA%_ "7HT;VS{1z3OMNa7z?3k s@tQy |IYAGv n [hN W.<b&u6&iI1M'5 [ j ژT ?dxp`f75@UѭS;rQ>jԷK))F)oʃT"-D+D-cZ5C{uxtnRg"QK<.'WRqeX(PJ lN*@UNh%x >e p#Ѽs '.k'*K˜oXd<o\0+5Bo AIf~gD'5_ʴ:)efP$b '(ME;UnlSGbМ ZmGBrk~c80 PBx W[*sŢσV/q@yp+ܣ_iuA-$&S6V 4(H HND7V* jShw:$ Q|ͭhc0:"sJ WF}=G( uoe.B?1 7*|U x3Ln't=app񠕠pWpU|+G|'TÍb 2}$?7W?.Ai0FARQ:n`f75  \"ͦ3Y)7L%Qj㍌ɌsJT¨pND5vWit I1to)'T&nWLyQ!Hiq8ZY K%PZ8A `-Q;XX^$D!LkIm-FJ #'`3zyP( ho-&" f3կ2QhDn-2V0ټFq$_ᨌ7>2rNiZoi0o}ΡZ=H+LR2VlBAAI'EB}r qM@uTU rTUXTSDU ԳDr wڛ(~vdȻ{D*g}LKJ+;Ы^=GwQ#Nzb?nEdkۯ\!䳷|_h葹ynoOۋ=#GΛ>鉍[:*exZi5˹|EF%9n|ؠG2kiwu6M``fM5m!]w5o.zㅅ7<@TXP(F5$S/6#BTRZzyiwv}i֥s=)m<_8s^"xIEEE7 BI~x<.;R@34z(?@"aİ+asK!&&4nҸў,f]oΌ m|0sI6mҮu&&6nک# p8vl*M̬{oiދ}N[LklDxSƒpeEo"TYz2D +SD 1W' /l5Ԓ(#r ((XG իyxK (G-ƈG+J~fV2CWu!n +_ ?6FUD.'\%bTBA9P7@A, Vw {˯1ƌ()JInr:dyذq^7u'Kv7oع)-F &&5tpJrrNn޳a,&::%9YuX7v}޽W^Р~|nݾ^3b(5dݞwmʔǞrcrrsz~'owcG|`ؘ֭ϜrƿrGx=&&,"beey.׉()_PŸݑi@.zCevǚk p'M[aYsδ;xU_ 8ٮukGO8ӧ>s恡C~ BNN\ll۱㥥eڷ+((LLh 6&ĩfΜöĸGw&5֭WVqc,[r[w\lڥwqWFEF8}~RϴN'Op17Y/nܼewI>yRGM|ЁZ C۶@qIYfo-p`߻gMyvҷظs^@v-uo^sxnW~|j_0Rp3]|U_ooھW_hW3<'=g.ȈtӶ?}Z L~Z Y?g^1ߐ fLی>l姟m999?ޙ={Ι3{ܓ}*;+3+>>SjC{tbcccD^Hѱ1:EDE!ؘ‚)㟚p\3=f(Z-5`[HJN]i:AaQh%Y R*PFoL5I7P*a)%m |(̊@L)|Zڥܤ"2 70Z9_XT\E xX*ᲀԂ ۪yVK\i?21̯2m5_ysg9yyC+*+>iRFܼO/WI著Op1{jsĄƃ^,7:g׮bcc+j<}I)hP~c;'#iiw{V* IDATtN~]bc8qEj*n:p@~A'6yRNn^ >LiNnKQeHKܿ9ӦD;y O{PKޝ>a|m-DDZAKKLh| 7TRZd֌CC{8`ѻ I^o/~?u[˖Ο7u+jIKJ-zNT$)).)˞}uzcS[:o ˟{ǏsߠA~Q8{ukg4"<<&&z Y|;ݾfw٧OkKӧՉ4_Y+vɇnݷo/[=3Ǐ+,,ТegR]vu8_^_`'N$ܪմ/Ȓnz\YLsX(wLM=9qk/Q"` \PXh2_=B:CCg5y$ & xM@on Ŵ̢)AUiRZ)8RJxbgӸCbM](2ംx'8?Rf(^Fq[L{jGLK۟Ѯu돿nD0w(51cd>:~晴 ԭܼ;{Ϛ6Q;]pmdی )0wߧO}e=QGW h pk~M?h,.6v߁#=?<22k.K-_0ҲV}5ߝ<}NTăC&&4^7x=%b68!aM 9%>akWnk׵`0J1o0hTVo mR !o,*ݵ?o.))}{ >{ʵ۵3շ׋ng'>̿ލ^ݻedNQLШߧO:>#G 0#P|\lYy`I>v=6&:'7/6&3KKvgdvKjA XlڄG###cbϙ=~|3#g/ywɬBe9y7+#iBcS~C=k8,}{=:Ȓж-V~lj:}oܼEhvٛ޽ӽ{tW oa?KH$+l'vZN=etY#f;+׮ A 0(URjz{6l 9eTTTII֭$lLkx`!W~23^s^_Fii?PlP^^c/DgYqQQ6nj+G_mF׺C-[6i~{j;v=ix no]|.> 2甇X+o44Yh-hȕTiT)o/@ ߀*7:U#Fi FjaJ0"p T(8U<={e 7wږ-wVej`,%tKޑ*'7P__㓮ޘ:a|Jrˍ,5c۞}k7t\mMb __,1>/(Ό)^͇pGvJIn1b̫͛7Dpso䖯~znĸN|d윥 =9M/bCoaZbB?ݑv[:9y7-=$-">\yf/Hӊ^_xTv|*+_f4g|qy+rn 8'7<1Ow O兙|)oWkoS#vH~yGL2hʊ⣆9:eGISzj54T8Dܓ*J"h6VH,xE˄sK65o&P a?X*E6h@!Qs KvJ+P "ܯ NwLYl86Klܸ{j=Yո]ZI= '7OKL >~-:N95UxL #III9F9yԉ;np1̙v[7kڤMRg| ###v7B3_xU=['AEM8zQoB'}#Whхܼ˖Ӯy3uwigFޜ=S%~~O^?o^\RUR yJcw{̻o}t;v ,oڸ۹gooGz׮}())V͞1= ] βoۣ{̬RZ%;͚ QYJ1=pگOoaM1VvڭU[7o-Μ> ;;{mf4C/>[٧oǞxkr[*.>>cGmVŧ+_ 2 ? =5i/ 3&><̽n5uKrry܉SKMXc9!<oO%CnPaV>A:xB9hn h̷y)뎽.%m㍘I|V*s3}67TyZc*EYV` ((([/ tHݳ2'U ˍ>''iP)KOfnĘ{2JOl-[צEsjbp;yrǞ)-u6 aO{'O: =~-%>ݰ,;=&&zݏ?JlӢ z o!,.cݽ9'` .&BNNlL>l:[nY/vIKyokXZM|e٩.^ڸyˁâihtDb >bn}+Xւª;3ݻ۾s!O{xGΞ{ꑱS_o~g  W o:xp|~B3cb3~;2z`Z:sp̜gZxcOFތ-9d ^A{ux3oyhDg޽q;>zFZbiaOk>͛_['k͛[&%;O=les4~u{qIOOn0i?޿p^^^&ۏ=w?xoS'$>okw=[W~კ/|pf斍Ea#{9/ط檩F:I= gIhp)H`sIÄAJ` S  PʼvXtN)JLi277»\/̨V[(OmcBot%H09)ȽtXC)%[oq8)H/ ޙ xtCJ [_P?ǟ>=w gL q1q1dEYGƩ/.bN]~h._%;oRoOL(/w9a⼥1a'n߽BNά ̚p}ɣ{k11gΟ; +Wxz1{7}_z ^sxbH2f/yNTԒY3v}#t_P(5lZIKWh0!/<^-cѻ"#"zwɏ=KċHyF~I үl`߻S[ܳW>&>qTvx}#c6rcƼYT\kÇ=>Zv4S;t98'ҊOwq_:L=ed8KM w߭WG5ln~ڃ C7tt2IIBZx'{xѓR{x ܼ~޽G}.Z?^lLu/YnC}/+҃C>-xu;^=ڴJ^Ǝnߢ[W o,zwYAY`_>tpoeZ@GU[` DvjݢɓbcbX 99G?E#n-4qCzgx}o'Ϝͫ[m;Jj1kٯ,xd_F?YMʋ,n$L.m۶"v#!1&M= ;vz;.>NB{#ػkw=濵h Hi{@>,=Z~s'tzgŋBڼܜaG~j#r|+dD#ڜYS߶ L!oLQpr 甮*J9!|GjڐQ2 f^2ȥ}ԡȽTs bOiJ AڬPnpSr>{!sn+"WWo/[ XC- nede<bǟlܶCXG K;SrYs|sIǎ=ਖ਼3swIMwkW>@]>b0.bRgM*F)\ o4+"Ĺ #BW"ERMmpTʌY`# 0P ( 8ݨpE7Z]rON5 DƗ?4VDՏjekzzXK[4Pp~tFXnՍڸ}ĕfS"!ul{Sdؘ.b6o\}&A@BvZ\Rz7e̝6zMzqe~a60aNVNBBo $riT}岗_i/(Nv! \9P_iwQTTtؘ-e砐o"ٓi%AރTF"MǷՎꗺ={d39=0e0*%Se)s2UT'$M@*STBB'|=UUo]n%t$ J|AUQ5u0$Gų3{v+14Ez&/Vq((\M&7dSOpu34*B4ZHE ,nה!LU!!ZHIgq8X]1P})p}:9B-Z ]F(O@9R& 3%qVWX@Xh yB9`}4kp?5Q&1b{&_gRMʱz]BbᐤTMndDEӣWuk:_aImT^8Cܘ7LpC[ @G˹Z)ax̂ s?)$ݘ_V)3VQT5(ig}~cu2گHh֣X凼TlAGOVEV0'r()Q (Қa{I[m|.MʝT ʭ=DD)| >KR~C|#mLsQ0zIɵdMBetSݒt0&: 9"lC%?sc ryte 4+P  sIl M; ̩/JF*ǯ+ߗR%.(ZTB6@1!Bf~67~]u+Y*U4 Z&\zWt7J"9 Fc_(:OߘsNm3of2`@sbdA4;vp.OPNXQ r"nCx8it{jXZ 6#ԁ3ޘ"ݷjٍ':2niR Q«{oh#sJ¡o %QoovBoB;1Co_z/&u>#NXn}|$Jp^Z>DMF!Ŧb'9Fega`a$6S Z$sN1)06 ~%JW/b֘qD\dX!COxY, Eճܱ%tO꿆U{ Cx٘Q $g*B&m"9-L7&XH0%Rc)pNXQjeX|ë4{te8s5o<y97o_ 'ppP9] O8gaZ[k0kmL$3u)f"1 )u.vVHЮDgB09Ԯ֪|nOhLeԭe75~|N T;4FoNvh_(~%2`o؋o y1S6KQ?)kjmNv{ms8WChoD6@}>RyE%غuz%6&z#Zܡ]Ŷ׮ bY^y0XuxzɽUhפA}KT"}7^N[:u:rԯ弚tHNآokխcYoGƍ:s.ʕ D##bc8 .UTTWN;;F;QS:vekD5#~|ܺЮu~Q#wٛs!Gʩ:mykԎqqOϟܙ-ZDFFoy L)Z_tkj6#oǮs$ܞصWϯW|q .(R$6oÄFbБYMlV9%GԉIJd{sż9ʋГl߾K+gy~J~1Ϟܺ7\uhQNٙGtûSpH%6qk?Z%ԉ.iZ1Ӄ;S!{zS`KuJXbLxx]9g/K?mڦvN]zYPZRsi٤9U~-n۾urJsvSڴo,a(Qܱ@z]*/;< D"|w">)MRf$xxtqb|%7Z8$4O(Js[6N5lָ)U֭jl<|)i)͛8yp?eɭ7çN i%4ѹj>{nwfTlOs͚4Gqѯ.]ch?0;;Ohයu?^Fл{ƪ4Oh%cxx<ۉs4kܸaÌGNRTrVڤ؄7Ⱥtzt:=:8r0HߓbfuR[jݲkNg|lΞyHhXSۧ$]ancc._޲s֏ł⊊£pw6'{7t˹o'n[T͚5fU\zѣ< zsZowSOv0+A|{ u|8bz#LnШ3t[M[e6W eew[?ߎ]kڲVmuwnzޕT7|Z'nJ6l%x̓QDyt h}X[]{?/@$ղjb9D*!c>Px4IT+s] vBkծ- Qŝ8rLaiݡmTq ?'uܺa՜+R|,1To_rM]A?p8dh>`V~+hrſ>6fǶݕl[4˻pT4lXM6䔖y/_+4D~npEb {r&3[D)!F$eAH [ ߐ^Rz1!hHJp8lR\Zڹ]nl|g-W=;wvV=R72RHf%&ѹ _ѹsӵˍaw[mڦMߞ>{OՉ? "ԭYBX-ͻvnn?|?,8un=/?Z:?TMxCUO`xk*kbxp9wO9G6Ϝnmlo*1tc^^ 5:^?}ce2ٕy~>jΜJ˚~xv[keo)ˮkAm ap7F^ G01`I71q_| LssHpCFsMgOiITX>a._-)+۴4vl^5ݍOWK-mu-uD)ʆO ni3٧.^>%ÃĄ^Nޟҩ 4ᵫ)3g8;=ӭVu )`4vǓcLJihjnk_n6s.4u>'sqU(@ku垞ge}5ٻ5LMjSɄ9Xn)ݽ dLڮ>$JXt0GH{Ϻ:r*y 7Jrec9R%? VAQS@g=Z zb.J̃2iWO/KI ?x{_HpP~jr(JKJ) Q)yLJF_}1zcDm-\S8Ͻܜ̹HԄHJ;tL:eNe7w߸eC1\8>ʻ2 ŅfR`cLг)9!Nן/,gg](Yٹe)Nc?ۻzx9k@0mJ|Lf58,[x篧N ʪjbUP RP(w*UUU!#HJ9]G͙F%~qaQQaaFf-E{S`ED >1!>1Nz/?:`:n\n8(~iSˊKy@^+7k|[jHζƖa(p7sCR@^NLAԓ:*a \k*f i$\T8Ӎ땗KM[/̜: ã#+ Nxf/[9LHIʁ!ݸ~< hvs\K  枹H]zy{@@Kу(ؤث&9\"*YuiB/xzxYH)+˫=<ǍG+˫r/v '@9%oZ.2N78\g8Xc% v'y=Pxf&u3 cp\r1n);~ i4]H׿CQ{c':cétGU]=q;uuFGeC=d{TxM^h4-*dnbHpP- JKNˉӞk5uu-rp E%J=ܗ͛;IPTQ~#6,$bRpgWRBJ|g]ZcGc/;qܑ:;@qY9LJ Hll:;〩{`sfjp؜V.srr2Z:Z:4p՛?D-.-.p_?>#\W<ԥJ8i9!иIQajzV2\d_axLP`r6l6:.MSw{{5044tI*Ґq6 X{k`66>.~pӺޮ^SBSbv 78`hs Bx C4htbbA7&~K!pg~n9p(3H` ?a-Owvrʿf4 M7:n O2%2,TE)2Iե֑oϟ~R(#_ Rul¥^fh膛++,0`ji?`b8ʹi( #2oL'1 !BnntվJGyu Ezp,G4`.^&?HYSs=1:\-Hګh ci2պɤjMߡ@٩ + ):*9!>Vc]*2!RzkA:}VśrK@^UOϴ3^Nܻj!dFʴ)p39&Sii3arL ~\Td u !nnnjd)SD:ft!ÛbD/r/\1+HڮjmSiRhJ]@iZV&5LMO2OH}u)O rrv&yRo8:;@RzjOTB\TB\GU me\-Dg_ Z 4!jʌiAѓzm5 w߹pJz:Q$犓S_OԗJh흊 >527׉ah>S(|e OCM-d2'\44h:_}'bkVFZIQ t4uPCϝ0st)ZI /ؽL|C`/:$aҘ͂\nq Mb oDdaHB$ @Xx018ˍc>ķa&˹^M^ܺkk`ԩסbXAT޾{&uѦ {q I,#*bq$m4cJ|cS;A5- 4ofMMts5?!/d\deJe>)yM*UJv|ՈdIJDk(j̜^V[G||裌ι>*eMFGu}cK16 2t ^={U:oRƱ~d7?ugX1:C쟎&̙A#dnjS5-w8'7 bİIJ_"Wѩjj;2W37zOCjbk5]eONՀmw IDAT/ͽsF5?0K ]Ycd1s MoKРYg:99]3b4|CdXoRp @ #ir ߠXq%0fnĶTRh$2̞:5:,W.+cBC[;: ,hbyM-ݥ..4_lU`z\B'^)2z9yy65MZYW}FtH4RJ]ܝ:Ry]?G}<%)8CLhHjJ2KJRuwtN>Nܙ3\NIQdKg77Kz5|c21dE>i`' o WowO^$r), vKB'j͝*8)5K{}('pIVFꔸ WWVu8;9JJt()/7}VX^! b{5}dBBO\I`#޽TfhTLJ >kp?EJ%\U*5y=K @_Wf sWar(4662>ڊ̰899dJ 9-U;8Xr9n‚Sf֔Uhdn2uJ0YחD h7~ZR έK`KV7Ow^eUƍ%(vδ8F} THMOz_?'~aUI* )|贱]]:r2C&TcnϦ+*)~O^'@@I1Oը\t<*H1b,q9@SMCU@e´p5*eWvqIq\SfNpv}@V%S ɇfk70-L|-F|BgpLOxܣH04cn)? :,+%%NcZw,!2,42,ǣǺdH(-$L8ѡ!}}ݚ~:-9)kf* bBCz5 < ^ѫc>r.;) ҩZÑ_bU&%굩qXNuLzdK3]e0:_RtG+oti AmŕUrw)ё^2L^-uwߥVT3xU|3A*fƐt{{WT_T\Pd.0Ĺrs 0(Ζs.)((hV,bD6]ɹ4+sQO:3E&8E WxP^r%6y%c񂖺%JÃ/nlf׶}c9}}J1{Kp >SY5NQvL>)(\knC1Z@qmsK-K/Uc@{ DҲV'>& zyz 5%Cq@^O*4 &(͝j!I555w43=w+e1~>ꚬԹ@߄Nu˹3 }MCSIe6q.rO6Zw}?-m>-!Ѝ!7Jd%y7 .hoꉍzJV08] ~ct%454r/7cz&hzxx  NI{2-fiom=sؐVMɳf$ϚApT\5zߒAQ^r!"߫i#"Zݰ N3)XUC.+hlXגf:rߴ95efm<{z]U?jҴpsRp|su]䨰) _[KK|Zәuq!zږeXt<ƹ.Y{Xz}n.dzzH(qَ؎о^;x> ` >$cH/l \.gO3v7ޡ!^?߷c8f.ϝ1ksF 4p1ߐɈ)-z9/1ހoL ,c%1 ѣ_#z~LOu55O.61KC)j }߳6^}a21&2i^fo?A6%12ύE$ ebúp҉"3q4Àf00rQVzj N+QCMuhcT:..0n" q b@M1wvvi%ÍIfyɪĞp4`L !WJ<(e oU[jA“Z1*&pp gVTEjY!8- $UHL$t}]XFLlbΤ=U%Pʐr8QBt92@4Q08/`Km7zuv3E‰!pnpc{ll=IG`{w0Xbn3E=,>d#s@^ WW2v2{xC(HUc۩O>mJ0ǖ$ֈ/ @4H(+¶e .d&l2 dcLPh`~eL o!5p& T&p&oHb.%pxm?ܶ brDЏ0a!ˊrfl#a#KkG2ȸo BvntCk̐ 넍 U\&;qH8ټKAb[3 %Dpgɡ0ئg#&4~]8YzBGD i̗E7aL'Fav9X:{*GpKtSN1aL |YopJcj.d#oX.:zfq| LqC/!ၚ#<эR@TMo#5o*JvыbΠ ᥬ\ WO,78xUQ n &ج7lf1Lgd9EQ50 )4ކID 8F Y+F̻ml%9EVKgˋzF8%9uoeaz#b 4s Z߈D ^mIc-0F`36Fל*BkPTC8A|m!Ycۢgzl(4r% ?p oddőqFaAic44ˉ 30We!^EXy5+Wr@^#\CxVO ꍺZmO_l%h4YYkG-=*:pfU-gƘ!K'hl Ƙf$1ޙ暍o84|6J"fg7@7Y.پ-CbMk"Qۺ{Fl)1>>݉D̽ ò?:hTqb1/?%bdIx>|i Q-9э ĩqtB טd=Y< #H|">6, NkQaxmQV.=h&ua7tM .* 4Nƺ.ou;L Y-x! " P&A7BVIFMQU,IYGܵ~%# OѰHXd~ìb'?H;y,߰S0a1,N3O ϥo+b9 G7i8xf.|gi Qt| .[8FȂ<ρvn:y<ΩQ@|w<I D?b6Uu/' S=vQ}X6x yXp8iױƏj|#jR 3U ƔAeSz sbcn8MPl&y4b1|^UΩ7Fv1cƆŕh>.59FyD[0;b>袥mu[}Abʋˑ@[% Y#'s΀CH,;X1Z17@dh )_l7ΩъoDB!o p qp `@P~0B$wk֨O@N|0OM3&W E%{wR{ mi #]3^5qVJB6u) .a- |(p,0[v gX aF"nXϔ 7E> n0uE:--ܘ% Daw1oC4Ц [bA C_m7c|L°3IL]&a ~½܃yG-p &atebDZb!Jfs,.nY1Ę42dB)YٍAjnB' qBC࿧ơ7Lbt׺[Fx%71xcb =a``As>(dUAgYJtPصdmi9Imɂ޶nSJ a01;'K~S3HLJW룄&ͻ5p9 ,f0BDY`CV5Y'6ؐ,Mcm7]:̹DŽ j6b>vm{ZP8IC  KcSMvk&Q\N0}{U$lVo̯2,Z0c`DȰ_c8aD#_*]l|Ï8HљcEE*ox;=Z4CDo"6ij/82"C~vᴏQɬWfPom~.x(1Յ67+bO4# =XPUI&Ta, [A?.t΋f$9Ơ PfFn#m@?֚F^k(:aXU55S)[oR ߈$ZD\((qRh|c2Hc_r\ ?ȣYo/"nqHD,Hnb4X(h[0wIpp#*wQٛlڍ"!Ha "Hbb@=Q<|HBO1kDAl4Jw7( 3 9%`l7|YL|#RF-s"fP׭Mo[oB5xއ9$+Z7!lb:ɆuGB"qSvn^8ABMkF;jY*{1L@HɌTzj`70h饌$dfC;`ܮƤ#OS8<[棍~p9:Y +3MbSD-.""/`agFb\ 5#N4iY_u))b8GF߀Iтc8< P#z$1oH n7YAD/Ay" o\rq:R5ۉJ dkde|"x;)G? d .\Z"I2R6iQkٽ^/Q=`t 70 q>1G#p>tga `f5l\П^ NS3Hp l%kj'3pݓ&p;O+oH ƌ+3fhh=ngKG6/OC6g4B Б䰛a}NjFӦ %ۯK:̖9G<慙 (xѹu MXa1 ;F9HSG3 ӬE@/8+$Kf*0lS+13^H)+ ?y^:h N<2=dc9Y}{0Nӧgmb5^ }jaږ0A=r,(+! L0ZY !8XP'NK$0ހEï pqly %,@ :F"CNedvzZh-Rٖ>dd1o-!;(1n1oP KA'm oE*@tNQXL#8*n.(X BΉFeBln1^ [~ Մc^pԱR v1#sY pDV;j@BA罽1G qi49FKڛm o0 C0^ʌgˢ>l9|PKCpl7 Yl׌%Ð߰SLH|cnDno`(`fp1gvq D}*&6k tC9avv3G5aш~-#٥K71c!0Y7DZS|4p@aYf67O6Mϒ-J=,9ag H<AT)㜢#9Hit~&D3,g 35ܼyi E=d~O"`nEc&%Wi<[Fc=ͷXYaكij>|ԙ|P Y|L>(Ё,3,8sD߈0ޘ8jiiy^oii'R6XLaZ%RL߉\0K n v@Fvp,8[`}o'Z 8.gbg\6G”dV[11T =`y)a3!kX*ٿOmI@Fj;례V<1Gf,-^((ZܬFK! A_-~n c_p2=|kbpG"F S)1{Lb0o11/5ڑl4YR"ݤQDl pNR,F9,4(`\Fij[+ߘ{-do1F]x9G3x63F07Bw(7 bbnI[!CDJo/FdyUh8?GQڥWG֠J gr `(+fWs[񍹂\̲yY|.-7V%a4<Mfs?~# 'Vj q$H$d!v\3/AtmJ4H|cI(q82?N 5ZB٫DrKo1f1Q*aQr/%ؽ @A NC[a8/ "1XF@oUG9bto.97A ~֔ A͜(|cxOb 'eX79e"K/c`6.&ı y7`|;q˰=8"'ww[>CΦמ:)ĤzҒǻN}Dzsdku δĉ~$N:7uEw޿j3~pJe :=vOf䘥ͧnI0ˮ䏟C_\Qɉ_Oھ"7֫˘1 ߿EqR\XE rKJKX7{ޞv<}fJDH0N jnk̨пViiYWw^/*"-n [R_چqKlӒO7Qh:>ާ}HcNh? ։xp_~`"|9=qE9di6rߘ)ƾ`kc#ĔT!R+4 t1nkc_ L`(~z It/j7"]I@ro3vdD2$m"2cm;@Pd8V{͛9 >s6$8׷›oz{z?s9nn9Du7)5w-&.'GG(}eSK녂BX'4ࣿ9M]>3r7aNjxtZ7Wࠠ |78(pbN~RIzt77ࠠgly!CvDJ545wTťeU?ʦ.Z]K>vI\,(J߶ekZ27c튻4dg墫]=RReZn͝-mm[6cw|W"7=)1#-՘ pXGWqټnͦs>v<.&fͣO$%&p {hâ+twX}gz;^W8)(0000xbPEU ֭]# 9鳣"˴95 'snƜ9 J ##VZPR;I*Kgg9}pA-8 $qܑO`o@> ~ŗw>_ORgݽ_FG^_dqTddSso#ǎq{ɞ'F[['pw翿px qzWW7=[Mtw/_kxqۋPQ^ҶyqtU{.YĪ闶/Xxu:ݚ؊er͂$BDKݚ #f0O.`e31khXs1-1(|#R|SNa`#04an,F'1}fI$.ٞcMα_$,ٻ/rni] pO?x?>&'޳|yqYyYMǟx5, Z𙳦k W׬v*ۏw ??%~^x/pX-Z_X?9&~r vꔤe |^(-+ee/WV׬\zנV{xCSRIťs dijn 2$(r Ӓk ;rV/_byvyݸnmyeU]S~?hˊOn2{ɽ>~ ~k/=$c9?|G{5}~soɻvBݵ{nnKߵ{O1iOpC?ҫ˧]g aŏ?t{7=w~>'7m<|xN~7l\w=>qŬuvw[ gN.Xc**vܛ Ͻs_~Kߔ|u�}jIp *IQQ~8YQQI0(@T&\E J777zbs{pwwWׇ|Pp) Gzubf;B$`xl0ncLG,n_D `X8$P, V,1< (",k$a؉l|#f1syWb$J/pcll7#l 6$_>s62@}: ^VU?ʤ ?OyE߿_'7`=_0Ӽu WזWtݟI+9I?>:2B`h8|K6ݿ~E?:L@۶z{ݼQFGFlۼ(nRw7\r8DG@-vcPNTySKr%ϯ^DFUV`sϽ̛晭]]]yi⑻{'>AEEE PHi鳷l} L2f7׿s+N-,(xlU ǞNөڭ8 0B9yFBS.3=Kq~ݵN"SP99r4,$DP\r%5%峿jhjKMIp7_yq``?`eA**_{ÈISFUBdHK+/߼qOLdY?1=Y´mյ|v/->?'ۻzTpw/mޘ2mb`@Ye[ǻoj\6&2(CĥT*|mKw>M]^Y̖t+MoikTv4XbyWWj͊~5_߱TQEU'N-,*IDzeekE h+J]ixmyב?EwRtc8aOrxtcpH0DEGY2mOuwj|r kNd'Ya"?f 6_$cx;x#ҬriGC@d%\|cF,㴘c[p:eyf VI{oFl#/7|/{BG_ʻ2+#!6"xq~y/{t"=#mV~aQRbU$߯{ſŌh k0CRje HR\}9?U&[000_(J)c= J;nnnמ#Vu|Ͽ_/Tѯ>JRtAuk-7Ŵ?L*}?Q)o}" Ud@Yu L~!ȤR2oбi0QVYWXvR |*WwC|q%r/"zoW7DL ~f懞\jI *JȈ؉iۿjŋ~7D㇩4mZҫ;_il_L&V{ةS)ҨCPF)λmxhnn.z?Ls)&~rXdDpHdTz9EF,LqTb陲)!؆$zQVa8)<4( 2(άb2ka$ ¥!u1!( c`Gtq3N6wã |gϮ~ Y{9]={94'u&P_f,`ރ0|fjA#@,~ S'L`ikUw9@xHKl)8mYER8vp LJLHO_X8عm]?9UnuWWCS[ꚚV^@{gW^xvӧm&n3=W!sDN ~&'&@xL~!HyY&f$o-_wP0>q*&2~ӛ;fSfۖG$NXy/) aAubHCSq6Wr p3qbСG]sfR歷Ȉ+W@nnGg@5Zhiڵ'K)L1m[Zy)1V8zd^^fǮ  "v4FYDZ84DUB7*FH(㍹Ki7f4 O%nA-7%&@\L II.m\M-tz]((t{ Ǿ{Q*p",!G0g,mTloShGk{̔ >JJu q11gתkrxz'%&On(Ɉ kMM8v?}斉_8[{Q|6}4BWqu-GOAҔիky1QrQI(Kl\^Yr  8rcB)sAX鮕9>cZGoNٰG㥃GJңNsWuw>r[;f{{ˏ^/.i켐[p.o InV\]+0_ںE&'&ڽgǮ~m=l;kzhLm_|oZˣCw+l۲;o@@tx(_491~\~¸׬.zw0ғjާGO_t7p߲ſ،Ew"dN>{bF|Vxca:7m˯"X0/ 3fϢW+/Cm|'_0O| {A2YiI鞿}N;yoGV_?&b_¼|/?d@(,*rs`Η.\,n*M  (MQ +`"ł^뵡"EzHIhi$v{s <<33,:s~p}Ψ#FSP3^]9_/4P:ѫP!!(%b"7$ _< |a$ooŸW_1"9IP]$[QꕗaaVﯿ>|y5O>0m>|w,^|3e{0?iS&K1,LH(=]FsfAaap対4f t!ۃ3={O?k쫯ύy}cΝ:M26|^9}q|K?jg!_5z'}̍cc/s˗Y Uam{u߹w.dKK8am&xSuMϬxog9=Б7`¨RIǍ*XJ9gݹsIfhE;_Z d7ڻosزg}ryYYO++)+/wkI}o,尡Cge*LZbTC3S&N21UmkjjVkuUDGw:8~8dVێͿ?txuَMP[vZw5k.**T8Lw% 旘h'NCKbKaԊ!0Q$?6ƭ[q(#L\ث92˕HR[F(ysx %0(z"vq݅d͍hh#.Vv5R=~}=[z^qI^qIDX,EKko\K-yxzxJK/]p8f2CvPph#4bnB5wQ^qx^^aQѼ鷌m)%$tڥS'~s>r-7qw:>((]]S#>ۏ?mkW[r6nGoĚڠqgi3磌o ~ǗX wN"}vP:O̹͏>{EK~OOKn GJ%/>xH{ sqQCzͺΚ'6HQP]"#WCpĶmsOxh 2n2;$ư,'|l {nW̞uױ½Y9d[ؔƏ;]^~q Gl7mv62t"t"$!6O?kunjiSٴ'pr0u>{*U>#oy?(1"#((?z<_r 97sϝrԽNt˗.X]g1 JmuM'߀een_QQ1u|7u iI!4`ȧ, Q i8ѭyJeZHSC6%Yi15)n4l. ("xn 'Z#gT"e2KK=IIo ѕ]7if֧mܱ3<} ˯T\}9yyT3U5 zIi))Σt: NqV/>XoV7u쨑k~\W\2fpb`K.snj<  Z_پ {MVNnP`ྃ.]_/_ Znu]Ͽ쟚:>chBM"6?4|NWekjyVa#GݺgڋYfNQ/.[B*ΰdRFܻ_禠*ɝ0jQ?æ Tŧ^n#NJJN^8_Yy˗*^lh8VT _\>0-eoVӧ~:ǎ]g~s[{fqVN_cFܧW cOY㺪G? ~KjjN5k/]rMvٹG+*|{廢ڍ9-!7:%%*+|fu=q͏bIy凟R}l1_[|;t87߸Y3/3 ,^҅/>= }vHZtQs ġ@H| ߘ8V%-OL@<F!A", 0j R7;KID\<& ^!;57W  &XU"EׯU'\.Dk?oXtC_+G8am3cmeE_F{tuG` cùaa}$V)D2 Qpɹ!2ҹCD U)%L?GtQr<. 3gL̊S:vqi%3vaa}Y7clMwaƛ7EnaUa)4?iF.q/W՜}g$Տ`@Z2㛆JP_*D*+ATdI7pb 9(1URڗ1=ZoEԲ %yT3mA#.Qr)i_r&07Y'"L5(J QDOUx%WkdҳUY8=$μlBF(Ho 2$&į&PdR/X5$D"%2\1M? B+ą$Zvϴ6BgE01zYܘF<&jŸK$mNt Uz7R /[D FcLYgi$\ C@*1ia)Nkg@w^.ŲDgJ*'D28E!fCYo~jFvĊKr.v bݻG h] +젩ԥ&t 2wD&&Fr7u˃8ƫmsU>f?lRflL.Q9#@rޛua۾1YON  ҇$zD*C ιaeslHjJ%;"\I/ a]%eLC !`r!+֏ִd n&%'%$g圭)bdoV6DIؾ}cekT¢b}Dw߳rVUgu}(;$vkضձ_Jjmll-(9)7~I;D|z 122#y{Bk~ tӉ¢E0qTƕ+u΀+>aܖ{56%%FFط~X 1>;YZvZckAE0w4QM'&:hַ1Oo6`coEzjͥ=$>r,;na6bcf jl?uSJұšnZshty@3707x8u(MnWQyl|xg<>"*ui*9J3f4?!CtՄ)>A FĊ]֔(hCD(Ļ#+:nҀoܡJi<*Ҷ $(o Ѵ$Idrc12Oѿ jLjձ5uu}DlYkbqQ%OۆGo5:t"KNV,RdD8T ^Jl8e'NU|_rQk#a?dMa/*}(1`6ju=߄5ЩC$W]./)H^AeE,PUݻGBeuun6KZ͜/"5!2b.|#h~cYMV^0 )cdwqխP|چ\~:F.jQTz[tGpGEFH5hlllll3j+1 ,EFDG׳}K/;PqWH*΀=^\#>*]cuVGPf*naꦝ{{WԎ>l[%(n?n!lJ=㙳چ46^okfsJJRט.e]PID-rH A!zXyH<zxx5+HCta+d`$ʭP-C4tW Ԓچ@ۣW\QsVa ;Wp8Y˧߮),*v8ťеSǨvv"ҩ3z$tnonOܲu;aBy-ԉy9-Q73¤!z>Q 7OX (gLj2p@tɔ&x$bWaw0}$-Hps(Fp)Sbo۳y*74<ˉ-4*{!Q:窪.7tlSX>u0_ZV *]  Kn>3oR"d\IdNPrX89WTV9#38{ ޾cvѼvvVKFظz QCܼ>U5gN:u1nogr9WYik 1GN-(~@JRm]}\l2ĥgXO/hn GuuW8!!U ]"]D.T5``s+sndrUbeQlbu]Isi飝\q 4,Q4N)|NYVGNdJ512IF4I ) 6L-hI!`Fz"G1l IISX\n 8{>>6lU%t.(*תCx8_5еstf{7Jݾ/+ XJO]z-[W8wMpҦuhp0&իc VU] }j/5;;Ջ mC۴f ~na![f:DPeiӺmp:Dqjm=1Kkh*imPa4ÎMc%#e@QٙJ)!ٹ#{8B<1kېHVY]h@s fj,_|E*:o0M>i@j'Kۆ{"alR2c' 5׵Ɯ@fúvcyF49ʺ*(44$je"jȾi7o:e$yp$uӌ6c}eXnK(8;]F?(SPM&˥x߈lp8zLbqWH#- LQBo!!Wt Ѩ qȆ^m IQ0Ցy j9WY/<{0؉S+ؖ)jؐ $pKcccpPPĚ'W= #bi YɥeC3ѣM2p@,'GoDv(z4߈?G/8V&hp@(!UCp!jAB6 n_OŘ;zf&Ҋ3A# ެC>Nt<&u ~扸|£m%#yG?eزk/3677u?oѡ]x1<kM\+\߼gh[}{UVu\{I7oll|q(xEeՠĄnʪ=^̻.*;ӻGBF8_U7;֌=3OFwLc'?旜jm6*9 w砠kl׷ zZcsPieuuaqPPTr0(ֵg\lϜ,3& (pի:ٯ__s+H; Y)o4&|TG$R6Q?zX`OK|d0 cB[p_ $'#H4EL5J})ʨqC7ODo 455'7@C]/]=sy'/ #[]D80?"iFwwF+._fLۼsܾ!TJᄙSc4#A O\eF?c%!! JN-8ᭁGiƏ zCWD|o~#,Gܣ`a^=~fO ;D)&$Vq`ƖK5Rc XrSq7IXϨ!fdC 4xS,,gw0% 1a-(rpi(. MB\W%V}yX5AP$[*qG:O*b\d2Mz_A&6 FjnfN\g%`ĺ4VFxQ[Nbh}dORۓ"ai_1~K)+9HDHGCy=E@oTxE~z=PKd'ݨ@Yz%61GɨLxÖg`EٶD%OzhąXQF6V|EkDFLqnCk׼F:FҰD)e}]I&h`~$QV L #ie|P5E)'#ye-M( =bd+!;iHuFpN!Fl N͎lI_t-F}Y52 Йt2`/rE# >I[Dc\wH.NM)\1e5vRcрIG^\ Nf~ A&!&CwE8d8kSWiZB?M (t݀43D>tavՖ7Vy܈&z& hn-Yrم(Cx eƬ P`"9m#f Lz.c|lnA C3-k/>J-hQH7l2R Jl AFd\ ~ ChЗ%Ya0yqF9@(5@L:44W}$!J| Wޘ\bvyҰ-iV٧e1?ޤ2>kOYLzѹf)OZʗRVP1<U31Do+&F@hwB1y0&H$Dj1ũP3x8\Vϋ"p&_)g,q5A f5]njWWGh#Tu :& OOtRדj %~o#t1Mb8whvXp 7}~z\B897$'PoIM#oԚlHqM265vJ{`oa\<]&ebgnr#ogC6>gQ}@vW Ma|tf2䲌tj1O@& Vc:DgY<ܣCF&EHpz.O. J_G)( X>$暗dۧxŒ$3w43B´O3Ն udpiF_ #O5ORtv?  j1L/$E-ct9Z52yd(t8HR BS8f sS2<6V1.5pWQJmy{옼ѤOaG"K@.f́5*)(Eek(G+ P59I)HdML4Q{1[57H /~a'I|I7˗$Ri_A5.x")f莞1yAB;;F!8ВE=iA7\j''e4 QN3>"||"XU ;iˊ+Ns|:&HX;4Mv?~o_Fklx$$ȕ(^ ȥ7 d^BrcO%کRP!ۥBy#1J0 qrpXÝۆ%]ї``EVTy)Ĕ&PD2-4Z##I /zd5n> Q LtI"EQÌJܢ yf|#@3\@sbH0vBz5QܛPةB:gU8Z(J7}mzpucgoA @6޹IYwVC^ ?5Сl:mL>0^):6O>Rވq(QoEQ [FvqB\Q9ߘh0-8 DHBȥPWo{G!r]UPqX9OCcn25*ؑX"pv(7_X01cLE y%DP(Ju!::-((Ga%;p"O6;&Ȇ)|P4M‰|PZKS8LCo\e"GIsaU8ߘT'JztEx¢ F^_4+=b?H#a&N ?&”N7aZr懋~KWi4!f_ jCLFfx8% f(M(Be6_HI Ĺ)X$*7JÞ͛n4yēUKa)~YA9v +0 Æp@\SH舢PBϜo-WK\ ')DuUF@ X,[@"j^OM(۠]zd:$:*J%K C-@IQ%I!REm7Tvruc݅}l0*{xQO^cLlj}k#eJ+"} ߖ /#d q,Δ#t^@{0p$OCgt=_Tj*~LMHJ22q@RSdUk޴Jo>_Ien:wT95k:G|Rk(`Dcp ^ػ9!^&X(`?ŏE`KQOCQ*JBȅ(`5 B녴f=5;^_0rPd{0 :2 P e^z/6ѡnUd+swi4b&zb/dbCC(#enƊ>W nU=ݳЗ:$Vw 327=.M3p\bkLJ(t٤J)hi[[JBдPpF* oFL`B WPWip67wzr.ee~*aɤoTVtM"9o Ϩ0 uT(CJ<}إGKbI8V$0,}vgeNF~x| Di1 &L|h ӈRxE֣P'o":ĐO^1ZaDToRܟ! !ORz1e')p =zhpQS(l.>aIze4 $aZ@Q#:a#&WoS,jaЬ!ƅ#Ȉ1|12B+i>1$RUF@}4FD}$zV]\y3.1%-\ɋf܅Tu`>y:g/a6U+?,5J & ;E$s"ڸP0nw`' {VBS{K  O}Z,>QӒ;KIb"Jۙ1'aS# FpDy/kuZ].PJP`Bd+(A G."?"9IzM?0k$[11#PHKZ E7dTҰ'KI=RKP O-ODaGy-#CTAa*l UɬJܨɋ]%y7Na{AqJQWkb܅ F ZH*X<5dFʹJgT㐍*zO#vNdt6 + u!~qY8px{cYLQ$Nmjv})g cv@#.$z^x1N)r1OBG4bcc=\|G2堣HYn%8ͭDZvkPr9}L%6Bp㳚x})h2Kxp OA˪T1yAzI1*IϒoPԯ!=lJ)AaLFraNwP&HT8WKt'͒lԈ1Rat/󖬼!F .Dk[V5hPؘH3HM imI\qpSbW6RyS2;%ʌUk ƥsJ劯rD&7 Y4T tF/glCVZ(`LEX AD}|I^CR_xcM PY0AʜpdDli0 hB 5%4@$ROS&["^Ӡ&`}*)k@6,54+k+huYpƯUS,d3 z@q#V}o GQ-*m RZHh\^* mR hC9͂BcxbmR7ʗT+|Y#Y_T> * C֨ nMLhu9(D.JKFTv S@əy=l|}~zZ0.˿G^- QuuK#EV yp]IwcӘLQ>(q}~֕q3}s'ʷ%=u]wr uGBl uCuWo85_2<#xg٫%%3}_x ƍ.Ғ%1yfXooy~>~x:"3'q1l`;[-?C>Uk=iB︘͚NHЬIW"41#={YKS7{{ 64-yݧUL&^/"lap>nD OH){ן ۞q+G`GxÕBZs}`>*nxD_R}o{}wJʷ1M8|aJFgΫoZtuQx<@=CWгTވkl$QJQxPT2BrZ]GB@2Za2 ^BpU7͸[{C55Ҕ,{چuعgo``஍^$>Vɓ6'{&$D/]Ɩ9s 3d/xdL Nr/ @|l̽:sl~QC;O헟~_PϲuG`@@tNw١KW>N:t<9#8γ#0(stG{×._ ]]DO,|ʚZo9eUG+(.AG=QX>^-8s |@Jin`ޜ_ka3Nnhp{0mb>̛`XytzwxM9ctTGbp#/_?߉5}Dٹ>{(oJ}~Ǎ)/t8}_O,~n.;uҹSl͞0noW}Ӈ+++g'yİ`XsN"(ù}oآkKA&O#! -D~VEGTF6*z#N3_)ydK2J amd.'UTT.f cg&8(bq>m={P E <_{QSS6xᕥwYwUTTX?޲X,wΜ>e-6-!!dϘ>pZ-qqܳo6f{55uun/64Խ>SYS;~xzZd0<=!>ז> :=NgD Kmm{9чE*ef_YXx}ͺ/避#[}=xyC^::nν.T_,l2srgϺҕ֭珺T=/%i葏=”c_ZQ1rlϪO |';Du_bmK=N)`+:7WƦE-~t:'u㛹掛0&.z)f6/t˦X\nN2/2Mrr0"pi-8s=h-Tm$  ց]iP|#妳o,Ic,d0DCF^D5 0_r466 ӄhi22ywˀO~/#rbfe@|X翿z}M[8Ɵ|zlFq1.ӹ⽏zg{[;o ?lpz]l>?,pN{{yޝ1tbYv5y™6o?z?߰yw;Y/?1n |KO[ǍuJZ,VBMB\ۧN֬pX?za 7>ׁg {eOȑO?Ywfg<)6j,Na~!^{zwվ{__~{=m6ۦ?^!:H"'Vu:U8ɴ7 rjB:`l2bTvm68!JqqU~12NԫcF&`L @q ;!p!0 q VjO>}ɅsR/, ܴeZx/} sr7lB GRX| cofLF3 V51=8X̞6uO?wwao2x N7 ,=Uv2<\o[׮p?_}MV+=}[w8g64\}ѝ _zخ?y+}z!זgckjjξg۞kh-A+,,?[UUUrhhrM]A 3c҄}SܕK/_y.xucV\Y xwḆzƴ 1t0:nLuM+W,=e` 2vE #mںx#n.'7b!)-7^]tm;KJJm)?qx(X-o￳ .{|ۮ[.c5 bf9^{=˗/_8{J2mLHLhR7-+X qLZD`bXk!i*3\)0 ^]Dz3 BVh:|Q2LvR8l#.LHkt1M&:F4.1.Qn/: o zhޜ݉pl۲=%-L:~ϜxY^Vv _6u\=m6[yY:M]7`0{AȬJWJ"eΌE 8%uUa(vQ 0Mwe+]oR*o ƑQՈBX5Ӧ+ݚ\1 .4$n` Tb\$\\o}'+Wla}M֥S/dU5a&vm'E^+_{<>6=f)]sgseKIپ=oe>w߇ 7];GWWWlaYr]{ܼX"S~~=ܶm{r;9i)IC }w٫;`ݷr;}jjjOWUW/åe'N8Y|e/,^C:֟?7,1e}=+뛒yyk..~u,b9 v[؄#'%{RFMQC viwWΝ{kW.}itL?5WKGw?wn:2|Eh=`]cTcKݺ;߸I;v?~kK@\|iMU}Կ<{^vQ%$Gv8ΚN{&KP[].ϧ~|7ôit|@?i 8 gA6 >IH L5D`Bxo~.!$]KS0B/]&O8Mܪs3@M HA0@q[O¦=32 Vֺ?9ܤ$@ZjW}$2sN .=߭;aؑ`1\!9Nw IDAT P%DEEYw8:wiN1#-K' {ڹs1y'K1$mvjJҚRS N7@Zrʶٷ/\to'Ɯ.+?qd~\}qrW2_ź-Ny\|{&Ľ[9d3_s?`߯-*-ӫ-߼`V.bC%=r{df},CuM߬ɉE% W@s % O=|jeg9OjtڕR^W_s֝l_60{b)(, ۼnr-J/"(XTĂ5j,1j)lմMݔMbLƴM$)MݘbwR+s~̽sgN9S.s>/Zb"̿ق /0ILLdG^jS.g%K[,邩w /xq=U yrvc I#6-3^a(kF|81;1oԖ2wJX؈6, )8a)(>7I)sǃGr˻ntwx̨K3jz/'OP__69|ןVQ$O?%Kn@ܼ= ܮYol %KXbL#<iW n~:vOxƏ?pn-//rgNko}]zdvz“]Onޚq{P ۫D(x2jȀמ{Mwߧoǻ _4%aڋ xzAr(XasoϬS7lֿCޞwB̴?JҺ)9{/r{z̩SuMϏHp WͽcȄ)~6lYn؋G_νxOMs/K[?dюZE4q89ǎxz~tUďڻw;ogRp6s—տwE}/z6s[ou|̩އCFe@}JP ͙C@)G;4uQ_? ϞiwſO.ěgݶ_~moLxM+{ som ko4U}+}pޠ_|yGu2 `;?'Yhs"OUXPcFھ#'(S^RѹyA{ %\|oOvմiW^|UN**|֥.]Oo>;gKزeTW_6 6]%Z'>Lx>{ml ߿X{SqC~ QO#5Y^Z/Tr衉laJ/[od?-YbBᾏ%+,h8O9 |n :.42k-7᧋q1sϏ=YRY믾g^| O=YW__Ww^؞sh~͙gꮹj%{R:^ݧ_uଁyy ?p=>:)Oʥݻ$u>X?T]]}g;Lf=SziӦW>|s`^^iv.YvݜAVTTD+m{~7]~?__p)ygM"gʵ}+o}SRs>dѵW_}(o6mݗwt/6R=X__??^ioz _s=zᕧ? a ^RE?k vWOY^eu3S֙;+O>/ѳ_%ILdl{:zҋ+cw2g􈋎;XAс#{x??Q0o}uLeB7" [ S}ii۲=yg޼M @߾Yn{}n(1L[vè#_xŗ{a&_9e#wf|gJ=rpE<>$TQQq7 p#'Vtʹd]br Z/-,ϳZ*otN̷|_I[JHw'@G=oT7@.Fd2.^jjn$G7B*lml#hKf' N&~vu{{=sTVzG++/7zԫg = }ṣ?$/E_4nQ# t _}_sזjkkk@S[{@fu<0aM8a ,[zӖg~eڳ=ztq/?pϿ,5~4hi=8_hO\rx-P__̓蜜TPPXYywۯrd?xo~6و0b?]! jڸe}ݻ?-%A#1%E˃R &)C8^ȋh) @"|5GLFj{:wdz?<;l+j]K*vi-mVRo2 v XuA0M!yW+[ V#H eƁ}?XRT?)x,o,LϪkue|`[:ٺ}H췱<OI#s:A^lR75[1"մl@6L<&<~8Q( ;NS1ѺFC+!2k[<bXnIk0Vھq|?еhaKN+#Αi(o"3N/Қ1Tѽ5Eq9J8p5£Һeێhy GugYb5R% Fe?+0 x:l "!>[.֖-˝`yB!7u6,$Kv/cKIj{ UB)xpfݑK[ڨJ5o")fTb,BklFZbBwu&k!jt @ S*cdȣ0oIr(Xb[yʭ97@$4ከ ol !'N?( l32BmZnq,C-S4njXӥ1aP{-ԧ,YL#Ȇc^?h.ΐ`wMB7v)PWLN`&N>I_#%j[K߈Į6!'Y^LTBl( J3ȅ$k۵Q2miquҷIQXQ[ȲԏPH!NIW= Jo! ho^a8՘-\y`NtS S(@B#>qNύb?1ҁem"F c.L 0JM٦[0eV5t2oJwwpf FV".W/̯:#D-e0J'X_YXw axBx SN<)T ݺmaGxղ RM("8:O6 SxЫI˔+U]4 3UQ" z̨Hd$ɗjiSMbOYƺBDʚqR+h+0$ XRh"6֑P)o97(@x4"K"@%>~ - t6)1)ҍAPR rmڞFyh3~_geL W0RvKpϓ;v蛑e)VR9sX~0J>sfV# ذcgTȋ R9yVY:WwaЁv; >'pA Z1!>w=mfʣVUYUu-7\vBV}{Ա֞)(,?;xq̙CyGݭZ 2`Ƕy׻jVZ@E;wn)]Sw8U3(-۸v2i)u:͞Et;PD!L99D"i ?ii*P%<%a'pJXlZ1  ((> ߔ/fWtu:B8i((A Nj:'̺k7d⿏\.x=t@ ӷWkjkfRI'w9NvҒrii=N!ccczgYI̝'۹cˈtEEvյdekt &kXT92d&8P(mL*x™,8RVRSꟋ$ҋCz\t 6ʞBT#!rPpʕO& T&;0l` OuKNܿ5=]ǰ͠~^@t[wU[wdwZGG)0brvI9|*wD->U9eej2+*3#]*I_ ٲsOQIٿ}-mA;rfϕޢoVշ0׵E [*2@֭: m;~u*//0bXNć +.SpxDˢJB>03/]?S|{ݗe^ OLdf{g=Ξ=YR᢯Wj ޵{\i䳯IKLf݆ mh|ǻ\(wDغy;?mXıȻvuU8vbڍ:jj;zStA}bj,v)jQE6Ŭ |lv %:dQg١c3a̵}قC[$]}V'!@jn{=|X}C_/9lt?~xA1kJAhLbPtح[;DEE޳TI򴞩Ɯt(׻fko< ml$ Q/.)+.)OK!D\7H U0>8Y«;Oẗ A zӶ" |qEJo*"BkFDxw7DG?߸iݻ& H nI qqVf=v3t`\۶qIWU/⮨Gr)[l33Oko7z8SVtl0~CnӖS%Z~\md|f͚.E8tHttٱ+%%)[RKC$y[оcӥ`̺4'p&29l"8+JlCt"+ZB# )gHԿvvWDjmA(5գ[Z >pZ TT|jŚ];1nԈ+VvZV^Q_{tܱò_WO7o!e5z0˵k~`_5/tx)ɝ{_v[1l G7^Wx"X ­[E^<|H?zݖ!3ԟ;2ҳk׶哓K p`srwAƀ };Ku.ݺFEc۵ 5KM^L|ZX p"Sް0@'6F~N"fm(^;'<8~P pMG[igо?)˔JAA…#}"\4prʄ}N*u3n,fP®[R޽diE\0!޳e "#" sRɝs8ӧV]S}gA3;wjs :?7ĵk[]]I!Ъ|a7oxAQddaK}r&1ѓ6` pWDx>>e@YYŶ1S̾?XЬLWklbcnܼcߡ|a'4Xgs?2Ҫjϟ qekGzw̛uW?Qu%c~ZLy\5a\IYbHAyG$'up\G Fݻ/7)Caaq\Xr7z8nڒ{§Q#41^U5/\+**NWzhQJהGW>rtKeo˾ys?{a-NX #OPyf ݴ!S)#[T gaN|)Z: J1I3+.Wή +#bT· )o8좃yQHJ&Q4P=]4xPYy9**K3{;>#gYyy;mL 11\Cݺ6?У[׺z M[|Z݆TV^B3{UT*-ԹDD?oEw ϑ#NJNLQ\\ kJʡGs]TX3GRݺP]]ݣ[׆ y\>a]z}VF ޸5/-0|c' :w6x@o^fUtԱc'fճmlj*Ȼ-'O}b]Kq\+x_XvcQIaϚ2D4# )mLIr^9~L]]}xٺW3˾qo\Ikڼsݒ Om޹Gт"v<^oya/ǫII]v}K%\yvs/ 8Bi=KzT1]:bXA~A}d1;,172qXMQ dZP ̐<(Tmb)2gUo(|'A0!ք41(Ư>R0 g\4FB(xJyPE?.<@B|#RT\\\Zq{.7FT`I8Y\|t}EUJrga4.WG8tTJ;w\Gp({]yAcFPVZr:.O9{J~Ǐeko5 gj]]ݚjPB7R{Pɒ5}{=򏝨n&]2rj%[JкA&$^X'V@x>!ceD TiY۶muIJxJI+:Pp|~nIbWu~Z[R'TTl;M>F9~0˵aշSU5^}{=SkJO[vU b}:e04mL.qn>SgеGUm޾mv!ꟚE_z/D-0TN^YibA'Bc~JEmS6VȜ~ fZ1E5+1t%RcǘnŁjr2_Cp>%$8< Uycy4k\(x7 q,] A߳p>~ibs .gIkvW.=%y{Ξ0յg>Ǻs B{vOݺ":gVp(bDg LS w --]۶Tk:UDޠ(///=\o_wl +9%y䘑vyn2fXo2 .ccx'Fl[~d/^jfZ2P߮'&9hߪG@pYv)č7'6",aNE6ĝ a~ `E>oͅ hZVEfG6"6SvN]R ts-{V3xvάV..ϔp3|DJW=-WK!T9B}!Ku$tE zԟk8׺Udq5}؀=D@#ʫtF)J9W&%<]::T!I7WFQpS x61˸5qoQ=-)akiFx.ЈOJQ)OuAmY&xI5US6_Y 3`XY,!ňsȍIlZЄ2eHv{1T9_!nA4+NNsr!` ;" g)(D[%1dLq~L 4AQ>76^aAwiLV{CV8 Xy *Yeu`J2TވjEL,VIOTNڀg贴fš̓tLKeBЫm['vd_ڃ9U@F^J l34`c 8ib7sGq7K w6)Jd7@-T6I:‘`wq̑E^V*xkZ|cԋыnKFSac'1 !}W*-3 !VcjPIFw#A',6nmgoDT #F#P2>rNSMwNږ\mZ ,bJ"sM"5Q [b5F! QXiY#}jL +UbsPL\e J)pL/  p2Ahjٔ8˚O2Ckn7bC-:KscicQ8Ke;GPPWB`}lpcIE/ve ]'%Iۻ"vľDŽ#άi9a琍qDxOYQd*oDZġ[$&Ug @%WV<[%nVKe*rb8 k j6k L6< Ҷ$N%,E#D%ӱ ʙ ` TB`= o NnԴ`}UZVB|ФF܂)U-K,d i: sϱ98 kH20.'Unj@Gݩ(f57L~yL(.>py41vғjr3Mb]3}VZUlHZ8?yhhp+=(y{0hL XM,ߺbCTwW h7^!/ԃrL2h?dN9,S+Bֽ;F|cŧ\Dqh ik~@XxU8yI#?JR4)x޷$-4~ҴCa AUF}A]F쭪Ay!ع29?T>߄ZJ4׌BP"$B 2=v:jRZR:v~ viD#JWm8 _G R$;)iOl"L~F`n2fRq@-1(2;6*jͧGM#2R[S3 9QVq˩tڪ*+3))h];OхPp6 p0[FVbH~TPZ8IgDaQA?(Xè?TkjVi5:ːnġ7H5KCUZdev`bI $!~nDaǗ^EO8M1=uxI5N |¸ JRRlRp$%|ſ A/"XH>8"Djb =mhkTSsWs[ߓMq6E0e6{0>? [Sʀoǽm 6,lr#L*1݈A' b1Fԣ-9Y(5ԛJv zEpr%JDeq ܷEiv*hǧ@ӑ9S4(qKm'rM݊2j}PeDvV>-2c'Jh/׳Idcc+AFN7H%g/E6zsVLuŠENX!q1jD' dg*H)o?Wqpj@ ^ÃP8kl%+p lœD%p;}IR9WZvxSYDR1Sf$.2^1ǺqoeN7:fHb K\5r Uvr \HPF=+n“WgEmިAk,\1GqY)ÄkcӄF!;deꗷoBhjKb5L]CKZ>3 FձX8pDž8.7!@Ka`j$Ek$ i"A.Vpq0J0=YhF",%Ia fD?ǯґZ;Q}knscيR!fSk$Y ՊKO+U%}nCORG4#gq\D70Qt/y6V=JibC0DyW;j'vR3KD ܰ ji 񈇼k1&گdN0|PBK0A (!(CD1<FIb6\{I07xK&?赣1V$ ,L(Uehhn=38(Jpc:r2"F$zU`-6j F} rRz Aş0YMF6IkqK>Q& >S⇟RdN#v ldLKȒچa3hK갆Uy+m$C|B!Q8Sj$yvjtMdLJPq*]g@?X'7&H@y5sm#D2[y?F m-nzG)%~B`QsL"g9f+/!aHLU%e"!ag8RŤ峥6o}2ed=/4KjI>"F5!\a^0Rqnͧ U\ 3lBfl )z9弪o AcsWc! fTڒ5#Ri2Q7E UN|{^0YCfcEdC(`+@b&ְ_f*dcC*B 9C1兣+Fy9WC LT!"&Gˆh8)J 6#VP U|nv߀MIȜP d{-f&̛+WibKyJjU*jAT0iFd@DbāITD0QXBs}ʃ7x5.1ZX>(̣)U'#B/@ILݲjG)S&,B`7E6UVռiY,ZskZtS 02(ll*rdĄ "ᗨs3D IMowfIqЪC-\mcU<}86-Acvn4/75f'?-3S 5D`Xo+o+ &DҵC̙^N<ѬeB=okN.D{<{s*2Xٙ\'^c6M&L^C 9:U%y|9\ճc_wV*4Á$6Ap3MoQla)roREd47C ΑFF/"3>CJSy,JAA|nl,US:.)KST UIw-#$≦Q5OQhG:hbG6` NJiy*33[=ӋN:;[.2Uǹ)Nc%]bKbjk1op|ᄃ!UۘM%5īmҒg&.\@ t2-zW[5t(oP'gkjF2kAYx/)/&CSQ H5 K݇/iUQ ES/2N/P"[[G'JF9 E7i)CC~*IәLK}Ҳier ЉȮQ#LLRb"F6ȁ˦>0.< ƒ(x0k7+L4$M%qюIFK fЁi2y>T,6^3jY[4W(HL?'87 KS,uXc2`Q[5{:^1-6eWjYREr6Nٸ{v?u,Lt{xU]Ԃg_gS6s\'!nΜ녋_y3o~oCf}7t᫯=7lhp=thVZz3|/8al 0sƔon޼[}f?}u/_}'M#y͌)~w֯QM͘'{om8z{i c铃CO;/g5tෟ-eZ'.Tw_˨! E)F&#Y_~N*/z"\BBܻ|}qƒ ǽt;ߥ{ͼj7qIhЍި*pu_*M}XӔӓ| \_VIұi" 3xƅ+ps)t6#qzluS'K\~S***(x' ?0>`ͺ$}iW_3mpۻwZmݞ `7OG)gi=tcɓyG\%9)֭ى "!λsmgj϶nzѫV5%-ǂGzJK+YX*U}]Ғ=^l&//8{TxRZVYPP8c>NNuN0yw>'vښ3\SZVU3Y? `Oc+.I$wxf'Oٳo}sf:9_?7l46l͹'OT?&_i g?c%)99kG#yM|٫thИѣӎ/nG)r{Kƌs1(;'{gZzڌB\JēyVv`B75Hf\O1s cK, ysޝ 8UIcz|? >g1^Fj(SazkTD H)M<"kw)}ӦMfF'NYaXv%+[+**yԙ5Ӧλ.&\M6mn7|'<1cJJJo8jHx7x]EEŊ嫥zjC{̹‚¨(Æ)+/ݿ]ԩWz=z5.**񜭫[~>t'cWTTTWU RVvz1,[F:L8&==مg$;oYv{*nGήGK:[n蕞x'_x8n/ ѫ&OZ~cIY uk?OoZ^Pxj']zONr굛O|R:nؚ#yO.^|êZ?|dqsj"VPKEGG?C;woneN߾O /:hPV]}ݫ=/⋯mp`#OLP__eӄھk\&ܳW#O>x<uK-Y곯%9Dlɉ ߌFqL bƘ 1bNa9/Ĕ&Ն?V˳J_q{-{QDž'OJOeþo?}#:JR]}ҕO믛{,}vsoޝcF]󯕔U ʟ{͋X5J/IMwRZV JN4aQ>w0 |湿*<<>(-|o%7tcMm$}5p@.k9(Y6ߴ Z&L>QZOY[O< k9c/=ReiK.;o+//!f" a$6`,Pgd"4 qtGLKk3™ʲU  H:]9PB(E#9p[0${X`%H7Ӽ[;$ٵK7aCg.|iժ#DYY#o:~(jPlmְ%yH;MٴNYii3Hڴi{oۑΌm8%۲,QH||g98uW^yֲYt3 oU^ō 7g;B1@S3zܜ|?.IOOw:sVwަ?Iy)Ξ;=Rc8<-;{wx… 쬾g7~s47bCfVh-Ak`KHOO;pbmC#N%p̆SO/ޝ`Kx殮n)))#|Sgҋ$YlYI^}}tnehھu}}}^{&VmF};ZP/;ݼi낚YYNg<7zYYliiٿw?\M弪9s[ZZM6n gs IDAT1zze]_GpmT_jE#S~_x ◫Ynoin>3 gܯtww?ޣ˖/n_w-;k}s+}-<7Ǐsʊg2ҧ^{uIܚ}+=r<{nuS`ދ/_Opkq*se%o>to|㫜?VoUyyٻeKH8\w:qO+߸we9D'z~T`͔dGC&TބV`QFFBttodH@0?S[-RcS$AlSgYe3{{}_}NycO>sD xfbGD[ *lܴ{ \!rטsݡ_ ;x}_j=w\:_t~bVhKY<{z(2y[7re gMIICSO^{OѦM[!t_x?򝺺c? +;U|-^w{\ߛX/jkkmY?|Оs"y OۤB.6"_ PbTگ[yd$/%hz;O ˨9Ө2e =-L}g]rkW^#ĵWs:NپsWY%/l$ذ ⦅iY ~[{4KIn'|i;̩Sp(=#7;Nι8!!9O7O%ttv_~Zϖ`{?7|͛}箾f]WW}^/9%%AݑڷrO(-/}So::^0~7E_6eO~/7lp=oniݾs1[oaמx_}9򥊲|KgM9zfǾww:=̩o~FaWzDȓ^)Nƒ߷Oq7e?mݾ+ǿ22!)_]?\V:t>XT`>r|͚eG۷mw~6oZ*yVSLlORnz7O:ϡ~xJJ JJnZ~;#78/?t>X3:C_Um7VH@`7-2w|U3amJi ksX"I1~rAq{ϕ Tz(ϗu?=⏾ ?n,^陙_}ꖇ_V_o3Po~|#91{vySS3疕μګ Qϟ?6 [XtL=͝w|;}Ζ֟I?yyOr9S t:K}ޞ[ƍox`wp믽^~_\}ͺ' Ɔf?=.-^3|K?pa9|"YSJAS##Sg÷y+k+o}ݟPޮ~@q?_sw͂yi}feŋW;<ǿw]p7-Oko}KkW @}ù>+Ko5 m۶ֶN74;~T7p}zz-fSZ6 󼑠tO=:::ӧκKJg9βoʔ)e/ 8s׿}?ظ}_=/yʔ~Z~9^3?| ۝NolxӖ?{CyYcO>Gaq^vls:cj*qi\4.e?qчzᇄg=ß5|}QA>gYw O7|Ū|CvNk׭ŻV\v™.??lc|? ooK o![n:pBӾ}uB_*oS*VX:!!S}n|3W7ܱk=z,\Vsq[}1%Ν9piMzzzo¾ۿx;w!L=tF LSruu=3K S!{V)f#1G *Yg}a˔yzu o񍑅@M~œo}Nx2ԫ JTm))&~{g>/v<wӏzr,= 8/Y,/fG{|+.uVW^yy]ݑ} ph{Y`>6}s'x۫᪫q~|9))iCCC̙3}g㷿{m.ʵe%OMdOz?~M(#ٿ07xFq jk;np{uG9Z[~Uē8_ þQjWgP^e`o8pkZw)7lޞ;\ck=ͻ/ѓg$vGn>wӵo{l{˽֊@Kk;}ګ8Tw[<ukVιګ;ܼ۽><˃CC=N_[||ݜ:e9uA7޲KJf58uOkkkx$$$lwojo~gO>e?I_ύ SATnr#7r""k WҨDE]Fsl}6ꓬd 8nb>r#LZvc܉A ܞnl>쬧ۄO٥~#}$n"|a½C=}ҧ]9 *JVyI1v{?xjeOHzK̩ u8H1d2ҧڕW7SL_|Z633(H i_"_%s[)@;0@vԅ 6lo~rݚģ'ΜoeTz' fgN]4r`3Cayw|nn4ܵHIcɒTr)%Kj322ҋgwlpHLT8D_P^X]RǀKHhge-FD.Z&c& ٛCY*֕vP?$U,Mqhݗ{~}.Tӟ"|"&`!!+^S}h!&0V^~E!ɆXX(.q"n$7(FF`T>,7TQy]f`&%r#7 NB'7P&, Ɇa.0=Fqr(<͓0p? 5@Q+BrL@*Y02(%4'A8F!7i#7?u^#6!1İÂeA`X\Xۇε~%p!#>5ą jїI-3K4wR՗ LT 1f8IF-wRQ ]t\>)hL+b))Cs4XiW ʶ4@? $tdI'sV0?KwfC&RH\x?-5S`^havՊb(hD݋ XIPׯFX%9a j 6cY#ɚЈRO;a>u,4a!t X%cjDxo!/]y.ˈGˡ5#ͳFъ.I4MBn.O=h.z/&'˥gv( y ,N"hwkU Dh(Zt%Ϣ{ ?[HEh y8֤3L5Eƛbӊ׃?A IyZш/,'DK_R.{P'} #>sd]7 0M2jTO#~hCn-4iyUs#knˇb}Zr>ҩM_.uS}PD F (B,'TMd/5tS4ɣ]wvc-لo0Y |Xi!&zHnhTrk?`~tB},6B;mE&?JhaTQdNcA+ @˗_2kn,@)Ê\mXƷpk6لXL['@cizU zZ Ҿ`b'&ܓ&f oLLbޑ!KC<&G#0P+u]ǾfpÜBĂf0| %A.TP%Q[nmJP?uGmAr@qM[Ai kRF& 9K㌉-zIuUB(9ɴT㈻Df(#N+^>f"kؖMJä@)Xĺf@;!.W 0ЭU֘=+HKKe|EFNե^P&W1OE|Yy9I/.'wz򃇎 'WTHE9p!!>n{I[Z~N[|\(N5Z\}q~՜޾ە"`ZvF՜}(76>;o۶ ->RapKKgŜٽ`xhB||쯋[l/9$|o%N֏-X4oFQc'6q{{{wm6a |d٧oRO ׀ȼU90d \db>x5N5 Ey+ls)OmZC Ra”O?!aCB(j %\.#Nm05%yʥ))`νͫ˛ŝdQuJJڳ@Sk;߂g8\WTzfs\4kOm3cF@Eeyep88`ҒY6۷l/))l{6-k⚔d˵o6Iy9))/ wgEj"ݽ) JP :{zz딴ܜN1 zw\ e@9pxZڔ9*wt9)S].v;u(+-ptϠNKI(S NJ Wuw[wybccc狫Z?oNŜ͎2\w WV{[\: c]yَ{zJKf 8z{|SRgWC{tQs+b ‚ ]6*UQi &߯%Z|jlbsޖ~)a68G;T}ByAG %,Ȁ3`ų,OcDyR4$klnioQpܦKj&\>_|IͻHLI\d`5zSSm6[SK-7|BKs{{WQA~͂mα1.L^nNㅦʊ9 ϟ_hQ_zwX|:|$yEŅ;kwXt>|K?TPdb !-QZ˗ w`Mmz[`ggO\\5+v^{Vv̌;;SfÉC;:{ka"K.>|cg ˞frz|e|\X516- v= /Kl#QɼW-,˝> 3}jGVw=,R>)aIuU/Xbcc2ӫ*\Jq::{k|K/9tg;ܣ'3wjjp_*>!@VVjMLLDs@WWK/+oZ.8Zw7\ܲvmAt3Mcy&WDW{ ma&7phhG^bQDPc%㻰,(˰̸2B J{x7m7 @GOo٬3g=!3#}ێ=Ϯ]4!>۶sߢU))|\vn{gdVZJ 3 ۻ:\ȮҒYf8v@B||JJJ&+Ʌ9xaEf6]hnnnhpFaScsss(e>tfK8qdWWOWWOIɬԔev\;sy))ɂ"JMKwhN!%kkw75/V IDAT,š9~Q55s {m7X&^G;$$%&ڲ2qBkRmFQ>x4VW u-sW?C2k?7m׏hmV"k‹7Or:ZTWXTz ҡed맣3--7\wБڭ/;kw-]'ݷ$VɘȔw6ڑ~ >a靁w$' O 6/5R,wn߸)6FbB"+*@ں_ŋj涵u8*GV,ʵ?O)}[EE9kVW3ywzY38r`Ç Wz޹lIs[fp# pr|DDy K 6P?v#%9Sւh K !,ԻJ,tN3RnxƟb_ &f9WFT ЌKsO{Z qαqnЈle;::7oY;be7m9n~͚ٗ3}w232݄WZjZ=hbb_b|lBrdŽέm/,ʫ[lHKX K/޿`kk._cw:KJg\ ^~vęn*,[.x +LojnVJNwΛ[^=2--yk~MMt>1F%(sc9#LCʲDlc3gK*/-Szӕ]~KܬYJ /ݩ,EjMZطz.ئvέ,JOKٶcСN;cqfP;o^/"hFQ-מ ?4rw4NUhO?NĜ"\ ԘJHR| ējp:2BA0Cܜ ,=5(t ߂B7 P]oa/a=*Tr%RlQ':z m>]VRff}4.]@~nN]TtcGyMIiTWɩ#cRRI;SqSAk1R 964ykVVFss,_lr;YYVjΩݱڝ\`_[XSeٽ@ZʔԔi ~t6<֮^w=6`DŽبm-E'\c>sO hjiKJ]n9~|՗umhvgNݬ,puddyD}~Ωi)kl . ho--eC |r>ń֮ZUާc2ks.̰qN" 0BSjW\Cx gNSby.]|eGLfx^7LM~"rߏG\F' Rtӂ60iwz`)B:ssFOCXPKo؈FevIEս>*{{:{z{}K+Jz{^cSszvp,.Y\4:: 3#c~Vl֌*+]]=yy Β%5%%Ξ=15=}sM%e3(.<[>Ja ϝ=,U4(U4:p5OL~=>>>5%5MV/YZԚ31..;bv{GgsSsfVus攥sP18}]vM}F:"7.m^&Jtׁ-x:Snꑑcv_ngnշj˙&+%9#sSp\{\u -m_ߠTc'].]>&2z}S8v87NiAILv|SiyI- 9%KZZU{땷^VHnFeeJ/мB*r)QyKˮei(|Â$z(CB0 cI7 (E2333wvuwhʥW]pf\.UWp8M;-[\frvm;Jgp8}K/''g&<>|4j K 1֘V8{gGع}e v}G؉ Y3g̫+/s8ߍ;jw,.)5:QA&l_92HӗR l^ r񉉦$ۋ r8f70x척*y|z٥f 'œ̌4SϕP/_;>=+7';0pFz:Ԕ‚|g M͙b{己V/7r'MINVQ8lڐ"e!Cf W)dWZ߼{>Cmu7F0e 9 A¨8#6O77lSNq{z]s+f jz\NTKsKͯEϾߡW{q{p:xY8~~1ۚ6o/_XTk?u.s-kց$[o'OuEYTS?xbIctX>_)ST)c8޶wO//) X㸷-J1#JSG.حQZvA2IsnW>cHѥq82$$-OVE"A G, W^xށxaJ l1ԻCX)@;+ cY͍.xDơGԈW(a>F#Lb6Ae!3Jg 'Y߀>ظsLoLYBɒ|K0Ey1?b܆0tr)JEs18HD荄A &\SxhsjÂZ |~OR˸$Җ6vM5OM 1O(IrFi)\ӵGAK%k|ιR/a2UbUtx2IrEmU_m#?[QmzS/h-2z J@e8ݢ,~-%`V h(>)3ᣵ:GDWJ|˲-\GߴK9d+Y [k}R, F4NtA&mB6 Shk!G,V$ÕX Gܹ0j5P0<e`.wx,3OMJUzF L5mHT5Mru#X\n~uҧyk/+,obJ$Mżm rB$ޘHKNѯhM(Ye„VfMj=^S0es x(KRxh9ZA-@$*2EPMу_C)<7| G4-D[|glPMcJxii ̄٘xk$|[ՔPeW"L$} %q%OpUOr 0m!~Khz6uLDV΋ ׆0?K#1L$5xTz?}JpRP ,p{]hJ<' LDxGÕHNizih՛=J֚ o_a +KL=A"4k`뤰k%]WIdq'ʛhlKK+4XE)hnbaҘM6v^6`wEDhfxP-(Sk2PFEmTqm hσ9-׭[$'!TVEI]"k .-b"Fy#G *1R "f8AcBQJ F'aFfB 0((>ctؖ6JID#ݸ%ķf~ ɀ&QDuX^&Gq>ї] (N)8<,LT>~#`-~@(O &#)`ei Sc0h|\:{ѧU ;РNQϏ.R\*a8]gn~#sG,"p7\})(@bh (,oՁ:+dY43PW7HK/ B[jhS%w8xV7dATh0hg!N$!JC.e%~f4mC΃Xv(aIܧa$޳,s ď94LXuF.z&'&4CfY F P5ڢɌ%TK'!4ju zYeB.{P1_m0C L@k0A?!7\&D0ªZMK#ܴ$5GDtS3E74}QY05zLz.i:Ei )\/Z >ǯ  : X|qbD446k"1+j6! &{0*szSdKKQTKCmV{UQd x#_lNx`0 n<%%s)N`Yrjr%k7D3- z2xrBu6 R fws$QeX66Ӑ@ D<kO{#5mRAmBʼ*%"ӴI2DT >o=P}7Ag#[IPۄlB^۱8h,IC83HZ4|REr" oFjO´ͮQd6HF𦢡N"&u>JBT Tr۱k)} jdQ) PP XO 7,,%n&B^|Qʖd d+f{򘍬 ]ViL,p'4F,N`DAwThZ% w 7.Dv>1m|0_"DZ<5Eٱ1gУ-oZZ[8)+oUdXK768B-ut;9Wt ]#VeFk3O)uGG-$Aٛun?í`bA , Pʀ0DX rR jb(slN a6hM+;P24WKEK_ymU1GRԥK,ע5MLZu1zoxXE(1q7x0[S|RNRo&U^FN.5 !?ܥdZJ*'Ga,xvTL8ېOWn` nOq3 0 N")-޸0"OPhV8M5 qC2a[a,-h:%|=^C.6dpƐk2n)Z:eb{ՠ2ݥ`F1%)SjU 6M,C5Cp(pbM>fe ̥ Sc)b%FGNRWL 1  6butIL̆íEsQe\ /0n wbAYmxj|g{\HAtt UnӜ(ܬfvIH_%5@U~F AS®,waʛh IDAT\3}i1؈WOK!Ej( PC]+BÝvCx@YP0 x3&lEc:A ŜlZnFJ~Ӎ`&9IrrV&9,H 4|PVE0٤. UeL_.a2.jU@dnWi`R,d.g!s]eXZngڤdTo9iS{Usef f$aƨɝj> $t1/~dO+#9Wr"aӹ'mLv"j60pcQmNB6h,bFv { OS`XV d8Z,kLb,5FZByӳUȜpw=4`KlܜѺOן'$ĭYf5 *uUؐ;d@g"շ#6|Lp:0nLڌn0F?BB @Tu Z`Ƹ'eqZ%@0Dь O]dv.%įޏj'O2ra]],--u˶V,[f-۶N|AP{GW`VkD3gO{:}Y;XV6+//ns:DŽb bb7&~* f{;ZqEI~/ߜ0 Lڗ}w6EĚƪ0"nho"xFH0爚66.SP T6MLL(Ԋ , i.)TsX2~W6k2IJ1"QtR 6o[cXO PP+O8-c+k<4Fe,^]=AEy=1cF~n_cpx>{qlltɆuY1ɲLMMX @z)Im-1Q % ڧ WQ@/B-K JQ6K(j. IZ˥ N32)N>U X&VR dE&Ow.֠=ٺX>iRf7=++# isRR㬱FFF:l Q䤌,w;֑>0@rrkLlljD4%59:YGFbcc2#{&0 )cN| AHT: 1THz4\.l!t AwQ:?m¤dߨnMl" Pk=Iȴ%T%`QLgqB\^g3 V˂핫t\p&/liج4#%;\*7p,FG]=/:/:bb,q}JRǼW,甎vguutwXpD&klLBxI7x?C! 2 c4~SbHc&H:$dÕXN%oEPd7oSXf$n2!fz?(@`@F$0mS͖dqV6?Yy97wss65frs&'IS3SRO_fVE{ȴY3::%C$(yv7&I79DvVB:跭O%QKKyoykLK͛GF^$tEׁJʩ8;M#xzc 7zh C}xW(K<=3#?wcfNkghqA^eYfs\("xzԂ¼q1̪ktd0vEHyRsP _cZF/_eN H FɏFoUm&Q> D3n" 0IɩZ5BE0 P2,z T*;uΈ c‹O ^)-N%vvuv ;Nm,-.=F@ǿ#P,8G6~՗p 18HO+(w{ 4o$oinh8G$ z{c1v ZP=xɬظؠL X $uo<La#>-k39qJf 6Fw^N!11&H6+Ԃ-B={c3 4'a}7U)0B՟*z:?QCC|Ϟ畣˃{/{'VszoP_I7z甇o[ 8z:j`⛺ny|¦@(I{ yj{YR:GL}cC4STܶ'|(61ߏr?/e>>Đw 'U즶H*4@QR !dR>M\0M 6?h"B׬~'ݷDzxޟ"ETN:џNp\\ͽ{`/7!M屽QwCqr`;S8G?|0=UQ+x>?`y-{mSӭ^zHRG}dai0zvK=EN7x9u =eN_CcEIQf{O#J~_CywX~e(Wr A8XZ g:N([Nxd=^qzzt|{i1*vN.c O;_%ړ#4 2OX=t?{$oS ?wDms<;Ǒ#.Ed)j"fƣZ(9@܏Q9w3ReVwÊC ut:=+Xvr#6>f 0A<Z0/fyk]_7O)OUU7Tܕ%!8{11?~DF9Vیlngº'?IbFϒ)/8 pʩ^:x~_fsQqܣGA%/ԥ?\=|9e,vhy^Ur`-p؞USR:%lZCaWrCobS㡶.x ~*-G&׏6 }O8|1KRQ9 }R/R#1QJW09B(Pͳ9 nܓS;p~× 1yZ}y+{w{nylv6/psOT͝E'=ԍ\|:L.q^-RVb/-<=CK^%(RGyW.w.9.ܩxCojYR8|<.X? ÔN|x*:EzdU3QV]i|r:y!A?G'z{lyl7)0`H]cSڪQ,8$j<-[۾rF?,gszZ/ΑM`h˝[iN8@r_|ݷ/ڈ왪o#Շ,~ʺ‡~zN9f\iϨXy!,M% o5 !}Ad5Ǥ~f@`Dds ښ襽ͧ*o?̾0oUg;Co 9lN}i=y>u|_oQ^ܜ~ZϮ-ø wP~vq3RwlɍxoՃ#z5I{EViXaΟ.{3܃aP=ӉeR|{}PV=|."o>z$i~ՄO;WrS[xH5ؼΰBA:ޟ6$HL*-ǡOIU-{ SFؓɱWi11j_dӏn^?ػA#^;,G:}\l]͍YcmfvQő|6%RW6dj<5Nm0'fߩΙ{'J͂'?P|QhX*ѵ>9tǑCMJG(s1CPߛڸ穟DK/u۝P??km׺/O2gwc- $b` p7sxJYDd؏tddy8v̷ IDATo5CoپGOh3 h}p|Sݱ8xE胔;߽d{^I<#] O=;A}0GˉD싔Ft>-^:)#\|{t%:N{ûaz\wtG#51%wׯ_bWɯiΕ{-þ.:$뿬GhO Fm6Kyf{?,{g $źQkT'O}qc6eG0 oG+/'zU7ļFM@m/_|a͵y&V(Q6o7`*hgs ,p> ~R6hq42&dMY(dngˀ`h5V~/}S[/>;/_(ΨL凔ˡtؙyyAY{,)&*IAT3܎;?͚gSkB naj0o,gŢ :-7p ? @O0 og|ZQG e`_]>ſڄ .8 Ma,`HPNA"` ^.˫^oL{'6M lAw $yw>gv3?SߚyX E|+Kmkr B@JAd[ "kZup9;%O: A0# @X6#Ab`A`OVBG ackb,iMdUD,!7%&Y꿄9A{C 29/1X̰ѐ"`ALQ[FN%FLBe {75Ʈ\}{fV`dp7:+{K+^3[}n5Nn0+6G](6%re%xw.[IR sPt6} ]p`Dn6WW%>xo/wQ9CE ĭB@)FSAJ>"{d$D k*rD# jM*2BRnzl񂫞r2'6|D!"p=e.Ke Zf 椠 |p91L5#YI]di{w1sH$_W}y9m^ϕe T96첧olgw("uZ5'Ӛ> XP`o3~9ـ'. g Es 9 A`BtP >ic+7#7@,`MG3ҝ~k1UEV\iw{78)BGeY`]["rz6Pgp~}"~> Gh PBJ @\47)I @6k~ :xih[R(vo.+)% :HtDO ~$QZMA@&^ 6lE0+Gt7 70`Qԏa&g`R$+ӆzb^d=mB\#w @1 bV'('XzXu$ 2`مm @&OZ5TS@U۰A P`"`2\]/6"@pXΠuXR9XםX1*"@I0:LW G{: a.Z730"nLU+O+ JJbGv unWf~m\7׷_!Rn^d:EN=4f;O,ٙXRryNJHM cXB &l <b#Аqf7 Fv^2o7u21!ϭo>)%\"Pndd.}ԍcfPXHάwfq&OpAb(@B2~<񂫞Ř\҃SnM- H&y)ARV$vVkWy23&=Ә/bugen*+BYygb'9JJnDG#뀣cax⫋xsʛzfX{%d{mnşNV۴F5*0=N:ir5 >>" 87+eDaCsn ^|"d(` X `Tw=Rzpʟ].dtvT_ .ٲ:+ֹ{% b?Kf{c"݃1!z[ΆMϯޟw%14ұ p MHWJWyLW(n 5c0fX +Ued&00D@= ! 2x !Ov^WV`exF2Ո>g\\^eޔ5èދ# .tCFE..a=̺]pvW\j`D<ʫs1C#{C(V88FC 0e WH==VP H  ꡄҁM12T -#  `  (/P/?yCUx JFt׺3uqJ};%J!=~";]wdº|y{]\S #vNu&iMzyy׺[]zuϴ.n,W*Fc`QI;ά+십ŰV!hD.WlJE,ĮpYF0s|^~s}vf hP2d>7%~T"(BBa26[t6!!C0"eXi<8-nt&G:"Hx8k, 4{BA)U]qZNU&X۬I:U 5j7∦Ugoq=0D3L 8,#R^q.oz%] <غ}{sign I\Oz!^MPo[ ~M] J p" C :t,!AC^uZmu ]ǟ^㭯hG{?||N_l<|nXpY4n1iO#3$$ql7ٙ4~ $30/7 iThI&7 (8dX1D? x[=*geSk)xX]ߖ   fMiƤJnkb,\  h$;<2R*p^pqqyyp1@UE#Em@ף @xB:p>yY_tvK^n#ÔV`u\]{Fa (#9276PA$ڂ_t:"5%-g#<0 /!']F]۵]H%)B\.r7Adn3$L4M`0 v8S9z2(>90.Eܐ#4*7H0G8BtTOtt\'wyg _&RA $ы]R2+zo좜Wg^3 Vd=}2!]dށ]X/. LfERRXܚ $'ΊyTdYѻOUyv`p臒6X9J43d{,u[ٷn 0C*TiBa'}YIc>eB.h6#{>Y]2 ͔)(➆)ETSo΍0S}СpxoM[;'#3ĠGZź:) 0NzXFfǥs+]ƭ_pB0QUS((M{X*d>z"7a XэVX!TR2hHa= _nX&_WW#M7u='a;`VJE͊l/~ٕuѬx 11>0y|qF VIjGf@*0x+I[항Fd`=Cr49"Q7{.gU`ѭW}ZG`'JB D@Pd `n:hp"K:D;@X HP¼[r , Ѱdഝev;w^;zK=%">KRpsЩ.SA `VNRrIp jdKBWM)Y[ ws8*I*Տ?D$hHU B2:,4 7$+%Y(:idQ]g]gN&Zݙ$P0w53ԹK>t`*J,VRg}_5$y0<TVA*%DX(Uaprl6`$9,\"<)mq6 €JOTi6 it a7&@8nRY^*Cm&~R^tɚGvy!idg}CM$_a6p0# lfA5^1fH(U v=ϻ6Dզ>ROsL u_i R (Ӡ&cπ@N$Ya`wo"uuqyHZ ^H2!ѹء+P{Q82fSND̐l~, g[7Z6@jb)t#lTUڌ}ؾׅ*B HrSb/Le43=Ӫ nY"M񳬴h 8:&s& MP "ht) ܂ ta]jǪo꠭(!A&dB.ڤ~Y^9ܚkV>[c?k?@$aTpR^y9-h62cQ&yA앆.l-2I 7s" LI,@4‰$g蔚E_xYn]r3 yQ&Uͥ6d@.0yqƟ) vQ^>vX՞?0*[: y4)!,ޗ/0rМ8R]ηF]%Zc^ 9xp%Q䀱~T>BQ~uvt",C;9MA.3JPf/&*H&"2Y~|_:4siZyZ7ۧc; plGAI]o3U{qhL8MA嬥~{D& \߬ν\b<`Dm2M,bE#,oumɃ\=j+b,?2i!H1ῳIk&ʦ|f:*#u0`~uGv ,zK[@$dM-ATQl'hJ:nN4qje32F}(;5cwc UJ|*s4 ;gB8)Bu-rniV,Df(CpXb̆LᕋfD nݏm5E}O]QW;g&j?8[DfQ Q ,m;]tY~־e>2:LyWW.!α2]5s3!{z-7ɲU[(Gݱ_ܞ[`n֛ǭH ņRau;g:2zF|ଠYafYh 2 V 1{9Sҡ@Rl4vSE]ďǟVk/|`.{e3y&|9I4>9TK]>ÿAW.䶊IMLȉ{`L(zf;ξB+uEW3 eqh@(g_Ln)^ IDATpkW56}ktLctieG;$!\F]xq|S(בsyJK$ DMXiStl1.&c}p=N*aCqQujƾe;D+ D1u&Jf~J;Z!m-઱afs>N͎*[% )%IQ3-%#-+B!jG -NDPI#%I3[O0fETXE\P&x )4:6hW~onPk跓 &7yif_&њ *"dU5Hjl$\ߜO#B Nh:]A?nƥ T@٤W@0Xٖخ}lǛLd& M0B 4W1.>sqx 5>%t$j"$?Bi2gF Cq(>xI$"dl9fgρyp.93E6:!w8+{SVD5X#= YU%}of&Y:a &qʍ/X ˂#" eɐirID̚dDGf_9$wv{ʱ@^M}VF6K 47 ^*mmu=A 7WjNٕy/oq:?_^}4cNznUd4"2Ղb x8M^駝H[KKd-U)kbغH0!}(<*TdS=D˒QCX/VRߜXAyA e`2ÈL䂡&Cbe;YjnrU'=<9.W`QjmS-Q@U`]IUhk9N=ujN`,/1pD K4p!K#u|u2ԆA)eb8-/owVno=4-sd]j.lбu9w]" [>GtM>/{rso(1o ˖+\.;gwL+j0"׀w!!xK*{;'?7r''07e{iY֌젾i-KJ{%*^4-_;ڔc-5r_kgRQZz/8$V_2bAɏQ X!̥,dxA5S(4ybs,\VOf3.ƈ0hAk>,QY~ =W]:Nٚ$2j WS~m2p" Ab6DՓ@#bi ܙM (8GCb!)榺Jc]bl~;ҚyPt~E ![xx]|<"=gl߻m,>(i r;(ٽA P37'#daȌ:k̛\0F^t5,Ha7s/ y5),c&&o3Lw敉j600L;B BO^<{hb]j#<8jvtH"y͢+1F.@/*O%Sv*cn) R$A'ns 1+uFd,'$>c,"HUo\p*z0V6t2tnwMoysʖPzn`Sq708'E J} 2,%V\ + _N3%S% oOQA[/O]>g`{3=;aLޮzM칽)lzlYUgSۯM4@T]uM4yIFa/2Crl ,F͕R$uzu$QAU^ YWUQ&RO".,'<(E%TD^Z߶g~%Z$Cs? $ܞDLjrA3{8)Dc$pk<h:hS{1lMkp㻆c6|#[؁ԨTJ c', ,6+5&`U@8P][jN,]8HC)ɖV|v=dd!E c}0+-sAO4Biv,iTayp\c~[(3c~>Z>t_Nxk{MN99P䐪ݵo"s<|[F fģPJxzˣ rx6,23nѴ B,N ˄ @4max3Ӕk0#ֆZӾxj&J] L p<2dBQ([=JN F|wkR[=[/˙VYb22KvVǦ% k @$ ˆ&ǚd5-RƂ(S2#e,{F\e7Pez>໹"}ԞLc-}dۯ2Lr+Χ<."/a4 ? qJ*poA &HcZ] w6݆s73ڈ1Ju94LNֹj(n:< {p+՜W2.%_|,A.VR6XYM/zݦ{i" nR,)n5E"L):gf;W>g[đ8[69e;!Vs|K6E7YL6JA-92Y _ z;C= !ٹ|);ծ*N,{v6̰ZIl) 5WBR݆19 K)%FL&PD}A\qdT2JijdˣT~nm<77?̯TX )ǔr'- ۽u%TL"LmLlGj w!Y8.gSu2Hu;!x^SAWԲT¦.ɖ$k٠>Ŵ4zOfU®V .TJXjrgm?Lh4 :P MnTs!J cppEMM5CmpU׷HaH" h!Ĥhf]:$X8TQ47]O$kkKG-VR8 >1hO]q͑c4Z5 ֫ۦ|X;9T ry 5ȋy扳_)oPL `/X uz-4I8Iڒ;ߌnȈY&1Sy 2]/ń$sq}:ˈS9Ú`Wt{evƠ(c܌)9(:M-P1륐6-$YVko3?xeVVe=*Z-H 10f"|cf|# M2*22#q^ F܈2]nl[ɒD'MufTI4o ?2]],E~"Z6oCf;&)f=Q6{x i"{N@KX8(+pPK#ƽJ@ @`:X(jbzq)@0 qEi:-_S$"J)ʽ&W YDeWӕU#bwOĩi'({"t>OG,(idEt/^J,*3PpCls)Ÿ `EM3]\6)L=nWk[{ȷտ . 6e`BjpT8{QMaz՟\rrŞnA6dȆBkFjLUsBrYDVQ#vD`kX呰d$\ ٺVKM 'dK2.(0 &.>6i>/;dXiK78yL>]G|jZWϠ|BnW4NFCVpKf rx$9ꙁ՝$˓S'Zx4`l3Sm+ 9f'0(fpA D8p < [D|73/p! &B J6W:—xha1u <Vݱ5! 䨐$62rZUFXȂA;o1*  "(4\]AٓŨD&H6KBׄKv\pQtH ?xTak# ,(\87zVk<~}s! yգm!GuZ[Cf'(jxȬ=ɵȵ?OBgD>ޱx_TCT{ mэeh j@nk*ځ@bIJTi{,NLGlm Cόo*O&, !8Fj% N+׭-˪tљh7.b2Q>)"q:! G1wVv;xN 6u6d?c-['Ӷ]8Dg_SjD<тSY _x.E~)*a "tO'5: -:9BݜoHMCo*Sf $?O &X#U݌" =:ꄈ8U1tCU$/zcPiQ]i(0$BُУBp$C>sj0h H:gnϥL𪯧x=r|7{-F("ޅ,,C\ vn.{Y .&"bUpHmDyIwE}I;Ӽ$Aݖb4C6ĚuwC['RT7BM$J;9˸(]EL8}>Rv ,)WUw_pPH*ZQ~ s?qaggrjJ=Wu" "w!#*jm{kwYn~( c"rqaSpV2A\j:"42|@:l GJƤAnY}6×M}BR(_r$1|ϲ{-!iͦ]c*iN0(\}h<G ٝwxd3uΊ=1'eyt݈b\C͉"ET: tgqC3]f5= o__zҭI!(VHizjZ*xVPNw肅"SKu{/}Qޥs0Wp"rㇽ'lߝ@] / @ Tt:vddV$ޝǯNU^^-n{<܂7pڴKĻ$a,%+DPD֍ ˁ B]섻72*).dQ n[пTw㕭Ң9 |Y`& Nu)* 4˿oascxci@ԏV_?UCIZ !MHnR<3@>=uܙ0/tOߤg*EmSol'4:i:3}܌m ?cnGϚaD8pcYp e`B.jDމ湝Jp_p{{8TFYQB'[j5(\X)juD) b30\ߔ9)%+d* lYN8k7}KRJbP<< wz^Qoۛ D3 5$ER$_Kx)t!=Q*!"Jp)B9r].vؙ|c<8CaMOoe&cCo0L, y~P0I^@" K 6!j  [V[šw5xG='j.&[BfwC&R;L G֘4 d/nZMwzhCQm?at绫LڙC̤aE6zR 6,$&f2]S*L)7 |ߴ;yrR8=Z j"q6BAq3!0Y #^b:&0Iyӭ ]'F0BrubR5B@з~qoNffuǟ?mW߿_\4_tZh&C[@Cr{ZȍYm@*SUi)x׫m 4sI,z üߑbE# (q;[Sip+HԎF\Ehe_Z>thvZGݮ"JHKdR=ᑋOk;o[>Ⱦxc1Cq'tN;Hc&2ϴ6yECp뜫!LFw qkn쒞eњ7oҾvb@,ewjV.7WӠSH> 6Q+:vq4s#6կp %QDԳ*v'DIS^QN]B&ߴubnK땯1leL!"M=v3 *Y %dw2p =5vZ\?|)qYd' E5Aju'59NS]IZwf$1C!m&yC&duBuyQR-fay=pd<'=v)uIDAT`!&8vKՙ3/"쪍_ߩZ)q [-%o֟NJY f,9C1-ōM{y__}~qy>4%7Ml' ;8>)4Еh5@P(U%2GԵ`'^=(g;<|xXuv8GW(WfC^d=]m^$טqHQaF&*=Iro?043IN!(s/?{Oo\ywd7~Б1v efzY5耱{b1 aR8liIHnN[|];Љv_6U3'dd,#$ t@$|~I&IsE7nk;,[RdR(43x'>:I'0n6!Y&H4«v'H1Ktu%oxy8XzɚlEЭMXw x5#ɬVh4 |#QԵ.Ҽ:R\CstX>BPb 1{rFK[92 `(,pP3C-Da#ZT}Q*B5h8(ڀƎol 9 ; ~yȭlk}eH{Uk#")frꊴIe[6´$T+<]rD;gjvӌN?Ƀ-=P}fdhϻq$I#,'ɐɫE[u1/FpRaa IST bY-YS#gC`iS.Xn+!&H"(- !Hm7@x?FB= 'RhS\_g*y*TM#}Kvhf 6LXg0|cTZNx) ( NA+' SC }5Pd|چ,)۬t 9TxK=\PA˹MNp%2;d6Ww+wՄDU,zQԐz섒i665U#ArjFdSy I6LEuґc ; W (ۥ2rr5%BcGttס%=+3 }@ W*4:4$8`֜/4Ϛ9@XakZ[@ʐkdA^@ $W׆tEoFZ 0! IdZ˞!Ha0KUSh{sW1Pt1rE&uhJ"X`֝e2%"̓Ld%.IىB9蘨z^GK* pWC2aE2.<I@q/WA%wO7T`pg9lz)8NL6?:#}ʵud;T@eDi ";WX+=̀?6Si_PEO G*@`~ys|u_gGO~fy}%%@ LKd.;P2R/{k#-8yeCvLHN?q171W 41 ?ҟ_ciS_PBs Ia&"zCE-nbvIkQex87R2Ἣ}y] XzZ=>(`RA$[aW8N++3)$נR&^p:74me G MQrRfeN@`IEڰ BQv$8ңm$4 $]X% cT+; ⫉d9Zl Ԙqo\d8)QI&sTnB5 q뢷VBqݶ8џ/ID#C\)}VVjH vEj o6S|W~ؚBj7#"c6 KWGz GͩFN0du(@6Р%+V.2RM "4#1 lQB9L7_?~#7U?.H (^Kul5>ܘil*8/?\v_ \" м7^}d¯^5^>///gOn|w.- ,R$=֑AӀ# Qd^j\*OYgەWj͌,t)<,I=aH})P=\[Ib(FYwRLuWC:/ɁQM HPm@[QC4vf^nR1}vϞ2w齓nB{Mw_T@⛎lHF<>ڨ6O2x21Y8AD@_pUt%.Z;RSj 6u ruF'Q(y,kFPjň#yn EeCAJH 3$jT :H}>t6!&*-ZQsS'^ l iq<1h>UfGL>="Θ⽏]Ltj%]ˆZջuɠ+SH9lk4W\XbmQ^Zjr(b+t]HD=` 'EaG:<'tԥ^/PTW`Ƌ+µNWSt1'ьWfۘNOg'P#鵢#QHUP۝^K3p! vpP>S*~/x_z%~/_~yoO8ajz6g_s3fj=mU~^WهHϠ{)A&Չh MnS!ujvb@0t"8,ނoIWcU^GV nJg,q[=*,rJjjV56)54Ǟkwd*֊3brS]GH[7v$J^Ҙ=N}sd<:&_k-D~ hR4(jn[;=qva$1qwÙj蕋:UU'Q]`EJkMOQh3=*t !s+1uqEלb]WB,¨Mf9kHOtI"߁uw9>wK%,"%Iѱ*=! 7}ۅ3iB\_}|e#X<zv5?J~dƛ1=Vr4>h&5E7e߭vGRsõi<"P-TjZAW! 9%xm"bo"=wI \CBM8M,_3?|nݖ|W+UsΊr"W۸APF.kx~jTtIoB+ypO >pIENDB`ukui-notebook/data/ukui-notebook/en_US/index.md0000644000175000017500000000416014201136534020437 0ustar fengfeng# Note Book ## Abstract Kylin Notepad is a small plug-in in the sidebar, which provides convenient text recording and flexible interface display. ### Function I(Notes List) #### Notes List UI ![Fig 1 Notes List UI](image/1.png) (1)Sort in reverse order of modification time in real time. (2)The modification time and some text content of each note are displayed. (3)New: add a list entry and open a note tab. (4)Search: search by matching the text content of all notes in the list. (5)Delete: deletes the selected item in the current list. After deletion, the previous note in the list will be automatically selected. If the note of the corresponding item is open during deletion, the note page will be closed at the same time; If no entry is selected in the list, the deletion is invalid. (6)Double click the list / icon entry, open or reactivate the top note and get the input focus. ### Function II(Note Page) #### Note Page UI ![Fig 2 Note Page UI](image/2.png) (1)Support automatically save with text modification. (2)Support users to customize the note header color and save the database. (3)After the text is modified, the items in the corresponding note list of this note page will be automatically sorted at the top. (4)After the note header color is modified, the items in the note list corresponding to this note page are automatically updated and synchronized. (5)Delete this note: delete this note and delete the corresponding entry in the note list corresponding to this note page. (6)Open note book: any note can recall the note list. (7)New: creating a new note page in any note page will create a new note page and synchronize it to the note book. (8)Support exporting to PDF. (9)Close: close the current note page. If the text content of the current note page is empty, delete the note and delete the entry in the note book list corresponding to the note page. (10)Support bold, italic, underline, strikeout, unordered list and ordered list. (11)Support to modify font size and font color. ukui-notebook/data/ukui-notebook/zh_CN/0000755000175000017500000000000014201136534016775 5ustar fengfengukui-notebook/data/ukui-notebook/zh_CN/image/0000755000175000017500000000000014201136534020057 5ustar fengfengukui-notebook/data/ukui-notebook/zh_CN/image/2.png0000644000175000017500000025015414201136534020735 0ustar fengfengPNG  IHDR]usBITO pHYs+ IDATx{mUcε{jn!6$DA , #DH(BF8"Ze*PA(PZ TlTN<@ H Iyךs1dugz17_bdD?fbd"孲?W/[o2wpA$-ѝs_1פۣ9tۙ,JPѓ"mm%LE袟F,Ih q/z6mq';YqJvwCIwn&s͐$R-V\#+|8LqCzGĉV?Y^/B)sat @h&#2 6p5Q' 2et@bՐb lLX#NVNDSW40[p2h-%'(%-pzB^??Zz׮ 8# 5pP@i`JVDTC#!pBDbu4|$$]?׳jhuר5G @y+/pQ#HٕW7@\hxճ|ߩ54cqWP"]4DtIJ:>aT/Fj9h4fAcgZI#p..K}C#Zx={7gr&8dLLug". DaR,N+%C4:E&B^A$B ttApSzaI^BvSQFp:CW54Da MdCK/5唔X|jRb\eZ@S1mA0E,,qXN zj b_6`)7GK.䖆\h( z!V+N6$z5xLFrHw{U;. 5|q=p]"{WxBLDkvK׈v;3Owe͞.!c *4KF=8I'y"5 訸ty %"& 긥27qb"bã8$d`e%.9HpP &`!Y!J0 2cw՟dS]{zPĊpCd'2 ʎ JNj .Qʔ^Cif! qbWx";$E ZT@x1(L&,:JP9~_m6|qB @_c6F !'vq.[ vś;hݔ9JFW9J h@ "-5Ϫpwژckj5 Z]ܸX8p tU4aDT#O\޻BPHَ W\g!R pGUe逘+ QBz!⎃+PY h 2J\nn>u-D VKIW4_01q8qC2t,aɲc^`r&8bF_.mmdA#}bQkg;0w@T&,-*Sk8CNx X (3cUA38L,Lc% tìZӸRkFᕓ/.`(l_`欌Kev>\_4,m.+P׼l}P4o&P !"%}1P2t Xڶ7 sq_;)}dAfj6ٴw6V׈%x \V9L]ɝID4#n!#à|6MQe08%Ocld0m\wH!dQQ\50 rbcIȒyLYA✥DA2QmɁY]B3PϻcX u(L" qGJ+D ː(:n ܥ26Up`}q 4s2 T{+YNCμekÒ jZ_֞\YVZjj'm-؊[xV/5!wHk"~Y-0^xG(B/t4-iirjBCNݗ0; 9T@0 Bww\+ʽsrH]Mp[ǘ >ԠD+@=Gtfu1mvwiTvy*phd9С]ݹ$JHC=b~{`cM[518pc`тK6 \0#RV7Mv Έ*{'IrtDEqQ0qbd"{KQ7&^hbS &`!GCx>zGxʶ.A*'삇(\*V /P eQ&. dRPCWbXLK +W2ҵh3 LW29BobP!;)T9\ wԐ"a-KuC8Bya&cr Aƅiw`Z6U d%9AP". Dža(*rhRNX:t )4 R"!׵A?EHDJI(~aAw9"MV"~eXdͥZ'K#YsXX|ӗ1WPzÕfĂ*S ̒ZRz$l8ԍEF{T_̣ɩ1H^%ӣ̀P'As!c1I@U螃`!dh#ʰ& u)g`fFJt,3}nAu򰖰+NSWer  pYT@׉z,9!u O |P0anth|& b;3\8Yhͣ ZV j L*pB #,l3ЪerZ#xb[I}~a-`]+MW?R㚦-&"JBj+r< ~ RB!9Tf}/x|PQJ]WU:"{[g^3yf,"哊3C&p-lrB`h1 +ԝYN7*{a޹"rN>rLG[_pM0V!kD$n \ѥEY.PKU^HzO"ydg =sǬeVޱ$ *jf- PnbfT5Sh&!a;)!| U2I DZgl%V[d+RSHꎽfX(ZHp܅p.3;*x B0PmͰx5skiiqZ]x-# 6կ6ʉU'G:ŋdԶ,H=҇[ne-~9ś^iie4]\MbFbܽk>Nr@ dǂ9#,K!Ft`WwYo̜b#n SIQUV#Z;3D$bwBt,62+X)BpjdI-SUM[& C:d0Q:EaZ U*$&K4+RSr`;"8|e᝵;hAXLƳ!!MP*݈ x(L(ǪrnXW"6\Q& % 6􀙵#KMT7.:G2" cGi5(|U ֓5vJn3! =ZpUX[žb>/Xڢn>4A0@*)N^T/*ອoq-,CED5N/<0yOv[V(߱2ܙ"N&Fr|ڙmIsU`>ElMIqk|qٳĢd /ԫ-xDdH1,FbF"~$\vYwT:&k I}?4#R@}p8KgQ+٧ۋ>@>b{: J1R,o2b)5|UJLEU $?TPB-[J Ƃ7*1qEK ˾@_q_\ȨKTy.-F|Á3RʨXHPPBVþU=,J4^W} I1oFzݻ!u}{Eţtv]|i?@ube.# .'-n_q¼9ҥ`pDgGuxZ.c"} CJJzV3  &xW)1C'!!lpOd0/Eõxp)b;0LUeAP"05'솽E؉EDPj+dddR%*G#5 `A #@c##&uR =֨Gړb޺z%w.*oOִM^'v* {2M4E&H ˞OZk~au 9٫cQ#n5nnrBa,wv:JWlc{i7k8[}f4uiQ/_o_$C+1I=0ǴLHED Y 1SzuSvwDrͳe;xܧ<9Aqk:?- Ĭ5Y.AW $e(dG *ޟ*seFX ȇX|fnC`PxXWmnfĆȅ>5u&^ Z&uSd;>3a$ڭ%NM[M+I*9B. IWA% 9TH5VXV7ۖ*̜V3Or `)5xk*P8klx^&{:JULJզcC˶ -p㆏|]oyx>{ 8r}s#=ۧ>P|g^ Ư;LIS\+{g.?{.Hx˃sϯ~>ug߾=>5K_ܳ"AQ!3W|v~nx؟ ,r]>xL;A,&)˔XvgpM,NOWe)7N|~7TZ'b4@Vl3呣y >Ů"Ґ.BΈ {=S%V'*a|Át+`—iEp:Ў-\iZϱL M9@tpzsΜv2ܔpnH_:ҙ*`NVF3*&&Xt$4U Jd!hET= )&iu-\#*A~Vx~qL +ۏšeI,K+d*&2(@S{\1T &0~ L؀,z: nG)788 o3u}w6?vašCݵ7N--#{{z믖;&7}|7㓏??Ur'#O\uwO8s䡓?>w"SC+v#߿UG;yU/?'wƪ#@shUṬ] xfZIyّ`{+\Mm׻ZW% FԪ $AMXZ@ cU7w%=@d8:aXOudV[{:Q "t 4-隴AUSmN g5AJA0d*dMxHMd+i }ɞJ hhQj.6S3sm=Ea_,뭂eP#(Թbd)p#pXx&iVҹR.Ճ;i*Pe}fVOOHj___ho%RX|qc8sΟ^?Wn'>ɧ}(?#lnoƗLG$.w_P])ïog]}#;,'6^M.5ARO^o~Whjc~(rx GްeX;6w҈Hy>=n+N*a"cwF0zG0#G9:&Xܯв>].e}AYx+;/~⿩oyy1~ϟkk뾙_}_|._03od3^tnuz2,=0ZkF~7@1s$ܙW##C[%+ *tSǍ c ̖³bNLe3Db#LaHSUF֎;J0Ɇ*c#bbTG܉`l- te Ɠp4sc׉X. .0$U.eeZT"#;{4G*ȁ0TjPv3@end$"΋/[g_z'2M wq9zo{+>ƛ(~;e+G:~xKn567ÏmOS~P]PMw?q~BD_n}*'$v9Q5it,_}{C^gQ;Vνޡw6Ltƍ6]%S;V^2 Of1xĕ #2^WV q|sL[J*V"z#YI0rO` ![ ^)B蔙3i8"e7VLIhf"/ ]bpdD&;tKHXFzHj l@AٱI%sW!Е$+` #\I;IH@eB4d:J! tP:AbKҾm_xVSl>[)Z_k l#/]I\c ]K}||O>qo>]67/<} ?Ox]|<.V~#g.gU蒢cr4.Ԋ&US]ё0>91Ve%#97d~ț;2Kɵu?}s}@`b{6W2CֆfB6锡6MLle6腹sq. \Yq,Zq|6~ Ya0;}(}z j [b ֋qk+%0ﱹ}/;pI_ï.~M{vW]Ç?^|9oGN"'_1_~SS-pwA#xw #ɰ%+$U[z-Z7կ/mzȹ/nʣۚ-pa P 'jbBM`ۡm0~6XMf ]M!J+W e`+G:,.QRej P.3l GG66aޱLƎsŹ6pe`gBH~D5INs=|l[6|9B@GB,S{=.aK,a DNxŒhM}a ʍBFf#L>iF Uaku 4~"J^ `XEYJ=ܤxCH6%i__x=t~?84y/[-n KRp oox[y1~aiט>МQNt}~םu'/^M?P Ȼx'.Oş0"y |X^aȣW""d.3O"tWeLA$WɅ{u[; UcZ <7"Ꭵi:a(~  SЕ>K12 tiᯍ2 5 ,@[܄ybK9Yq[fLal8%.-H2&SlVV9qvڝDZ-tzR 5dL?Zovm|_er"Y\^A; V+wHh M887&`Rb *.($ֳ֕#ZuɅD]^8#.t$ c]S:;dte]C]֙EՔ`{g9˿| zg>{_OM'&^=ʇ{Y!nGx#Os*+0RDM9" UH:U؃ %G("3P(J(ܓQY90*s*¡ZU4"G'.n^3|~^CVx,ڵ^ZyfJĖA{zUB_:$UTE8Ptrd2r^jD+NN(QtfU`/[@rzuVh(dRTp]]83x2lEQPUy?B W[& ^7/IMXw8{eo5}y;{`|\?zw>2y/?#||۷ֿC_?:Bn@G鄍ÎmW7Wm4dC64y"4$ك?Tj`eeE0#$,b3,˼:Fxw'_Ev4XZtj!fŽlKG8!AeK:+bLd%_NIeY@T* kNEB1xqWd!rų|JsY8tig gWёX3@#(appp0CZE3!0ePVBߌ I"t B c` ,lmŷ3 Rg1\oyefok-쁷*uz }Ŗ% CUvKE:A6n@oƋqk(g2>kgz[;y/f>yO栿N$&m|jpӟ<;|mSοuvy[yyc<1N)z~{OFZ=4.bY !)A,<꼞~O\R{˻_7;""ZE{eRWYfE.bz)6;0hDan8%d$N y'h D<4aJ\|ڑDp@͈2> gjx2DĴGJDف=gLj׸dBPHxG J)Gl4L(.la2Yȵ *^HRh+N@( K0PƦҖ)N6RuEXedX N!#|֙;'`u,F-6&t$vl5[xL9~nS3)M(Kҍ~A bbnH OCyוje/>܁Z>+yp /הs~k7"KK0Y_?.~oW^q78rN?^T;ٌ;ZOc62]1X%|@:e*RJJuQvwB#h! )S~KH0Tס7ermD:983ea!V-HYB~qR3#Q#% 1Eʛ5 gT,֏aKߪ׮_^J_-AJƵ3}ݷvM0a>_dwȻn7y)^v~ѷgw!;M'_ϾGyK~]~[ӇX\%*2W E" ,ϸ!J`i!9w,Ldtxȴ/L#˰m 8cGrll?H阐 ޟVaӰX:g{?{F鄔U&\&8J0b&?`e>NP`dUmutμ;ܹjLsgfH&jbPM2MK2?Kw2`lD00:ydsKu)wр_١2퐲~H'Un@vB A$L֪jS1><0z]~|u4\{K%B+? 0+?X̮^myvhˏ瞿[Gt4Ut#QG+7?UOw?<.on8;bs?x{yOn߿+&E*?:{6Վ^{H(2wxO\©+a .^zWͮҗy+VPYROŀ*6F[uoݪ۟f֜1\9{s"Ss>\s5{1G9`1TuvkUh0a3:L{ nLO(7J yn^$m74Hjbr]$*IYi >[Bj-Z%sIPj- /PB%k:rA~**()'7dG085&V/'S)P4<=ܫ( ;K^M|S޼ZVMeO=OX'g?S\~y ~{7|с?OݯnU):Eټ^Wk%Q@#EIq =q_RBwI)V\<l{޶&/y/y%_xm/Go;KW~ݼPx{𶻸jo|\?kWXri=O}3$;{߸<׮Kn=p":$ I M hHhΪ_8LQUɛ=qF6l] jD=.PoPs$%:#I% 70-1+0dxNbU\֐#Uu=GkWCNӻYAɘ'6oQ*f,Lā* Gy$$*g5 4:@n97Gl'JhZ ekڍ55lcxx0~T[IۮL9QmHH3>"Y-2r;ޑКF ig+H1P{>h*a&a' RMap@DgB.kL3rG[(Ukee< * D4*aI3~nz4Ͽ_w< ?#Ν Oo/y}{νD`3oyύ͗޾'-?K~^r 'Mu-gO|]nGV1 }mAVn9lcB5@uѦD"[U:(U9wU]NkxotS $a%Sބ$ǚVGwBC/'Bm$9R[Ӏ 5cIWqޜ||L/w}9bwV?"-^@5!Fh` O9Eh[DڣcN^Xv̥5qmRk)KDz*ӎўHV PgܕL Hd u3B AaV;P !|~hqwE+DGtV<Ɗbgju1 Nqx穛]0;ۿwhK-;\?~}]V^>~_r|< y#?-3`4bۿ?G]˻= G"13{yl'N2*@c DR*"4σʺnVU2G7q'TXGT9Cr;V(ll~*~@#5pu:pCs+R2i4h< G 䁩8c$Fa.xC6+lĄzygܕV8˜amPx}̝;gI;[щKKo[䇳V_>ǭk{.'jZ߽GwkWT~s _|lo{o <&>oΣ6O=DIFF_>1|?1#M.W $ TV6y'{ X.bG<04<i 6P4hy@ZBd4r kl"1-KبY˔$WmНOs3Φ96jTH%4Ψ`΢!+!% T h[-iĝP XF#kdā1njH"F\kIvCi-5~DB8oa qLe¢pjx| k6G|, "CX@FE%3j"JT"P$X  əsY|1A#㲼W=:ݕrFEsC$gܾƓOғ\N" Ol>7zg#woğ ?/4wb>p;?ÿ>x^Nfo3O:"x:jekcM̳D4U| yķQ:Hã~|ZE:C3J ~aG3>ƒΊjU#Zٵ%uiN}M|Aہg'T4=j4\;ɾԢIj } 1vɀ\9&%ЊT*z*@Uc@OK99 TC21Z <[OGs9w3gз/h"xt5+ԑ4I'cO6k.%EAQOe8>WYVҲ Jmsf?1e~Nvni"sI5!=0:rxG#ciİꙔ% HO 4"#J;Bi %4-_x⎨D[8m ߩq&U ԘIb8cyu a?UEvgs\plJg?潧F;o~l]fINVlSe q8m]jetk-4昦 ɒ a42~Qa\L [je܈ ]MeWĀ SX` NR,zŽfk" OH.~$M,v|i-8{'ȑw^<&>f2! '}D#}͚[ xBh=#{*0pFӀ*3bf< "UBaFclE@*5Ѳcݖxma9H^W8d$}~кER s)RgѐPy"q < U$lϥI]g_>I!_QkLQU*=+[Xz_[Rlhч aS&ͭ"30D- ډtfv3^־mTȅ+ s sun[CbE.v* S-:fJ/?x_8p iDSRxwNo/H> nY MFG]ME=ZPzFeS9\ zבJ j䊔U;HI:#> 3PVԻ MKң;ID؉= O%o33BB"^O6qlzcbL4"BbvHjBUL!LȐuNឬq5ܟ t`+ ѹE`ODtx!6 P/ʅu(i+&J=-r9I+%w1׿KN}؊}_t=cm gDA+hH*H{Rd{~~LX$ێͪ6􈙪0o>2sJcxkβC{S&H6:m{6eyd%lÀFV辖Ad-+V=U P:2oN5^!8-PX{#t8ƣF|)>5?5w_." #yDѼⷩJNp  T*m!V9/'CnINc֢hZkp'#ݑR1VUr!ggITԹP-ן˙˚K.rbUIf3z}!|7FjP*yrGZ@ c@f0&FF雮9V )˨*#R.&7Oe\I;1̈6/u-JPbx-j5X6$֝V[P'uV/@[hJYpJRRyW*}BS˩j+yqTcB2*0wܙQyPIhkg3Dg!KȲDc6SYEpB8ƓC-E1څ:AE( 8ed?R.\ PKJm Z:@4̺rx2\HArE\Ro+'o^{ T~R 94AM"ؗCȩ=MGVӼq$֛helgJx4';  uGb)Z'*Q cY)JhvˆX-'Q _;ʑD3j2dM>bi+gLS[pT[uY#ŷ!DFEw+'SSڀt*sh;TD.h^i%5eϜ;59݁ "n\RD[~%vl7{ ӱ,r$OAP8 B>꒓$R|fLg1wKEdL<o<|Q+7货ݶ8o-Ԫ &k+"r IȺ!pCBPf=(hy)JȺ+Ohmo5GoNa0"4}Sg-P)+lKq)"O۶r`g4\A+}gE8 -P*ghJƤa:sd͔V'd\gJWr RMv(Y;s*&s\9]*rQ ǔqS!5+:Z#eF ++!ɪc2gabP_3fj`hYqfEK ]F(e")es&CFfgO(/gC'"9 ^?=)W h @qkf!{JLi=UH e{GJ;o8lUO+'8|p8>.RC=N6sy>=\&&z\0&l7eyV9f1!ĢkfhYR21l(Džo@d2w 8?O n;eraw\ :IӲiʏ8ѣD%j>ڼ D^6ݭw'ӷDI}$FH2 e$(iH쪬p86| `ć:Zcjs78E[fYjkq\>3x#&JXeN݊KDEfXIhFV3< ɃCZl(XAԔ0(JN4U<J!(xr4LI"&5h8WylW9G 3͙:8,C.t[c%T rDO'r3Qn/_(,ʠHRQD\z5[c=:lEHkPGR)"XAN̉C"+,҂1VD@x $j@bi)G \b2`A6Fy#J릗 ~R9鐃y-vTWʬ\U(0YvUzd24R9Mq0+vͩΒBrɉB #/Ts6p-q5ğL7¶ؒ T1n} 9?gWX3 *xS53#r0!APXXQhUAk L[S3'8Cz }:֊|6rUWD.GEeGtN] %(8RYF3* '81r'̎p=^j꡻1E$QE[ mG)2eX.'(U]6λ1Q/Z*1+ c+r&b=`VJ2N%rK0y[XT´ޅ:S~ۧpɞ]!k"It' M"޹NPE/*8IH B -. Ҷ`R"9X楃8-| JCG*Pd4BF4d\Ɯ =yDVUǶFV5= L%*Ȕj>cnJ!uEyɔo$EěJR[-/2KVJq\H\81R7uDC<^b XT|9)G41sf @w]&l"MTKME.aF_X(t攅}c)ldA."IRNF _u̦UʒTOilIk&!fb "3JQW&'XT-Ϟ,i-l 4 "I;V\JHI ԰h-f[ t?i2subԏb=d[r%͈S1NPvW1WTQ{#DFvgٓ|..Üф>`Kg|E 7m WMhEFaOsP1y"WSzpa/s3rvg%bM$LɅbiԂ%-%Bg]UܽiDH$QS޲M+H),iwH:ey2c*:/=̷b bN>8 Y I[ɘ\Vfh /A +Ss5&qԒWy*j^M;%siz$CN[5,EER+c̅tZ1ldhWpՔA-t/ Axia=rPh2tQXj6b!ju+?: s2f8:demJSDdao=17~g.٬q.3qW!vklR/|uC\آvݶ&xY#}cRcFM$H=@ 'tHFeWɶCWm)Ue!woOL iaTy +!lSWf>LY|(T-)(ZXl'bb+BEũָE8nC*Esңk z!4`|x\0^kKzD:Mu>jֹEJa*kRrdY6@,J쌙LW.u)2,MadbaB!˓vFqꓨs[O=k 6K)4 ԭq $ӽr h35&2>) S37fʎ;4f"@(RyzB%%$!8a0$)$ȥגVhW6*@d F'@/4(ApxRgVGLV-[3@%Ծ8q ʳZOkDICRH%1$ib ɪPewoFV*RN+TJ =gBt9EưV2rV4L|)`{TI OyKҁg¤~bKm)]?:z(mBaAƉ>X_?w B՘FHYq F>mrm5x4| UMdj1ϕt h bTŖ8̈>ωc+{[~Y _/'H[tk=CIpψzDRa9b؆ӒT\m" {j˜ssQ"1X].$!z[9 z28Y'*REpF7Y#W`n2 R.̸1,Y)^8)8P .xLf~Jϭ *?oj׀`-I1>sx@4A=ib>T@v\PmV;?{hJhA2%H ٹ gx wzLM~1'Dhm%G8C&+"l|bLaNJK$oaq؜h#9݌ u< q*IB`Ч q}b,fh%n\O' %@)85CXKR NUZ܄9,R QSz5˭0&3K2&rœ삃~(rAEթL_L.,d5iɰ>5Χ C]+=jsC[?z#lY.jء,cyD *e>U-}4.db6k;GZY+ȅ*ѷZ\?N*F5VAL.lHz:#6xlpP+uO`,NvJeRdaZWAQH{z^V|^K - 3.aO}a{z`:.(]$ 1eKTA\I+}%wg{#RT䠆 9j}Mnh j6xKkXJK3/U'm# qkhh!KnQ H eꄀFF ~H}b6ǝKH,.%|NXHF[zElVBcEDsw$?̅Ϋ1DžPaG/oCҘgqʌ< YnJ h ҈rȄ1"k5ǔguHT9U,"wOsѲ,"dsM"*:HVJ7t1A1 吚K,g 縉a2bZ8$x̃;u :il #/}RP0A$3b%],s&]}"= U˜9c$c0]=a9T-t[% {VwontB;ev' (373[ڑ)0eۓKOH͌]s33pDoyq6ympA.؈P(Edl=D4t͕jKZr)$&{*iޛ D/Oy9mnϜ=6,cg,JEda9 o7#n?W:kp̹-owq9gri3"jqӫ}z.3!LEqMbW,vhe_b~-a(,s٩}ϒ3i,}ݓR9W_B4\)cT9 %se,vfL+KnApUSj sF]U@Y]ְl[d;%QQ<ai١TѰP[eXmyE1)A=6H.&W0',0}HDuy*kc|2xW& s֕=v9Z.ݑvu/XkXG敿Ń,41qSO4w{ٻhN/r,GְGͅjK,l9'̱YYhFD&3w~ \r],2Y#y;S|lR_whvan,bAyv{x| 2&{Y޾dVeX!nCu,su۫= !_p}\B@H*ps%-zb<bGv2N~^u'ޏw`gsk-]6:ڂ'>ӠL.Sv*:2̝h]`~ռ߃C.05>{^aG+IJвZs,SK8 ͥ[ext_HMa K꼯& 8Y,sW?m~};'=~{}rEîm޶X5v*>&j7Hq;w+LCJ](tO4,T->eKn;2{=y yDSw]&A|,.e!s}{U!Rv OT\f/"F=!_AZ`D]}]0uU:4>NYlMm;1/8jfh)J3Slal˘wn0_b˪l=8pM1 Lʂ%y3˙_BesgP~pw~™;;LvٕT^,z"UorWѰ۠C4'! u}8f߃J\k0g^;kŵp/~H~?M4,~NԼrL.<ɀάI7]Zi5aW[]e/߿""BD+B'/-_ st`Z(M, +)~o[w7緽%_o|qo=W~'?ُ~﷽%߳ٹ}K/{Y?/|㷾Ӄ[/{S擞y7{3pϸڣZF~xx˟M?#~>[W՜hx;~7>ݒcy|Ӟre.u̵ۮ7U(/n?_~ g; pQW?O=__|/^'j.8 >g8r|<Y,\t73s;M_pdz_M<{rL_vޝ?֟w3gξ>;_|r{^\t¹|';{a7|[K>i4piϡ9s3{~(aFpIqi3/Y4ﵷ|o~RRx~C?mq]c&?z {}7AIytƣOMUG4G^ۺ7 ? !%"A@@,0@~@')*;P۹Hj vwT}Tڵ,+Jy+(,/+>FϘ|^A!{/z)1N9J|&nǟ<6^: esyub649r٢ޅZ&p8CG%%2_{s M{p8Ɓo_0.].UW5m=}9O9wGN))/G͜ oo~>zt(8rhvf.(vml҅Ky0-[zk[߬/)qG `÷+ uc\ߑyϯtOnrfMml! gAÆlXnśҳ1Ϝt:[L9Ѕ:юpkϿ -Z uCCfk"  0X4  8 0|`NB y32s=7?ur2>1ݳrOrMN;B||Lnīvt^~n.ק-]΋sgWTJ}mVVNTtԈa6MՋ7mڃ7駟?v$lZ={t0k=ztzaVI%%?8v/@y2go'o~T|L1GW~\Stt[M6jXZNxw-r( 3Ek~S_Ykնu||%4>Cl>a6OU j͊ klU?Hi;Inm>(( l-^bll̪o6p> (K~*+m䐕}ٕ^zYqŪu0!S}A;(Ki|koqGᄒwz޻ngx_??nŀ!op8b/=#2"b;3;@ؘz:uy.뫯WWTTN`dddll+]8?|C*G~ْޮM6:屇澴ȼp<3;>._?޽S5cߜ9Sa~y0N+c74jvȉ>Y //wy}gĎW|RM].|+1g<ک?S4w\6{У7ߤd};ȴ{q\ Ot:wn١cWw)_rnt\vȟw2%iBOh4Hސ W %3z!Ta{1! ^@ 8DIPi &[GBLU{kФwT i@n\ЇI+0v0 `N^|wu NZFuLm?wI1W_>;'DEGww{ &?6a w54? '+/?נQů.`yyGQ_|LVX^]x#7yVmRJ gx侖SJ/еw[,]zu>szxVdvϜ7mܔ'EJ{_U|uׁLzŅ#o/y/-n4`Ƕ2ګۮm;V1O>?ߨtկO<.8_@~}? iS_BWoI@9(a ׈PX  Z$")7 ^GzmDph9͚&<|][ԻYB ~tS9]Y[jN/4a݆{򱣙YNK t/r9$r& 1׫ r|orqdtnpظxI&=|QqIx?:3-_)} o,{g)d:]ˆhzFa xh 4q%< gjo-}ٯ^i{ڟʏk~" NL9i߶0b;vc0q'6ݤ.e%%% {;tL}z3O_wƮZqdz_x|&G 1ԉ,Uݔ#~Z%߻ygz냥?ظɣ6 IOAB)aD^*ٷ PP ( "B 58$TXFULb(1<=2"1~esbc^^ ?G^1&Ι9L{X8~l|7ѓgSfvpK?9W? 1Ͼm}mG,ݹkC6-Ktx{N_|/_,u\izo#7%f֓;F=46++qwsybm{￷e3dI`I?fǶ:8&yqzYn1Rm;1yo_ 4Gg?t蘪)UjGNTvOe1+E0B5^X$,D @) ,"$ w"4 N0IDxfV-gyCs5}{ɋ=W缿dKc-zift:/7@ΉSe啑QNs̨!\AG6U$ΏCgfqN)VLЧ[jќ&kh-[w*ʅ18EjҢ$**U_ `_n2y[36O=5}\umJJ.FGEl1=} _{_0{//_ã%9/,Zq}hfzzƫ g͈>|֭N:҉;3gW_3}z"e|>˵H~ޑ)) ^|esOwyז=i,{MEF5^ &>&PmI7vJi2`&-:߿|*gG6jDxAÆ;vɬ\+Z|S\|Oۇu\t&E/q=ŘQCzuܯOQ pPRrqϊ b;%4A򢬬@v-JJf_#3s 7lȈ^^^nOIWYO=n㦵Xg8tp-[=7hР?8Gu=s?5͵-= cAbg׾ 28˯;ϟ-͚%̟ڱ#'<2oÏߞ8Аss;0nmǏkn87b% ^ys^yk#2y_ gA?ed:YY,:wt~2v޳已K8gǮ#l|ې{Ə-߾i i fr <,~ojݮ̀!dsS޷yZ/ WsZW #$+_Hu#^-ifyE6񀗴~m)0$OuS5 l qØ3.B!Μ)$#*-;CiTu\[e6y( {݆-|z1_I4hG;͠>9VUO*e ;u㚟"o}Y>s ֪]ʰQù4-ۥ 5Y nRR@Wohtۤ~ovo7NQ\ VS݌AdHihZ T `60;^\@D e`< m6j3qSO6 ?TveF W%Ce,A]j"*=40UufHG ϴY7z@!kocAˠASzhR5 avD hdkjQ "D$)J  aQ5W5 4H!*%[f 1 œ!qO P5 Œb :#cu32D纆WQIjiA)R ɉҿS-\Tc^P/, V Z D=<;GiJ%1z0;3Q4j Tб&iQ55 Jn4Ymr]qy\TƨCL&Bk %_{R@E'n#@ #$&B`(H2mۨ;"})44A 2g:2Be0-ːAjB)UvVH-Gs4jjE`Q/ a'7,.XDXW'- %M)Zm#!Gob""F%!x%tSPPb̡R< h9 /j6/ 5P *z  k5lհXDI4u _ѭ+lB`9J6<C 4-=!je!,4!kB-tK,+(B<`AE7W @\aV倫`!F Խv'WصyMۃ~R)\+):0N2@ X@!3hքfD2]K]r_e( n HAE*NP' /0x}+]P)4(ȍCgA6 FeFt-!hiLzLPh0 BK$!&׈" `!TV/L` vBAH!~Foh_ ! FS<AX3mq*[h˯561L1gATE^]94:6xʠA[%A  TPB,"P,m[pNv0Je hUpuҚ.YcXMDj A.YԨk0Jn54ondRX@`8Vv/7Hlհy`o{ B>ZY=D'z%o& MÈ?&j*7;y6/}Ea凯5'(拷̜4}}PϮ=Dү}df4Y̘zyiyY`X[ykLC K~#=x!@9ד 27!B SQ',% 's yeX `cHEB@SIS, VDv'l?K@$սRB@CoT?`g|ȸf M*Av\m;~+fdtKmk٭ pr&Y= ؗqHlnVuYmÏ0Oi|E&x1 '6>C8Sٌ!E;zj:l iPrnFZ:g(.r}PG*)UDr ~jQNo' 2:A"@$pw/60 BJ2&KB@H)#B ۃQ5zշkș3);=c p\SW|7) w9]7މ,'7@f2̠AMF:LΡM`fZ \f h &@T}G6 xX51X GaQRDZ6_ WZJ96xfۆWȯ|s}"ck&=3bƭ'όp8V}kK5>uejP?~~wl۫{Wt|N)#"栠 c {oݭԧ^H1,ǰq=oA5sΫ@*4rR+k$mQ[:h5A57`D_f#"J=LK$'$BQ OO X `6:( _Iv}-~{ƭc&LE/h:1бuߟzܘQNK,zgk4٩eR"oӍQ"rt#S;zWNpݓΜ/Ah+fB(>P.Ч;޵ >PWr)>0jh =ѯzo?5> uנ\ .IxD c\`V B 7PQ*JD 3hgX/:v_I3Kf_`Cy$Cg Ns};.yYe?ǘ;wҸawk65kdws U+>>xBQyyŷk>$%9`2jx Њ$T!pT3#H}j F`nqPLsZ9uN0FA|nJ@ qDj@a@M½wnܸ!V)-"+8:Ji/eP\=궡#n{_Wʹ^ǩKͨ\è5 wul_.6jWPxH檯5ip۵Jiq5W7KKpl߱>?#䗡r f1pgDM1BIUA̧8PΕACpCa4X2DCuJþR  &shW?+Y_/e`AC%8:Rg?;܊C@Sk!p kf@2 2$[JF΂ '0b$k4/_ l]f4 Cq D x0 )$ L(GM@aH K^ Be{G(,:3j]~QQ9VK+Z&q2 6nYBE݆-72FFDT m)3+V دO!%Gcj9f?;uw޿ckt}5_.߿c/)D;DW3KGu1d V&ikDHWCj}(a-|d/4qA u @xs[ 07  HeM$IA$B K5,D Bh94ڴSq\O?1??Sx0}w w8r$@½w ޱ鋟0h@ Y/-iP? "q?<%wffɯx}澴ؗqH]nّ`iv<]͝3ީ-xb|jib!#2G74v] +u uqCb(@(V7!y 1JPRG@Ͼt޽|/Sv+5 mڴo4jp=[꛵iLI5@DBQ1i4a㦭ЅCLNڛq@9s">_6r͞D(;#%QYBGO>[=궡^asqftQO =JRITk(Md^ ĺ A n Bm"JX$HH P0@` F% Zr!DF J0Gm8w'Y0;G1 $OX{̟۵im^~-W-r3>R5kYӄCpSum;~ս~iəs۷N4w>=̜.w:u+({O>[=aV5@# ۍ$h7u2shlMMei+OB9$h0(B >4<P+(%`Ր. nlV ! )MYul5s{]8]~a9F64p j. 4&a~z%XF_鉏[0 IDAT,1H kn( 4 qBh@(5J(,6+ PAT "K!Z!i7O\R`Unx}Ց`2aݽLЧ[e6n|M-k,MP|AJM^spjh""Eh2]0 4N.}dCܟ>P7R:UOOCdXS35`U~Xt.nONuaIX$X%TՄ7a<׏cd,YhЎL_5\C 1Jg!@C"Ce AwNѤA dToz6 qЀ!hЧiz0` {8Hh$/l"(GɻP-2F}!GSPfh¹ݴQ @(# HP*@a;SP4gfg"EPB}kPU0A3%0e˻q vE\t$n >NJ\+QFm fdAfv0 BT00/ [w (Q&%FdP0Rq 7 r әf `btD"4ht+nag"$ b+,WX@@XENPH /@EJ$0 IL_" *"D0V~ Y3"Sl]!o|o`:h4ʠb JߚH@DM=xc 9ൃA,, X5 :Q] RDdAY%("c#I @/$d dzJSD'6!1ECHZ i`ҩ!|<IF:&#4ke љ<׌.@- t Ps>=2's]5`aXHxHѫ䫻DH^+$H7|V1fF G*m+J@Dh6:R_r 1F4dAčO~YV͸kYyA.AkwfxM ׂk">fP1ƂECr@  "$B@)j0'- J^945^G 3p䱄 @v 0.pL9v}vY!E 1H@ ӧTPx ,vPϳC` V"ur,e"%J 1")(РiYd 4@7l/4 vg \? ,Ҙ@& Z ]1brFFV$~/`a!T[@ADx-@U:k-"<G!%  Cy= Po$0fA,pX`˄mwyO}>^$o ,@Du .kYQZ"Jny֛'>}pݻS=ի͝o۞ѨalRR s:3'S>Α7?9k)Mޛqa?J(oXnd^ '9rҷ?/,P'*OԔkץe\MztK[~{!ztKPH4uYf5 ۰r-ov=1p ,p5(51>cvTAT&f\ "QQ"zq\ e`"  0H" PJ8pV(ęyQ۠T")sWh孶R1B栙izhѣouUU9š7o#׏S' II{tK3:yOpLQfu|I^{q;6'[/޸`6/>?w蛖5Ohпoi-'fsыym(a}7}7mimd巛C狕zu۴NھsҥVIMǏ'=Nnؼ7*-p u UlݾOhJlyժ3dWNQQ ))7JIǫr:]n-\k $#hP $4` Pgt:4Zr* yDRtc(@10/DzVN=6>Be/w#a 2@)$A6$ `kk/V.ר4А=}O Kh҈G=]xLѺە_7%}7C5DGH߹^:׶Nڱsͯ&tޙuD98aVvMKmsSQ;T ^{A^F rް#hX!ُYnz֮,Y1;/9zEbWj!USXxn߁l_ZW鬺eH͛wf߯sW|+/Mc@Jrγ`?N1c! G;œeJ ӭu>Z<3s^9IBGj'?PR Ux$vGĂسDT8A Z^"$b`zЩ+-L~BBJ"@{@, Jsj@b h!Э[zzvڱs/ҎrDJr<15אr\,!NdtTdAdAXwU5HLCZniNxN~4ѾMٜZRbmR Yl+ڸ`vZ#o6k);;tpVIMd<*gt~_߷?Mգ^?H߹76aO=Y8!g] n=daii3.zҷٽȳO?\r+̕9,;+O᠕Q`̯COB|#BC'uF kF ]aX؋`epX!0AA{W{wM%̐P-%H^"dfojd`X Wիۼy& 5lo((<[N#.],B/ Ξ-7K w+Yn;WI{_wHlֱM@@گ"&jhhԴKZwu}Qg3g@7+(hd[- &箮p`νkק4jX@fy6o|oY[cmms-n~&?wGAOW|W^Zˡ0j9 fmphm8H}^>҇; D fz "Eax!`6tPXJLB]aPH(h. ^@x? PwM7$50& %IB/PO°~W|MBF @νGd}1)IM [7%nwuni͛5iެnkڤ~6EЁLKmvWŤOW>HHkmZ'wrSf<Gаf-]Ff-UȚ g->k /0}֒ @Y>]ĖڴN.+g--9'_sPu-s5~ݵ;'JNn>*g xClStegfL|KM5u: 姶"#귆MЪs@ʯJ`A(ՑH 50JJ,q@(H Cp>*QQe I Y@#@mAZwlzd6FIdLU}fmҪ!˾| @ݺ׶NfAo9x87pV-#\: uFmb:nP.bVw-\`sސֿo}`ʭyE0!(S89rН#qUahѷ]wg-ؾP~=OזV8YN{]j:7>)j\Yy ^zS.2Zq ƌM|-֊kFA^TyOW(;J4 B@!܎b2.:#@ vA,ÂH t={=pA&bC.7 nǤ@&|<[  :O~kYs>|$m]/*XPXHs#m׾c{ A9wQL'3dVN^N0Q/rcfΝh{m}y.>)czCzOMk[ۺnMEby=+--ٲmwQlZ-rĉ*,wG:wy)GfiJ Ecf|v/V#Ah *=:Mh >OaD̟Ѽ7 y"hPfB<Ȫ`@0X`EpYBuPWbp U6 6MeH8GiUue H :,6n NʕkƍyX#cLzG =%5/0+f-}9*|/aa}(*rFu\*^oyj{rG]{רCȱnV*u?o}c{v`o8ga67pG~3͈eo2}Ž}zt@Yy]eeʹ/+t~7ゥo {3ulif>̩ѧgGmiY;&v2G޾w.nw6lR,`4d}wp P{ҧ1@q0aBB 63D 2 Vn/Qώ~ 8]f)980G)b!V]uh/,UMS0Ta W]ݨ짟--phOLf wNu@JR?mޱgﱱwݒֱO I鳖*^Zů,TJPrACe_+ݬFiF vh_KK׮uCZ%56ac۴N*(8zCg[V^q͛5ٴwJ}'@iYui6[ABN&q-;;ltۘ1'Z \yuimiHz#&#AsZBai1sA0 ,3yjΔڑk8qI9:.q@CdvhxlΧ)4fS:rLd 4ӯbjS^\hC@B2R_@/oLSn+ee@#`H!A7׌'Z ^q%jj9 /{;PB{\#pgR[4Y7OCHӧ5d(_Iٽ0Kl52Z5(>YHd"3KLgZSi_]̛p gR\ynhf`@S +1,`IL.gLy+`X`j8ޱp`(.G"{Nܭi )T:75iAxv(t/4mNZOdH{ k5;ҟ\/.f#mv=* SU- @Ie3 s=Quޅ<[.?J (U/<mЩ "NФ!i 2B@Wr="' ^>yhג[CCHz*А75Drsk7O4ԙuqCCxBδ,XM&=k($r#/ \ AQ(:F^:rQ jWv$sƣ?fYYւ![DBe뾠OʘE#[ȒgͪzNlJ_C>m v>l_Cwf0*IZs(@QS%LfyY*:ž2}nbH.Gcnoo\ܣ8`? mX;>ǝjvo_L|跋_4Xc2D7zDXB8iKZ"i#E%x!$dH鄆hZh "^j>ǡuhUGqЀW+@ U)h BfŜv*  v1j2(DŽJӬcDG+ۈiJF|vҸhN)ҾTEDȲ$rH4(|(s$ oD,8bEH`Y d/i+- V6irkW. UTfP4VB3rdY;9TAsW%qƍ,Ve2&ioTWbǔI\?¥j*\`/`־oO9A 1upTtfzLe޽ )IyZCrf&ZCt-"?|t2iu%XiI]Vf R`H4KNf-8i .hAC2 hZ#M$ k!- lc,g0eKJvFW I/ۣE̙/HiZ0(2B0x7X:sq'_i Cs"hZ4(⛚}@D MYǺɒ?2a{c͢FߢA-_ڌl[m&Q.Tю@.(jL4em`ewEYFWphQԒښ:-qLm*^ɯe: M?13_}eom۞144 ,YvѕW^bfϞeK㠤k]mǎ Ƌ\xI{5pe}3'yvw\ kn_ʍ?Yǟ7-S * y٥eOm{fp(tB!o-Szg& ][_{Vn+]xA^v7.{#IWX̛OIjirӒ@<~ZC&ݙZC&Z@Zp^kE&hlN6%B[B(! !4(Lm.&mf01pݘ%rp)DF(ow( lpfB {s?񑝟(Ѹ@-x S;wNRyhb;ĖrS=c_߬._{_xNi˷}kWS&7>˿*v-o\* ?|ʕI=kՏz7Ǟ;oyMK]_ _x~0ˣۿ~Gڟ=|_?zW{/n|_4V*S}[0DUf1iP\ Z5B<4D~ʫNTa9-TPAD`xOCb\i&57 ncqڿyM(DJ EJl;Չ1(3OYBwǰ%\]Y]Jڶ%è%E.݆3) v~e]4hވ˼=ʗ_{}}}grsΞ֕_%VXtr{.[b%7oW;9sf{l#?oyŽGΝ3OܵqaWwzޱ\W_`y^ks$ W\eع+y3tʞ{8BgRGjx7Z'@171h?g='7y1Y@cB(;'5&/=Ɩ.`AVE@ Jcn0 ä0/5zc\]SP.:S"7{ݜ?{Zؗ473Ϝtem{vlKVf-^|O;sߴu붾޳sm{|ח3&~a _e@wg]?w=lڱk~+z/c[l ВzMÁ hE"h4"ë 4D"2Hqw߁^zл5nYTVp[Xῼsf+vZ_u儞=8@CÞPӦN=ȿ\uW\tppmܼW]=yJD߸={Jn{n>;K_]^)U+-oVAz֮tuWL2}^91yJu^C o㸾p۪<]U73` 6o[dѕWn>w{GZWWGgG{qP/&O-[8wkj޿7Lԓ3gNڽ>{ڽ?_ 2ݑ]{N?-4@[4D Q 5PB /hESQ}Xʈ̳TIB*YcQu:-DhC.q4EH,@;Nц,a(DbE40P.j ibv <8g2bup|TPZˠǏV?zy>^/oխ+CW~ZcŊ?w͚V\VTr O;_/m H ߺ7TX;zsΙ;sKW^jPϲ.7Xzy_Ƿ>De/]y9̸x ݝW(+\7G_ek҆=^b @A.8Ih$4}UŁ1lm"T&P -j[rVAtMC-mFGZhhQ3 9UiJ<.TcvT8ڞ)i PL8 692TT"oK~?DFG\U;" 4K #TU .HIlC 18D8y1tclG}-.bȁF#AQ%!xӕW,Y\'j~{z߲͘9k?7|044=ndTToq ):CW{+^-|dl,|Bo>*4G`_Ə +|@bqoSy}3/?o_'F/Fww_۶c/+RyR wF^,W*/6#dB)2D #S҄!ZäA%4xm E zC#ㆆz yxɨ@ZɋmnQF^ywxc8exPWq 5qs 4ӑ(m"-hC &ssF-СƷtt._h<&{rP8F7\_n&(i(dZnC![ku֤" ZM^_Ml>L,bL C ZCgeǖ ҡ)6} @!FFT8"& 9&DBJZRKe&邋)0\"J FVBn 4c'?܇IQ qMZ>X_aQZd%V E8K  I~ѡEhG?_@$$ಡc[#pT {vLp5JHG[ e a%nUZڭ 8YZj-R(ݟ,$bOSG4$DMw&jSZMrc#3hC"o^`h5Pɪ'CD4;N> X2ecZ+ p@iC9LQ &XrBw/pLp )E8rm1pP=k*ա1_q")9:7F2&)^6f{Z= &F3fBCS2+ȑ*5۔᷻zK# Haڔꔲ ܊9`kt3f;GdT !eN% ۸A')Dh5F~tTIZTG!ƩI sq5&B?hc!N҂"|j:'4N# &<Y$2aDR;UZ!lt !c]3kb(;T@8-_DPr"ڕim"(T3?c%%׌2O&ᐭ2dG!RPuR̅BVAɕIjpS4iDhh n0,\t03eЖyCX1cp S:(!J4|/+ps:0p h/Cj|Aс-"־b CB`HN?]ӤEfҿС%(xq +5B];,[e˧<&pYRhۍk=U9+,-~jY5_M\Rga8bk-*y(KթJwK&G9'M7jC(*q'jzו(tj159 ]0B)Tw5(}Ȝ#>II儙-sϞn*i 1@vjuzbh )m5ZN҈<2%KXԫ3?peh ohNQFH#ap,W̲9fN('DQ (kY kBA+ QEtDhh} wX1!qjhF0{Q8h1!aR?YhHԡ֠!B@:4Z 9識-@iK.8#ߵj\\p%σ8BSHԺj3N9̂ xb:h1HoSS1$!x'2e<^pURu14bX=4@}C 4d5=> ;Z_I {;&N1z ݣRT mZjyCI1Su8A.Զ-yI֮B!8n GhwHzkt7")s:)oPHjz/Ph q?@0F'Jӂ'2oOjS 6E & "AAHH@" o{NhS˕܎#Uv~vP$M:tM) l]XvTq\_]A!*r_|?t_}֬~럀ڲ߅rrם_Ξs%;{%Kuww>m/ }cݸi]glW{%]=f//|~W?}gs+=@,iNmh9P$k#4_Y2$8hdb)ziOzuhYԥ˙ ꢑ%x5Y2EG ΤhyQcJ9fAj35BjST1}g| 1P9tQE9ЎQe 6Ytҷ*O8'kA>d7m'KܰO#,v vڷs۞mŋ.Vfkg//gݷwy7͏.zXpIU+N={֌|f͚L209R~+ظyǡCC ǎ;q3Ι=84<80-۾?΃OcȀvp$KC }262UOT{]?nBDBY蓝ieD_ *Vt;擃Gq4#FRvQtݜ--6#_taB2 r"9LM ohQwM ??O_+\%}v.;oγXsÊ_Lk/꥟=ww<޽oɒESwɧ9Vϟlٲ-oW}?ްyg8x>/?w)=6?ERxiBC,-( FiNֵ'A!ȤqbĨ"4ԋJi pIdH$LMx b36;OU-]S.jB+ӗ:gvV[U eal"PVTQ?OH/6K;[w(|T*GhzӝTϿ<̮<;ww_N:Ryӆ'rӻ =|w .魗xeW^\p~޻5yGBG".4jn^/@h0i*(9L;zNX+D =oξ}:2kh@'~C?;&0eu~leSNں;?^ǚ%K{Na;gߺjŭGFǀիpݺꆿnqYgG{Wgq`p48[umNŠBTS!LB"4nS큊FrVM:v-]KU = /eԥ葿-S`^Sm$Ոn;Ǵm͞ ĮRvJm RD#Kw= &F+(!rBC]A I_~BIoon 0446 myez&c=ٕ ]_b+݇/ .h {챍IPصtɢY- nڼXŋkZx&OC#9::VT:]x^DRˮ\{^ qy #޻tIgϚ̘qh#^Y- 7N2q/Yp_oMw`7aEζtݝŋ]aٻvtrRuN 4CCTNbꓡ!Vh*Ø?HMN"u dvoNE?svhǁ8\?6 H(uiqL8Q(ϿP7t ~ibXBU҂69Eu dtբ9r[_vnɚwn_~;-SNpGrʿg=Y k&X|AaǶa볷\lܰeɒE۶?CV.[q>goܣ6?>pʫ֛gKϘ:iΜJephxE?r 9G6\{͒=lc_;vJH焆NNRB3jD&Y,h5&\-"yKȢVx|sD#Ŏ:zh{6UX:UFTۜ3|]f;tph7xV`d9dԕ3Lh`\$$Q cňF`!P)L5Q2o  :ca;0=86i+2#,L-&9* S'Q0{ ӟ8`o7z9;zVAkAa a9,#0ٿ7,k a AK(Wx$rEpnX|/7 )AζW^f8 QOe1㦡osxu>1Kb2"Wkbj'&G N< @"?<9ƪed*JE1G/IM}ahe X6dB>)%+1)X۰7PҋRZ ZS[MJ!w}[4B_X7HK A\F' a&:4 >'-fSB !Q9VѶ4U˝F#c}:!ǣ g! pq\ Jdߥ8xJ0D PÈHN,)4CR4Ry\TZQN:KYH)}0.D5VM iN,u4D[66*F*9RF7 WIfuЮUrʆ}|q##ӏln㷣<U VZ?sQ290GhNzCe1'vFg$`B&:[bM^$e3 i%CCV#RǸ ̂fA-&&@HTdJP udx2i9sҜ͜Q-I`<8489~ Ϝ(%4P7\P]eJ *Cy 6ڪD855TxBƥ,4FdUƠAR&xBFZj D ;(0;zrӹnYfU;ZX9~šʴ1Z< F)U.ZՏiҁ;J\_0@ZhP@Iȣ-6n]MHPIq\M["݈hnds=!DlhHmqy"iyYVJd͎;ǤD8Aw Ui~pBRUNEG.0ϟ`ST~ _j( tf*e}8>"RNR>Ikb\C4* U`4MLy:<$4ƼEܶ",瑃U2R!ltRО͖Pq Y:O`0OL=heVߴI F۟=[$DD i>H@J@ &*wZWW2c$' Bo'h'IgҴ&Kyʭx!AhqJ qtHWk^: _h[C7P T )`RT1ta(j эYB*S]Ot;82-<1$}!b;۩@a*~'#$ s $uHP5ɕrBx1夭.-0<6Eh"iybCMn)6E Z,Ș!4͢oAT-Cvg4G٪]cHEqw J =GWϓ cǮ>Pi/-/um=kgM~)%Qkr'AhG$ IDATaL0Kn&!b$'ߚ٭^Hᴲk M)<~c^V݊ !FPS|PjAA!o9Uô+.+ܩe)LqgljܲqzL\"nNVN %Hh Eh % T8c/ܸa")'\RƷ1iRO)N1?8lh m:4d Aܢ1[ {FoY&3AL\-2\"0Š)2Um؀%BZXgb:*疥RjG(4ؚnڂ2 ӚHx_D&2OHN4;V o5d OqM#DR!垻hqNC=\I` IƎ:: Feբl`R.2 HUƌ5\}ZdjGFn̢yEZvK0t,fxm4Qt.zL0Azh+sߪD0qs˯Kkʕ[7OZzLgw"V8 K Y_)>!D24ct Z|tCCp"gŁ6:V-! (6 Tc*#R*2rZp.e4`ЁsU -$/9WF&Toj憗5wX~W,lߞnU%yny'$ֈΙq?YʕˁS'O2\gW#N b}p:иo&7/-VΆ wq'>ŗb !d^E:?KA8Y4WWF3.*'QZ9uv`jguptj1lѥEqjwei(' -.Z m?8c @r6ePW"O 4g`}vR b‹,N~~Q9gM#cO;w%[һ\lWqj%un0Aud'*$Ȅ|&WF8P'Db ;wE|}E жqTإnՎ[VaLYrb܊EAXEaJƮt3}T` Z4@ 8_LR`*L6Zf $swt̓/~:^UpБ<psݾ[u {|T*w~>V&vc65J! BZ_?b %E#( e qY&twtu<)%N2O\z`+\5n?qzŊ._k|X̿nʻ>z#=;"Ծy x H>!2HFSv4 Z.}dtzSn^zsZ5%18Jc\UYeakGvquQ? M-y.G)Q)v6|}+i:tm?-m#OXi0DgΘpmǁB!_'{pZ@Rygkw>riƓ(E`l,h^|Mc*@ZyF~!dܔ.B[QP@qiBCi#_JNSEcTI" e;'\ls]a]h*iV5!:p```i:  ʈߓmM[;:?-V-;1>n;N_:`; C$ xOHP(B11`ld9868I%14};}/{W9\UjUkUվ眡Ukۺo1c_im|u_\.?Zo^{@AO<5~7^/}图~;_!#&'48S X*v {bA@Cgݝe*ܔ[ j%GqAjڌ&jf,u:˯*]`y9bUZUaarHph~Wj+٬a,0BuivPcqx'X)魯W_/ۿ?[o棗~w|+/mCd.g?OovҚǏ~S_?zk#_gF;x)vt"Ùct:S`_hI S` W22BJ}vn̺p].C"@ znʁĐpC慗]emcw,`xJ&&*G4~&8ѷo'ʗӟCK_~3#Bqsz7~SǏ~6zG?O<O#_zO}~??'?ZG0UAhcZ,WVCdΈWNuf]0F)0Vb"[8;V2Jz9rx`,ph퍸V,`ϲ<1K@%xeX&Ԃ@0WiOkc$w |KγwS#?__+nNǾ/~K?~5K>G?~kwNA0y",2*r`B-@h8h06XlS 8i.P%chA`@if _s|#-_]/s\Ei.*",:6ڄ5I+P`@0Xfy7~7ʏ>yן _${γ~٣?˿?۾G>ɓR_|wO1>]_W N;~n_dαؘ.ex4# E}a 4Lfr+5oI H K.X[9B6ĒҬzj5I:.?5&*< T>1f@NxLuk{ͦްVs{O7?$m|`CGuY`SNq۳hls~?@o{z@'?jeHYlV-gcVF2#\^C%3!xkt0:(=bFa&\kFTvXu๲:q6CcsxHeTai$j\fA%a28$shDc)e?ᗿ~V,d‚IvM.Q]WX̑*)Ckߟ/*2\<3ҜLb3 s07fHy#u=Wh 1|Tx&:G &^D]i }ݸcư]#pM@VаUnvXoS-^{92$®Suez~|I WE\`B@TEd.KԵ;r}De91?鼧F {-kg4tFa*l^[Tk"&Z7Jav]oСi6w;t X?={'~$(GcLrUՏL,SG$߻0_BR~E( efx2L0!N\HlpQE]whBoԠyTQ}U9R76&8m:=;©QgSJOOo_xƳ]WYǤ| ym!= "x(U Vea+AC 6qpfa=`S í]fjө5ЀGB(aCx4``/LSLt</O;s4:ZYr `1yYvzG˕RI_ d ];!w *jI־S me*] 7 7 ǚ0Jq:9!8l-KAJY/?#??g_KbBe!,,`W3Kry󌜑 9R3)/_*(˧"p!$2 R諿zL CLx9/& 4` :a44}ŧ;Ӊj4G%3ۇ?Ocl`^X)\Ӟ!Es$a,qd݂?oB?Xx;BEhz6tܚf4q@s|rjS*(`g #,?pCӕ{`3a)DEvKS^<g^|3,͗P22k5I&L ɘ#u˯-#K$rH>3e#8 uX,,D8UR0>`3i&Å~L{;`kبUO'2c~߄*qsKЀ.<@:EvG{Ō#WIJDϫGңܝ94ʤrD3=W8!7%da>`K}"Ýv SlWma037Q 9^WV:l:Y/~o>u-ɂjLAF7(+yeCBnvX@MSA+/2|_lcD)'ZN64 sE[~h}71|o S Ǩ';B L檯_?ۿ`_ߌD(FC`tҘd~IwњKbA@MQ5%Nku*6X<#jMuQF 45"6s@v: T@èN\[9L^eW=Gs>l~%(#YT 2r,ϑ/{%Ao\Y1ȷذp5b0T };Da]v:4it65LT`u̡j5īoȿ0> T2T ʘg|^иBk&)#|S-v;Vnp P7Dn5sCx: a5m ,` jӌ/o ܐsP$HDb~Y7hb7enhUn7 : 0Zp8Xll'cU?sCxm2CJA;cobdgTs#g8~]sA8Qbܖ"eFS r* ) N!эN\&[ ,`K1o;ڮ{"{jȰ-lJ{/02HXCùY==5)+Gz1эnl.CC6zJD ԥKk^bkX.//}8zAЄŁ5 vcu9h2`1(SCk%QXӯKdQnr2GBos rj;Sroj~$LfQ7NgW%){ #8:u^0 ;_ I@18,wR*CL0rIYȧo{j)+2, t 7wv4i\q-NL9D _5TkH$bh$ >r#^'P2j=b00V#.v{"h Aiabii}S["rq4Ex e-E 2(!/.){3 '3<S-(W,HMBC1T<w8])44!y/_{,;?֯b=Z $*$8N \@ r!r\+K(Z6"ٸl fglǦ kڝ#Fٮn=QxaҺ6#Kp8NcA_rc<9`Q-=gR) enpgtay-P@K"g:7Z}8M7u֎AZ3(c :L_0_0_(?B܂&u{1S4{a ca4onoЀ:aV{]kS@u:p?")#(rlHD(Rw4m!.jlZ:5\T{@"0w^t8Vv#A+V"T3 z} +7aP("%'斊3 $c蓮F_ȒmYv4fk^k|kmD03-OP]YCβE*CDc>_}`bga- #:3ځ$()%xr;=`9!Kh2S bЈp 5{U28b0ǵ< c{1𫴓E-#bk=B)_ݦ\S3C-M.O,IeZq=iM IDAT́rd)ut0휍cKzOݹ*q nu6@arl5;ha#v!6*( M Glg3As*f[阙=c0jSGj`T|}Q/Tk-hw^Ou_CCǘ;[8UXD1 ނ-EI Re+ $BbQrfs#sH4%xM;羌W5|]źl{._IՏ=U(F mj&| m !+StCvǾJka{bb% )9P6_;`R2Du͊]/9qL-a77[Qe'pf SF7N~MǹjG;AQ#Pp&dP&dA{@1Hhlc֍b#])p[Dp0ܰ*a>j nCc|p="4K+P.pIA%,9"G$c yE'ԒwԤIfoA'tW9jOME[[B+X#ýS:p`ACTr,hKBNd3 ɐ+`)R1W =PR^Y7rp ׊q~nwtpp^a9r @Z(kmB, #Iz0ʘ"RT^/=ib;a}W^/$4!8L,}QtP>N*~" Pe_;%:lvC`sd-zdI%ʶ!> U?ybxlgaF^iEs Kv*?KWI5FR !)ɡ,4 H^rRLF<G;6#!A 7OM v˓_tstv'x0- `ާ7SҬĀ3hiSsX>& GJ zwh ]u8 t 8\GO#th St[X $Y= @ԕ٠l9c;/JM:7Ji긎lWttXs Z0 2#k  ˂GL2z=P`CJYprlq\G#:=@Ц[?yІwZSO%k,1μMd#a$elME9(SZ6Pn`'2\ohLmˁwaS6=;Ujzs)O&AR%9唂8(BF;K8Ǵ1l;K$tnd9&U?A(g{ [?; P~\rA5HWN̕eCJ&Kl#^f[OV%zK|TA4ejG,8FOW3j҅ $7wWnr,G 1E53E˕1ɴ#[wy%8υɭZOfV|B{9Ognv7Wϒtb}vS";O5"W"s$ He PBNkiɍg0Emw$jvmod/[Uzt4&i\i#TCņ ΦS}UG: `(˔ped)[$ 9.'A:LL:2)x 5llUu.u&[_id=Rۿ:^\1,~ƴ4p6NcJR$ fn>k"A9.&JrwwoA2kٚ d4Eŕ^A[G7ށnPձ3 ϧV;=ã? t_k1r69,3,Bja!<3, eHD46Rɔ'Wo,M~,ަ|E7C=CZUDOroVRe1=bId2K0(g 'ܐ %~|aPdO4U]L"kvw]N' nnTp8@gDkgS$ o,ui>4PVBP*I5f9`6y6֦@4D4Mѭ,mi#<`f~)/ B7(bzc:9H4!X jz`ȑ&ie,Q!l՗ڜvkŎ֍V_nu H:N8Sn):om})5 3F;= m*Ifr%%79^G4ʟ|v{?B fx!H)\7CCpN!ɏ jZp""VN)A,4G6qz;Z8$(5Io`ov9n 8pCYwg)Z,6#%n NIɈ`r&jz.CY]1`U15\!Uj om8m*h8>Խg#tB:bP+$Fp9! Ȋ ́E0XmHV\nZe{ie7 u)p'`d.yHrnIv5񰔰OS#G.!5nnͦ.I+i^8pP&w8Ltq*0x@ * ХOL2 p37?%;=Z?띦6=9ljxs5~.t8qs<%X3\d%Ü y19!Y:Nkm)gC&6%w3p^tPS#3=isjb2" E0ەB-H5TYHTh C++b³|||;OGЭ- &3⤅#ht5h$D)f50EgQ(P__(xz<4R/sn143ÄJ|8SEbE$V'Tb$ZrI; ,NH\ww&Y)Pz޹RpV)}dNv> :Kp(Ԉ~#sLa_)4mDg NytIdd1< c/_ N;f<FC0ݹt.tPx;!kͲQN:$@82fQ'N:NpT&-.߹W֜RevtO\ksjr6T-sa1+CN)DDܶ)z#SE4ib[zF>G,}ǁŝ ;t":fvylWkÚm и6rqX (9d j+a_uлt;lMН( 3VA) `yUDpDdvd(id+2; b=AF) %^SYbrMefEȍUwm*G.)PX#86`+ex#Ft MxѰ$ &`Kqq_' #}ϭM58t- kŗp%/ѡX"6KxM[ |[Hb%:,Ep̥$(H1{/hς#xVwx7 'v ojc:G޸.{)?.Ǘx8+Р2%" Y,^@6=Q2nb8(aL9}M܃p67/8.BP20H`AțF% LU"RI)e qo29I z&v~=Xg-s!t{47gi H` Jp#$iȂ Ak ug)Ew[C*':v? ' &MzD;;W0ӭlR6lN rg*uuٯUY 32m̀ 4f=/rZkOϕ_ZsYDT!3<^.= ,$>{bNX.x[9× @~9_!}E3fݑt-;{c ;K"dMr @fxQGVU,wl5{hF)=$S؄sv1uݙvj3bxA3ưW۲8-:r@9*?"uHPFUymgϑ o~/=X?/B|xWK,!w8KJa/QɗI/-uC6H딮_-UeCN3:{ b3***S̺!9Rkx4*ŧ|E9r^ūzz=ji\`BHD92%3f| 8’<Q;rqn>:T5^ ^/`plXTlIDAT28(`af*FI. +\XC՞Z&TBo1^̛~*o}3F"fDž1Ķ=ZgCźJtbV `2XA0KlpH!Yy9ga̗`zIF T&r{& JDC̪ g./8{//BfaǖZ_s=& ιyElE@gB[rkZ%T)ECE JY|^"* ̑jXS3h >);QNxZ w\$<@$J<[QEWz#HTe^vQ̢̍" Z&(`kr53','}V QuACঅ2&`AP'fXρ =pVɽsS{ܾ9m#Ka |McFN2g. -w< ]7Q\#2HNIrC6d3g䠜$S ?2.5\ 433~ln$mҙ%Vr1aRi%n0BHk:ֳ\6zjrg+Hoyjh_Ph@ag 뿥<rS Mw)]Umuk06i`IL-[U]ll4t_BR{.[N_-4@f|΋9s"~@IiOfo``2;B7t+z;B, OIڬ y9}MUw-vEZMj`$MxRÂ7TԤh(b,0iTkeh\[##qaX#X9bk50"f r\[giژ;Zބ ]l}!C۟M.@|٣k"NNa=[6! dʘW#jR~JfA h2j ZryPq*X2JY{XzV_ +61 ![ͦ6W'ȁLM_|ۗD,9<Kn%,}3:=i5#nNi-2lV!bzM7<0p&Y}5}vݲ2^[:02͋^E| sY$)\KMIL]/Z{n?{d'lv)ƈ '0u'58UF3Z9ryz$d'>jDD73'-sE2hfeh]T#l/4 3( 1OF27EPTC r$ xVR1sɋ"WGZ7ׇ. -ET9lηEk.R@j}|~Z}Y3 '$t!㥛#8Ծp#^]^π|IώJ%epBt#TE!wӥLPAd(hfr!: 1TnU&B0SR@ 46Ų.;P(( tcd4&c#3 1ӯ)D%P`WYȯBURj/VJ@cz~H#kPzyƻx. (n 2 `:VrN[XyskZ~K( k֣jK AS7[(uƂ~h[S1zpMPaL =ؘM߇*5#װd4c ]2 phJ]yjf7 I";lc7v?Sb13#2klU!@/@o@$Z(X/0AuӷfMЀnW3ksjmYMscPnn\]ʬ_6Eu @,- f=iث(+ "+/q+8UQIeLY۩*Uvn2x_h wmg&nue,eZM`k3|*f7.疮5eEzfwyZlxǘw͕D;jeיV=-ib#wkTEV .55Hi KHbD*u\r4-sKiltALD,ˢP@cҚCm)4B-v+d TE n~rWNK!{=*~#l8H. um KpkC3(2744Ώ`'ް۷vhzR (U0~s0 & f9Hw W} ,N +2a]]o6YJ&h}q}(P4MÒ#Y,<]jL1ux ; Erf eB>[ 9Yb[n=amHuusU r?CÓk] zhsa<>蛋NX]j?7ͫB-NgyebiUJXv?)$iߟ|um qGԒs+Ake[9[>v.{1_ "C&Tko+[3FL`0H+2|1 Y <KoN0(8acIMo_3|RA0_򐧁P4֐K&c`B VO3>}A+s|A^@op^5SQB`9fp wuKywp9t8=3TYӼDȜ&ED(,^$EBF"JdfbRB@BΓY!em 'XVkL/0bpI΢(K1 b_߈ Di;@XH tWp,Y795NVca 7b-?tC- t"x/cРr/v. 2")C?Bv/jG/4"=n]l^G PGjݗ;䞍\UWAZu"z_9}}XPAՃG !^>`.LT h 4j@5jzDA w#i H(2j#+kY5Y1o\o:w({VGY)DG9"Έ~e?AUZ'bsy/b 1F iP^i!Q4B>h:q+:ܥ [U]Pڐd﷣;=NU`_նIENDB`ukui-notebook/data/ukui-notebook/zh_CN/image/1.png0000644000175000017500000065101214201136534020732 0ustar fengfengPNG  IHDR{XLsBITO pHYs+ IDATxkevcGWN>~\'("$P)q((SK$$X $7N @Ce 1a~Tk10U]Uէk9k暏;J'>WW\+\Im?5K ?Hi/Tx5_b2?U 6JrT9aM04L?į?"wЊ`|zv`qjê\0P@a]v i(k~cYiY~ާy-_5M;`&x #s.;H`z$Sa^d=2TjR)Q`@faN_6P[̲ta1d -;/P3dJ@RԳ*P$D鄨PGTSVK,zɊT13*LQLb x*˭aօ$i"Li`1z,Y(J$0*dYE'  0wrLo, PD8iJAE([ą EkЕgMhQ1J^O^zK\3]tݘQWɘDue䄔&V[ b* \2V'4<+YɇC>ylP@8%le UB#Qsu Irqx-2aTiI0v xįqIPD:%1AG_1ѵ;$ +F2р*Xb`Wؾyv nҟ^h^t>W̳3=n  y):̗?O$j p2 /ܜqdOy1#GQc/ru±/H$]PvVm |߀QUѵܕu"uҽ/_לE{ދ޿0/>%ܼ(C"g>r=o礼?1cI)r}y&6#MebMSD[5, _PQ̦Q I[xBqRH*2q# 89r"tr!UD ;TQa nkMMh Wq|f*&s3K}7N^TQVrH"Qb$P ˠvi#N (Տ( pNmYH $JF%%Ck/BIKdmek]=׎GoKEE>n|,D*:LH RNEN O0)-MyiY{pb$%Jy{^;5׈ ts =dwۖ՗%¢}Xwݻwn_|zȯp֒N&$m*x`kH3 L :#JZErM=d҅r"˖}iYٞ]K"R>ջlgVJ59<._4bty*k\TQun}ȏ~GoM`I]RD1zj͵5ˁEK ;wF\e͟?G֔B,~u޽ua~v +.,v8؛흇lFjw, .0;@g*ٸa>^q1(rtRZY @b*m8j((6-Nfl‘JlX818nd۝4E7dBBDX0i "!dcT!GLIf= SQ.m~M%<݊haj(TU$zB}fiY #jIkJ1lcH9>r ̨'&zF\ F|b#mP@`3޵a/ h^ |SS3K<.PIW#O]4v*i'ͅe>7~mSQ;Cο7~黟_>b2zh*X]:f5sN!@=- jTNww3ԟylnT[.nqtw_5Vo<u`ec{{] w;xxDV7d90XGWji*0S_}bw8l :p }IQt;%53֢a; ]VeCnQ}۔h^;G)33S!R$ #2QۻT+O퐆P㮊~n2:k 9]0c"T=jc I '=SDSEr"< lP۳mr4 FP[ kj&oTXN5nn3JpU9& NiYx^| Jێfѥ-҉8quK uDX.Pz%3LtE+]]B?B:DgXҨ<$u szL% 92Ci oND4ӪO;T}ظI:Sgfo\_E~+;X!Y霎\ȼxN|Cn& Gk,Ű#ZM}_i1Y+˃2[\FctAw9d7:y"f8zȦU|S󁛗adۮr uvD%ňwaڹ+HnoY`Av=jj*(v0U ۳{kݮu2OevwWƖ_᫼u󗱿цkK}z~wVCxc"'uDKc0VJ GF)z`m'e4%0InC^weϺɲ;;f`wYvx[㸱(N6 3:Nh{F(gB(uj5`!4& <634Yv]Dy[Z$^!w-w:VDEere3 6y\d(5 O:32t9T-vHۦ/(Ȇd$dq$m"}24lidcŒ"b.`f7έݰ7~! {ix)F'L3jک U|!P#6L倛yup[𗗮Dl1S]\+1U*ʳ҅TA\uNO6H~ii9JujXWfAMp<;P(7ȟ7*;w8.Xإ;E4!b`5\XˁTgZ-ƾˌ4H٣}?qw-8(vyp{&71o׾Jx8p,]| Do{GlɜUyo/P(6m3ļse)brŏP0dTކw9 > p/ǰlXm LgҹczjKv ;=BI 0P K\whǕB$Q9ʏMaY-lR\ֵ`M`fSH댒`R+dOgR2Mf`ڠ1,=j2xM466B*֔?{~v :Nu0`t0dluf9(UNROkDO -Ӿ̆Uo#o՝RW]tN22׵GqFTK ECAvJW ;x3]El <5Z+NJ͂T`/3tkۂ Ŵ4[|'#Qt=semvî߿?|cC`Fq 4&$Bkl9RFr*JZGoZc7,7SIMW7vqf9W7}n.<p<tܜW!tɒONT0$:Mo~5p'1}Td_&%YTV,7؈NeUtײTʮ֎^Xog~oࢰzP78-ߥ:CGn 8Nb׮ŷݰ<8ýCONa^_&2#6E+N񂉹M\Ĕ}SuSE:Թ=L6Gp̗F>' X΅Yǰ]w"0w\8YŽq`wYHdH'b6Q;4ND,!bHIn ФJbt13sMfKeܝgC36PYMt1XT%"LEF4ZTB#*^-6id6ʗGvM}Yn``=(XÚ{Nەn)PMNUa>iB:\ &cY1 x(HZ ]BOARkkˍ|8avB&mDI:ӪKI ,IS%yk qq?j{ll&fjYZMiFl@vPi\9,\;UgSg(r~?*?_r(~2@ 0P5k'_Hh HVZo0q%_6dzUsfZlǗ$a/,Ҟ_۔v Nhmo,Z2ɶGْ߮(O`D?0-RPN/|2 A/CL`|u#?ȧa l X07},?e{v­=7V ; ,X}נLZNt@pTaՒQ.Qcf&Ӊ,JN̕"ҰΣ]q(&Ur\0,\pO ,jJSZ2h1ctP| Gutk/i`whf)GO97Z" @ӟ84Gmf;E!6\mknmqӾ υ粄(^kƁ5VhꈞJfV)7MnٛzM=-G#]me E489[JNge57 3İ$oN,M{%e.Yn*u;±hRl̝l3N'mE#uW ܼ99vp);P2|ps nuBZoBtWwf-' {7WAE珮<ý,#;pdPrmWV8^h3e4q4Tb&k9qE40T' =Ϧhhx?} }7/e"qgd1佁7G>s?9'8ji[Ơv؜!Vxոֳqwޒ[`wccfREm2eVRF!9vՎj"=̻mp"Pq%ȍ琝;)YbfBOyVGSB(V7`3CڑFfIXc08QH#f)NpU]I9-uj $:BZP$`81y#QfaA[BA{6z%3뺯Qb ʞP[]zweo#Tg"m>F?١디2d9E,`vOfx[J>% k퀛1b}ƃo'}o)d5)I4G*dS5e@# k֋ꅂ_IUU0=i.9E\ 7els;L[.OeE:ul ;;? e]ch.>YaQRE5nاtj7VZϭ>~u/&ڰp{r.׸v{d8i5uf+u`#"A$ro;fM=56']b 5E1&7joa#)dX,xۺk-8:\L+ٲcV槎1<ԯm5 ,kɢgcpʒފNac D ӖzL4$$Fhs1JY%,N) d)gѕi 4Bd lӥ,5,F:-cTVbTՍeJGDDstgcavI9?LrTgtjQ,SȜIq\vUymliw W6r,@f;P k+ߜtVy7,W5TGruXm ב e@”Rz#iEuYٸʔl4%Z{ {{WY#ȘSXm,WdM0[{kf `c Z[5NVY]Ӡ?w9asw,imU| > m|fOeW.TcJN|W]u%NoTi5e49Gs?mmQ6D&Ja>s.67}Dz);r=s#_䚿{`A?7[MK[l>epQ(ɍz펛 n.Xv ga'bA5'؉ IDAT qM@C\ < w'=ŠWPs*!"pơ*=+1X(+uCD栬}CᛴA-JwwZ1h;A7MX9kY'EΩ驑xitiJQL{i,X#"'؋ls>U-|]"]a _b_O)qK7՘.l.,l' EFgn꒥Dc_2rj!`,qq~3?woWeaRgП:\Ij1˪Mz.Jۗ< ͽg gev{-8:K_|${kdYU(GT;6QXܭ&Ak;pI-AJg=흴X Zl45Ŵb4SKj>I6L˔V6IU;3ԕ\utŻ2Z]vخ+n5:6o9ȹ9ktheA;ŹQ8puPﴷ`QraU%Ԕ NI䲹)mH#>mLeN3[ob2K0ǮblUk9fp2jVZVj9ؘҘ1xlTMM:{cvctogN8ё +# +T[C"fxi24I`ge~ jcdSBXظkes22c,yIpL3:O[xva2-:-{w-b1sG;Fq{komIEXKz?1'=~+>[뤱2u_u/v;X~Gg٩6VdaaKd3J8UY#Y 2 aΤԘ7LCaY0鼋@2JDxf*q5jF&լZʇq#{ON]"1q*ү-hPܚiFNgs01LNE4fB9 2iȻ^wTKQ\cg[FWbcزZTv-C=rXƙnفS2B|}٣fN:oZ8Itv%bQ]+VhTch1X=x`Yn*+@ Z$ehlH;8 Y=AtdgL;-_<s$T]wanWb}֙ww:/:>>,ŷY&p3q^}&>1RVX'>ÿ`Q-$KHyxz_6ZVD8/w33 8X{%?X^a_|pw^Foo\HXmS-dMH4GJ5LScMԙμ,ZB)bUXv{pSj3ZGpT؛P0ICS9hr.PeV f'ZIcn=Ϋ{vV{*yXĚjqdU|@Iuha JZL͊X:aR-,4 dNY{GBӹ3RM,&;2̭[JŸx o[sPU28lxޚ/ѱ79ܜ07¦V yUb2Dp^y[in.ؓlIwS8gs.iZBcπ{9ed~R k[ ]l^^|ؙ4响)YZ[ivwHTȕWFօb y5L.Jjo劾+yZwo}oO5`g.e/ak-򻷨ZjL'7un'lgi-f]E&Eٌy#o6aυO mRmh3Kq}eB7yg8s"-Bmm*cP6 , k7Oi'a0\vOak4$|Luz%isY^7;0'[0SoNѢӱrvrur00]#RU(s Gpz=R dنI fF;&qS&*Af;Gah('G!봱ZKU}PD9S76nPBN@2uZ`(DB۴^IмNj'W s&y -< *,zһ !\( ##GqWN:Ӿ#LQo9ȍiyيo.vcLÕyLImژ vb'mxӿ+}tk_οuĝ@ &?'Էz fl$"l6r}O0o|ot븤5r?\Wr;!Ω3y3?2ZSٞ؏g0v~4DN=Yg_:ayWmy2Bɴwg'_{gy*e~#~sivjxQ6ϋOg{1}^^M2"?O3 V7tп֗=:stC㿋8x7Ivm|Z{s&֝jnNl78^s͇o?/}l.?G <0oK8==Y p 7,y<udsƛ3)¢έc;/|/t:Kۻ/SKm:=Q=3N7tG8v\^ï ޻//XAIT_ 9%z{'zȰa_Ʈ2 nȦ=տ\ȆlNyYdsVM<2 slLW@64Oy>c7:ËO zk.狮N5-װ>ت8Y~Au{v qe]/>v~lc7ŷ~??o~O&!S0Ϗ{^&%=yXAD0 wB6vEXl}K4E=#\5=m\eN9>d f'{N㞳ldsV'[+#3:puF;ѹ_ٜ9lI^Pw:ht_ĹJ:~A- \ą%X`m_X7^qp|w~]#+TL:7ST9\;St+%ʹ頟$Q_y_@檘fkl>E؜!. dXi8S _Nx5d g|dxut&y2Nx,y֠;y8W}4o4MUZK?hUkZ^xv!M\'\&=U['2dCG;cc= BEj:Ss&vٵ]Sr+c:0=7!@LbB63~OqλH9<Fl*tm 8L {smƋѦS_}п^Xʋ8 o$x*(|7\XVe7L2tϾr,eoo]o^G2_:4MW7?} 2eFPO@\55`/dsSEYTdz RW/s`z6yVp {]lK~)Ja{'IQOul w.p(Ȝ$I(HTbzQEAy~fDb@S$4bHB8~+j8Df#4MR |Nd#:0Q4ߩAdc_|"R:e# ߡC(IdͯIpҚƆ:^~W>,J GQ0E4ss1JReH:OX{WI6T G]jgNFUڊd7\gTڇ_O}ldz]v9~G6bܠ`l\:we>r[[dMө9ĤI&uJš_P1LW}aQŢUI(uuud2ʢߗ:m~]F9U@06T״nWARULd.؝R缌3f MU78?pu,Ж?nT*ft 6$c+rO)xFpj RRogxz-IݖIa;,D'?M$dPSO9DYkXL%;_ {4dS5Ql@cw?]nh֥uRٮcDsIY@) xQ >Y 8IB(PE6zT15 bLQrqw f` Ÿ]'vb JXyf)Iod 6 N6 mXG`bhQAo^$ll x X@ca:rv]Sy1cg+~&=oD*)3@@ (*043^fb 0߰,"^L=K4CtULܫřD϶(:f6&Tuj*?<:gw\>隚D^ &lDlT&7#3rE#ُScAl亢ș[֒OSos7A^&6ڞuNE7Z*[rM>35J@+ \jG-M5o.(Ǜ{S#+PAA> @;+(aj IMdګ~˻ Wܔ݊l9Ve+VbݘͿW=-:~䝕?.JxƟޝB|O(ʶ]n**[-^4OLNI7^) IDATtVh"٘HljAGǮV}ejfS 9;114uקR{[k޽ G# 5 Usv8oLf ;\65nk{#TC] P_[ 7Ex.guiB,1B'%bMpت6-W8qN_QPo}ѿ/gaoً !f !̚0Q(tzI$RR֯(&32Zp_y @M-y1Uߗξ.FK{lu0.عGkj i2GQؿoW7xC'YC9tɢg֮ WKC=mP]UL&k&6ҲCã%L'tMMBUAZW*h.cNL37lt4K^HJ&woki=mۍilfs:t4'tkcZOmޑZnkK$Ԇg9MLNNlI"MLMu5}g{Kijl1 >Q|~]Z?ę&DydJ7VT# @q"@$|ax ZG)i;6wkQhw~-^'ˆ7)c,0 T1-Ml֒֝kJzr uqe7 ?&1|q㒏]tM~ћk̍MpJs/}!5=݅Rn VtΡj?V#,?-AQ^xxKSCȈOvsZ[f47564f&rlhP4UQ*ŋc*(ZM+Ed0ڕpЧ-Zoh {Hfm` MnPhPO?k*z5>p6r;gƕ]ܙ3F2-kkjtt}[sS[jΞL@#ZCc׌VfC׻wW++5uhmn۵g+#@++Zo:9ױlmQdTUe@!mmL=z/*L.q,[o``Wo ]SyJM̟ݕpbjm;LNE[@6>J q/6d32lk⮶xM,|"K2|}0m&hlQ |o隍7}~cMߖ]$ !l n[^)$@2QBL:/AW}l57..7N:6z wf]W7o(mwpJ3dQ^qikinb*?1ji燲ٖzJTKC(Ù,dž۰&=2P]]W71ˢ 5Uô$Tu^WԫwT(y]yyY-:;,I{ؼ@Ubr2pN+[NLM5Oi# ZSF 6"@m* ;BgnkN̞zwh6\_``dj\UL6 ¶9s_@V]ni>dI[MFMȆyoP262jO3fj 8PSh.9M6&dAJ@Q KSuubRQ@)@@* H`Pf PK6Y?:#$7Vd}-Tn1`;G\ssã Ov''~_`;>cjEj@fl`ђيP)>BAߣJ&džچxE29#X&H7l"?I=Y]֐t}}>799ɦ ۺG'=IUQnUD_n2N guu57>9Y]YٚN hW^GL) bƯCJO1lp+xTt$ #"ȡTj!7Q2́enbQD ^15G6O6hYP`%%$<MD6ao0{&_0sJpڛkLU1 ݢ`nF ;tPE]g-v~^qW6+Dd*wڭbj*>=J;86jRL蓷-cܖd"zݻ{G8CΜ`Ξ3g|c/x"67< `|bbN{[sC=vզ4M+кTjۮ^஁=\E$386:/P%]W{j*G0՗ڦDbl1t}|rrhd=w;>pf4]mR9>=[7g)`ay Slk§vƕw$g 'Of917>Ubryx+\~s]  flL1@q` PTc)Ece]L@(@"-f`lUύ2G_{ GSiod?ߟ= 6׹$ϝ4G{ *&m=cmM3Mˌ4P\u5ݸaG7\~nfSڂƺ9m35m٣o;Fe*Jw׌d+Sƍ;g6ue,{Ս96TU&N̚\yO={v 5?gH&gx^,=BUEEh6(hY''*+1Lek_UU9@*U 6üd×m'NqM,dc2:l6{ Lb.cEҹQ> 7ᬮqz6ֹq֧b172f̹틏yM{}W}֢|IU]^UQ}TDo-[,cٱln 3f`D~{We2my@׌䤵D2zc{*OԤRUJl&2*XRnژ˼޽<c0MgkF2|bAW'LUٳ6naykM["")L!WeMώ**UU OMr`QƵjml\dS\7y#b+H?abA ΍K{|)bAqoˆ7րND)h.(P0 2 íf^L!e{{V]w-u3wͪ>L W׺#>_M| C^CtD돋}?˼$rc zyq-;_x\A{ u￴2Y_3N=K*DCmmM*LjRUu@хWЏf˖m3wv vTs3:k-SR:g~shFdliUyמThrFsSm*58:mW/1MM RyGwU29m939ow&_ښ U2;"{wKq].!xAޡ OdCg'FWXرɑ("$~S7-r$.1]4)=m`Ξh&9sX7fs-{2S ,*\pkE6e'sy9]C[w**͚5MmO;2mњT|>?훘# NN3太6׏f3= mrj3 k[y_GK.̌eDnAKy*<*@_MRL39bx* E6N wEQFPNkoE¦ K8ot~M~@*ǀbA?%18 uƕG_' uf%qD>EBV|WF6?g UUIT)*V]C`0 s'K'+2]^%l 鍒}joIs34,{ڼ}GP8hႝaź7f^`G-Vx[MLupnwO_4akn111y6owb!x.g`'{dFh'(}lP1/o^YNJ#d'FE_a[8^_W77ā~Jx=g52tDot#VTXXX2PL#~pc*z~qoVJӳͶeo|$ ߜZ$d#^3cWM ;h3oEN6>7, وr?BL'{kEd =j$wS+LEࡱ|f.!\1@ӉejL*oJ (I(d0UPc( AK(P7ƣ(QǦ&r[i? F6VWp7QQW< @1{K\e$ql7Srd3X,VGoUi]-6D/?$ܹޘoCVVq\/P!0 ť7$ 0c}c)K/ ƙ 5ʍ7I2ò`MoX$& ٸ@RA6m NFs\_͞6JC*lLB' 6]OQ tHJ\a )v&Whx#֏r@X W;pT$KڱΙ*R%fd\yxn{UQ@hBH( B3'nSJ1ϨB g&HwB#oA䙃wxH]dOǘ _Kon!q{F sHp# l<@Ȇ+K!,bW,& uCb^H0](=I/X7{|>":@)L! P@ ASI PDaoēgڐNߴg5C]an԰JirM`nm( :|.olÉ暢+"7CA)^oD#"$.~t1+bSc-$iaY=JxeK !/]( A_q7]@\`Z+$GjdĜ-)Hh( MRr_wջ}-Wj~^-~03d槼kT?5Nc=ݲ`|t>x`J. DeE+$rd(.u{O :0 IDAT~DK*z1$dE !AK%G IbccU$"߿ &;i =M*HL5j_L(L1 J;WxˮC-Ojr>[FNPHMtd435UTc=PuR8R&0}5?66FyZ,!)GTA(1ڞPo$L77X9CʽYT>]',%a'3 V<,`߳Cq4FC[!zX<^;kwˁEH1]'%AF8}B˾W$IBFa7D2e?c1lFǎU\d~7"q}C$ڃ(=s+| @ τ2(B 0 /ILD3+ͬFK rk~>l_Ú@0NIdc3.x۟"q`iAC?K&[?՛$Ȇ}D MLX}\!FoDw{ !A|y kӒ|՘0ׅ.:K-0PRE>j&!@=d<5/CXONp1{40D_-Up 5*CZӋ>=L`BFl\ 9l$ӻMo:7wnV'^q{*b^dҝX“M. g8ׂ;ҍ*O H)M,*@R/ hF7>NQf5X€݋QP*CB#%̕plFLٸ#ؾ5L&Yǂ5-JVAdYVgm/sJfHN]i#6O63MPa-s:;&yQʭf0^ڗ+#ߔ9%]dfQǡ ?>Aw,ӷ@@`̙j8S sx ga?d[ 4KXBɤ6iADF_<ن{$!}x_g3%F6Opp\:hqZͭBbX7C\_!*Tkl]@""^I Ysʖ&}x QA QAJ3h`!"5ҙʽg 'wlOWBEA%jH u/H|?8l KjӢQdkDG#"\ ߔFۯ_+Z#8q$y oJCZsp7E(0FC@PPHT e%'Tf{͛kJcYgj;k_$B7.Yf >{1)(^ЊS|qMj1MXigq|Jl8emF`̧` c3N1Aut4!eѤWt!1'rTg9LdϬK܊S$|S٦d#h*œKyKHX; QfoRƕS0&8Gl&ӽ҄|&p;(~~d#z8 2S2o%aE6a{%R (UbSBNvX ϵt|c])eFѷ-xCD_X` H+)*Oq@q) 5E5N4᝜ H 6c!6)^!H҉> u3V %{U<ɦ܂oBi {яx{ԥEp(+6PɅ(l:IF{ 1w<#S OBi(bdLnlWe!%p>5b[5ǁۢa(aP0oe~oj7j?1Ƨ?]K*x\ u- Ql @6IT7uC_uN/|tbIʉ8a{8Tr}I钹L7a Ph(.P EtP_⏘*F!MQeݗɦCn2 y~-0_*X,rX!8adᜂ׉N O d5qeC!#pWjNW}̵))߄+Ex'x=V<7vT C U{.CK!nJG4 ' .o 4!Nn`0@P(5/ S4sabƵ4 ` 4@Kb}=%,@ƒkԂ,g(؈xyȆ*qR_b+ȡWsys5wWg>B-B۳a,{!ZJ2~"#܌ }`2}˸X?!BD.J8"!67=IIJ܃i *.F1@MQ(F@14{J%b |fΈ|>&ed8l0)\fdD(oT;nSPBu[<]:Kr'| f%U6H04\‘/ɏ 86 uy1d$b5z)r q 2g\*"ʣFd!G( (P)40gN!cJ0kt-a-L6ӆ5ј&tB7iEryld#VbAܭl\|!Z׹V#~!'L@tI|{YZTa OjR;0 #&_$OjùY`r^TTgKgxsCK8rɁRchh@TFQ/Q2}=bqr"+Ȃެt@6EȦ؄,XN*90ᰆ܄ɂ6E}L3v,a28x9}؇9.=A/gcN{rS⼘,M=(|!L)JHsaѧ_ƭ^ 9D,{:]yY0S>f>D{Kwzj"4M+LGyC a,G5@GS*,椁fTicnVVJL􎐖K\ dL6NmF|jd'+n,#XNLgi'xw\e<3o{ir]cb㥝~c&\41*k'_>f+Pd}x| 7D! PUurrg?l(_myP3o00FL9aFF6Ӊ5| 0X\$xlxքd!] R;7b67˓;}{\dk$6j 1%aM3Di +W(I.~(`W9,r$HFH&!OD՘M  Qh S1ĜثhXnJ'(="=^l#lz?;ȭ=#B`ld~JɑDp^OĽR|%ld|VrZv)3W+ u"i019c:Ə q$GKXH1DٞSR'TuMDx!iR  F& 4890xfSZq*)V9} "MoC8+k$L4j`)dS<ȓ1\/VNċ̏4^GewF6XqBF zb(%? 6-_ꛯ5RTfyqGq(詂d IQʑx.HE Xy sL$<:i(n i] H6 ܮ-<,pH6zh Ȕ,.3q׽tf!mwZu9 >>E6 ~ t^ihcNyMr+"yEqS轫70TafTePTPPj<ٌ!GA(1^ALct` ldf g}|8x5d#KW]9޼lm$Ml!S&zX+O6V 3t@+Պu$2 8 9e̎~,=z$j{N[n` jFǍcmI .Qn2]kۼȦk ޗK$iq*k K6V;Pח(|V[It'ۈ:6=/ED2xKm%_`?ŵB%wG+< \sqLꄒT\ho|-x)NV)`0`goȠ/G*1)7{HfaFa͊5>kEO9⃱-lm;C6B5S+KС+v({rMy7fJx#JTz[I3p_#?bx)&CstJ?fn*X,i@).2hYR&S [Xgj!iK7؝#*W 8!o Ϡ^)P|GPӳ< s9.T^H6Ӌ5goC@^Nk`2y]2G `(q+&&g>O dDoĴ#nJ`bL(T(06g D5|k#r(Oy;&D;&*ko( Qr =q #p6ę?q` ‧o鿅qAR}Zɦ#yho9I!ǽ"셑ԁ̸|(؂:"/ބy`*C6BhWeB ,fM[*1^'%= 5bi' k{w(xFp_>Z3WCH=Tc4ZC!mw^]&Q0 (F pOxr /JPb&xA& T 0v 'Aoi% ;&~f/a~Kp n3RXct6%秘l pn p׾ j#࣌SJ'I _e1{$̵O?r6:/mA]{u""Jnbw$$qg5"H,&aޓIp%>خ'Թb+ʝP7!)&F"$0Q 5Me/f,.Q3Ֆ)$F0R k X#l. D8le gA1eF~Ė317ZRE{}ol;#̷dh K3WȲÏAdg-=|8^8]B"e P]Q0 E~)T]W 1FC\KEI4=5uC،d$5) qQA&lxEZu-.gb b~ڢ.% 90wR̓G6>X "N 5Ao-ЧRq&t:¡6_UT}ҏ( BWNI'/#ԗTHVᓄusb$ِ%1B$*33!%bEeK*.=CgĚw,_P|l 졞}!xOH&$y<0ȯGV&FR ?\R1~|rl8kb?CD }wﵧH&pzB[QN ! _T$@+$a;hk?aRl]Ҡ194fd#77Yr{lp7^t{q2gvȈsκCJ^9G^ǟ~oo׫Jpg/?zɬYpݹLLt&&\~~p˧S_l}\:{s_b~ӟO~?dzgsh&1uыgzKO=樷/?N켳?vyۊ?=ʊ֖n}?ٵa{~'w}8?>;cH\\u9;wiظ}~~cc/oڬm+.9W#}nPͦ~㫻vC6Kך[t~UXqyg͛3kޜ޲}6 ʫ ANÖ˽>ϯ|M_zYmogm[kC?w~[[j3cc'\pɢK-XpEm۷ls9`wqT-qql8u:-Y$H6C܎$"1Կ+1bk|chV$?T+'0Oݬ!4_;À tsymOQvDR@`4Ø10cOMƙ~VuqMgq[bfX~t}4 IDAT[׾R_n3V^Xq}%V.<֦KWM?-͙LVmWЧ_Zǯgя\~c]荷~'_Zǹsjkjtu1#~ގfXޮy9u5s:o}G?X6WW:깳;/>똣oz{uwچ>卛zV tϽu)Sg{Ej =}ɏ]}eKs+Ot9ڥ͹+/7?~𮻿WX~AuSӊ15nZ`eF:}ˍÿ=4d#|ot?eDsN;+=i㫞oյ-p-yחx'l<~s)cHRk׬]h;>!=zkn?|Id#ق|ZcBeW΅B6|vQ/aS34Gș@._o(bz}^Ѿfh.JU IP@S%@R A`fS @hIJ` 'pi?2<6d%}{}];n?NU~Ϸ37_|=ϻӬ\mKsZ~%?:nRgm-yį.8Z+u瞓JUꏏOɗ=37_7ghe*ᷧRU=sO]ْnZ`ůozg9>J5ԳϿМNyء-o~`hhhteY7_6~w;9uշ^sO>i`p蓟k^/QJd³108Go ?Jw|峟oeŵ_u^y◵55lvWoo]mʓO|؏zA+O>_㫞6?:8;_׾~5wu-IϞ=!>d?-_}Mnim.9zĥm_knSVҷ*]zLC*0&Bwp!Ƨ`b |7ѥJV}6nE$PoB?qǏ~ăZ|ߧ-ԏ8xtr]U4.AK1U$@@cPq hy })s@qD ||moek{ zٰmO~蜳f57=gH7^|Yn|ѭ?/{m-?Ͽ}V#}?ӟ <SV<Һe-[H?h9rÖmG,;Ooԏ{mÁx |e}f=mx/>f[wwkssDW_Ь-hzeynqW^uѻ|~̝s%Y`/y/_?o_xفw|o55m"srG]>wӍzoO?vGbȥ=}?Ad] c9ssC׿>|=O\9OqG}n }j?u JW[G7n]2 >?/~m^4'ѽ[o׾;ܼu%]bƍ֮Yz!Y樣ڹsiůN{ :Xojnkj" .zwSsw5z -ɕ-Xkw|%v^1. ¬\z=Kc !A1$RX>4$C9!SE"~F`"q( dx (7VAZa0Z}Xg3P FoFߋʖ͙<%s9wf3cgGOϚmaM|]~ȡ^]tz[<{/njJ_ek֭%KR> 6Tn䆺ZB8=Ho_ի z~˟~{n'.a yU~^ sm7zh qUJ/$ ~6㏾WXfQ.߱}퟼s}q ҋkn⚡=Ӂfo&!.==d9ZbckBM~g RwQ )?3n+w^ Tki(PLH0$T ,@40 U_)5BK4G3"^+kۓg_yeŵ.^\N:OX9W_?K/>` rk_sz8E ?>o?vcی{c6o?vnІM-Xp @mشi|cX*:31<Ύw_zfXh˯@l&ڳǞRn\ qPd#A5ޙ9$a P ULI?!#ŠP %2':p<E&~UQPo@) P4T B ?TQ;\S#*$,l 1Kl $vS)7 $PP `,w7*eɒsvcO2;{ΑLμ̳;E.?x7F Ч`;+}I賓 ͎]k׶]h!׈1+k_8j|^~{3+WK_/{V7>ԭ;vN;&|˷\{- W^37ޮS2_`쬢c55E6nq-n,蓗7eܘwƛm;n>7ӧ{N45=_Ϯw}?ߏ>@7ljU|隫 nQ6pǷ~w굋w}G?DѣFxz O %:mشy;sƓϿOnv\շd?\mٶŋķǪߥ%%G*+q'~_vV>Wӧ[׬]G4 +/ve.Zx_þ߯XQu_-7lҥ=~'b_@uU={xenpsTV6n?L!bsC6x #sv&/^ ^o.*=wdiaGxVđqu&.4@D9SH.R:gdѣ CDĎ]PT 4D_TdL(u%#B6=w'O-`ʔWV/W7zwMlL8E},֞^.'F|r*[aJѣ0o? =LMө=)?{+KSP'-7޳~S_e+ި>~[:A/Ok?}K tԱpx} '?\r'n #ʇjw_[ޯ7= ~w3gDK}b+׮|ݒ_96_%% ×p{PiIYiIiI z-ò=8r_zrek׮peUUvs8Νw_ͮx!Ⴧ^}뮿nͪ5%1lg_^ңN6ܷwTlZe}+lSM2i]+'ap㕠KʴMJİpo̶ /+Yƞ\>KQ?OxuFC;"PLߔQU/˜9AV @P(>j|r{( Ǝ$Q8~4dǫU\|:U3f0LJ:|>Ԉlٹ3o~wS?`y3g2n~-vj ravXIf^:{fvvc:2zg52}. M'{dO7f߁?dYƎ}7'0~cܖ)ceًOz7-/ZTY[{hw}AScrΟfsA}ry[͙='L{$bmXM|j*vaElۋ Bz{w[i]y%GL!PU]=kmw1<.+\ՆF;U ^!\[w޼bÇ F됸\z׾C:x֭y%yXԷouU՞{F3*avYwE ߍ]4ܹScַu-wݞRG ;KKjPVTbA65==6HvT(1#ZN 8,6"r*FX7 ^v^IK'  Ђ` "~P*@` L BbZ !! @3dA%Xr͚5VY< ee*+a.?=ܱ{6o9g?q݉y6yc~w-eJ9_~/TQ.5OAw3Ƭ9p#;;ŋvŋ }rqvvV8sgV]smwbmݳC\s~zsgL{kK/nv>>}/C<[+gL|ɢuO45-YB᭕07>v po׷ᄋiSvTl9kr?y跈>\Y秒}Px}Wz/tnݹ{\7|T7V 28+7e5 I&dgg:tK.t _[׾?aZ}{OT!޳{y[֯Z{ɕwO3}B\۷m r;Uo9dX%W^^Gnέ[>ٝ^[{7} 8^{JO#~&Δ+<nR'wDŒLْg_Ygn{gP^]Q"1%|C@4W {F%Vus4?">"PuBU "JA4A!`>h dH#y~]} \Ѫ|ẽMM?ꗍ}Sn}WL u/}zi5`csNv ~Dkllj˯sv0nG>ntpÏ?n?TCGV?$7yֹӧ'6G^z|7?{޹q{A-28f G&L"(ÌVBV5͘L)zbeI ?4~A@A5UhP3 jѨW&#/\7hEђGsǏ(/noG|G۷<ږn o\xAq~v]{hѰ8:p%>=8zЛ.p_0gPPPЧTl)ٳl-.w࠾<{؜ [?{a/.5=Q 3d-fڵ~|/-ӓ[9콇yO?|rL IDATڥ{?t˶ͯ),,0rUU=| [T>dp E]`ڔɈorɞ}<\]Sӻw0l໾[Uu%\u<oOK1^_Fd3tȐK/h5jTuu5 ]qiwKi&O,..PRZgnL޷{e/}㫗^y٦6Θ5G|qs?o~szxAN:zLǬ5U՗,^dU5BRmqV@LX=JD上sqmumm[۪kkO57?\ O|ʄ [qG?:r pR۶ ޭ8xΙ=s [n{Okhl'? /Ԇgm&77+.a.lM  *n]39w,P]]?_0믭={ޜ'ۯ1~ʤo}KrpyW]m~Y3m_1]BH 5bqX#⎻\Mﹻq㜯K@LXEҽN˻7Qm# aC0Iuf 1) OE .('н`O^fv yI2V1ZOP3M%j!@>QB4pC4 A?e@_~ >s#OH#! FFphSkOaGѱ rɪ>:s6=v5qg2Y>ϡ4MwHj>)w &F?A1p"[7㸁M, 4 BGOύd刦ĊooH7F@4 ZLcg*$J50@(F"C!.~h&lMz,!'"ja0y/5b"*!9mdmpDdJ+3X"%FYjLXIQ=Q'SF6݇RG?nc|E։QѾ0P 3!@Az?ɬr]NIܾe eP(A%HHu @A(j_WKQ-FceSm!XxwTfzH#b.RId#!D3TE֌K!A5VcwHJtH3F|^(&ay[aH88*?̚F q8,[QQ|c߈/ӊ > uQAB0uR} APH$ e03EFbrƑ t!l Jd֤E. k(@6NRĩPNjK>2`c&yGƹ7t{13و ފ- .t+=c$]FLl4XĆo\$F,:u`Q2էF|+i`Ơh #940E YPЅ!Ƞ10@kz`dIHɱmQ)dCE7K#l19A]%q5!1݀l N?ƖY*KsT;q5U`ݯ=l%3;Yt\(7I-w+;"\%тNb2־[W &_Tx BSj\٬AUt'AYӺBDThG2?Y`~D ADeAS|dx܄בsF椬oѼ 9墴Gl,3h/m^}y v;dpP#GBm}ianA;JyLܯ ;TR¹'(`C> pE+䆲4hgNꗗ_@uNo۵[G6SƏI 5î};:n|&p mXrssO57w+W>QW7|PtD"l=9ȝM.׳AWO Kl!_$]dYLdLྛlq dd^7cdT&1Oq8J ,.A szy y!"BZ(#`L jZiYQEQT1?QUz`?tթ-蓅S\2]g?-zh%{s㦶N g W_ΦMkb B!Kv&ODV}&O|iu"" I:#׮>zyS&j͈Ak/*6fl]Sj5G?ٻ+7yykk[`N7\Sw;vBYA )+ݱg?ҁw>7''ɛ` `lvy@!GYaSu]ͅ aX٠HW[S8y؆Ɠ:ZeCZa#Lla)rEmqU ؑ1D}U?:jxosmmGՔ [M96 ņ'+UX'm۹豪1F翿q]`@ ϟ'я ڥ`as w{᯸H$oKƸuza=M)tisH 7b:m##psSsZ~XbI"Gیc~6T$ (g|c#fP3Ï1 "FTƠhv@Z(]~-PhiLSӐ|]D; A>+I}7AMqlrS'?@ձ+ϝn۶7l;a 9x |B.[n;ven 8;l:ZאtѬ ~ rE}V~艆, g TicM Æm߻#=JO^Z(+0(' e57 "`癲ưҒS'}TX+0mkL2CUU(HYFp<ٰpUҒg}KtS& 7?/JMݰHU5F5깗_ lv;7w̴5 Μqԩ_{޺pG-v}k<邵;~Կ_uuo͕8=×̨({v"L^bg#Sg^R-~c҄M=t¥K%>y|#`Mca'}BX6(J?h2t5UD8ƤKLMsB63rC[V>sEga+]0a„#* y*CJK'.0PИO}F%}7$/[E D#{qĜP΀~EEu'DE]CCPHϢ6=t\y={ݧ}~]-sWI~#ˇ6~oδO)Kllb2< ;rH$cTNv&w&?f9m3g|ɶJ[/8 >e2Ɠ'%W{ﮞ9kUW]gϞm*DwjL:$-hpX/6l֤lvx$h3N([Mwzi9w GڲEP~{ sPy٠cGxpE.S!fA3\T[oA#`#l fpB먢~ɳmm_ [<<8U]{"fDPH/Cyi J8}h{G;.?o[o< _ߪz@ @X?ٳoe N4/_p@VVE "ZiڻgpYيwޝ1q|xFM)/8@NNnm #Gn `:c*5m,**ˌOI۶wuvM?[?>3>ضm(Kf?k!Gva V&Aȋg\ME lR5״N > IDAT[nX0fbP27Ds$#XC0֩I|0cH{Ehi0@QOc)B0USħ(~0$D1> !O8@KnI;<e#K' mcxN0pƴMno6fLWW}EvzytT1_QxC:"khlhڴ^Ћִvv56>sau흝]Y`YS--rzF} #9TyRk/9~x>t(;4o295[^ ZsϞGYh `-OlbΟN|XNvhYG}^n^~eH_oMC*pEY-ԑM:"帓0K%KdgZKノ'zb썙&b%|M)#of3(ȧJjCC4튯 iRh 40 XDUPe-Q.v}U֙fpK[g}'?o]֥Cae6Al޹M-Xr֭Ol޼斕7%k>ںpKϛwe>ڵ{st¦qG'22?ѢrBwpy'ORUQnSG kd3nT>ٱ{sƌA{U8l9b~4L I4PVpa:+wE#͟鳬kO74l߳o⸱ 88|'Mu{]]Fd:gİeGGegZ.aC3:u_n|E)%7\x1Z4]|E2BJT *fE AOqB6b=3m#%L]ime¥xd /T]<8ћbMiVKE'AT0ҮhH@P4MS(aAt2yK.CM=-%W`ձmoy˴SG`ӾdF ۿ+Wu[ZJ}}ZUiU5`am}74F}*U^0?/+u]C_T>9?عȑ gQ>㊝w7mƦ,;:z5wcsˋo}??XU}R`[7\Z2gڔqg)^mm?ں!> ????A?yŋ-ͧ[c>HS7D;;+^>74ԛ/^ GY&Nh붎Ǫ7|X / ;崽D++ƍ"CxuH9K,G(+){xm(뉨'Tne(tVu*<16\ע$  )82YļbWc9ʢ1Vu oX  e b;N4S,US)S( hJAVA8/+iQYm-hj1Ĩź"-#?מ[JـXYߢ+>Fۑ.䰍%޲2,񟤑cE¼8bK9 OG;쬬sF W}'RY>H9əOOO>VYrΟ.nwK1;hv7W5 .g3mnyU |Ośq@aXm9:dbםX uxё&k\ROxw'U#LGRNl佫~3E_wbS!9Y9| h-(-P#YB4 FRAQ#[*l,W$H-1)d=7d#GxD6aB IñM?)I!pʑK8Hj\'FOeHh?%z\͝iIqG6p!o䄟^f5{Q& {.DM mjj'4l+5A*Y :pWF29*FVc EHHnBuJPʂ*A@A_{M:$3m##xfv qh%鄍3qQ`f"Y8NJB8C0@xSqzxOrɌ04) >cY3V SP}Ш´xFL!~% 0kiK?l(P`,{cшXK${E^rǼ0Ell TDR- )7!%̥6,muHӦ84(B $F}>ӈƢUʨFWKU%znF3?=60ΰ:9SG6b%kb*@kj 6=l}D&&U*pEK6S2bsm1M${DEeIHYdwxO(]$( D۬/eERA%*c>QBI0 #t4b_Ӻ 1I%VA4Vd%m/1ӧ)?HGd78 @6 4aVdc'dٸfdd_ADHSNmNRvȏ*^hrM摍m˛o9'j]e"^G )ɵUm'~3yC^N`Jv1@ (qz)$,Bs4-JN|4Qh $ o^LDJs> "ZKQ),Gl𲆳\?B6|%QIrfd"vOtw \ ŽwJ..^sq6Gݎ7XkF[{RHJ.յ3"qFR)<,Y,nӓ"}T13%c6 bT0 m̥u $"MI|c˗neOoJFI))`LLM"P A,@SST %HsX`*Ƙ{ D[yF6vBj zs^CZ\ f%N\UjFrŻOh,8KB'3uB(;{cܑd X?mvtj0ۛ`=pjL1#c8 Ft5B*ک0tՈ.E:@^!G)DS(Ҙ#wp!na;ؓj#RD6TM\""uF662/c=3Qݍlzk\s$]bJQpAKPs(]d Vl.(Qe/eRs&fo$L8&aJr'b85D{R)d#!7϶O8{d^52'h?vݼbL!b.e1yP3$Pc11G?.3ܨ/_u#WEhN/ bB|~l;ٴ~o&6;i8KUg\&6Wf.GR@4;SCo'kbLEFEfUʜ8V>e;9+ind5KǓÚ z7 STPTolPU`{5^(bFІ7Zo?K+n=>2k"p,8/m(G8%x|[„pcR3;[Z&q[~ܽH Kܽݔ˽e&"y$Q@aP@UA/)#Qtu2M*נ*Lo)Im#/&D66k݅lNt%f?EMҺ k)(H5oA?գ!YLqJ,ɛ|z@tڲ&g牝FFČɲ8F #XΓ H Gp4!jNp@ߢ PDI@4DU@dhv׷Tڛ_r1-x &CΘG6Ȇ%EtXԳ?>m-tƴn gDWߝZ Eiq8dH[n d,CSst2Qbmc7' 4sB DggY5υ\(" h(eEݛXDUedS䫔haJP) кXbvKy_%/23P31^xԑMU!Z+=ו9D^>[@źM{AdQ&\֪d`tH &gYqRpe EP[7ED}mfaMxS:'ԘH$]JX 0@^V0 BT%)BrZVB4qZ91TdB%ydO۽Ȇ"L6 `w )@.1gWܜMYW珦Dh2όh%)OoGFS܅7Paw6XB,YBVt !sحXN:7QL4>2hQP!hE&PDAdٸJgq :p6<=ֳp OL8ҡmzF8]7+gA= dlT/%ye2!=(gb& "?A|b*YiI"k/7piW,\ߘt mlBP Րb( Q"RDe9qY73dy 㜉f NC4E1~\l:QI`ڮ(N뤀l<@ۢ 6wDl|^Ffת` bLrr3;mx_uk IDATL`Bxc{YĻs4L_oҲ֚c}X]nl/`br7 喴XQ'ZT[*bpJ,RBkq.19=9*lt+W2dg@U EA?Y*(* H@UEL/aз-v[d K_8>ycD%tPd$@6U#L/L@n3Q igY%31SxfsK땍CTvpQ}&"+XYGб`NQ8@/HVL\d w9@Ah,"^x}*"PXwWWuEQ $p#w823L9G}UO=tuuշOu&v!%,(F vBƹF:%SU)lDEU"BE&Ȇ nusQr;SMoӜ P" " _xK). ֘3, T%{|#H(NoJ@+ hTH m@'A,Lp_d:PA*(ٞX50INvȍQ?#=l GFMOئeLQl)gf9~XShwNo\dEڽ|O/FԊo,g ȊUmMPL"MGY|׏3>2h@ @ba7[QC(a@;!0`Y0,Ιs?A[[omNW9|_A2%+ 4É teݍ '>X 0CJWU2>@ŗ~iZ5 ؑ}V x[4JA܋0- )HwLX-Lchc.f}U4@v +Eˆt2:N,M׉j˔~ 8S8G()nv'>m+Hg}B6s6 /nC68l_m1X _ q3Ka?pp`9*&[I)YFLMq)q8{ʳ#rA;#`Ӑ'Ær;`@ MF8 ء v-@XA Ku߹?A6prd#$G6TQ7:_Q(JFIEO_%ʻeQu -Lɸ!"]>e(JhwRA.!6H+3`̰@pfSXkРCfE%h@`B7ۙo)m#)*B*@~?ѳtOglT.7RXCJ*(ljQx >d7muQ+4H62'ͷ1YBb\|zŀ"+-@Q ԰ha`):5`Bhh@#jnb%LRBT~3(Ul bl?OS"d\Y@EGZP6D6*R7i E=5 &O(xmx#92+iS":B.^E]buQDlvJC;"4`ю2p M0@Ag';@L#i TI*|8"d#xBQJsA3ċj('H{bqŻ JCTUOij(}y}׫ atL`38Y *zSR55KG :al8̠AvZ\D4ߖr HnEk"TlvL3u |(G7ߨ#W~-+ض7ٕy\6~[R2 3y #o(dô#(8e K(@aD:QLhGP B;@CR n+#2.Gf7ūBE(J U WO׃L~l/^]ݨ;`p*OƩ.IRP~֑,#ov oD:hөlYrAF@[@t_&m8 <Z;t6a`avַU*6Pt1{DU d#RQ[MwK;I/2VA ¼VݲoP%]y>6>U JT"bDgn"VJjc=6 z;+3! Xp@PO`P.C1zr $ Q3X3FA3tFjoȮ zRW&v*Iy|V~@&ߋj5r j֑3WS]#*T8\0 h)P ІBOag/&'CIAt`jFka;hUj /Ƒ@"chf/rKҹvH7^.T "D PRHrGA7?'~Ȕ ; v3;vjb9E. Q8E Ng7Ynjp fKG$<43g>B ,]<0%.??HCCc F j'3[[͖7 %yؐAM7k﮿;oʩ'T sf~7ۤNO1o욺r)S[ƓsGXtwoqzG[RQ0__>wci (5wE]tɮ]?8q\jJ SRS* H[ǏojlIkէ**Rŵ[Z+*>.1- .OLLL_]^B_|KKSSsCHͪ8)`9hSdO@\+"My7x#a Ѻd%YWH<-~>D0+]L>ŋ+|Tܕ[[:/)VT2v.Da4JXP:! pmPk5[P,F w}Qֶoi@rJ]WW>YQ]+^]$]E{. nWΈ3)(ಆdekim|wֹ5p{a!mii{{e#G" nHIJJ߿_k[$%%?ph߸8WU7̙n0$'qlko7&Okԇ/{r MW{h2cSEUu;S&,{+sl~]>!=D/7}=rw)00-ty+q`Zݷ-ޛop]vB#SK?)11)!ْ'˒۱X 6tOxپcA]`BB\7uEK(ٻqӇ\csILNLLLLLN8[]0gİ'zp_ᚗ_33<733-_p,oĤVv\7ibޤ aaEEW]=a1[ w,Z~In^zSZqо'5[v= 虊`qc8V,q^Șq ħLҡF.&Oyu̦Zef ؞7֕ot<IJ|O>P{~=zS;|>ڙwSP0(3Ec123߿sFV/u̫"#Ἲ 뷸Gط;o_S&7^?Ơsɨ5Gs5cF1fPffٙ3o~YfA1 zcccF5<SsK { KKNۏ8jZnim DϘ:eێƦn_<-?ߕeB9oڋvkf|kܜYt[ O< ""bSM |H ^~i!Ξej0W)JOK2>OO=ꚵg+\^ёYqۢE7m 7"# x|ʿcsss _[qL`֭[zEEFFYrȚWvҗּg=wݑ`FN0kf^{ ge'N/bYz/ii|ˋi[2?bE3F?포e7ʫ#-$q]O(Dž6A IJƧ7B:a'-R5Mð[cA_b%0VV Xҧgh>|C'**\[֛#I~$8YYyÏ<{f.dg17A=? %O~'EGK6okL{Í\3;Sdgdgr)ӯFgFqy ^zA܏_xx>3kƌvs8ʪX|X[{!CLɉb8~,%1Ty{ gN+?ݷzE g}7ڽ:!/oێ_7Ea9w/]W|cǚOw%rۢOѧ[ t]Ko4qÏ?w3ڽ{?up\)o[5p._~r}i'woSS]>/zY~⸸GWS]&&%zCe9d> w]1qF굥HHAٯzѻ' ^H}}0.\q,PP*O-aE^r٭ -y'`tpz 8{DاI :P `vP NЁi@v(h@֠Ab`n]S٩)ozv7ʚ_1%ZzVԜt}֩yy=rXcLEuեCsQWVrb~? s`\ .6>m%cc'O޵VWdn~S\pjԈs3iܸIYt۲ۖ 7..S+4(+>L?czSÿ>Kjj0gw:% ͙9|Y-..3-?DYwa18TT^U}_{{r~"-',RyꚚD}yU7~eG'M:urϽ;(Vg^}'y//Vwݶ@Kk_׬1>immoF `ܬL_]1cܹӧMf۷ę8~}7/`0rˑA0[>}Nu@s< &[?z<?0{|?p}sc@RVbX_mpbY馆FݭK&̬{@qQyܾ@aGUVT≮vϬ 3oGz.Q>x%Q- < /ewsY"𔂼<>Z̚ǥ<׬mji=FdӧǏLy)S-<B1ߥ?xp̙/_MØQߟxྶ?/*;}&""|֌ɉn,w O29@vf&m;v4< }Ly훝vʕ91!ŋLM;~ŸV~⤋v)\tiWpknnkhCged-[>Wλ6ϙ-.窱߾a_`:y,+#EnkeNϝ[WW{)L&TٸѣF HK-!^w}?u4aM7.N}XXDd8wxn^8eﹷ+D~pہ?0oo0[,]x-[/X:V{]m-cr[|Ru7O sP67,v} ~ElwL2=Bb~݌s" sh Nd?" q䚹/_8"NᎴc3ID V sP;@fz`KF b>w ~Gb1n/pY⢢-Hí;hnmz A9yl݅2X[fw\3E>‹\7S7Pq\g ؿ^l|%,s\1723]}b9SЇc1U55r>L!1#sM7[̟n޾dpcGLMlꓭ_= _:ӧN75WubFHIMu IDATbB<{8Yѧ[rN_'9,Б~C`&.buմ}׷;vL偉W]p|^SeƏ`rػގRbD7468[^__Ə>mrRQYyͬĤr' 2m~H80Az"_}u欙O-'\ʲ]v-_VW?ꙶgxid6{؈ٸ%spPS]sן}?>O?g JH:|0}ء~K 5;y#ԲY>|Aw`}>GwJp[r+B7Z æe`##,(U AYZZA[g2E'`eH6ha@jn +zA}3/eڼ};RnjJM7W!4?,~XuG ͉@q?g}s ``Z.z-F7s׬>m>L 0[>;e pxՐ![xaz.>UUS~8.6O~æƦ% egfn۱vն}]-_v#u?kkS{s1hj08tdsv g@С7`\W>|gkhl &|v|/ uv-I^tb^pbwRb"wɈQ K3ΜX5sLp&m@ZuU`٦ƲI/so=sT='0o?0]e3m'b7(=a͛/iI%J;Y#D3*W9w(};gR-R~< l-,刜_"}O85.|#=0O5 (T3 va`!;ìCEDtm:-ڬŽR,S/) `ҥ][n[09jj`=%fի[x9:p}`\QÇsܓS <7wukNIqu9z}yeeٙ3C JKMHKIpa'Nt&t֑egع0""mdlx˜w.ZtϜVP][W^Uԃ+}'ZSUS6^A-I NW⽪ y%LU{KMm[7\2,#%߻ kr(g'ɇVΔ)/bҤ?AooPS[sL[o\ӱO|~ܹ?{Q=7HO[F7fLZ[۸e.4 Aݰ^f\^^qq1LŜeֹpGΟ;n&ڷg/Dd-Y2 [yslIOw/XpۯoueA9C\>ݸ)ӧ}|wo䉏>ƻZqC+\y_d II5ojbzۡN h|.[ʪ7. G|#0,iSB cSǓKȢ6!57v ,˂j-l + "Z' 7=RL\veR*6vlJb7;wN⊬jbN_1ltIz!{KO0-.2zR K]r4=-s9ykL?nxnԽ86a7۾%Xdj߷|ђ;v{;v:o;v 8b1/iᦏ6quCsN>̘́6oђ/grY_]Yy\^?^Rop pg>S VsqwP.'M̼rά_:'+]mn RӤWF7_#Spu|N* iv-T0M%3TU,Pu DO,.o9:׍D;.R VN (Xh BDDūO^W~0.rUqQK?^v75V~Ѿƾu8kOyyq›-?WQ]at˜K9Gpu&oNV=aCSf=+s?4~ÇO:@ׇ556n|k/̌+.=EM zE.-)%s68|+XswݓX̖u}pSKLJϚĤ$3t"Q56ADaWGcz` sOD1TPX ݲSK6 T-(qDӴ0`l`l`  = m^ tmP?ysgf>z͉qQ}O~ G^~\gZf'./oim7)(H3g9JIwSgfq/;uرgT645umw /FDDIOzޕuԂ}#Y /+vݻݶcNJnÝKwa{.ǎ{1 C˗p"֬-*=6sZAfzv=vlpVLM.echcںm{|~'N|qN`O'Og/~)+=v nhlz}ݻת= )!X `۰cwRΖWHOK+h;9vsO,+:r4=-Fc@vvVUUui鱊*ӧMk>1S/= Mn^'Μ>][[g^0HKIwŲWڜ뮹_>tl[u.gwB6Nq.~a30Mmǹ}!6*0%'G 5k׿8p߹xC?xAo8S^ٷۿ;nǚoxW^USS^Y𧫯/; 0eOjڌNWd޹QL}CE\Ѧ:]^dݼu+U鉓U55." K徱w'CEUsl޺?;r!'.Z0{9[!XLy%q8q… m5u--g+ܟ.13/|`m]gaJ~s8q}˗(++ѦO>ʼn=a6W"l/ `[ϙϓvR M8hIicOKKLH϶oUpx) ⟙td -)*=nGOCGoin8uOLԒCE^gF"ru_(XX͑'蚳Νj sgrj;~;͸N82BƹY+eca8G3AsLbҷա &ʂaa#9n퀹-ac&Ȇ9@6uy͗n^Y8DI8&5A_Aopis77EݕYwU=6_-/'*>@bàp#b- /y?HF%U< I/oX?ERxq;?:e4SU0tA kPS)̥FIKJtfeBLaӣSZ`J)( ;(gHzRՠ3ph-DYS)(6}0}i4%S s | b⌽"}V Vp UR-(nU1(.(Gq[A ̀kle,( (R 26ZQ4j5Fg540@` c; "=K/2LB{B0RmL5隹 g )H݄D&!_U ~3s !70ԗ%GI+. 8fKd]D'2J>3UQUƚBa,t贬!Lc5F ,! `9Y ;1bn`* SH5jKe5!li䍬KJ6m L A:ߢq WȔTt p4pG2|Ź7>)WFhg;!6(@jLxlD 4Z-40h;>i1#-!wq& }}1n(=xgX\V*eUQ+Su۷6^zU|vol., oMR$@{lbJhрpDzN{9K C8; ڇ3~W w\?Yt[Pؖ+x|#dZۑ񘼄}O{9tk(:/}}4EDkQLD ^GەBoD>.EnrF~LJmۅi3%`BlZbah`%`F f4,6@@ ;arRw^r)_D6 d^9(dԚQXEsT6`U&XkH/FC$%Q[$J)}B*ԇ@o]:oyFI !fa\!}O<}O=YöRX RM Ym6" 6zX z0тA`nHF=C#3{$ +E6z@y8 "q>$I?> F+xU y_' fuLBH,*]z>lǧԺM܉({c3h:0Vh `Z`"۞Xmp! }$#0$Kt q}vCZ?BCkАFCʦ)5y5uVW`]$u*Yc,JbRi&CjP,1ձ|}Nd7u" G -U\*`_dAOL?VKluPttBGIA)t[bh01DGV `QHTY]v޴,,$dtw[]՜p"8Y "CRtTĕ_~dqKguWNie|8,R]YE\)2L Uuu)mN_77|Ș8fjP/'8 OӌR"pD \6QL.F9`Qõx̔&R3|]V҂wz?F(Uo7 ,(/KRXhltThH+t  `Xhm8 Ϥl  逽 `UYyrUWL9R}S[뿿~ґ?ƙ=o22$" Xԉ z'ZF V{\Ss+GQ鱰if"/NȃZZtQCtZms\\'28sO@h2;Ye8ؿD+&?u챓eL&&riy f^#>V'7@@Եr Wr)<s ԩ}\FQNȊ7X6N?1#5jF;b8/*ҿvq5ŘKtZå贺Hopܸ~52:*ԔD^ϭ9v $ocIMjrA/*)=wಉ~,4bv  M0C XweJ B#tٍ'TߪFrHxI&7D"䍴ҭHKD7F [8STw8B==nv;;`бY!`585`gIf1@:[ap#l%W K]6fԦ8v 8df@bf?$9 hlm\Ӓ˫9ϓ']:ŶyH@SCcO|ty%qFc457-\AƁXvS2h2mqoDae}cIM--XuΊDFD\6Iyc~iH'f[?Mɛ֣ HRDbHjwkf\$(A4"D=W`^oRQ/B lɆp؉0Z0ՊPODmF&7 6L fu9o2˘ܜvep)) }w2aHVw n/s'-P]HlLc'O&'~Gsga$@r||B??(Aϕiuָ:^.*=Ÿ`DGFt)5NqFNSz$C ʬw?q|s)o! ATF|ܸGM 6؂TUGA`xEDF^O~S2FH%>6԰!, lh% D PP۔8*Ziw>`)m)NijG~ԞcmI'$%ϋpvzKa^. &r2g=cڱJC(ϕNF1n;x^@Xx{މޠ!7߇@']ےXw{Q*ҫ"pmP}]w,q~FXX;@HHA"X`:("'UXf ]W36z+:~>>TXHȤQ'#swvXKΜ%#9e܋Col7B8Chj봻ڈIfJ%CsVC,%gN52gpLt#rc1jϝ?o2˹ܬYiN j$L@4'rde`X4ҊJJi f68+à;__ϭqc'us{8]QYSwn䰜dc\\zsQqFcEU odaNЯA:7 ʽ`2]0xTX##eT? ~ $ Q =A^^LYڹE$PI:Ɋ 1 nC"hV  W#,\=`5 +,h36$k#;l cm)K^TI۸W8#7iun8c55v=jll7\kAqUݹ>ucz_4VV]>aSg; #5%k`zB|s,,$dit[~>T+7֘;dPnWU&'ߐZmܪaА:ÇZ E:S=?dC- (+ILI_A K/jQ<\'ox&7XS k " eKI3 XS, DCebCEmbG8 !PJpV46+,f1v?2jגͮw3 DBUg8RxG?bLl8*~D7,$$;cҢ%tdfIMyH=sT.a4ݯ]#ȳz]=v?x&h|X{~znHw yXIdqa}ޔ2&cK4 {Ք)yG3NI[%"]jwUWcJW0^^dRt yjodG?phs6 PwУVlpk>&:- %`X !`` V 0iVkvtX&x+N@EЀe2P |nqd=\e*ٺTaS-/ ,m*fBڢE6[ P۞l}WCJVZDUt+"hTh/3 Aˢa+QH3EW@w*J60VC0 @YP4 ꭰ 6j(<e6a],CWn.>m#SP%Ph8EW by]iUdR!{%n`:@㪚gzu=,fr.//>^GUS~Cap&dA Bf0^vVP+4f tRh(Bk -q;OC v9a 0 >i/Cd!=Q$os={UpgFvt9"È[(PDkAjS֔S詮MyIO@|# >7İ9 0 L @`g@5р, dfQoa)`g WsSEj }KȆg^ ["O 㩩(U 'u A$Kͺr1 Xq5Rjг, gdCx~Bw7b 6&^) |X eL=tM B&lV0Gh,0T0cX>#A Jq1FA%f#@ǎE|o{)Hޖ-O C(kO!R_ JQ|%oax+Bب:)ǡJ*|= {Y!%5_BoBނΉB4 M'NǗXt6+(,hm"lm HSihY@7|7Ge^wKF/uWVK}f0a 4}#o#?ЩQFUuȘB4穮_sh!P XՂX3 h%VF/j3fH0XEXMT4Ůܲbiq;S5+$P[0862e~=Q/bCdg ['!j, .zaElk DD2WW_ѐArDxjj#!v0Dh0X뀾Z, j<\DNCм ǀT#kWuƟQO#S> E}vEfo"of c+&~rF|1mw*(RNZ7FO*T`k`0@0` X:>I)vP3hi\Rkn8,Q,_>eZ>ʉZ(|MCVL4t)X|CuJ@d=ruxt6+( +F| ,Q+@^:-+^]jdCŏIڤ(nNJl6`ŤU%eI|#XS gJmînBpk YFQ(Z[t&(%\ӎIO3oBd\TPL^d~SYYbƒ;np`),PP7jQ@,JP+anجXapp&*4e2" {k-ax-GNB8DZ6Rg~P[M!/j3[~Rf'w%DVy!}Hq1AF?2Y?U\w6jI2 [#_f 0>ɉ"R U/"7Dv11y>AӎѧF̎@+Q⁑o}#aZlhv<K%S |}GUk܉pP` Z7H]y;6P.a1 `2 dc$D6%5_Z]$K4`'Tt~qs2ND87Vx?e3 n7@ V8UJ`9TK<'#a< (`$ofE b;HtO"Ƣ0>m$nbIf2MXkSz MEg3s1X8Jod*K^ MPd]HUj Q X X] 7p[<+ip9`, 5CaEVš ӟꗐP>N* 6߇^՚Zh}-&V8E539%?ujO,@+.Dqpe6ޘKF|_o of#/4ԟ@. 7`6TRX) HV&>nER'a< <-$B|ۣh8tWȮmI׉岬Tr8eCަ_IZ1¨oevn5L2 e琑96|p ]ec̕I*iEQR*å(NّSMx9979:S8x=ŏlJ:T5V4y IzUbd -eHDXghcdNx@ص O,LX^G KXB]uZ 9F N U]On%ɾcΗ<ρ/6T:+aN2;n jY`q=gE=,7].vGBna[ D/U2VkӳU|(W3ҊdfdUIG[Iਓ`$ 3iKӯsրaZRޣIjֽ:d٣PJRDՂʒ#,h(\M\ 9gpjäHV.rP,5 `%ZA)@Aj W9X+ ?Nztm%#Mu=mH3d AV s Қs}'䝼eŁP+0 Vg']lA̹!692ܤ0Eu:4)3)44-!й0Wǖb`+hÃo_|bbZ10%8`+(p|p8 \@pv}V n ]P7zG|׶ UQΈ|=_@0F&(_}|#j`B͞[ 7 gѕEFfQDϣo\ɫ֯*6 .;;\)Pه.HUUJJ jD+gVy0_` F5|X,U)@7x upV \DOՆ7 /.,58s?t]GTR>bBD7ު6M͑yE 2 `*X#oTj(;PuD7KUlF\vפQ7ijqOUn*@)@@ypy  )ǁFU]v@3m!%E6b!I>pHua7\CX74f4if*&I|mD?+}X17RǷHQչ$GE8+ xC$?h裳K$ѶjHL6M3iϫ}[7fR0(9.;@  lW`ppt↥6%1LHƒ^G[zz դݧyޝT)$Q-~4W yiZb)U7d.5wKc3"M:T UFO)IZDI;_M$b3(77xxr`pQɡC>&^tD )! H,V *pQuA8_6:@AY2 `d^ ̶cuR1 1M}=aKs3R2Vɑ S$:ߓ%Y=o՛)Y]zjή!90̘bX[O^5a|۔(2(4`}!olT-bj'ay Cԩ7>+8 08 " PTzb(XH5P65Cʯo6bL  kB"j ꄼ*_bЗ !"cx#zK/+uaÎtLKckdt7 WA pѴ9eQv-ҶB~X$GY L:PJhi|c`\$P+||X iPUpNX\p@ P'(.V pSX80T% _H%XS>)6Кn!BD3E0aϼ>"aF#$ix2v̵1eBf -x甘DMN]ϒtxRjFKeY:Wo4i>SƀQ3z͛pOgJCb,D|<ۭm8ڨP W.'UܠP \.yjpaBn:b0Eh͙:PXZ!!4`c^y6o~i>vk$!3@Xc@{'w|nS&K=Սo[Ωwi`hB|kiX,ac84sF}*di6ޘtN)61b5 qwsPodʡkԴzpF P)_*P'x*X9P' K!8 0)Ujˍa mpΤgJ5 d6fZ/4:&DH"M3X ];mIkOdjBI (ԄV~  } 9CA%_ "7HT;VS{1z3OMNa7z?3k s@tQy |IYAGv n [hN W.<b&u6&iI1M'5 [ j ژT ?dxp`f75@UѭS;rQ>jԷK))F)oʃT"-D+D-cZ5C{uxtnRg"QK<.'WRqeX(PJ lN*@UNh%x >e p#Ѽs '.k'*K˜oXd<o\0+5Bo AIf~gD'5_ʴ:)efP$b '(ME;UnlSGbМ ZmGBrk~c80 PBx W[*sŢσV/q@yp+ܣ_iuA-$&S6V 4(H HND7V* jShw:$ Q|ͭhc0:"sJ WF}=G( uoe.B?1 7*|U x3Ln't=app񠕠pWpU|+G|'TÍb 2}$?7W?.Ai0FARQ:n`f75  \"ͦ3Y)7L%Qj㍌ɌsJT¨pND5vWit I1to)'T&nWLyQ!Hiq8ZY K%PZ8A `-Q;XX^$D!LkIm-FJ #'`3zyP( ho-&" f3կ2QhDn-2V0ټFq$_ᨌ7>2rNiZoi0o}ΡZ=H+LR2VlBAAI'EB}r qM@uTU rTUXTSDU ԳDr wڛ(~vdȻ{D*g}LKJ+;Ы^=GwQ#Nzb?nEdkۯ\!䳷|_h葹ynoOۋ=#GΛ>鉍[:*exZi5˹|EF%9n|ؠG2kiwu6M``fM5m!]w5o.zㅅ7<@TXP(F5$S/6#BTRZzyiwv}i֥s=)m<_8s^"xIEEE7 BI~x<.;R@34z(?@"aİ+asK!&&4nҸў,f]oΌ m|0sI6mҮu&&6nک# p8vl*M̬{oiދ}N[LklDxSƒpeEo"TYz2D +SD 1W' /l5Ԓ(#r ((XG իyxK (G-ƈG+J~fV2CWu!n +_ ?6FUD.'\%bTBA9P7@A, Vw {˯1ƌ()JInr:dyذq^7u'Kv7oع)-F &&5tpJrrNn޳a,&::%9YuX7v}޽W^Р~|nݾ^3b(5dݞwmʔǞrcrrsz~'owcG|`ؘ֭ϜrƿrGx=&&,"beey.׉()_PŸݑi@.zCevǚk p'M[aYsδ;xU_ 8ٮukGO8ӧ>s恡C~ BNN\ll۱㥥eڷ+((LLh 6&ĩfΜöĸGw&5֭WVqc,[r[w\lڥwqWFEF8}~RϴN'Op17Y/nܼewI>yRGM|ЁZ C۶@qIYfo-p`߻gMyvҷظs^@v-uo^sxnW~|j_0Rp3]|U_ooھW_hW3<'=g.ȈtӶ?}Z L~Z Y?g^1ߐ fLی>l姟m999?ޙ={Ι3{ܓ}*;+3+>>SjC{tbcccD^Hѱ1:EDE!ؘ‚)㟚p\3=f(Z-5`[HJN]i:AaQh%Y R*PFoL5I7P*a)%m |(̊@L)|Zڥܤ"2 70Z9_XT\E xX*ᲀԂ ۪yVK\i?21̯2m5_ysg9yyC+*+>iRFܼO/WI著Op1{jsĄƃ^,7:g׮bcc+j<}I)hP~c;'#iiw{V* IDATtN~]bc8qEj*n:p@~A'6yRNn^ >LiNnKQeHKܿ9ӦD;y O{PKޝ>a|m-DDZAKKLh| 7TRZd֌CC{8`ѻ I^o/~?u[˖Ο7u+jIKJ-zNT$)).)˞}uzcS[:o ˟{ǏsߠA~Q8{ukg4"<<&&z Y|;ݾfw٧OkKӧՉ4_Y+vɇnݷo/[=3Ǐ+,,ТegR]vu8_^_`'N$ܪմ/Ȓnz\YLsX(wLM=9qk/Q"` \PXh2_=B:CCg5y$ & xM@on Ŵ̢)AUiRZ)8RJxbgӸCbM](2ംx'8?Rf(^Fq[L{jGLK۟Ѯu돿nD0w(51cd>:~晴 ԭܼ;{Ϛ6Q;]pmdی )0wߧO}e=QGW h pk~M?h,.6v߁#=?<22k.K-_0ҲV}5ߝ<}NTăC&&4^7x=%b68!aM 9%>akWnk׵`0J1o0hTVo mR !o,*ݵ?o.))}{ >{ʵ۵3շ׋ng'>̿ލ^ݻedNQLШߧO:>#G 0#P|\lYy`I>v=6&:'7/6&3KKvgdvKjA XlڄG###cbϙ=~|3#g/ywɬBe9y7+#iBcS~C=k8,}{=:Ȓж-V~lj:}oܼEhvٛ޽ӽ{tW oa?KH$+l'vZN=etY#f;+׮ A 0(URjz{6l 9eTTTII֭$lLkx`!W~23^s^_Fii?PlP^^c/DgYqQQ6nj+G_mF׺C-[6i~{j;v=ix no]|.> 2甇X+o44Yh-hȕTiT)o/@ ߀*7:U#Fi FjaJ0"p T(8U<={e 7wږ-wVej`,%tKޑ*'7P__㓮ޘ:a|Jrˍ,5c۞}k7t\mMb __,1>/(Ό)^͇pGvJIn1b̫͛7Dpso䖯~znĸN|d윥 =9M/bCoaZbB?ݑv[:9y7-=$-">\yf/Hӊ^_xTv|*+_f4g|qy+rn 8'7<1Ow O兙|)oWkoS#vH~yGL2hʊ⣆9:eGISzj54T8Dܓ*J"h6VH,xE˄sK65o&P a?X*E6h@!Qs KvJ+P "ܯ NwLYl86Klܸ{j=Yո]ZI= '7OKL >~-:N95UxL #III9F9yԉ;np1̙v[7kڤMRg| ###v7B3_xU=['AEM8zQoB'}#Whхܼ˖Ӯy3uwigFޜ=S%~~O^?o^\RUR yJcw{̻o}t;v ,oڸ۹gooGz׮}())V͞1= ] βoۣ{̬RZ%;͚ QYJ1=pگOoaM1VvڭU[7o-Μ> ;;{mf4C/>[٧oǞxkr[*.>>cGmVŧ+_ 2 ? =5i/ 3&><̽n5uKrry܉SKMXc9!<oO%CnPaV>A:xB9hn h̷y)뎽.%m㍘I|V*s3}67TyZc*EYV` ((([/ tHݳ2'U ˍ>''iP)KOfnĘ{2JOl-[צEsjbp;yrǞ)-u6 aO{'O: =~-%>ݰ,;=&&zݏ?JlӢ z o!,.cݽ9'` .&BNNlL>l:[nY/vIKyokXZM|e٩.^ڸyˁâihtDb >bn}+Xւª;3ݻ۾s!O{xGΞ{ꑱS_o~g  W o:xp|~B3cb3~;2z`Z:sp̜gZxcOFތ-9d ^A{ux3oyhDg޽q;>zFZbiaOk>͛_['k͛[&%;O=les4~u{qIOOn0i?޿p^^^&ۏ=w?xoS'$>okw=[W~კ/|pf斍Ea#{9/ط檩F:I= gIhp)H`sIÄAJ` S  PʼvXtN)JLi277»\/̨V[(OmcBot%H09)ȽtXC)%[oq8)H/ ޙ xtCJ [_P?ǟ>=w gL q1q1dEYGƩ/.bN]~h._%;oRoOL(/w9a⼥1a'n߽BNά ̚p}ɣ{k11gΟ; +Wxz1{7}_z ^sxbH2f/yNTԒY3v}#t_P(5lZIKWh0!/<^-cѻ"#"zwɏ=KċHyF~I үl`߻S[ܳW>&>qTvx}#c6rcƼYT\kÇ=>Zv4S;t98'ҊOwq_:L=ed8KM w߭WG5ln~ڃ C7tt2IIBZx'{xѓR{x ܼ~޽G}.Z?^lLu/YnC}/+҃C>-xu;^=ڴJ^Ǝnߢ[W o,zwYAY`_>tpoeZ@GU[` DvjݢɓbcbX 99G?E#n-4qCzgx}o'Ϝͫ[m;Jj1kٯ,xd_F?YMʋ,n$L.m۶"v#!1&M= ;vz;.>NB{#ػkw=濵h Hi{@>,=Z~s'tzgŋBڼܜaG~j#r|+dD#ڜYS߶ L!oLQpr 甮*J9!|GjڐQ2 f^2ȥ}ԡȽTs bOiJ AڬPnpSr>{!sn+"WWo/[ XC- nede<bǟlܶCXG K;SrYs|sIǎ=ਖ਼3swIMwkW>@]>b0.bRgM*F)\ o4+"Ĺ #BW"ERMmpTʌY`# 0P ( 8ݨpE7Z]rON5 DƗ?4VDՏjekzzXK[4Pp~tFXnՍڸ}ĕfS"!ul{Sdؘ.b6o\}&A@BvZ\Rz7e̝6zMzqe~a60aNVNBBo $riT}岗_i/(Nv! \9P_iwQTTtؘ-e砐o"ٓi%AރTF"MǷՎꗺ={d39=0e0*%Se)s2UT'$M@*STBB'|=UUo]n%t$ J|AUQ5u0$Gų3{v+14Ez&/Vq((\M&7dSOpu34*B4ZHE ,nה!LU!!ZHIgq8X]1P})p}:9B-Z ]F(O@9R& 3%qVWX@Xh yB9`}4kp?5Q&1b{&_gRMʱz]BbᐤTMndDEӣWuk:_aImT^8Cܘ7LpC[ @G˹Z)ax̂ s?)$ݘ_V)3VQT5(ig}~cu2گHh֣X凼TlAGOVEV0'r()Q (Қa{I[m|.MʝT ʭ=DD)| >KR~C|#mLsQ0zIɵdMBetSݒt0&: 9"lC%?sc ryte 4+P  sIl M; ̩/JF*ǯ+ߗR%.(ZTB6@1!Bf~67~]u+Y*U4 Z&\zWt7J"9 Fc_(:OߘsNm3of2`@sbdA4;vp.OPNXQ r"nCx8it{jXZ 6#ԁ3ޘ"ݷjٍ':2niR Q«{oh#sJ¡o %QoovBoB;1Co_z/&u>#NXn}|$Jp^Z>DMF!Ŧb'9Fega`a$6S Z$sN1)06 ~%JW/b֘qD\dX!COxY, Eճܱ%tO꿆U{ Cx٘Q $g*B&m"9-L7&XH0%Rc)pNXQjeX|ë4{te8s5o<y97o_ 'ppP9] O8gaZ[k0kmL$3u)f"1 )u.vVHЮDgB09Ԯ֪|nOhLeԭe75~|N T;4FoNvh_(~%2`o؋o y1S6KQ?)kjmNv{ms8WChoD6@}>RyE%غuz%6&z#Zܡ]Ŷ׮ bY^y0XuxzɽUhפA}KT"}7^N[:u:rԯ弚tHNآokխcYoGƍ:s.ʕ D##bc8 .UTTWN;;F;QS:vekD5#~|ܺЮu~Q#wٛs!Gʩ:mykԎqqOϟܙ-ZDFFoy L)Z_tkj6#oǮs$ܞصWϯW|q .(R$6oÄFbБYMlV9%GԉIJd{sż9ʋГl߾K+gy~J~1Ϟܺ7\uhQNٙGtûSpH%6qk?Z%ԉ.iZ1Ӄ;S!{zS`KuJXbLxx]9g/K?mڦvN]zYPZRsi٤9U~-n۾urJsvSڴo,a(Qܱ@z]*/;< D"|w">)MRf$xxtqb|%7Z8$4O(Js[6N5lָ)U֭jl<|)i)͛8yp?eɭ7çN i%4ѹj>{nwfTlOs͚4Gqѯ.]ch?0;;Ohයu?^Fл{ƪ4Oh%cxx<ۉs4kܸaÌGNRTrVڤ؄7Ⱥtzt:=:8r0HߓbfuR[jݲkNg|lΞyHhXSۧ$]ancc._޲s֏ł⊊£pw6'{7t˹o'n[T͚5fU\zѣ< zsZowSOv0+A|{ u|8bz#LnШ3t[M[e6W eew[?ߎ]kڲVmuwnzޕT7|Z'nJ6l%x̓QDyt h}X[]{?/@$ղjb9D*!c>Px4IT+s] vBkծ- Qŝ8rLaiݡmTq ?'uܺa՜+R|,1To_rM]A?p8dh>`V~+hrſ>6fǶݕl[4˻pT4lXM6䔖y/_+4D~npEb {r&3[D)!F$eAH [ ߐ^Rz1!hHJp8lR\Zڹ]nl|g-W=;wvV=R72RHf%&ѹ _ѹsӵˍaw[mڦMߞ>{OՉ? "ԭYBX-ͻvnn?|?,8un=/?Z:?TMxCUO`xk*kbxp9wO9G6Ϝnmlo*1tc^^ 5:^?}ce2ٕy~>jΜJ˚~xv[keo)ˮkAm ap7F^ G01`I71q_| LssHpCFsMgOiITX>a._-)+۴4vl^5ݍOWK-mu-uD)ʆO ni3٧.^>%ÃĄ^Nޟҩ 4ᵫ)3g8;=ӭVu )`4vǓcLJihjnk_n6s.4u>'sqU(@ku垞ge}5ٻ5LMjSɄ9Xn)ݽ dLڮ>$JXt0GH{Ϻ:r*y 7Jrec9R%? VAQS@g=Z zb.J̃2iWO/KI ?x{_HpP~jr(JKJ) Q)yLJF_}1zcDm-\S8Ͻܜ̹HԄHJ;tL:eNe7w߸eC1\8>ʻ2 ŅfR`cLг)9!Nן/,gg](Yٹe)Nc?ۻzx9k@0mJ|Lf58,[x篧N ʪjbUP RP(w*UUU!#HJ9]G͙F%~qaQQaaFf-E{S`ED >1!>1Nz/?:`:n\n8(~iSˊKy@^+7k|[jHζƖa(p7sCR@^NLAԓ:*a \k*f i$\T8Ӎ땗KM[/̜: ã#+ Nxf/[9LHIʁ!ݸ~< hvs\K  枹H]zy{@@Kу(ؤث&9\"*YuiB/xzxYH)+˫=<ǍG+˫r/v '@9%oZ.2N78\g8Xc% v'y=Pxf&u3 cp\r1n);~ i4]H׿CQ{c':cétGU]=q;uuFGeC=d{TxM^h4-*dnbHpP- JKNˉӞk5uu-rp E%J=ܗ͛;IPTQ~#6,$bRpgWRBJ|g]ZcGc/;qܑ:;@qY9LJ Hll:;〩{`sfjp؜V.srr2Z:Z:4p՛?D-.-.p_?>#\W<ԥJ8i9!иIQajzV2\d_axLP`r6l6:.MSw{{5044tI*Ґq6 X{k`66>.~pӺޮ^SBSbv 78`hs Bx C4htbbA7&~K!pg~n9p(3H` ?a-Owvrʿf4 M7:n O2%2,TE)2Iե֑oϟ~R(#_ Rul¥^fh膛++,0`ji?`b8ʹi( #2oL'1 !BnntվJGyu Ezp,G4`.^&?HYSs=1:\-Hګh ci2պɤjMߡ@٩ + ):*9!>Vc]*2!RzkA:}VśrK@^UOϴ3^Nܻj!dFʴ)p39&Sii3arL ~\Td u !nnnjd)SD:ft!ÛbD/r/\1+HڮjmSiRhJ]@iZV&5LMO2OH}u)O rrv&yRo8:;@RzjOTB\TB\GU me\-Dg_ Z 4!jʌiAѓzm5 w߹pJz:Q$犓S_OԗJh흊 >527׉ah>S(|e OCM-d2'\44h:_}'bkVFZIQ t4uPCϝ0st)ZI /ؽL|C`/:$aҘ͂\nq Mb oDdaHB$ @Xx018ˍc>ķa&˹^M^ܺkk`ԩסbXAT޾{&uѦ {q I,#*bq$m4cJ|cS;A5- 4ofMMts5?!/d\deJe>)yM*UJv|ՈdIJDk(j̜^V[G||裌ι>*eMFGu}cK16 2t ^={U:oRƱ~d7?ugX1:C쟎&̙A#dnjS5-w8'7 bİIJ_"Wѩjj;2W37zOCjbk5]eONՀmw IDAT/ͽsF5?0K ]Ycd1s MoKРYg:99]3b4|CdXoRp @ #ir ߠXq%0fnĶTRh$2̞:5:,W.+cBC[;: ,hbyM-ݥ..4_lU`z\B'^)2z9yy65MZYW}FtH4RJ]ܝ:Ry]?G}<%)8CLhHjJ2KJRuwtN>Nܙ3\NIQdKg77Kz5|c21dE>i`' o WowO^$r), vKB'j͝*8)5K{}('pIVFꔸ WWVu8;9JJt()/7}VX^! b{5}dBBO\I`#޽TfhTLJ >kp?EJ%\U*5y=K @_Wf sWar(4662>ڊ̰899dJ 9-U;8Xr9n‚Sf֔Uhdn2uJ0YחD h7~ZR έK`KV7Ow^eUƍ%(vδ8F} THMOz_?'~aUI* )|贱]]:r2C&TcnϦ+*)~O^'@@I1Oը\t<*H1b,q9@SMCU@e´p5*eWvqIq\SfNpv}@V%S ɇfk70-L|-F|BgpLOxܣH04cn)? :,+%%NcZw,!2,42,ǣǺdH(-$L8ѡ!}}ݚ~:-9)kf* bBCz5 < ^ѫc>r.;) ҩZÑ_bU&%굩qXNuLzdK3]e0:_RtG+oti AmŕUrw)ё^2L^-uwߥVT3xU|3A*fƐt{{WT_T\Pd.0Ĺrs 0(Ζs.)((hV,bD6]ɹ4+sQO:3E&8E WxP^r%6y%c񂖺%JÃ/nlf׶}c9}}J1{Kp >SY5NQvL>)(\knC1Z@qmsK-K/Uc@{ DҲV'>& zyz 5%Cq@^O*4 &(͝j!I555w43=w+e1~>ꚬԹ@߄Nu˹3 }MCSIe6q.rO6Zw}?-m>-!Ѝ!7Jd%y7 .hoꉍzJV08] ~ct%454r/7cz&hzxx  NI{2-fiom=sؐVMɳf$ϚApT\5zߒAQ^r!"߫i#"Zݰ N3)XUC.+hlXגf:rߴ95efm<{z]U?jҴpsRp|su]䨰) _[KK|Zәuq!zږeXt<ƹ.Y{Xz}n.dzzH(qَ؎о^;x> ` >$cH/l \.gO3v7ޡ!^?߷c8f.ϝ1ksF 4p1ߐɈ)-z9/1ހoL ,c%1 ѣ_#z~LOu55O.61KC)j }߳6^}a21&2i^fo?A6%12ύE$ ebúp҉"3q4Àf00rQVzj N+QCMuhcT:..0n" q b@M1wvvi%ÍIfyɪĞp4`L !WJ<(e oU[jA“Z1*&pp gVTEjY!8- $UHL$t}]XFLlbΤ=U%Pʐr8QBt92@4Q08/`Km7zuv3E‰!pnpc{ll=IG`{w0Xbn3E=,>d#s@^ WW2v2{xC(HUc۩O>mJ0ǖ$ֈ/ @4H(+¶e .d&l2 dcLPh`~eL o!5p& T&p&oHb.%pxm?ܶ brDЏ0a!ˊrfl#a#KkG2ȸo BvntCk̐ 넍 U\&;qH8ټKAb[3 %Dpgɡ0ئg#&4~]8YzBGD i̗E7aL'Fav9X:{*GpKtSN1aL |YopJcj.d#oX.:zfq| LqC/!ၚ#<эR@TMo#5o*JvыbΠ ᥬ\ WO,78xUQ n &ج7lf1Lgd9EQ50 )4ކID 8F Y+F̻ml%9EVKgˋzF8%9uoeaz#b 4s Z߈D ^mIc-0F`36Fל*BkPTC8A|m!Ycۢgzl(4r% ?p oddőqFaAic44ˉ 30We!^EXy5+Wr@^#\CxVO ꍺZmO_l%h4YYkG-=*:pfU-gƘ!K'hl Ƙf$1ޙ暍o84|6J"fg7@7Y.پ-CbMk"Qۺ{Fl)1>>݉D̽ ò?:hTqb1/?%bdIx>|i Q-9э ĩqtB טd=Y< #H|">6, NkQaxmQV.=h&ua7tM .* 4Nƺ.ou;L Y-x! " P&A7BVIFMQU,IYGܵ~%# OѰHXd~ìb'?H;y,߰S0a1,N3O ϥo+b9 G7i8xf.|gi Qt| .[8FȂ<ρvn:y<ΩQ@|w<I D?b6Uu/' S=vQ}X6x yXp8iױƏj|#jR 3U ƔAeSz sbcn8MPl&y4b1|^UΩ7Fv1cƆŕh>.59FyD[0;b>袥mu[}Abʋˑ@[% Y#'s΀CH,;X1Z17@dh )_l7ΩъoDB!o p qp `@P~0B$wk֨O@N|0OM3&W E%{wR{ mi #]3^5qVJB6u) .a- |(p,0[v gX aF"nXϔ 7E> n0uE:--ܘ% Daw1oC4Ц [bA C_m7c|L°3IL]&a ~½܃yG-p &atebDZb!Jfs,.nY1Ę42dB)YٍAjnB' qBC࿧ơ7Lbt׺[Fx%71xcb =a``As>(dUAgYJtPصdmi9Imɂ޶nSJ a01;'K~S3HLJW룄&ͻ5p9 ,f0BDY`CV5Y'6ؐ,Mcm7]:̹DŽ j6b>vm{ZP8IC  KcSMvk&Q\N0}{U$lVo̯2,Z0c`DȰ_c8aD#_*]l|Ï8HљcEE*ox;=Z4CDo"6ij/82"C~vᴏQɬWfPom~.x(1Յ67+bO4# =XPUI&Ta, [A?.t΋f$9Ơ PfFn#m@?֚F^k(:aXU55S)[oR ߈$ZD\((qRh|c2Hc_r\ ?ȣYo/"nqHD,Hnb4X(h[0wIpp#*wQٛlڍ"!Ha "Hbb@=Q<|HBO1kDAl4Jw7( 3 9%`l7|YL|#RF-s"fP׭Mo[oB5xއ9$+Z7!lb:ɆuGB"qSvn^8ABMkF;jY*{1L@HɌTzj`70h饌$dfC;`ܮƤ#OS8<[棍~p9:Y +3MbSD-.""/`agFb\ 5#N4iY_u))b8GF߀Iтc8< P#z$1oH n7YAD/Ay" o\rq:R5ۉJ dkde|"x;)G? d .\Z"I2R6iQkٽ^/Q=`t 70 q>1G#p>tga `f5l\П^ NS3Hp l%kj'3pݓ&p;O+oH ƌ+3fhh=ngKG6/OC6g4B Б䰛a}NjFӦ %ۯK:̖9G<慙 (xѹu MXa1 ;F9HSG3 ӬE@/8+$Kf*0lS+13^H)+ ?y^:h N<2=dc9Y}{0Nӧgmb5^ }jaږ0A=r,(+! L0ZY !8XP'NK$0ހEï pqly %,@ :F"CNedvzZh-Rٖ>dd1o-!;(1n1oP KA'm oE*@tNQXL#8*n.(X BΉFeBln1^ [~ Մc^pԱR v1#sY pDV;j@BA罽1G qi49FKڛm o0 C0^ʌgˢ>l9|PKCpl7 Yl׌%Ð߰SLH|cnDno`(`fp1gvq D}*&6k tC9avv3G5aш~-#٥K71c!0Y7DZS|4p@aYf67O6Mϒ-J=,9ag H<AT)㜢#9Hit~&D3,g 35ܼyi E=d~O"`nEc&%Wi<[Fc=ͷXYaكij>|ԙ|P Y|L>(Ё,3,8sD߈0ޘ8jiiy^oii'R6XLaZ%RL߉\0K n v@Fvp,8[`}o'Z 8.gbg\6G”dV[11T =`y)a3!kX*ٿOmI@Fj;례V<1Gf,-^((ZܬFK! A_-~n c_p2=|kbpG"F S)1{Lb0o11/5ڑl4YR"ݤQDl pNR,F9,4(`\Fij[+ߘ{-do1F]x9G3x63F07Bw(7 bbnI[!CDJo/FdyUh8?GQڥWG֠J gr `(+fWs[񍹂\̲yY|.-7V%a4<Mfs?~# 'Vj q$H$d!v\3/AtmJ4H|cI(q82?N 5ZB٫DrKo1f1Q*aQr/%ؽ @A NC[a8/ "1XF@oUG9bto.97A ~֔ A͜(|cxOb 'eX79e"K/c`6.&ı y7`|;q˰=8"'ww[>CΦמ:)ĤzҒǻN}Dzsdku δĉ~$N:7uEw޿j3~pJe :=vOf䘥ͧnI0ˮ䏟C_\Qɉ_Oھ"7֫˘1 ߿EqR\XE rKJKX7{ޞv<}fJDH0N jnk̨пViiYWw^/*"-n [R_چqKlӒO7Qh:>ާ}HcNh? ։xp_~`"|9=qE9di6rߘ)ƾ`kc#ĔT!R+4 t1nkc_ L`(~z It/j7"]I@ro3vdD2$m"2cm;@Pd8V{͛9 >s6$8׷›oz{z?s9nn9Du7)5w-&.'GG(}eSK녂BX'4ࣿ9M]>3r7aNjxtZ7Wࠠ |78(pbN~RIzt77ࠠgly!CvDJ545wTťeU?ʦ.Z]K>vI\,(J߶ekZ27c튻4dg墫]=RReZn͝-mm[6cw|W"7=)1#-՘ pXGWqټnͦs>v<.&fͣO$%&p {hâ+twX}gz;^W8)(0000xbPEU ֭]# 9鳣"˴95 'snƜ9 J ##VZPR;I*Kgg9}pA-8 $qܑO`o@> ~ŗw>_ORgݽ_FG^_dqTddSso#ǎq{ɞ'F[['pw翿px qzWW7=[Mtw/_kxqۋPQ^ҶyqtU{.YĪ闶/Xxu:ݚ؊er͂$BDKݚ #f0O.`e31khXs1-1(|#R|SNa`#04an,F'1}fI$.ٞcMα_$,ٻ/rni] pO?x?>&'޳|yqYyYMǟx5, Z𙳦k W׬v*ۏw ??%~^x/pX-Z_X?9&~r vꔤe |^(-+ee/WV׬\zנV{xCSRIťs dijn 2$(r Ӓk ;rV/_byvyݸnmyeU]S~?hˊOn2{ɽ>~ ~k/=$c9?|G{5}~soɻvBݵ{nnKߵ{O1iOpC?ҫ˧]g aŏ?t{7=w~>'7m<|xN~7l\w=>qŬuvw[ gN.Xc**vܛ Ͻs_~Kߔ|u�}jIp *IQQ~8YQQI0(@T&\E J777zbs{pwwWׇ|Pp) Gzubf;B$`xl0ncLG,n_D `X8$P, V,1< (",k$a؉l|#f1syWb$J/pcll7#l 6$_>s62@}: ^VU?ʤ ?OyE߿_'7`=_0Ӽu WזWtݟI+9I?>:2B`h8|K6ݿ~E?:L@۶z{ݼQFGFlۼ(nRw7\r8DG@-vcPNTySKr%ϯ^DFUV`sϽ̛晭]]]yi⑻{'>AEEE PHi鳷l} L2f7׿s+N-,(xlU ǞNөڭ8 0B9yFBS.3=Kq~ݵN"SP99r4,$DP\r%5%峿jhjKMIp7_yq``?`eA**_{ÈISFUBdHK+/߼qOLdY?1=Y´mյ|v/->?'ۻzTpw/mޘ2mb`@Ye[ǻoj\6&2(CĥT*|mKw>M]^Y̖t+MoikTv4XbyWWj͊~5_߱TQEU'N-,*IDzeekE h+J]ixmyב?EwRtc8aOrxtcpH0DEGY2mOuwj|r kNd'Ya"?f 6_$cx;x#ҬriGC@d%\|cF,㴘c[p:eyf VI{oFl#/7|/{BG_ʻ2+#!6"xq~y/{t"=#mV~aQRbU$߯{ſŌh k0CRje HR\}9?U&[000_(J)c= J;nnnמ#Vu|Ͽ_/Tѯ>JRtAuk-7Ŵ?L*}?Q)o}" Ud@Yu L~!ȤR2oбi0QVYWXvR |*WwC|q%r/"zoW7DL ~f懞\jI *JȈ؉iۿjŋ~7D㇩4mZҫ;_il_L&V{ةS)ҨCPF)λmxhnn.z?Ls)&~rXdDpHdTz9EF,LqTb陲)!؆$zQVa8)<4( 2(άb2ka$ ¥!u1!( c`Gtq3N6wã |gϮ~ Y{9]={94'u&P_f,`ރ0|fjA#@,~ S'L`ikUw9@xHKl)8mYER8vp LJLHO_X8عm]?9UnuWWCS[ꚚV^@{gW^xvӧm&n3=W!sDN ~&'&@xL~!HyY&f$o-_wP0>q*&2~ӛ;fSfۖG$NXy/) aAubHCSq6Wr p3qbСG]sfR歷Ȉ+W@nnGg@5Zhiڵ'K)L1m[Zy)1V8zd^^fǮ  "v4FYDZ84DUB7*FH(㍹Ki7f4 O%nA-7%&@\L II.m\M-tz]((t{ Ǿ{Q*p",!G0g,mTloShGk{̔ >JJu q11gתkrxz'%&On(Ɉ kMM8v?}斉_8[{Q|6}4BWqu-GOAҔիky1QrQI(Kl\^Yr  8rcB)sAX鮕9>cZGoNٰG㥃GJңNsWuw>r[;f{{ˏ^/.i켐[p.o InV\]+0_ںE&'&ڽgǮ~m=l;kzhLm_|oZˣCw+l۲;o@@tx(_491~\~¸׬.zw0ғjާGO_t7p߲ſ،Ew"dN>{bF|Vxca:7m˯"X0/ 3fϢW+/Cm|'_0O| {A2YiI鞿}N;yoGV_?&b_¼|/?d@(,*rs`Η.\,n*M  (MQ +`"ł^뵡"EzHIhi$v{s <<33,:s~p}Ψ#FSP3^]9_/4P:ѫP!!(%b"7$ _< |a$ooŸW_1"9IP]$[QꕗaaVﯿ>|y5O>0m>|w,^|3e{0?iS&K1,LH(=]FsfAaap対4f t!ۃ3={O?k쫯ύy}cΝ:M26|^9}q|K?jg!_5z'}̍cc/s˗Y Uam{u߹w.dKK8am&xSuMϬxog9=Б7`¨RIǍ*XJ9gݹsIfhE;_Z d7ڻosزg}ryYYO++)+/wkI}o,尡Cge*LZbTC3S&N21UmkjjVkuUDGw:8~8dVێͿ?txuَMP[vZw5k.**T8Lw% 旘h'NCKbKaԊ!0Q$?6ƭ[q(#L\ث92˕HR[F(ysx %0(z"vq݅d͍hh#.Vv5R=~}=[z^qI^qIDX,EKko\K-yxzxJK/]p8f2CvPph#4bnB5wQ^qx^^aQѼ鷌m)%$tڥS'~s>r-7qw:>((]]S#>ۏ?mkW[r6nGoĚڠqgi3磌o ~ǗX wN"}vP:O̹͏>{EK~OOKn GJ%/>xH{ sqQCzͺΚ'6HQP]"#WCpĶmsOxh 2n2;$ư,'|l {nW̞uױ½Y9d[ؔƏ;]^~q Gl7mv62t"t"$!6O?kunjiSٴ'pr0u>{*U>#oy?(1"#((?z<_r 97sϝrԽNt˗.X]g1 JmuM'߀een_QQ1u|7u iI!4`ȧ, Q i8ѭyJeZHSC6%Yi15)n4l. ("xn 'Z#gT"e2KK=IIo ѕ]7if֧mܱ3<} ˯T\}9yyT3U5 zIi))Σt: NqV/>XoV7u쨑k~\W\2fpb`K.snj<  Z_پ {MVNnP`ྃ.]_/_ Znu]Ͽ쟚:>chBM"6?4|NWekjyVa#GݺgڋYfNQ/.[B*ΰdRFܻ_禠*ɝ0jQ?æ Tŧ^n#NJJN^8_Yy˗*^lh8VT _\>0-eoVӧ~:ǎ]g~s[{fqVN_cFܧW cOY㺪G? ~KjjN5k/]rMvٹG+*|{廢ڍ9-!7:%%*+|fu=q͏bIy凟R}l1_[|;t87߸Y3/3 ,^҅/>= }vHZtQs ġ@H| ߘ8V%-OL@<F!A", 0j R7;KID\<& ^!;57W  &XU"EׯU'\.Dk?oXtC_+G8am3cmeE_F{tuG` cùaa}$V)D2 Qpɹ!2ҹCD U)%L?GtQr<. 3gL̊S:vqi%3vaa}Y7clMwaƛ7EnaUa)4?iF.q/W՜}g$Տ`@Z2㛆JP_*D*+ATdI7pb 9(1URڗ1=ZoEԲ %yT3mA#.Qr)i_r&07Y'"L5(J QDOUx%WkdҳUY8=$μlBF(Ho 2$&į&PdR/X5$D"%2\1M? B+ą$Zvϴ6BgE01zYܘF<&jŸK$mNt Uz7R /[D FcLYgi$\ C@*1ia)Nkg@w^.ŲDgJ*'D28E!fCYo~jFvĊKr.v bݻG h] +젩ԥ&t 2wD&&Fr7u˃8ƫmsU>f?lRflL.Q9#@rޛua۾1YON  ҇$zD*C ιaeslHjJ%;"\I/ a]%eLC !`r!+֏ִd n&%'%$g圭)bdoV6DIؾ}cekT¢b}Dw߳rVUgu}(;$vkضձ_Jjmll-(9)7~I;D|z 122#y{Bk~ tӉ¢E0qTƕ+u΀+>aܖ{56%%FFط~X 1>;YZvZckAE0w4QM'&:hַ1Oo6`coEzjͥ=$>r,;na6bcf jl?uSJұšnZshty@3707x8u(MnWQyl|xg<>"*ui*9J3f4?!CtՄ)>A FĊ]֔(hCD(Ļ#+:nҀoܡJi<*Ҷ $(o Ѵ$Idrc12Oѿ jLjձ5uu}DlYkbqQ%OۆGo5:t"KNV,RdD8T ^Jl8e'NU|_rQk#a?dMa/*}(1`6ju=߄5ЩC$W]./)H^AeE,PUݻGBeuun6KZ͜/"5!2b.|#h~cYMV^0 )cdwqխP|چ\~:F.jQTz[tGpGEFH5hlllll3j+1 ,EFDG׳}K/;PqWH*΀=^\#>*]cuVGPf*naꦝ{{WԎ>l[%(n?n!lJ=㙳چ46^okfsJJRט.e]PID-rH A!zXyH<zxx5+HCta+d`$ʭP-C4tW Ԓچ@ۣW\QsVa ;Wp8Y˧߮),*v8ťеSǨvv"ҩ3z$tnonOܲu;aBy-ԉy9-Q73¤!z>Q 7OX (gLj2p@tɔ&x$bWaw0}$-Hps(Fp)Sbo۳y*74<ˉ-4*{!Q:窪.7tlSX>u0_ZV *]  Kn>3oR"d\IdNPrX89WTV9#38{ ޾cvѼvvVKFظz QCܼ>U5gN:u1nogr9WYik 1GN-(~@JRm]}\l2ĥgXO/hn GuuW8!!U ]"]D.T5``s+sndrUbeQlbu]Isi飝\q 4,Q4N)|NYVGNdJ512IF4I ) 6L-hI!`Fz"G1l IISX\n 8{>>6lU%t.(*תCx8_5еstf{7Jݾ/+ XJO]z-[W8wMpҦuhp0&իc VU] }j/5;;Ջ mC۴f ~na![f:DPeiӺmp:Dqjm=1Kkh*imPa4ÎMc%#e@QٙJ)!ٹ#{8B<1kېHVY]h@s fj,_|E*:o0M>i@j'Kۆ{"alR2c' 5׵Ɯ@fúvcyF49ʺ*(44$je"jȾi7o:e$yp$uӌ6c}eXnK(8;]F?(SPM&˥x߈lp8zLbqWH#- LQBo!!Wt Ѩ qȆ^m IQ0Ցy j9WY/<{0؉S+ؖ)jؐ $pKcccpPPĚ'W= #bi YɥeC3ѣM2p@,'GoDv(z4߈?G/8V&hp@(!UCp!jAB6 n_OŘ;zf&Ҋ3A# ެC>Nt<&u ~扸|£m%#yG?eزk/3677u?oѡ]x1<kM\+\߼gh[}{UVu\{I7oll|q(xEeՠĄnʪ=^̻.*;ӻGBF8_U7;֌=3OFwLc'?旜jm6*9 w砠kl׷ zZcsPieuuaqPPTr0(ֵg\lϜ,3& (pի:ٯ__s+H; Y)o4&|TG$R6Q?zX`OK|d0 cB[p_ $'#H4EL5J})ʨqC7ODo 455'7@C]/]=sy'/ #[]D80?"iFwwF+._fLۼsܾ!TJᄙSc4#A O\eF?c%!! JN-8ᭁGiƏ zCWD|o~#,Gܣ`a^=~fO ;D)&$Vq`ƖK5Rc XrSq7IXϨ!fdC 4xS,,gw0% 1a-(rpi(. MB\W%V}yX5AP$[*qG:O*b\d2Mz_A&6 FjnfN\g%`ĺ4VFxQ[Nbh}dORۓ"ai_1~K)+9HDHGCy=E@oTxE~z=PKd'ݨ@Yz%61GɨLxÖg`EٶD%OzhąXQF6V|EkDFLqnCk׼F:FҰD)e}]I&h`~$QV L #ie|P5E)'#ye-M( =bd+!;iHuFpN!Fl N͎lI_t-F}Y52 Йt2`/rE# >I[Dc\wH.NM)\1e5vRcрIG^\ Nf~ A&!&CwE8d8kSWiZB?M (t݀43D>tavՖ7Vy܈&z& hn-Yrم(Cx eƬ P`"9m#f Lz.c|lnA C3-k/>J-hQH7l2R Jl AFd\ ~ ChЗ%Ya0yqF9@(5@L:44W}$!J| Wޘ\bvyҰ-iV٧e1?ޤ2>kOYLzѹf)OZʗRVP1<U31Do+&F@hwB1y0&H$Dj1ũP3x8\Vϋ"p&_)g,q5A f5]njWWGh#Tu :& OOtRדj %~o#t1Mb8whvXp 7}~z\B897$'PoIM#oԚlHqM265vJ{`oa\<]&ebgnr#ogC6>gQ}@vW Ma|tf2䲌tj1O@& Vc:DgY<ܣCF&EHpz.O. J_G)( X>$暗dۧxŒ$3w43B´O3Ն udpiF_ #O5ORtv?  j1L/$E-ct9Z52yd(t8HR BS8f sS2<6V1.5pWQJmy{옼ѤOaG"K@.f́5*)(Eek(G+ P59I)HdML4Q{1[57H /~a'I|I7˗$Ri_A5.x")f莞1yAB;;F!8ВE=iA7\j''e4 QN3>"||"XU ;iˊ+Ns|:&HX;4Mv?~o_Fklx$$ȕ(^ ȥ7 d^BrcO%کRP!ۥBy#1J0 qrpXÝۆ%]ї``EVTy)Ĕ&PD2-4Z##I /zd5n> Q LtI"EQÌJܢ yf|#@3\@sbH0vBz5QܛPةB:gU8Z(J7}mzpucgoA @6޹IYwVC^ ?5Сl:mL>0^):6O>Rވq(QoEQ [FvqB\Q9ߘh0-8 DHBȥPWo{G!r]UPqX9OCcn25*ؑX"pv(7_X01cLE y%DP(Ju!::-((Ga%;p"O6;&Ȇ)|P4M‰|PZKS8LCo\e"GIsaU8ߘT'JztEx¢ F^_4+=b?H#a&N ?&”N7aZr懋~KWi4!f_ jCLFfx8% f(M(Be6_HI Ĺ)X$*7JÞ͛n4yēUKa)~YA9v +0 Æp@\SH舢PBϜo-WK\ ')DuUF@ X,[@"j^OM(۠]zd:$:*J%K C-@IQ%I!REm7Tvruc݅}l0*{xQO^cLlj}k#eJ+"} ߖ /#d q,Δ#t^@{0p$OCgt=_Tj*~LMHJ22q@RSdUk޴Jo>_Ien:wT95k:G|Rk(`Dcp ^ػ9!^&X(`?ŏE`KQOCQ*JBȅ(`5 B녴f=5;^_0rPd{0 :2 P e^z/6ѡnUd+swi4b&zb/dbCC(#enƊ>W nU=ݳЗ:$Vw 327=.M3p\bkLJ(t٤J)hi[[JBдPpF* oFL`B WPWip67wzr.ee~*aɤoTVtM"9o Ϩ0 uT(CJ<}إGKbI8V$0,}vgeNF~x| Di1 &L|h ӈRxE֣P'o":ĐO^1ZaDToRܟ! !ORz1e')p =zhpQS(l.>aIze4 $aZ@Q#:a#&WoS,jaЬ!ƅ#Ȉ1|12B+i>1$RUF@}4FD}$zV]\y3.1%-\ɋf܅Tu`>y:g/a6U+?,5J & ;E$s"ڸP0nw`' {VBS{K  O}Z,>QӒ;KIb"Jۙ1'aS# FpDy/kuZ].PJP`Bd+(A G."?"9IzM?0k$[11#PHKZ E7dTҰ'KI=RKP O-ODaGy-#CTAa*l UɬJܨɋ]%y7Na{AqJQWkb܅ F ZH*X<5dFʹJgT㐍*zO#vNdt6 + u!~qY8px{cYLQ$Nmjv})g cv@#.$z^x1N)r1OBG4bcc=\|G2堣HYn%8ͭDZvkPr9}L%6Bp㳚x})h2Kxp OA˪T1yAzI1*IϒoPԯ!=lJ)AaLFraNwP&HT8WKt'͒lԈ1Rat/󖬼!F .Dk[V5hPؘH3HM imI\qpSbW6RyS2;%ʌUk ƥsJ劯rD&7 Y4T tF/glCVZ(`LEX AD}|I^CR_xcM PY0AʜpdDli0 hB 5%4@$ROS&["^Ӡ&`}*)k@6,54+k+huYpƯUS,d3 z@q#V}o GQ-*m RZHh\^* mR hC9͂BcxbmR7ʗT+|Y#Y_T> * C֨ nMLhu9(D.JKFTv S@əy=l|}~zZ0.˿G^- QuuK#EV yp]IwcӘLQ>(q}~֕q3}s'ʷ%=u]wr uGBl uCuWo85_2<#xg٫%%3}_x ƍ.Ғ%1yfXooy~>~x:"3'q1l`;[-?C>Uk=iB︘͚NHЬIW"41#={YKS7{{ 64-yݧUL&^/"lap>nD OH){ן ۞q+G`GxÕBZs}`>*nxD_R}o{}wJʷ1M8|aJFgΫoZtuQx<@=CWгTވkl$QJQxPT2BrZ]GB@2Za2 ^BpU7͸[{C55Ҕ,{چuعgo``஍^$>Vɓ6'{&$D/]Ɩ9s 3d/xdL Nr/ @|l̽:sl~QC;O헟~_PϲuG`@@tNw١KW>N:t<9#8γ#0(stG{×._ ]]DO,|ʚZo9eUG+(.AG=QX>^-8s |@Jin`ޜ_ka3Nnhp{0mb>̛`XytzwxM9ctTGbp#/_?߉5}Dٹ>{(oJ}~Ǎ)/t8}_O,~n.;uҹSl͞0noW}Ӈ+++g'yİ`XsN"(ù}oآkKA&O#! -D~VEGTF6*z#N3_)ydK2J amd.'UTT.f cg&8(bq>m={P E <_{QSS6xᕥwYwUTTX?޲X,wΜ>e-6-!!dϘ>pZ-qqܳo6f{55uun/64Խ>SYS;~xzZd0<=!>ז> :=NgD Kmm{9чE*ef_YXx}ͺ/避#[}=xyC^::nν.T_,l2srgϺҕ֭珺T=/%i葏=”c_ZQ1rlϪO |';Du_bmK=N)`+:7WƦE-~t:'u㛹掛0&.z)f6/t˦X\nN2/2Mrr0"pi-8s=h-Tm$  ց]iP|#妳o,Ic,d0DCF^D5 0_r466 ӄhi22ywˀO~/#rbfe@|X翿z}M[8Ɵ|zlFq1.ӹ⽏zg{[;o ?lpz]l>?,pN{{yޝ1tbYv5y™6o?z?߰yw;Y/?1n |KO[ǍuJZ,VBMB\ۧN֬pX?za 7>ׁg {eOȑO?Ywfg<)6j,Na~!^{zwվ{__~{=m6ۦ?^!:H"'Vu:U8ɴ7 rjB:`l2bTvm68!JqqU~12NԫcF&`L @q ;!p!0 q VjO>}ɅsR/, ܴeZx/} sr7lB GRX| cofLF3 V51=8X̞6uO?wwao2x N7 ,=Uv2<\o[׮p?_}MV+=}[w8g64\}ѝ _zخ?y+}z!זgckjjξg۞kh-A+,,?[UUUrhhrM]A 3c҄}SܕK/_y.xucV\Y xwḆzƴ 1t0:nLuM+W,=e` 2vE #mںx#n.'7b!)-7^]tm;KJJm)?qx(X-o￳ .{|ۮ[.c5 bf9^{=˗/_8{J2mLHLhR7-+X qLZD`bXk!i*3\)0 ^]Dz3 BVh:|Q2LvR8l#.LHkt1M&:F4.1.Qn/: o zhޜ݉pl۲=%-L:~ϜxY^Vv _6u\=m6[yY:M]7`0{AȬJWJ"eΌE 8%uUa(vQ 0Mwe+]oR*o ƑQՈBX5Ӧ+ݚ\1 .4$n` Tb\$\\o}'+Wla}M֥S/dU5a&vm'E^+_{<>6=f)]sgseKIپ=oe>w߇ 7];GWWWlaYr]{ܼX"S~~=ܶm{r;9i)IC }w٫;`ݷr;}jjjOWUW/åe'N8Y|e/,^C:֟?7,1e}=+뛒yyk..~u,b9 v[؄#'%{RFMQC viwWΝ{kW.}itL?5WKGw?wn:2|Eh=`]cTcKݺ;߸I;v?~kK@\|iMU}Կ<{^vQ%$Gv8ΚN{&KP[].ϧ~|7ôit|@?i 8 gA6 >IH L5D`Bxo~.!$]KS0B/]&O8Mܪs3@M HA0@q[O¦=32 Vֺ?9ܤ$@ZjW}$2sN .=߭;aؑ`1\!9Nw IDAT P%DEEYw8:wiN1#-K' {ڹs1y'K1$mvjJҚRS N7@Zrʶٷ/\to'Ɯ.+?qd~\}qrW2_ź-Ny\|{&Ľ[9d3_s?`߯-*-ӫ-߼`V.bC%=r{df},CuM߬ɉE% W@s % O=|jeg9OjtڕR^W_s֝l_60{b)(, ۼnr-J/"(XTĂ5j,1j)lմMݔMbLƴM$)MݘbwR+s~̽sgN9S.s>/Zb"̿ق /0ILLdG^jS.g%K[,邩w /xq=U yrvc I#6-3^a(kF|81;1oԖ2wJX؈6, )8a)(>7I)sǃGr˻ntwx̨K3jz/'OP__69|ןVQ$O?%Kn@ܼ= ܮYol %KXbL#<iW n~:vOxƏ?pn-//rgNko}]zdvz“]Onޚq{P ۫D(x2jȀמ{Mwߧoǻ _4%aڋ xzAr(XasoϬS7lֿCޞwB̴?JҺ)9{/r{z̩SuMϏHp WͽcȄ)~6lYn؋G_νxOMs/K[?dюZE4q89ǎxz~tUďڻw;ogRp6s—տwE}/z6s[ou|̩އCFe@}JP ͙C@)G;4uQ_? ϞiwſO.ěgݶ_~moLxM+{ som ko4U}+}pޠ_|yGu2 `;?'Yhs"OUXPcFھ#'(S^RѹyA{ %\|oOvմiW^|UN**|֥.]Oo>;gKزeTW_6 6]%Z'>Lx>{ml ߿X{SqC~ QO#5Y^Z/Tr衉laJ/[od?-YbBᾏ%+,h8O9 |n :.42k-7᧋q1sϏ=YRY믾g^| O=YW__Ww^؞sh~͙gꮹj%{R:^ݧ_uଁyy ?p=>:)Oʥݻ$u>X?T]]}g;Lf=SziӦW>|s`^^iv.YvݜAVTTD+m{~7]~?__p)ygM"gʵ}+o}SRs>dѵW_}(o6mݗwt/6R=X__??^ioz _s=zᕧ? a ^RE?k vWOY^eu3S֙;+O>/ѳ_%ILdl{:zҋ+cw2g􈋎;XAс#{x??Q0o}uLeB7" [ S}ii۲=yg޼M @߾Yn{}n(1L[vè#_xŗ{a&_9e#wf|gJ=rpE<>$TQQq7 p#'Vtʹd]br Z/-,ϳZ*otN̷|_I[JHw'@G=oT7@.Fd2.^jjn$G7B*lml#hKf' N&~vu{{=sTVzG++/7zԫg = }ṣ?$/E_4nQ# t _}_sזjkkk@S[{@fu<0aM8a ,[zӖg~eڳ=ztq/?pϿ,5~4hi=8_hO\rx-P__̓蜜TPPXYywۯrd?xo~6و0b?]! jڸe}ݻ?-%A#1%E˃R &)C8^ȋh) @"|5GLFj{:wdz?<;l+j]K*vi-mVRo2 v XuA0M!yW+[ V#H eƁ}?XRT?)x,o,LϪkue|`[:ٺ}H췱<OI#s:A^lR75[1"մl@6L<&<~8Q( ;NS1ѺFC+!2k[<bXnIk0Vھq|?еhaKN+#Αi(o"3N/Қ1Tѽ5Eq9J8p5£Һeێhy GugYb5R% Fe?+0 x:l "!>[.֖-˝`yB!7u6,$Kv/cKIj{ UB)xpfݑK[ڨJ5o")fTb,BklFZbBwu&k!jt @ S*cdȣ0oIr(Xb[yʭ97@$4ከ ol !'N?( l32BmZnq,C-S4njXӥ1aP{-ԧ,YL#Ȇc^?h.ΐ`wMB7v)PWLN`&N>I_#%j[K߈Į6!'Y^LTBl( J3ȅ$k۵Q2miquҷIQXQ[ȲԏPH!NIW= Jo! ho^a8՘-\y`NtS S(@B#>qNύb?1ҁem"F c.L 0JM٦[0eV5t2oJwwpf FV".W/̯:#D-e0J'X_YXw axBx SN<)T ݺmaGxղ RM("8:O6 SxЫI˔+U]4 3UQ" z̨Hd$ɗjiSMbOYƺBDʚqR+h+0$ XRh"6֑P)o97(@x4"K"@%>~ - t6)1)ҍAPR rmڞFyh3~_geL W0RvKpϓ;v蛑e)VR9sX~0J>sfV# ذcgTȋ R9yVY:WwaЁv; >'pA Z1!>w=mfʣVUYUu-7\vBV}{Ա֞)(,?;xq̙CyGݭZ 2`Ƕy׻jVZ@E;wn)]Sw8U3(-۸v2i)u:͞Et;PD!L99D"i ?ii*P%<%a'pJXlZ1  ((> ߔ/fWtu:B8i((A Nj:'̺k7d⿏\.x=t@ ӷWkjkfRI'w9NvҒrii=N!ccczgYI̝'۹cˈtEEvյdekt &kXT92d&8P(mL*x™,8RVRSꟋ$ҋCz\t 6ʞBT#!rPpʕO& T&;0l` OuKNܿ5=]ǰ͠~^@t[wU[wdwZGG)0brvI9|*wD->U9eej2+*3#]*I_ ٲsOQIٿ}-mA;rfϕޢoVշ0׵E [*2@֭: m;~u*//0bXNć +.SpxDˢJB>03/]?S|{ݗe^ OLdf{g=Ξ=YR᢯Wj ޵{\i䳯IKLf݆ mh|ǻ\(wDغy;?mXıȻvuU8vbڍ:jj;zStA}bj,v)jQE6Ŭ |lv %:dQg١c3a̵}قC[$]}V'!@jn{=|X}C_/9lt?~xA1kJAhLbPtح[;DEE޳TI򴞩Ɯt(׻fko< ml$ Q/.)+.)OK!D\7H U0>8Y«;Oẗ A zӶ" |qEJo*"BkFDxw7DG?߸iݻ& H nI qqVf=v3t`\۶qIWU/⮨Gr)[l33Oko7z8SVtl0~CnӖS%Z~\md|f͚.E8tHttٱ+%%)[RKC$y[оcӥ`̺4'p&29l"8+JlCt"+ZB# )gHԿvvWDjmA(5գ[Z >pZ TT|jŚ];1nԈ+VvZV^Q_{tܱò_WO7o!e5z0˵k~`_5/tx)ɝ{_v[1l G7^Wx"X ­[E^<|H?zݖ!3ԟ;2ҳk׶哓K p`srwAƀ };Ku.ݺFEc۵ 5KM^L|ZX p"Sް0@'6F~N"fm(^;'<8~P pMG[igо?)˔JAA…#}"\4prʄ}N*u3n,fP®[R޽diE\0!޳e "#" sRɝs8ӧV]S}gA3;wjs :?7ĵk[]]I!Ъ|a7oxAQddaK}r&1ѓ6` pWDx>>e@YYŶ1S̾?XЬLWklbcnܼcߡ|a'4Xgs?2Ҫjϟ qekGzw̛uW?Qu%c~ZLy\5a\IYbHAyG$'up\G Fݻ/7)Caaq\Xr7z8nڒ{§Q#41^U5/\+**NWzhQJהGW>rtKeo˾ys?{a-NX #OPyf ݴ!S)#[T gaN|)Z: J1I3+.Wή +#bT· )o8좃yQHJ&Q4P=]4xPYy9**K3{;>#gYyy;mL 11\Cݺ6?У[׺z M[|Z݆TV^B3{UT*-ԹDD?oEw ϑ#NJNLQ\\ kJʡGs]TX3GRݺP]]ݣ[׆ y\>a]z}VF ޸5/-0|c' :w6x@o^fUtԱc'fճmlj*Ȼ-'O}b]Kq\+x_XvcQIaϚ2D4# )mLIr^9~L]]}xٺW3˾qo\Ikڼsݒ Om޹Gт"v<^oya/ǫII]v}K%\yvs/ 8Bi=KzT1]:bXA~A}d1;,172qXMQ dZP ̐<(Tmb)2gUo(|'A0!ք41(Ư>R0 g\4FB(xJyPE?.<@B|#RT\\\Zq{.7FT`I8Y\|t}EUJrga4.WG8tTJ;w\Gp({]yAcFPVZr:.O9{J~Ǐeko5 gj]]ݚjPB7R{Pɒ5}{=򏝨n&]2rj%[JкA&$^X'V@x>!ceD TiY۶muIJxJI+:Pp|~nIbWu~Z[R'TTl;M>F9~0˵aշSU5^}{=SkJO[vU b}:e04mL.qn>SgеGUm޾mv!ꟚE_z/D-0TN^YibA'Bc~JEmS6VȜ~ fZ1E5+1t%RcǘnŁjr2_Cp>%$8< Uycy4k\(x7 q,] A߳p>~ibs .gIkvW.=%y{Ξ0յg>Ǻs B{vOݺ":gVp(bDg LS w --]۶Tk:UDޠ(///=\o_wl +9%y䘑vyn2fXo2 .ccx'Fl[~d/^jfZ2P߮'&9hߪG@pYv)č7'6",aNE6ĝ a~ `E>oͅ hZVEfG6"6SvN]R ts-{V3xvάV..ϔp3|DJW=-WK!T9B}!Ku$tE zԟk8׺Udq5}؀=D@#ʫtF)J9W&%<]::T!I7WFQpS x61˸5qoQ=-)akiFx.ЈOJQ)OuAmY&xI5US6_Y 3`XY,!ňsȍIlZЄ2eHv{1T9_!nA4+NNsr!` ;" g)(D[%1dLq~L 4AQ>76^aAwiLV{CV8 Xy *Yeu`J2TވjEL,VIOTNڀg贴fš̓tLKeBЫm['vd_ڃ9U@F^J l34`c 8ib7sGq7K w6)Jd7@-T6I:‘`wq̑E^V*xkZ|cԋыnKFSac'1 !}W*-3 !VcjPIFw#A',6nmgoDT #F#P2>rNSMwNږ\mZ ,bJ"sM"5Q [b5F! QXiY#}jL +UbsPL\e J)pL/  p2Ahjٔ8˚O2Ckn7bC-:KscicQ8Ke;GPPWB`}lpcIE/ve ]'%Iۻ"vľDŽ#άi9a琍qDxOYQd*oDZġ[$&Ug @%WV<[%nVKe*rb8 k j6k L6< Ҷ$N%,E#D%ӱ ʙ ` TB`= o NnԴ`}UZVB|ФF܂)U-K,d i: sϱ98 kH20.'Unj@Gݩ(f57L~yL(.>py41vғjr3Mb]3}VZUlHZ8?yhhp+=(y{0hL XM,ߺbCTwW h7^!/ԃrL2h?dN9,S+Bֽ;F|cŧ\Dqh ik~@XxU8yI#?JR4)x޷$-4~ҴCa AUF}A]F쭪Ay!ع29?T>߄ZJ4׌BP"$B 2=v:jRZR:v~ viD#JWm8 _G R$;)iOl"L~F`n2fRq@-1(2;6*jͧGM#2R[S3 9QVq˩tڪ*+3))h];OхPp6 p0[FVbH~TPZ8IgDaQA?(Xè?TkjVi5:ːnġ7H5KCUZdev`bI $!~nDaǗ^EO8M1=uxI5N |¸ JRRlRp$%|ſ A/"XH>8"Djb =mhkTSsWs[ߓMq6E0e6{0>? [Sʀoǽm 6,lr#L*1݈A' b1Fԣ-9Y(5ԛJv zEpr%JDeq ܷEiv*hǧ@ӑ9S4(qKm'rM݊2j}PeDvV>-2c'Jh/׳Idcc+AFN7H%g/E6zsVLuŠENX!q1jD' dg*H)o?Wqpj@ ^ÃP8kl%+p lœD%p;}IR9WZvxSYDR1Sf$.2^1ǺqoeN7:fHb K\5r Uvr \HPF=+n“WgEmިAk,\1GqY)ÄkcӄF!;deꗷoBhjKb5L]CKZ>3 FձX8pDž8.7!@Ka`j$Ek$ i"A.Vpq0J0=YhF",%Ia fD?ǯґZ;Q}knscيR!fSk$Y ՊKO+U%}nCORG4#gq\D70Qt/y6V=JibC0DyW;j'vR3KD ܰ ji 񈇼k1&گdN0|PBK0A (!(CD1<FIb6\{I07xK&?赣1V$ ,L(Uehhn=38(Jpc:r2"F$zU`-6j F} rRz Aş0YMF6IkqK>Q& >S⇟RdN#v ldLKȒچa3hK갆Uy+m$C|B!Q8Sj$yvjtMdLJPq*]g@?X'7&H@y5sm#D2[y?F m-nzG)%~B`QsL"g9f+/!aHLU%e"!ag8RŤ峥6o}2ed=/4KjI>"F5!\a^0Rqnͧ U\ 3lBfl )z9弪o AcsWc! fTڒ5#Ri2Q7E UN|{^0YCfcEdC(`+@b&ְ_f*dcC*B 9C1兣+Fy9WC LT!"&Gˆh8)J 6#VP U|nv߀MIȜP d{-f&̛+WibKyJjU*jAT0iFd@DbāITD0QXBs}ʃ7x5.1ZX>(̣)U'#B/@ILݲjG)S&,B`7E6UVռiY,ZskZtS 02(ll*rdĄ "ᗨs3D IMowfIqЪC-\mcU<}86-Acvn4/75f'?-3S 5D`Xo+o+ &DҵC̙^N<ѬeB=okN.D{<{s*2Xٙ\'^c6M&L^C 9:U%y|9\ճc_wV*4Á$6Ap3MoQla)roREd47C ΑFF/"3>CJSy,JAA|nl,US:.)KST UIw-#$≦Q5OQhG:hbG6` NJiy*33[=ӋN:;[.2Uǹ)Nc%]bKbjk1op|ᄃ!UۘM%5īmҒg&.\@ t2-zW[5t(oP'gkjF2kAYx/)/&CSQ H5 K݇/iUQ ES/2N/P"[[G'JF9 E7i)CC~*IәLK}Ҳier ЉȮQ#LLRb"F6ȁ˦>0.< ƒ(x0k7+L4$M%qюIFK fЁi2y>T,6^3jY[4W(HL?'87 KS,uXc2`Q[5{:^1-6eWjYREr6Nٸ{v?u,Lt{xU]Ԃg_gS6s\'!nΜ녋_y3o~oCf}7t᫯=7lhp=thVZz3|/8al 0sƔon޼[}f?}u/_}'M#y͌)~w֯QM͘'{om8z{i c铃CO;/g5tෟ-eZ'.Tw_˨! E)F&#Y_~N*/z"\BBܻ|}qƒ ǽt;ߥ{ͼj7qIhЍި*pu_*M}XӔӓ| \_VIұi" 3xƅ+ps)t6#qzluS'K\~S***(x' ?0>`ͺ$}iW_3mpۻwZmݞ `7OG)gi=tcɓyG\%9)֭ى "!λsmgj϶nzѫV5%-ǂGzJK+YX*U}]Ғ=^l&//8{TxRZVYPP8c>NNuN0yw>'vښ3\SZVU3Y? `Oc+.I$wxf'Oٳo}sf:9_?7l46l͹'OT?&_i g?c%)99kG#yM|٫thИѣӎ/nG)r{Kƌs1(;'{gZzڌB\JēyVv`B75Hf\O1s cK, ysޝ 8UIcz|? >g1^Fj(SazkTD H)M<"kw)}ӦMfF'NYaXv%+[+**yԙ5Ӧλ.&\M6mn7|'<1cJJJo8jHx7x]EEŊ嫥zjC{̹‚¨(Æ)+/ݿ]ԩWz=z5.**񜭫[~>t'cWTTTWU RVvz1,[F:L8&==مg$;oYv{*nGήGK:[n蕞x'_x8n/ ѫ&OZ~cIY uk?OoZ^Pxj']zONr굛O|R:nؚ#yO.^|êZ?|dqsj"VPKEGG?C;woneN߾O /:hPV]}ݫ=/⋯mp`#OLP__eӄھk\&ܳW#O>x<uK-Y곯%9Dlɉ ߌFqL bƘ 1bNa9/Ĕ&Ն?V˳J_q{-{QDž'OJOeþo?}#:JR]}ҕO믛{,}vsoޝcF]󯕔U ʟ{͋X5J/IMwRZV JN4aQ>w0 |湿*<<>(-|o%7tcMm$}5p@.k9(Y6ߴ Z&L>QZOY[O< k9c/=ReiK.;o+//!f" a$6`,Pgd"4 qtGLKk3™ʲU  H:]9PB(E#9p[0${X`%H7Ӽ[;$ٵK7aCg.|iժ#DYY#o:~(jPlmְ%yH;MٴNYii3Hڴi{oۑΌm8%۲,QH||g98uW^yֲYt3 oU^ō 7g;B1@S3zܜ|?.IOOw:sVwަ?Iy)Ξ;=Rc8<-;{wx… 쬾g7~s47bCfVh-Ak`KHOO;pbmC#N%p̆SO/ޝ`Kx殮n)))#|Sgҋ$YlYI^}}tnehھu}}}^{&VmF};ZP/;ݼi낚YYNg<7zYYliiٿw?\M弪9s[ZZM6n gs IDAT1zze]_GpmT_jE#S~_x ◫Ynoin>3 gܯtww?ޣ˖/n_w-;k}s+}-<7Ǐsʊg2ҧ^{uIܚ}+=r<{nuS`ދ/_Opkq*se%o>to|㫜?VoUyyٻeKH8\w:qO+߸we9D'z~T`͔dGC&TބV`QFFBttodH@0?S[-RcS$AlSgYe3{{}_}NycO>sD xfbGD[ *lܴ{ \!rטsݡ_ ;x}_j=w\:_t~bVhKY<{z(2y[7re gMIICSO^{OѦM[!t_x?򝺺c? +;U|-^w{\ߛX/jkkmY?|Оs"y OۤB.6"_ PbTگ[yd$/%hz;O ˨9Ө2e =-L}g]rkW^#ĵWs:NپsWY%/l$ذ ⦅iY ~[{4KIn'|i;̩Sp(=#7;Nι8!!9O7O%ttv_~Zϖ`{?7|͛}箾f]WW}^/9%%AݑڷrO(-/}So::^0~7E_6eO~/7lp=oniݾs1[oaמx_}9򥊲|KgM9zfǾww:=̩o~FaWzDȓ^)Nƒ߷Oq7e?mݾ+ǿ22!)_]?\V:t>XT`>r|͚eG۷mw~6oZ*yVSLlORnz7O:ϡ~xJJ JJnZ~;#78/?t>X3:C_Um7VH@`7-2w|U3amJi ksX"I1~rAq{ϕ Tz(ϗu?=⏾ ?n,^陙_}ꖇ_V_o3Po~|#91{vySS3疕μګ Qϟ?6 [XtL=͝w|;}Ζ֟I?yyOr9S t:K}ޞ[ƍox`wp믽^~_\}ͺ' Ɔf?=.-^3|K?pa9|"YSJAS##Sg÷y+k+o}ݟPޮ~@q?_sw͂yi}feŋW;<ǿw]p7-Oko}KkW @}ù>+Ko5 m۶ֶN74;~T7p}zz-fSZ6 󼑠tO=:::ӧκKJg9βoʔ)e/ 8s׿}?ظ}_=/yʔ~Z~9^3?| ۝NolxӖ?{CyYcO>Gaq^vls:cj*qi\4.e?qчzᇄg=ß5|}QA>gYw O7|Ū|CvNk׭ŻV\v™.??lc|? ooK o![n:pBӾ}uB_*oS*VX:!!S}n|3W7ܱk=z,\Vsq[}1%Ν9piMzzzo¾ۿx;w!L=tF LSruu=3K S!{V)f#1G *Yg}a˔yzu o񍑅@M~œo}Nx2ԫ JTm))&~{g>/v<wӏzr,= 8/Y,/fG{|+.uVW^yy]ݑ} ph{Y`>6}s'x۫᪫q~|9))iCCC̙3}g㷿{m.ʵe%OMdOz?~M(#ٿ07xFq jk;np{uG9Z[~Uē8_ þQjWgP^e`o8pkZw)7lޞ;\ck=ͻ/ѓg$vGn>wӵo{l{˽֊@Kk;}ګ8Tw[<ukVιګ;ܼ۽><˃CC=N_[||ݜ:e9uA7޲KJf58uOkkkx$$$lwojo~gO>e?I_ύ SATnr#7r""k WҨDE]Fsl}6ꓬd 8nb>r#LZvc܉A ܞnl>쬧ۄO٥~#}$n"|a½C=}ҧ]9 *JVyI1v{?xjeOHzK̩ u8H1d2ҧڕW7SL_|Z633(H i_"_%s[)@;0@vԅ 6lo~rݚģ'ΜoeTz' fgN]4r`3Cayw|nn4ܵHIcɒTr)%Kj322ҋgwlpHLT8D_P^X]RǀKHhge-FD.Z&c& ٛCY*֕vP?$U,Mqhݗ{~}.Tӟ"|"&`!!+^S}h!&0V^~E!ɆXX(.q"n$7(FF`T>,7TQy]f`&%r#7 NB'7P&, Ɇa.0=Fqr(<͓0p? 5@Q+BrL@*Y02(%4'A8F!7i#7?u^#6!1İÂeA`X\Xۇε~%p!#>5ą jїI-3K4wR՗ LT 1f8IF-wRQ ]t\>)hL+b))Cs4XiW ʶ4@? $tdI'sV0?KwfC&RH\x?-5S`^havՊb(hD݋ XIPׯFX%9a j 6cY#ɚЈRO;a>u,4a!t X%cjDxo!/]y.ˈGˡ5#ͳFъ.I4MBn.O=h.z/&'˥gv( y ,N"hwkU Dh(Zt%Ϣ{ ?[HEh y8֤3L5Eƛbӊ׃?A IyZш/,'DK_R.{P'} #>sd]7 0M2jTO#~hCn-4iyUs#knˇb}Zr>ҩM_.uS}PD F (B,'TMd/5tS4ɣ]wvc-لo0Y |Xi!&zHnhTrk?`~tB},6B;mE&?JhaTQdNcA+ @˗_2kn,@)Ê\mXƷpk6لXL['@cizU zZ Ҿ`b'&ܓ&f oLLbޑ!KC<&G#0P+u]ǾfpÜBĂf0| %A.TP%Q[nmJP?uGmAr@qM[Ai kRF& 9K㌉-zIuUB(9ɴT㈻Df(#N+^>f"kؖMJä@)Xĺf@;!.W 0ЭU֘=+HKKe|EFNե^P&W1OE|Yy9I/.'wz򃇎 'WTHE9p!!>n{I[Z~N[|\(N5Z\}q~՜޾ە"`ZvF՜}(76>;o۶ ->RapKKgŜٽ`xhB||쯋[l/9$|o%N֏-X4oFQc'6q{{{wm6a |d٧oRO ׀ȼU90d \db>x5N5 Ey+ls)OmZC Ra”O?!aCB(j %\.#Nm05%yʥ))`νͫ˛ŝdQuJJڳ@Sk;߂g8\WTzfs\4kOm3cF@Eeyep88`ҒY6۷l/))l{6-k⚔d˵o6Iy9))/ wgEj"ݽ) JP :{zz딴ܜN1 zw\ e@9pxZڔ9*wt9)S].v;u(+-ptϠNKI(S NJ Wuw[wybccc狫Z?oNŜ͎2\w WV{[\: c]yَ{zJKf 8z{|SRgWC{tQs+b ‚ ]6*UQi &߯%Z|jlbsޖ~)a68G;T}ByAG %,Ȁ3`ų,OcDyR4$klnioQpܦKj&\>_|IͻHLI\d`5zSSm6[SK-7|BKs{{WQA~͂mα1.L^nNㅦʊ9 ϟ_hQ_zwX|:|$yEŅ;kwXt>|K?TPdb !-QZ˗ w`Mmz[`ggO\\5+v^{Vv̌;;SfÉC;:{ka"K.>|cg ˞frz|e|\X516- v= /Kl#QɼW-,˝> 3}jGVw=,R>)aIuU/Xbcc2ӫ*\Jq::{k|K/9tg;ܣ'3wjjp_*>!@VVjMLLDs@WWK/+oZ.8Zw7\ܲvmAt3Mcy&WDW{ ma&7phhG^bQDPc%㻰,(˰̸2B J{x7m7 @GOo٬3g=!3#}ێ=Ϯ]4!>۶sߢU))|\vn{gdVZJ 3 ۻ:\ȮҒYf8v@B||JJJ&+Ʌ9xaEf6]hnnnhpFaScsss(e>tfK8qdWWOWWOIɬԔev\;sy))ɂ"JMKwhN!%kkw75/V IDAT,š9~Q55s {m7X&^G;$$%&ڲ2qBkRmFQ>x4VW u-sW?C2k?7m׏hmV"k‹7Or:ZTWXTz ҡed맣3--7\wБڭ/;kw-]'ݷ$VɘȔw6ڑ~ >a靁w$' O 6/5R,wn߸)6FbB"+*@ں_ŋj涵u8*GV,ʵ?O)}[EE9kVW3ywzY38r`Ç Wz޹lIs[fp# pr|DDy K 6P?v#%9Sւh K !,ԻJ,tN3RnxƟb_ &f9WFT ЌKsO{Z qαqnЈle;::7oY;be7m9n~͚ٗ3}w232݄WZjZ=hbb_b|lBrdŽέm/,ʫ[lHKX K/޿`kk._cw:KJg\ ^~vęn*,[.x +LojnVJNwΛ[^=2--yk~MMt>1F%(sc9#LCʲDlc3gK*/-Szӕ]~KܬYJ /ݩ,EjMZطz.ئvέ,JOKٶcСN;cqfP;o^/"hFQ-מ ?4rw4NUhO?NĜ"\ ԘJHR| ējp:2BA0Cܜ ,=5(t ߂B7 P]oa/a=*Tr%RlQ':z m>]VRff}4.]@~nN]TtcGyMIiTWɩ#cRRI;SqSAk1R 964ykVVFss,_lr;YYVjΩݱڝ\`_[XSeٽ@ZʔԔi ~t6<֮^w=6`DŽبm-E'\c>sO hjiKJ]n9~|՗umhvgNݬ,puddyD}~Ωi)kl . ho--eC |r>ń֮ZUާc2ks.̰qN" 0BSjW\Cx gNSby.]|eGLfx^7LM~"rߏG\F' Rtӂ60iwz`)B:ssFOCXPKo؈FevIEս>*{{:{z{}K+Jz{^cSszvp,.Y\4:: 3#c~Vl֌*+]]=yy Β%5%%Ξ=15=}sM%e3(.<[>Ja ϝ=,U4(U4:p5OL~=>>>5%5MV/YZԚ31..;bv{GgsSsfVus攥sP18}]vM}F:"7.m^&Jtׁ-x:Snꑑcv_ngnշj˙&+%9#sSp\{\u -m_ߠTc'].]>&2z}S8v87NiAILv|SiyI- 9%KZZU{땷^VHnFeeJ/мB*r)QyKˮei(|Â$z(CB0 cI7 (E2333wvuwhʥW]pf\.UWp8M;-[\frvm;Jgp8}K/''g&<>|4j K 1֘V8{gGع}e v}G؉ Y3g̫+/s8ߍ;jw,.)5:QA&l_92HӗR l^ r񉉦$ۋ r8f70x척*y|z٥f 'œ̌4SϕP/_;>=+7';0pFz:Ԕ‚|g M͙b{己V/7r'MINVQ8lڐ"e!Cf W)dWZ߼{>Cmu7F0e 9 A¨8#6O77lSNq{z]s+f jz\NTKsKͯEϾߡW{q{p:xY8~~1ۚ6o/_XTk?u.s-kց$[o'OuEYTS?xbIctX>_)ST)c8޶wO//) X㸷-J1#JSG.حQZvA2IsnW>cHѥq82$$-OVE"A G, W^xށxaJ l1ԻCX)@;+ cY͍.xDơGԈW(a>F#Lb6Ae!3Jg 'Y߀>ظsLoLYBɒ|K0Ey1?b܆0tr)JEs18HD荄A &\SxhsjÂZ |~OR˸$Җ6vM5OM 1O(IrFi)\ӵGAK%k|ιR/a2UbUtx2IrEmU_m#?[QmzS/h-2z J@e8ݢ,~-%`V h(>)3ᣵ:GDWJ|˲-\GߴK9d+Y [k}R, F4NtA&mB6 Shk!G,V$ÕX Gܹ0j5P0<e`.wx,3OMJUzF L5mHT5Mru#X\n~uҧyk/+,obJ$Mżm rB$ޘHKNѯhM(Ye„VfMj=^S0es x(KRxh9ZA-@$*2EPMу_C)<7| G4-D[|glPMcJxii ̄٘xk$|[ՔPeW"L$} %q%OpUOr 0m!~Khz6uLDV΋ ׆0?K#1L$5xTz?}JpRP ,p{]hJ<' LDxGÕHNizih՛=J֚ o_a +KL=A"4k`뤰k%]WIdq'ʛhlKK+4XE)hnbaҘM6v^6`wEDhfxP-(Sk2PFEmTqm hσ9-׭[$'!TVEI]"k .-b"Fy#G *1R "f8AcBQJ F'aFfB 0((>ctؖ6JID#ݸ%ķf~ ɀ&QDuX^&Gq>ї] (N)8<,LT>~#`-~@(O &#)`ei Sc0h|\:{ѧU ;РNQϏ.R\*a8]gn~#sG,"p7\})(@bh (,oՁ:+dY43PW7HK/ B[jhS%w8xV7dATh0hg!N$!JC.e%~f4mC΃Xv(aIܧa$޳,s ď94LXuF.z&'&4CfY F P5ڢɌ%TK'!4ju zYeB.{P1_m0C L@k0A?!7\&D0ªZMK#ܴ$5GDtS3E74}QY05zLz.i:Ei )\/Z >ǯ  : X|qbD446k"1+j6! &{0*szSdKKQTKCmV{UQd x#_lNx`0 n<%%s)N`Yrjr%k7D3- z2xrBu6 R fws$QeX66Ӑ@ D<kO{#5mRAmBʼ*%"ӴI2DT >o=P}7Ag#[IPۄlB^۱8h,IC83HZ4|REr" oFjO´ͮQd6HF𦢡N"&u>JBT Tr۱k)} jdQ) PP XO 7,,%n&B^|Qʖd d+f{򘍬 ]ViL,p'4F,N`DAwThZ% w 7.Dv>1m|0_"DZ<5Eٱ1gУ-oZZ[8)+oUdXK768B-ut;9Wt ]#VeFk3O)uGG-$Aٛun?í`bA , Pʀ0DX rR jb(slN a6hM+;P24WKEK_ymU1GRԥK,ע5MLZu1zoxXE(1q7x0[S|RNRo&U^FN.5 !?ܥdZJ*'Ga,xvTL8ېOWn` nOq3 0 N")-޸0"OPhV8M5 qC2a[a,-h:%|=^C.6dpƐk2n)Z:eb{ՠ2ݥ`F1%)SjU 6M,C5Cp(pbM>fe ̥ Sc)b%FGNRWL 1  6butIL̆íEsQe\ /0n wbAYmxj|g{\HAtt UnӜ(ܬfvIH_%5@U~F AS®,waʛh IDAT\3}i1؈WOK!Ej( PC]+BÝvCx@YP0 x3&lEc:A ŜlZnFJ~Ӎ`&9IrrV&9,H 4|PVE0٤. UeL_.a2.jU@dnWi`R,d.g!s]eXZngڤdTo9iS{Usef f$aƨɝj> $t1/~dO+#9Wr"aӹ'mLv"j60pcQmNB6h,bFv { OS`XV d8Z,kLb,5FZByӳUȜpw=4`KlܜѺOן'$ĭYf5 *uUؐ;d@g"շ#6|Lp:0nLڌn0F?BB @Tu Z`Ƹ'eqZ%@0Dь O]dv.%įޏj'O2ra]],--u˶V,[f-۶N|AP{GW`VkD3gO{:}Y;XV6+//ns:DŽb bb7&~* f{;ZqEI~/ߜ0 Lڗ}w6EĚƪ0"nho"xFH0爚66.SP T6MLL(Ԋ , i.)TsX2~W6k2IJ1"QtR 6o[cXO PP+O8-c+k<4Fe,^]=AEy=1cF~n_cpx>{qlltɆuY1ɲLMMX @z)Im-1Q % ڧ WQ@/B-K JQ6K(j. IZ˥ N32)N>U X&VR dE&Ow.֠=ٺX>iRf7=++# isRR㬱FFF:l Q䤌,w;֑>0@rrkLlljD4%59:YGFbcc2#{&0 )cN| AHT: 1THz4\.l!t AwQ:?m¤dߨnMl" Pk=Iȴ%T%`QLgqB\^g3 V˂핫t\p&/liج4#%;\*7p,FG]=/:/:bb,q}JRǼW,甎vguutwXpD&klLBxI7x?C! 2 c4~SbHc&H:$dÕXN%oEPd7oSXf$n2!fz?(@`@F$0mS͖dqV6?Yy97wss65frs&'IS3SRO_fVE{ȴY3::%C$(yv7&I79DvVB:跭O%QKKyoykLK͛GF^$tEׁJʩ8;M#xzc 7zh C}xW(K<=3#?wcfNkghqA^eYfs\("xzԂ¼q1̪ktd0vEHyRsP _cZF/_eN H FɏFoUm&Q> D3n" 0IɩZ5BE0 P2,z T*;uΈ c‹O ^)-N%vvuv ;Nm,-.=F@ǿ#P,8G6~՗p 18HO+(w{ 4o$oinh8G$ z{c1v ZP=xɬظؠL X $uo<La#>-k39qJf 6Fw^N!11&H6+Ԃ-B={c3 4'a}7U)0B՟*z:?QCC|Ϟ畣˃{/{'VszoP_I7z甇o[ 8z:j`⛺ny|¦@(I{ yj{YR:GL}cC4STܶ'|(61ߏr?/e>>Đw 'U즶H*4@QR !dR>M\0M 6?h"B׬~'ݷDzxޟ"ETN:џNp\\ͽ{`/7!M屽QwCqr`;S8G?|0=UQ+x>?`y-{mSӭ^zHRG}dai0zvK=EN7x9u =eN_CcEIQf{O#J~_CywX~e(Wr A8XZ g:N([Nxd=^qzzt|{i1*vN.c O;_%ړ#4 2OX=t?{$oS ?wDms<;Ǒ#.Ed)j"fƣZ(9@܏Q9w3ReVwÊC ut:=+Xvr#6>f 0A<Z0/fyk]_7O)OUU7Tܕ%!8{11?~DF9Vیlngº'?IbFϒ)/8 pʩ^:x~_fsQqܣGA%/ԥ?\=|9e,vhy^Ur`-p؞USR:%lZCaWrCobS㡶.x ~*-G&׏6 }O8|1KRQ9 }R/R#1QJW09B(Pͳ9 nܓS;p~× 1yZ}y+{w{nylv6/psOT͝E'=ԍ\|:L.q^-RVb/-<=CK^%(RGyW.w.9.ܩxCojYR8|<.X? ÔN|x*:EzdU3QV]i|r:y!A?G'z{lyl7)0`H]cSڪQ,8$j<-[۾rF?,gszZ/ΑM`h˝[iN8@r_|ݷ/ڈ왪o#Շ,~ʺ‡~zN9f\iϨXy!,M% o5 !}Ad5Ǥ~f@`Dds ښ襽ͧ*o?̾0oUg;Co 9lN}i=y>u|_oQ^ܜ~ZϮ-ø wP~vq3RwlɍxoՃ#z5I{EViXaΟ.{3܃aP=ӉeR|{}PV=|."o>z$i~ՄO;WrS[xH5ؼΰBA:ޟ6$HL*-ǡOIU-{ SFؓɱWi11j_dӏn^?ػA#^;,G:}\l]͍YcmfvQő|6%RW6dj<5Nm0'fߩΙ{'J͂'?P|QhX*ѵ>9tǑCMJG(s1CPߛڸ穟DK/u۝P??km׺/O2gwc- $b` p7sxJYDd؏tddy8v̷ IDATo5CoپGOh3 h}p|Sݱ8xE胔;߽d{^I<#] O=;A}0GˉD싔Ft>-^:)#\|{t%:N{ûaz\wtG#51%wׯ_bWɯiΕ{-þ.:$뿬GhO Fm6Kyf{?,{g $źQkT'O}qc6eG0 oG+/'zU7ļFM@m/_|a͵y&V(Q6o7`*hgs ,p> ~R6hq42&dMY(dngˀ`h5V~/}S[/>;/_(ΨL凔ˡtؙyyAY{,)&*IAT3܎;?͚gSkB naj0o,gŢ :-7p ? @O0 og|ZQG e`_]>ſڄ .8 Ma,`HPNA"` ^.˫^oL{'6M lAw $yw>gv3?SߚyX E|+Kmkr B@JAd[ "kZup9;%O: A0# @X6#Ab`A`OVBG ackb,iMdUD,!7%&Y꿄9A{C 29/1X̰ѐ"`ALQ[FN%FLBe {75Ʈ\}{fV`dp7:+{K+^3[}n5Nn0+6G](6%re%xw.[IR sPt6} ]p`Dn6WW%>xo/wQ9CE ĭB@)FSAJ>"{d$D k*rD# jM*2BRnzl񂫞r2'6|D!"p=e.Ke Zf 椠 |p91L5#YI]di{w1sH$_W}y9m^ϕe T96첧olgw("uZ5'Ӛ> XP`o3~9ـ'. g Es 9 A`BtP >ic+7#7@,`MG3ҝ~k1UEV\iw{78)BGeY`]["rz6Pgp~}"~> Gh PBJ @\47)I @6k~ :xih[R(vo.+)% :HtDO ~$QZMA@&^ 6lE0+Gt7 70`Qԏa&g`R$+ӆzb^d=mB\#w @1 bV'('XzXu$ 2`مm @&OZ5TS@U۰A P`"`2\]/6"@pXΠuXR9XםX1*"@I0:LW G{: a.Z730"nLU+O+ JJbGv unWf~m\7׷_!Rn^d:EN=4f;O,ٙXRryNJHM cXB &l <b#Аqf7 Fv^2o7u21!ϭo>)%\"Pndd.}ԍcfPXHάwfq&OpAb(@B2~<񂫞Ř\҃SnM- H&y)ARV$vVkWy23&=Ә/bugen*+BYygb'9JJnDG#뀣cax⫋xsʛzfX{%d{mnşNV۴F5*0=N:ir5 >>" 87+eDaCsn ^|"d(` X `Tw=Rzpʟ].dtvT_ .ٲ:+ֹ{% b?Kf{c"݃1!z[ΆMϯޟw%14ұ p MHWJWyLW(n 5c0fX +Ued&00D@= ! 2x !Ov^WV`exF2Ո>g\\^eޔ5èދ# .tCFE..a=̺]pvW\j`D<ʫs1C#{C(V88FC 0e WH==VP H  ꡄҁM12T -#  `  (/P/?yCUx JFt׺3uqJ};%J!=~";]wdº|y{]\S #vNu&iMzyy׺[]zuϴ.n,W*Fc`QI;ά+십ŰV!hD.WlJE,ĮpYF0s|^~s}vf hP2d>7%~T"(BBa26[t6!!C0"eXi<8-nt&G:"Hx8k, 4{BA)U]qZNU&X۬I:U 5j7∦Ugoq=0D3L 8,#R^q.oz%] <غ}{sign I\Oz!^MPo[ ~M] J p" C :t,!AC^uZmu ]ǟ^㭯hG{?||N_l<|nXpY4n1iO#3$$ql7ٙ4~ $30/7 iThI&7 (8dX1D? x[=*geSk)xX]ߖ   fMiƤJnkb,\  h$;<2R*p^pqqyyp1@UE#Em@ף @xB:p>yY_tvK^n#ÔV`u\]{Fa (#9276PA$ڂ_t:"5%-g#<0 /!']F]۵]H%)B\.r7Adn3$L4M`0 v8S9z2(>90.Eܐ#4*7H0G8BtTOtt\'wyg _&RA $ы]R2+zo좜Wg^3 Vd=}2!]dށ]X/. LfERRXܚ $'ΊyTdYѻOUyv`p臒6X9J43d{,u[ٷn 0C*TiBa'}YIc>eB.h6#{>Y]2 ͔)(➆)ETSo΍0S}СpxoM[;'#3ĠGZź:) 0NzXFfǥs+]ƭ_pB0QUS((M{X*d>z"7a XэVX!TR2hHa= _nX&_WW#M7u='a;`VJE͊l/~ٕuѬx 11>0y|qF VIjGf@*0x+I[항Fd`=Cr49"Q7{.gU`ѭW}ZG`'JB D@Pd `n:hp"K:D;@X HP¼[r , Ѱdഝev;w^;zK=%">KRpsЩ.SA `VNRrIp jdKBWM)Y[ ws8*I*Տ?D$hHU B2:,4 7$+%Y(:idQ]g]gN&Zݙ$P0w53ԹK>t`*J,VRg}_5$y0<TVA*%DX(Uaprl6`$9,\"<)mq6 €JOTi6 it a7&@8nRY^*Cm&~R^tɚGvy!idg}CM$_a6p0# lfA5^1fH(U v=ϻ6Dզ>ROsL u_i R (Ӡ&cπ@N$Ya`wo"uuqyHZ ^H2!ѹء+P{Q82fSND̐l~, g[7Z6@jb)t#lTUڌ}ؾׅ*B HrSb/Le43=Ӫ nY"M񳬴h 8:&s& MP "ht) ܂ ta]jǪo꠭(!A&dB.ڤ~Y^9ܚkV>[c?k?@$aTpR^y9-h62cQ&yA앆.l-2I 7s" LI,@4‰$g蔚E_xYn]r3 yQ&Uͥ6d@.0yqƟ) vQ^>vX՞?0*[: y4)!,ޗ/0rМ8R]ηF]%Zc^ 9xp%Q䀱~T>BQ~uvt",C;9MA.3JPf/&*H&"2Y~|_:4siZyZ7ۧc; plGAI]o3U{qhL8MA嬥~{D& \߬ν\b<`Dm2M,bE#,oumɃ\=j+b,?2i!H1ῳIk&ʦ|f:*#u0`~uGv ,zK[@$dM-ATQl'hJ:nN4qje32F}(;5cwc UJ|*s4 ;gB8)Bu-rniV,Df(CpXb̆LᕋfD nݏm5E}O]QW;g&j?8[DfQ Q ,m;]tY~־e>2:LyWW.!α2]5s3!{z-7ɲU[(Gݱ_ܞ[`n֛ǭH ņRau;g:2zF|ଠYafYh 2 V 1{9Sҡ@Rl4vSE]ďǟVk/|`.{e3y&|9I4>9TK]>ÿAW.䶊IMLȉ{`L(zf;ξB+uEW3 eqh@(g_Ln)^ IDATpkW56}ktLctieG;$!\F]xq|S(בsyJK$ DMXiStl1.&c}p=N*aCqQujƾe;D+ D1u&Jf~J;Z!m-઱afs>N͎*[% )%IQ3-%#-+B!jG -NDPI#%I3[O0fETXE\P&x )4:6hW~onPk跓 &7yif_&њ *"dU5Hjl$\ߜO#B Nh:]A?nƥ T@٤W@0Xٖخ}lǛLd& M0B 4W1.>sqx 5>%t$j"$?Bi2gF Cq(>xI$"dl9fgρyp.93E6:!w8+{SVD5X#= YU%}of&Y:a &qʍ/X ˂#" eɐirID̚dDGf_9$wv{ʱ@^M}VF6K 47 ^*mmu=A 7WjNٕy/oq:?_^}4cNznUd4"2Ղb x8M^駝H[KKd-U)kbغH0!}(<*TdS=D˒QCX/VRߜXAyA e`2ÈL䂡&Cbe;YjnrU'=<9.W`QjmS-Q@U`]IUhk9N=ujN`,/1pD K4p!K#u|u2ԆA)eb8-/owVno=4-sd]j.lбu9w]" [>GtM>/{rso(1o ˖+\.;gwL+j0"׀w!!xK*{;'?7r''07e{iY֌젾i-KJ{%*^4-_;ڔc-5r_kgRQZz/8$V_2bAɏQ X!̥,dxA5S(4ybs,\VOf3.ƈ0hAk>,QY~ =W]:Nٚ$2j WS~m2p" Ab6DՓ@#bi ܙM (8GCb!)榺Jc]bl~;ҚyPt~E ![xx]|<"=gl߻m,>(i r;(ٽA P37'#daȌ:k̛\0F^t5,Ha7s/ y5),c&&o3Lw敉j600L;B BO^<{hb]j#<8jvtH"y͢+1F.@/*O%Sv*cn) R$A'ns 1+uFd,'$>c,"HUo\p*z0V6t2tnwMoysʖPzn`Sq708'E J} 2,%V\ + _N3%S% oOQA[/O]>g`{3=;aLޮzM칽)lzlYUgSۯM4@T]uM4yIFa/2Crl ,F͕R$uzu$QAU^ YWUQ&RO".,'<(E%TD^Z߶g~%Z$Cs? $ܞDLjrA3{8)Dc$pk<h:hS{1lMkp㻆c6|#[؁ԨTJ c', ,6+5&`U@8P][jN,]8HC)ɖV|v=dd!E c}0+-sAO4Biv,iTayp\c~[(3c~>Z>t_Nxk{MN99P䐪ݵo"s<|[F fģPJxzˣ rx6,23nѴ B,N ˄ @4max3Ӕk0#ֆZӾxj&J] L p<2dBQ([=JN F|wkR[=[/˙VYb22KvVǦ% k @$ ˆ&ǚd5-RƂ(S2#e,{F\e7Pez>໹"}ԞLc-}dۯ2Lr+Χ<."/a4 ? qJ*poA &HcZ] w6݆s73ڈ1Ju94LNֹj(n:< {p+՜W2.%_|,A.VR6XYM/zݦ{i" nR,)n5E"L):gf;W>g[đ8[69e;!Vs|K6E7YL6JA-92Y _ z;C= !ٹ|);ծ*N,{v6̰ZIl) 5WBR݆19 K)%FL&PD}A\qdT2JijdˣT~nm<77?̯TX )ǔr'- ۽u%TL"LmLlGj w!Y8.gSu2Hu;!x^SAWԲT¦.ɖ$k٠>Ŵ4zOfU®V .TJXjrgm?Lh4 :P MnTs!J cppEMM5CmpU׷HaH" h!Ĥhf]:$X8TQ47]O$kkKG-VR8 >1hO]q͑c4Z5 ֫ۦ|X;9T ry 5ȋy扳_)oPL `/X uz-4I8Iڒ;ߌnȈY&1Sy 2]/ń$sq}:ˈS9Ú`Wt{evƠ(c܌)9(:M-P1륐6-$YVko3?xeVVe=*Z-H 10f"|cf|# M2*22#q^ F܈2]nl[ɒD'MufTI4o ?2]],E~"Z6oCf;&)f=Q6{x i"{N@KX8(+pPK#ƽJ@ @`:X(jbzq)@0 qEi:-_S$"J)ʽ&W YDeWӕU#bwOĩi'({"t>OG,(idEt/^J,*3PpCls)Ÿ `EM3]\6)L=nWk[{ȷտ . 6e`BjpT8{QMaz՟\rrŞnA6dȆBkFjLUsBrYDVQ#vD`kX呰d$\ ٺVKM 'dK2.(0 &.>6i>/;dXiK78yL>]G|jZWϠ|BnW4NFCVpKf rx$9ꙁ՝$˓S'Zx4`l3Sm+ 9f'0(fpA D8p < [D|73/p! &B J6W:—xha1u <Vݱ5! 䨐$62rZUFXȂA;o1*  "(4\]AٓŨD&H6KBׄKv\pQtH ?xTak# ,(\87zVk<~}s! yգm!GuZ[Cf'(jxȬ=ɵȵ?OBgD>ޱx_TCT{ mэeh j@nk*ځ@bIJTi{,NLGlm Cόo*O&, !8Fj% N+׭-˪tљh7.b2Q>)"q:! G1wVv;xN 6u6d?c-['Ӷ]8Dg_SjD<тSY _x.E~)*a "tO'5: -:9BݜoHMCo*Sf $?O &X#U݌" =:ꄈ8U1tCU$/zcPiQ]i(0$BُУBp$C>sj0h H:gnϥL𪯧x=r|7{-F("ޅ,,C\ vn.{Y .&"bUpHmDyIwE}I;Ӽ$Aݖb4C6ĚuwC['RT7BM$J;9˸(]EL8}>Rv ,)WUw_pPH*ZQ~ s?qaggrjJ=Wu" "w!#*jm{kwYn~( c"rqaSpV2A\j:"42|@:l GJƤAnY}6×M}BR(_r$1|ϲ{-!iͦ]c*iN0(\}h<G ٝwxd3uΊ=1'eyt݈b\C͉"ET: tgqC3]f5= o__zҭI!(VHizjZ*xVPNw肅"SKu{/}Qޥs0Wp"rㇽ'lߝ@] / @ Tt:vddV$ޝǯNU^^-n{<܂7pڴKĻ$a,%+DPD֍ ˁ B]섻72*).dQ n[пTw㕭Ң9 |Y`& Nu)* 4˿oascxci@ԏV_?UCIZ !MHnR<3@>=uܙ0/tOߤg*EmSol'4:i:3}܌m ?cnGϚaD8pcYp e`B.jDމ湝Jp_p{{8TFYQB'[j5(\X)juD) b30\ߔ9)%+d* lYN8k7}KRJbP<< wz^Qoۛ D3 5$ER$_Kx)t!=Q*!"Jp)B9r].vؙ|c<8CaMOoe&cCo0L, y~P0I^@" K 6!j  [V[šw5xG='j.&[BfwC&R;L G֘4 d/nZMwzhCQm?at绫LڙC̤aE6zR 6,$&f2]S*L)7 |ߴ;yrR8=Z j"q6BAq3!0Y #^b:&0Iyӭ ]'F0BrubR5B@з~qoNffuǟ?mW߿_\4_tZh&C[@Cr{ZȍYm@*SUi)x׫m 4sI,z üߑbE# (q;[Sip+HԎF\Ehe_Z>thvZGݮ"JHKdR=ᑋOk;o[>Ⱦxc1Cq'tN;Hc&2ϴ6yECp뜫!LFw qkn쒞eњ7oҾvb@,ewjV.7WӠSH> 6Q+:vq4s#6կp %QDԳ*v'DIS^QN]B&ߴubnK땯1leL!"M=v3 *Y %dw2p =5vZ\?|)qYd' E5Aju'59NS]IZwf$1C!m&yC&duBuyQR-fay=pd<'=v)uIDAT`!&8vKՙ3/"쪍_ߩZ)q [-%o֟NJY f,9C1-ōM{y__}~qy>4%7Ml' ;8>)4Еh5@P(U%2GԵ`'^=(g;<|xXuv8GW(WfC^d=]m^$טqHQaF&*=Iro?043IN!(s/?{Oo\ywd7~Б1v efzY5耱{b1 aR8liIHnN[|];Љv_6U3'dd,#$ t@$|~I&IsE7nk;,[RdR(43x'>:I'0n6!Y&H4«v'H1Ktu%oxy8XzɚlEЭMXw x5#ɬVh4 |#QԵ.Ҽ:R\CstX>BPb 1{rFK[92 `(,pP3C-Da#ZT}Q*B5h8(ڀƎol 9 ; ~yȭlk}eH{Uk#")frꊴIe[6´$T+<]rD;gjvӌN?Ƀ-=P}fdhϻq$I#,'ɐɫE[u1/FpRaa IST bY-YS#gC`iS.Xn+!&H"(- !Hm7@x?FB= 'RhS\_g*y*TM#}Kvhf 6LXg0|cTZNx) ( NA+' SC }5Pd|چ,)۬t 9TxK=\PA˹MNp%2;d6Ww+wՄDU,zQԐz섒i665U#ArjFdSy I6LEuґc ; W (ۥ2rr5%BcGttס%=+3 }@ W*4:4$8`֜/4Ϛ9@XakZ[@ʐkdA^@ $W׆tEoFZ 0! IdZ˞!Ha0KUSh{sW1Pt1rE&uhJ"X`֝e2%"̓Ld%.IىB9蘨z^GK* pWC2aE2.<I@q/WA%wO7T`pg9lz)8NL6?:#}ʵud;T@eDi ";WX+=̀?6Si_PEO G*@`~ys|u_gGO~fy}%%@ LKd.;P2R/{k#-8yeCvLHN?q171W 41 ?ҟ_ciS_PBs Ia&"zCE-nbvIkQex87R2Ἣ}y] XzZ=>(`RA$[aW8N++3)$נR&^p:74me G MQrRfeN@`IEڰ BQv$8ңm$4 $]X% cT+; ⫉d9Zl Ԙqo\d8)QI&sTnB5 q뢷VBqݶ8џ/ID#C\)}VVjH vEj o6S|W~ؚBj7#"c6 KWGz GͩFN0du(@6Р%+V.2RM "4#1 lQB9L7_?~#7U?.H (^Kul5>ܘil*8/?\v_ \" м7^}d¯^5^>///gOn|w.- ,R$=֑AӀ# Qd^j\*OYgەWj͌,t)<,I=aH})P=\[Ib(FYwRLuWC:/ɁQM HPm@[QC4vf^nR1}vϞ2w齓nB{Mw_T@⛎lHF<>ڨ6O2x21Y8AD@_pUt%.Z;RSj 6u ruF'Q(y,kFPjň#yn EeCAJH 3$jT :H}>t6!&*-ZQsS'^ l iq<1h>UfGL>="Θ⽏]Ltj%]ˆZջuɠ+SH9lk4W\XbmQ^Zjr(b+t]HD=` 'EaG:<'tԥ^/PTW`Ƌ+µNWSt1'ьWfۘNOg'P#鵢#QHUP۝^K3p! vpP>S*~/x_z%~/_~yoO8ajz6g_s3fj=mU~^WهHϠ{)A&Չh MnS!ujvb@0t"8,ނoIWcU^GV nJg,q[=*,rJjjV56)54Ǟkwd*֊3brS]GH[7v$J^Ҙ=N}sd<:&_k-D~ hR4(jn[;=qva$1qwÙj蕋:UU'Q]`EJkMOQh3=*t !s+1uqEלb]WB,¨Mf9kHOtI"߁uw9>wK%,"%Iѱ*=! 7}ۅ3iB\_}|e#X<zv5?J~dƛ1=Vr4>h&5E7e߭vGRsõi<"P-TjZAW! 9%xm"bo"=wI \CBM8M,_3?|nݖ|W+UsΊr"W۸APF.kx~jTtIoB+ypO >pIENDB`ukui-notebook/data/ukui-notebook/zh_CN/index.md0000644000175000017500000000340014201136534020423 0ustar fengfeng# 便签本 ## 概 述 麒麟便签本是侧边栏的一个小插件,提供便捷的文本记录和灵活的界面展示。 ### 软件功能一(便签列表) #### 便签列表界面 ![图 1 便签列表界面](image/1.png) (1)实时按照修改时间倒序排序 (2)显示每条便签的修改时间和部分文本内容 (3)新建:列表条目增加并打开一个便签页 (4)搜索:匹配列表中所有便签的文本内容进行搜索 (5)删除:删除当前列表选中条目,删除后自动选中列表中上一条便签,若删除时,对应条目的便签为打开状态,则同时关闭此便签页;若无列表中无条目选中,则删除无效 (6)支持双击列表/图标条目,打开或重新激活置顶便签并获取输入焦点 ### 软件功能二(便签页) #### 便签页界面 ![图 2 便签页界面](image/2.png) (1)支持文本修改自动保存 (2)支持用户自定义便签头颜色并保存数据库 (3)文本修改后,此便签页对应便签列表中条目自动置顶排序 (4)便签头颜色修改后,此便签页对应便签列表中条目自动更新同步 (5)删除此便签:删除此便签,并删除此便签页对应便签列表中对应条目 (6)打开便签本:任意便签可重新唤起便签列表 (7)新建:在任一便签页新建会创建新便签页,同步到便签本 (8)支持导出为pdf (9)关闭:关闭当前便签页,若当前便签页文本内容为空,则删除此便签,并删除此便签页对应便签本列表中条目 (10)支持加粗、斜体、下划线、删除线、无序列表、有序列表 (11)支持修改字体大小,字体颜色 ukui-notebook/data/ukui-notebook/kylin-notebook.png0000644000175000017500000001521214201136534021447 0ustar fengfengPNG  IHDR>aiCCPICC profile(}=H@_[*38d.Zq*BZu0 4$).kŪ "%/)=ziV8鶙JLvU " 3˘$|=|,s^5g1 2ô77m>J|N.Ш94N3p:0IzEm⺥){0dȦJ!|x?o@Ϛ[s@JH}ۿgprgf7bKGD pHYs B(xtIME  +*2hIDATx]yxSնiڤ-t`hh+XIESA(RNQ< C2 PK C(4ii?JmR&-}2sk Ȑ!C 2dȸ@zs͡^ot!DMQJ/ZʺDBx(E+.Y+ \shYCx,A r:5MlRptSn1d=h peٟV1uq&Mz'CŒJAPjn{x^r=؁VǑ.-XXƴ1D*}C"G٧4dkD '#kݟsJ!wRQBtM%y{lSbS3>V8bP:uh xR s?~ƣLqQ!DQ%Q䎦A4 EZPR O!zrĤiFS!cYNRQTBBTzNhi<v rsnߣSY BJKKQZZ* ]X#Ԏը^i&gJ4>]#$G*Jߵ K /EJa j'P@~0iLqjN x jy9@v2} B@LBy> PVDE2G] \*-3O 1F$ 0id4(;% ,`@C jA,=ndh&!z &dBL@Y8DA9lt $(PM26DQ`=@@ͥ3(JEyПCjv,Z"h)oAX[Bs,h ֬bBey$Y{ ^sݿm7Y`U >>^&gO-v< u|9UPEe>n(p<"MX]MEiOma~|/]͔NHHHoœA~=ЊJ BWYz|z,σp\σyAD\@dNz5T9v49=G$%vPoG. cb!u?aC,%TAaFOYfKAu QwvDvy |&Cdg`ػw?裏 %sEZ ڵq)ddĜ93ѪUK(JPUa.d+O9˗BvYFRRj5hqp\dCCdǏ? +ڴi3>AΩP6cY,J %gΜːu M4}3"].W9Wnych׮-:vlf5,Z;wq^CK>tV)k0tcX|jymĊ O<(F4KW 6 vBdVXRW_'OƜ9p% /"@4AW0Bt:^*JY[, 9s ڂ]PYV#h53Ï;69v͛FTTN'22zBTBE8<"d%SM`~W0Biυ`l#´X,سg?N<7n@QC !!lY~#`ٳs~7JCC1nXFBt:lEQ7zM; \?C*o0d/Z?WDj poc˖F޽i/>#DFF1ؽ{Z-ӻKΔX0wصk/bccУG7)Jc +Ee]ep٥໴ *wPTdoW"5 ꏔ`YiO8r$ _~9S_]8whl6Pm~üy p8䓏 Bݷ q୷^C}##'Nw?иq#M609%Kѣǐ&tR ٌ>XzN:JaÆB*>V w ys~Պ)SCzzwB`Zapȟ8u*zgt8Nzf͚[wH?DFQy. 'NláCGp$&@tt4`ذXGXn!!: 4aaૼ^J BQ !/M7%X*|rر M6ꕎFr0 DQĖ-ÇlC-6-c=ٟ#6IW@Eu/#4k@<Dବc8} zD0oY{?-[vʕ+eN:HS!"23'Jߝ>}|0:$^֭;}` 5%~Ρ\LO) PP(.:[lÍ-Z47(< GZL^̙s@AZZG}LVEFtt4˙;q!|l6df}3n:ENNMH){ǒ% 1Grjо[*˅ΝSpWR\MQxǴicժx]vvV+v, ߘ5`XrAcY i6ѣ/˜1O#1E"NQ,H_zwnp8VC*Eb;|ZV;{gF "aٱaF\,cќ{@Y^Bpaq\",ڷO0!Xl%`̘wQIII`͚M%KBa޼F$oY>|C oBQ`. ݮ JdwzƫVA_}5 X{8 Gz[B0`@?Co <_Ow[Aމurrr8aaLtk&\A`DRR"xdž pIt o5+^͗^wޭE=ztEJJ;?~aZZ^b޼ظq3rsu$ > B5EOBwߝ$_~ق~ `Ԩx'iXYdsuwvVP8J0=HPD|d_6?zU\x)j]EQ,4P\7E3(b~8ƽl !D2wp+_zmh^_Z|3!$([n+oo6`/Ioiy]ZdEy漋kƬ\N=Y#eWΞIB&j໋p s3i~foO]{ @g7+t]<Þ%wopn󋉣ޱ\@ԥ jlLC$7k?s1GQ4;x 5|O_d$RD⥕KH`LG]/cncƃ/*YF E_K]=/RΞ?s{v־rvs4[&ɫ ⦧;T$V4"8ܕٕ|74x ukui-notebook/COPYING0000644000175000017500000010451314174170620013332 0ustar fengfeng 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 . ukui-notebook/uNoteDbusServer/0000755000175000017500000000000014201140431015356 5ustar fengfengukui-notebook/uNoteDbusServer/uNoteDbusServer.h0000644000175000017500000000255014201136534020641 0ustar fengfeng/* * Copyright (C) 2021 Tianjin KYLIN Information Technology Co., Ltd. * * This program is free software; you can 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, 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 #include #include #include #include #include #include struct Note{ int id; time_t editTime; QString noteText; }; class UNoteDbusServer : public QObject { Q_OBJECT //定义Interface名称 Q_CLASSINFO("D-Bus Interface", "org.ukui.note.interface") public: explicit UNoteDbusServer(); public slots: QVariantMap keywordMatch(QStringList keyList); public: bool exportAllNotes(QList&); private: QMap loadSqlDB(); private: QVariantMap keywordsMatched; }; #endif // UNOTEDBUSSERVER_H ukui-notebook/uNoteDbusServer/uNoteDbusServer.pro0000644000175000017500000000235314174170620021216 0ustar fengfengTEMPLATE = app TARGET = ukui-notebook-server INCLUDEPATH += . QT += dbus core sql # The following define makes your compiler warn you if you use any # feature of Qt which has been marked as deprecated (the exact warnings # depend on your compiler). Please consult the documentation of the # deprecated API in order to know how to port your code away from it. DEFINES += QT_DEPRECATED_WARNINGS # You can also make your code fail to compile if you use deprecated APIs. # In order to do so, uncomment the following line. # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 # Input DBUS_ADAPTORS += ../data/org.ukui.note.xml DBUS_INTERFACES += ../data/org.ukui.note.xml HEADERS += \ uNoteDbusServer.h SOURCES += \ main.cpp \ uNoteDbusServer.cpp target.path = /usr/bin/ !isEmpty(target.path): INSTALLS += target dbus_conf.path = /etc/dbus-1/system.d dbus_conf.files += ../data/org.ukui.note.conf INSTALLS += dbus_conf systemd_service.path = /usr/share/dbus-1/services/ #systemd_service.path = /lib/systemd/system systemd_service.files += ../data/org.ukui.note.service INSTALLS += systemd_service ukui-notebook/uNoteDbusServer/uNoteDbusServer.cpp0000644000175000017500000000744014201140431021166 0ustar fengfeng/* * Copyright (C) 2020, KylinSoft Co., Ltd. * * This program is free software: you can 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 . */ #include "uNoteDbusServer.h" UNoteDbusServer::UNoteDbusServer() { } QVariantMap UNoteDbusServer::keywordMatch(QStringList keyList) { QVariantMap keyMap; qDebug() << keyList.count(); QString sql; if(keyList.count() >= 1) { sql = QStringLiteral("SELECT id, md_content, full_title FROM active_notes WHERE md_content LIKE '%%1%'").arg(keyList.at(0)); for(int i = 1; i < keyList.count(); i++) { QString tmpSql = QStringLiteral(" AND md_content LIKE '%%1%'").arg(keyList.at(i)); sql.append(tmpSql); } } qDebug() << sql <(content); keyMap.insert(query.value(0).toString(), var); } } qDebug() << keyMap; return keyMap; } QMap UNoteDbusServer::loadSqlDB() { qDebug() << QSqlDatabase::drivers(); QVariantMap keyMap; QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE"); db.setDatabaseName(QDir::homePath() + "/.config/kylin-note/kyNotes.db"); if(!db.open()){ //如果数据库打开失败 qWarning() << "error!" << db.lastError(); } QSqlQuery query; if(query.exec("SELECT id, md_content FROM active_notes")) { while(query.next()){ keyMap.insert(query.value(0).toString(), query.value(1)); qDebug() << query.value(0).toString() << query.value(1).toString(); } } return keyMap; } //增加一个读取所有的接口 bool UNoteDbusServer::exportAllNotes(QList &data) { QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE"); db.setDatabaseName(QDir::homePath() + "/.config/kylin-note/kyNotes.db"); if(!db.open()){ //如果数据库打开失败 qWarning() << "error!" << db.lastError().text(); return false; } QString sql = QString("SELECT id, modification_date, md_content FROM active_notes"); QSqlQuery query; if(query.exec(sql)) { while(query.next()){ int id = query.value(0).toInt(); time_t modTime = query.value(1).toInt(); QString content = query.value(2).toString(); qDebug() << id << modTime << content; Note note; note.id = id; note.editTime = modTime; note.noteText = content; data.push_back(note); } } return true; } ukui-notebook/uNoteDbusServer/main.cpp0000644000175000017500000000274014201140431017011 0ustar fengfeng/* * Copyright (C) 2020, KylinSoft Co., Ltd. * * This program is free software: you can 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 . */ #include #include #include #include #include #include #include "uNoteDbusServer.h" #include "note_adaptor.h" int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); QDBusConnection sessionDbus = QDBusConnection::sessionBus(); if(!sessionDbus.registerService("org.ukui.note")) { qCritical() << "QDbus register service failed reason:" << sessionDbus.lastError().message(); //exit(1); } UNoteDbusServer *dbus = new UNoteDbusServer(); new InterfaceAdaptor(dbus); if(!sessionDbus.registerObject("/org/ukui/note", dbus)) { qCritical() << "QDbus register object failed reason:" << sessionDbus.lastError().message(); } return a.exec(); } ukui-notebook/translations/0000755000175000017500000000000014174170620015014 5ustar fengfengukui-notebook/translations/clean-translated-resources.sh0000755000175000017500000000016214174170620022603 0ustar fengfengecho "clean qm files..." for file in $(dirname $0)/*/*.qm do echo "delete $file" rm -f ${file} done echo "done" ukui-notebook/translations/ukui-notebook/0000755000175000017500000000000014201136534017604 5ustar fengfengukui-notebook/translations/ukui-notebook/ukui-notebook_tr.qm0000644000175000017500000000622314201136534023446 0ustar fengfeng /g th Zp Zp r  㮳 !y be A 6 A u ݥ @  o & iQsNAboutAboutDialogAboutO{~4NotesAboutfO{~4f/N;xSvOh^u(\cN [cONN0[vuLb0OcwvdO\0z3[vR eW(SY}vu(b7OSa0Notes is a self-developed sidebar application plug-in, which provides a rich interface, convenient operation and stable functions, aiming at a friendly user experience.Aboutg RNe/cV Service & Support: About rHg,S%1 Version: %1AboutR|BoldEditPage[WOSr Font ColorEditPage[WS Font SizeEditPagecQeVrG InsertPictureEditPageeOSItalicEditPage~JPEG (*.jpg);; GIF (*.gif);; PNG (*.png);; BMP (*.bmp);; Qh (*)@JPEG (*.jpg);; GIF (*.gif);; PNG (*.png);; BMP (*.bmp);; All (*)EditPageO{~4NotesEditPageg ^RhOrderedEditPage bVrGSelect an imageEditPageR d~ StrikeoutEditPageN R~ UnderlineEditPagee^Rh UnorderedEditPageY R6copyEditPage\ N-S:WY R6R0eO{~copy to newpageEditPageRjRcutEditPage|4pasteEditPage`bY redoEditPagedundoEditPage14 Edit_pageForm Edit_page Sort Type HeaderBar[VrG] [picture]NoteDataForm PaletteWidgetf>y:showQObjectForm SelectColorForm SetFontColorForm SetFontSizeQsNAboutWidgetQsCloseWidgete^O{~Create New NoteWidgetR dDelete Selected NoteWidget nzzO{~g, Empty NoteWidgetQExitWidget^.RHelpWidgetSUMenuWidgetg\SMinimizeWidgete^NewWidgetO{~4NotesWidgetd}"SearchWidgetRcbV Switch ViewWidget$k"Ou(O{~4 SQSO{~Q[0Welcome to use Notes.WidgetWidgetWidget[VrG] [picture]Widget`xn[nzzO{~g,TAre you sure empty notebook? emptyNotesDialog emptyNotesN Qcy:No Tips emptyNotesSmcancel emptyNotes nzzO{~g, emptyNotes emptyNotesxn[yes emptyNotesForm fontButtonNY) Today iconViewModeDelegatef(Y)  Yesterday iconViewModeDelegateNY) Today listViewModeDelegatef(Y)  Yesterday listViewModeDelegatexnQO{~g,T?#Are you sure to exit the note book?noteExitWindowT eQshLbO{~u,Close the desktop note page at the same timenoteExitWindowDialognoteExitWindowSmNonoteExitWindowxn[YesnoteExitWindowFormnoteHead`;W(v\BAlways in the front noteHeadMenuQsClose noteHeadMenue^O{~Create New Note noteHeadMenu R dkdO{~Delete this note noteHeadMenuForm noteHeadMenuSUMenu noteHeadMenu bS_O{~g,Open note list noteHeadMenurgPalette noteHeadMenuRNShare noteHeadMenuForm paletteButtonukui-notebook/translations/ukui-notebook/ukui-notebook_tr.ts0000644000175000017500000002762314174170620023471 0ustar fengfeng Edit_page Form ukui-memo Close Kapat Kapat Open Notepad Notepad Aç Notepad Aç New Yeni Yeni HeaderBar Sort Type Sıralama Türü PaletteWidget Form QObject %1 records in total Toplam %1 kayıt Toplam %1 kayıt Set_font_color_page Form Set_font_size_page Form TextEditWidget Form 14 Text_editing Form Widget Widget New Yeni Yeni ukui-note ukui-not ukui-not Welcome to use Kylin Note. Not defterine hoş geldiniz. Not defterine hoş geldiniz. Search Ara Ara Create New Note Yeni Not Oluştur Yeni Not Oluştur Empty Note Boş Not Boş Not Delete Selected Note Seçilen Notu Sil Seçilen Notu Sil Switch View Görünümü Değiştir Görünümü Değiştir Sort Sırala Sırala Switching Themes Tema Değiştir Tema Değiştir Exit Çıkış Çıkış Mini Menu Menü Menü Welcome to use Kylin system, you will experience more intimate service. Ukui sistemini kullanmaya hoş geldiniz, daha samimi bir hizmet göreceksiniz. Ukui sistemini kullanmaya hoş geldiniz, daha samimi bir hizmet göreceksiniz. emptyNotes Dialog 确定要清空便签本吗? Yapışkan notu silmek istediğinizden emin misiniz? 不再询问 Artık Sorma 取消 İptal Et 确定 Onayla fontButton Form iconViewModeDelegate Today Bugün Bugün Yesterday Dün Dün listViewModeDelegate Today Bugün Bugün Yesterday Dün Dün noteExitWindow Dialog Are you sure to exit the note book? Not defterinden çıkmak istediğinizden emin misiniz? Not defterinden çıkmak istediğinizden emin misiniz? Close the desktop note page at the same time Masaüstü not sayfasını aynı anda kapatın Masaüstü not sayfasını aynı anda kapatın No Hayır Hayır Yes Evet Evet noteHead Form noteHeadMenu Form paletteButton Form select_color_page Form ukui-notebook/translations/ukui-notebook/ukui-notebook_zh_CN.ts0000644000175000017500000006647614201136534024053 0ustar fengfeng About Dialog Note 麒麟便签本 Kylin Note 麒麟便签本 麒麟便签本 About 关于 关于 Kylin Memo 麒麟便签本 麒麟便签本 Notes 便签贴 便签贴 Version: 2020.1.0 版本: 2020.1.0 版本: 2020.1.0 Version: %1 版本号:%1 Notes is a self-developed sidebar application plug-in, which provides a rich interface, convenient operation and stable functions, aiming at a friendly user experience. 便签贴是自主研发的侧边栏应用小插件,它提供了丰富的界面、便捷的操作、稳定的功能,旨在友好的用户体验感。 便签贴是自主研发的侧边栏应用小插件,它提供了丰富的界面、便捷的操作、稳定的功能,旨在友好的用户体验感。 Service & Support: 服务与支持团队: 服务与支持团队: Kylin Memo is a self-developed sidebar application plug-in, which provides a rich interface, convenient operation and stable functions, aiming at a friendly user experience. 麒麟便签本是自主研发的侧边栏应用小插件,它提供了丰富的界面、便捷的操作、稳定的功能,旨在友好的用户体验感。 麒麟便签本是自主研发的侧边栏应用小插件,它提供了丰富的界面、便捷的操作、稳定的功能,旨在友好的用户体验感。 Support: support@kylinos.cn 服务与支持团队:support@kylinos.cn 服务与支持团队:support@kylinos.cn Kylin Note is a self-developed sidebar application plug-in, which provides a rich interface, convenient operation and stable functions, aiming at a friendly user experience. 麒麟便签本是自主研发的侧边栏应用小插件,它提供了丰富的界面、便捷的操作、稳定的功能,旨在友好的用户体验感。 麒麟便签本是自主研发的侧边栏应用小插件,它提供了丰富的界面、便捷的操作、稳定的功能,旨在友好的用户体验感。 Developer: yueshuai@kylinos.cn 开发者: yueshuai@kylinos.cn 开发者: yueshuai@kylinos.cn EditPage Notes 便签贴 Bold 加粗 Italic 斜体 Underline 下划线 Strikeout 删除线 Unordered 无序列表 Ordered 有序列表 Font Size 字号 Font Color 字体颜色 InsertPicture 插入图片 undo 撤销 redo 恢复 cut 剪切 copy 复制 paste 粘贴 copy to newpage 将选中区域复制到新便签 Select an image 请选择图片 JPEG (*.jpg);; GIF (*.gif);; PNG (*.png);; BMP (*.bmp);; All (*) JPEG (*.jpg);; GIF (*.gif);; PNG (*.png);; BMP (*.bmp);; 全部 (*) Edit_page Form 14 ukui-memo 麒麟便签页 麒麟便签页 Kylin Memo 麒麟便签本 麒麟便签本 Notes 便签贴 便签贴 Bold 加粗 加粗 Italic 斜体 斜体 Underline 下划线 下划线 Strikeout 删除线 删除线 Unordered 无序列表 无序列表 Ordered 有序列表 有序列表 Font Size 字号 字号 Font Color 字体颜色 字体颜色 InsertPicture 插入图片 Select an image 请选择图片 JPEG (*.jpg);; GIF (*.gif);; PNG (*.png);; BMP (*.bmp);; All (*) JPEG (*.jpg);; GIF (*.gif);; PNG (*.png);; BMP (*.bmp);; 全部 (*) Always in the front 总在顶层 总在顶层 Cancle in the front 取消置顶 取消置顶 undo 撤销 redo 恢复 cut 剪切 copy 复制 paste 粘贴 copy to newpage 将选中区域复制到新便签 Close 关闭 关闭 Open Notepad 打开便签本 打开便签本 New 新建 新建 HeaderBar Sort Type NoteData [picture] [图片] PaletteWidget Form QObject %1 records in total %1条记录 %1条记录 show 显示 SelectColor Form SetFontColor Form SetFontSize Form Widget Widget Kylin Note 麒麟便签本 麒麟便签本 Note 麒麟便签本 麒麟便签本 New 新建 新建 ukui-note 麒麟便签本 麒麟便签本 About 关于 关于 Welcome to use Kylin Note. 欢迎使用麒麟便签本。 欢迎使用麒麟便签本。 Search 搜索 搜索 Create New Note 新建便签 新建便签 Kylin Memo 麒麟便签本 麒麟便签本 Notes 便签贴 便签贴 Help 帮助 帮助 Empty Note 清空便签本 清空便签本 Close 关闭 关闭 Minimize 最小化 最小化 Welcome to use Notes. 欢迎使用便签贴,双击可编辑便签内容。 欢迎使用便签贴,双击可编辑便签内容。 [picture] [图片] Welcome to use Kylin Memo. 欢迎使用便签本,双击可编辑便签内容。 欢迎使用便签本,双击可编辑便签内容。 Creation Date 创建时间 创建时间 Modified Date 修改时间 修改时间 Note Name 便签名称 便签名称 Delete Selected Note 删除 删除 Switch View 切换视图 切换视图 Sort 排序 排序 Switching Themes 换肤 换肤 Exit 退出 退出 Mini 最小化 最小化 Menu 菜单 菜单 Welcome to use Kylin system, you will experience more intimate service. 欢迎使用优麒麟系统,您将体会到更贴心的服务。 欢迎使用优麒麟系统,您将体会到更贴心的服务。 emptyNotes Dialog Are you sure empty notebook? 您确定要清空便签本吗? 您确定要清空便签本吗? No Tips 不再提示 不再提示 cancel 取消 取消 yes 确定 确定 emptyNotes 清空便签本 清空便签本 fontButton Form iconViewModeDelegate Today 今天 今天 Yesterday 昨天 昨天 Today 今天 今天 Yesterday 昨天 昨天 listViewModeDelegate Today 今天 今天 Yesterday 昨天 昨天 Today 今天 Yesterday 昨天 noteExitWindow Dialog Are you sure to exit the note book? 确认要退出便签本吗? 确认要退出便签本吗? Close the desktop note page at the same time 同时关闭桌面便签页 同时关闭桌面便签页 No 取消 取消 Yes 确定 确定 noteHead Form noteHeadMenu Form Open note list 打开便签本 打开便签本 Always in the front 总在顶层 总在顶层 Delete this note 删除此便签 删除此便签 Share 分享 分享 Create New Note 新建便签 新建便签 Close 关闭 关闭 Exit 关闭 关闭 Menu 菜单 菜单 Palette 调色板 paletteButton Form ukui-notebook/translations/ukui-notebook/ukui-notebook_fr.ts0000644000175000017500000003005414174170620023443 0ustar fengfeng Edit_page Form Forme ukui-memo ukui-memo Close Kapat Fermer Open Notepad Notepad Aç Ouvrir le bloc-notes New Yeni Yeni HeaderBar Sort Type Type de tri PaletteWidget Form Forme QObject %1 records in total Toplam %1 kayıt %1 enregistrements au total Set_font_color_page Form Forme Set_font_size_page Form Forme TextEditWidget Form Forme 14 14 Text_editing Form Forme Widget Widget Widget New Yeni Nouveau ukui-note ukui-not ukui-note Welcome to use Kylin Note. Not defterine hoş geldiniz. Bienvenue dans Kylin Note. Search Ara Chercher Create New Note Yeni Not Oluştur Créer une nouvelle note Empty Note Boş Not Note vide Delete Selected Note Seçilen Notu Sil Supprimer la note sélectionnée Switch View Görünümü Değiştir Changer de vue Sort Sırala Trier Switching Themes Tema Değiştir Changer de thème Exit Çıkış Sortie Mini Mini Menu Menü Menu Welcome to use Kylin system, you will experience more intimate service. Ukui sistemini kullanmaya hoş geldiniz, daha samimi bir hizmet göreceksiniz. Bienvenue à utiliser le système Kylin, vous ferez l'expérience d'un service plus intime. emptyNotes Dialog Dialogue 确定要清空便签本吗? Voulez-vous vraiment vider le bloc-notes ? 不再询问 Ne plus demander 取消 Annuler 确定 Déterminer fontButton Form Forme iconViewModeDelegate Today Bugün Aujourd'hui Yesterday Dün Hier listViewModeDelegate Today Bugün Aujourd'hui Yesterday Dün Hier noteExitWindow Dialog Dialogue Are you sure to exit the note book? Not defterinden çıkmak istediğinizden emin misiniz? Êtes-vous sûr de quitter le carnet de notes ? Close the desktop note page at the same time Masaüstü not sayfasını aynı anda kapatın Fermez la page de notes du bureau en même temps No Hayır Non Yes Evet Oui noteHead Form Forme noteHeadMenu Form Forme paletteButton Form Forme select_color_page Form Forme ukui-notebook/translations/ukui-notebook/ukui-notebook_bo_CN.ts0000644000175000017500000003035414174170620024017 0ustar fengfeng Edit_page Form ukui-memo Close Kapat Open Notepad Notepad Aç New Yeni Yeni HeaderBar Sort Type PaletteWidget Form QObject %1 records in total Toplam %1 kayıt Set_font_color_page Form Set_font_size_page Form TextEditWidget Form 14 Text_editing Form Widget Widget New Yeni ukui-note ukui-not Welcome to use Kylin Note. Not defterine hoş geldiniz. Search Ara Create New Note Yeni Not Oluştur Empty Note Boş Not Delete Selected Note Seçilen Notu Sil Switch View Görünümü Değiştir Sort Sırala Switching Themes Tema Değiştir Exit Çıkış Mini Menu Menü Welcome to use Kylin system, you will experience more intimate service. Ukui sistemini kullanmaya hoş geldiniz, daha samimi bir hizmet göreceksiniz. emptyNotes Dialog 确定要清空便签本吗? 不再询问 取消 确定 fontButton Form iconViewModeDelegate Today Bugün Yesterday Dün listViewModeDelegate Today Bugün Yesterday Dün noteExitWindow Dialog Are you sure to exit the note book? Not defterinden çıkmak istediğinizden emin misiniz? Close the desktop note page at the same time Masaüstü not sayfasını aynı anda kapatın No Hayır Yes Evet noteHead Form noteHeadMenu Form paletteButton Form select_color_page Form ukui-notebook/translations/update-translations.sh0000755000175000017500000000046614174170620021362 0ustar fengfengecho "update translations..." lupdate ./src/plugins/notification_plugin/notification_plugin.pro echo "generate new translate resources files" for file in $(dirname $0)/*/*.ts do ts="*.ts" qm="*.qm" target=${file%.*}.qm echo ${target} echo "release $file $target" lrelease $file $target done echo "done" ukui-notebook/man/0000755000175000017500000000000014201140431013032 5ustar fengfengukui-notebook/man/ukui-notebook-server.10000644000175000017500000000134214201140431017213 0ustar fengfeng.\" Man Page for ukui-notebook-server .TH UKUI-NOTEBOOK 1 "2020-02-03" "UKUI Desktop Environment" .\" Please adjust this date when revising the manpage. .\" .SH "NAME" \fBukui-notebook-server\fR \- A NOTEBOOK PLUGIN IN UKUI .SH "SYNOPSIS" .B ukui-notebook-server [OPTIONS] .SH "DESCRIPTION" A notebook plugin for UKUI. .SH "OPTIONS" .TP \fB\-v, \-\-version\fR Output version information and exit. .SH "BUGS" .SS Should you encounter any bugs, they may be reported at: http://github.com/ukui/ukui-notebook/issues .SH "AUTHORS" .SS This Manual Page has been written for the UKUI Desktop Environment by: liuliang (2020) .SH "SEE ALSO" .SS Further information may also be available at: http://wiki.ukui-desktop.org/docs ukui-notebook/man/ukui-notebook.10000644000175000017500000000131514201140431015707 0ustar fengfeng.\" Man Page for ukui-notebook .TH UKUI-NOTEBOOK 1 "2020-02-03" "UKUI Desktop Environment" .\" Please adjust this date when revising the manpage. .\" .SH "NAME" \fBukui-notebook\fR \- A NOTEBOOK PLUGIN IN UKUI .SH "SYNOPSIS" .B ukui-notebook [OPTIONS] .SH "DESCRIPTION" A notebook plugin for UKUI. .SH "OPTIONS" .TP \fB\-v, \-\-version\fR Output version information and exit. .SH "BUGS" .SS Should you encounter any bugs, they may be reported at: http://github.com/ukui/ukui-notebook/issues .SH "AUTHORS" .SS This Manual Page has been written for the UKUI Desktop Environment by: liuliang (2020) .SH "SEE ALSO" .SS Further information may also be available at: http://wiki.ukui-desktop.org/docs ukui-notebook/src/0000755000175000017500000000000014201140431013046 5ustar fengfengukui-notebook/src/noteExitWindow.cpp0000644000175000017500000000740714174170620016565 0ustar fengfeng/* * Copyright (C) 2020 Tianjin KYLIN Information Technology Co., Ltd. * * This program is free software; you can 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, 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 setupUi(this); pNotebook = page; setAttribute(Qt::WA_TranslucentBackground); setWindowFlags(Qt::FramelessWindowHint | Qt::Dialog); QPainterPath blurPath; blurPath.addRoundedRect(rect().adjusted(6, 6, -6, -6), 6, 6); //增加圆角 setProperty("useSystemStyleBlur", true); setProperty("blurRegion", QRegion(blurPath.toFillPolygon().toPolygon()));//使用QPainterPath的api生成多边形Region QBitmap bmp(this->size()); bmp.fill(); QPainter p(&bmp); p.setPen(Qt::NoPen); p.setBrush(Qt::black); p.setRenderHint(QPainter::Antialiasing); p.drawRoundedRect(bmp.rect(),6,6); setMask(bmp); } noteExitWindow::~noteExitWindow() { delete ui; } void noteExitWindow::paintEvent(QPaintEvent *event) { Q_UNUSED(event); QPainter p(this); p.setRenderHint(QPainter::Antialiasing); // 反锯齿; QPainterPath rectPath; rectPath.addRoundedRect(this->rect().adjusted(6, 6, -6, -6), 6, 6); // 画一个黑底 QPixmap pixmap(this->rect().size()); pixmap.fill(Qt::transparent); QPainter pixmapPainter(&pixmap); pixmapPainter.setRenderHint(QPainter::Antialiasing); pixmapPainter.setPen(Qt::transparent); pixmapPainter.setBrush(Qt::black); pixmapPainter.drawPath(rectPath); pixmapPainter.end(); // 模糊这个黑底 QImage img = pixmap.toImage(); qt_blurImage(img, 10, false, false); // 挖掉中心 pixmap = QPixmap::fromImage(img); QPainter pixmapPainter2(&pixmap); pixmapPainter2.setRenderHint(QPainter::Antialiasing); pixmapPainter2.setCompositionMode(QPainter::CompositionMode_Clear); pixmapPainter2.setPen(Qt::transparent); pixmapPainter2.setBrush(Qt::transparent); pixmapPainter2.drawPath(rectPath); // 绘制阴影 p.drawPixmap(this->rect(), pixmap, pixmap.rect()); // 绘制一个背景 p.save(); //p.setOpacity(0.7); p.fillPath(rectPath,palette().color(QPalette::Base)); p.restore(); } void noteExitWindow::on_pushButton_clicked() { this->close(); } void noteExitWindow::on_pushButton_2_clicked() { this->close(); pNotebook->close(); if(ui->checkBox->isChecked()==true){ for (auto it = pNotebook->m_editors.begin(); it!= pNotebook->m_editors.end();it++) { (*it)->close(); //qDebug() << "before swap" << pNotebook->m_editors.size(); //std::vector tmp; //pNotebook->m_editors.swap(tmp); //qDebug() << "after swap" << pNotebook->m_editors.size(); } } } void noteExitWindow::exitImmediate() { this->close(); pNotebook->close(); // if(ui->checkBox->isChecked()==true){ // for (auto it = pNotebook->m_editors.begin(); it!= pNotebook->m_editors.end();it++) { // (*it)->close(); // } // } } ukui-notebook/src/editPage.h0000644000175000017500000001210414201136534014750 0ustar fengfeng/* * Copyright (C) 2020 Tianjin KYLIN Information Technology Co., Ltd. * * This program is free software; you can 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, 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 #include #include #include #include #include #include #include #include "noteHead.h" #include "noteHeadMenu.h" #include "ui_noteHeadMenu.h" #include "selectColorPage.h" #include "ui_selectColorPage.h" #include "paletteWidget.h" #include "ui_paletteWidget.h" #include "setFontColorPage.h" #include "ui_setFontColorPage.h" #include "setFontSizePage.h" #include "ui_setFontSizePage.h" namespace Ui { class Edit_page; } class Widget; class EditPage : public QWidget { Q_OBJECT public: EditPage(Widget* p , int noteId, QWidget *parent = nullptr); ~EditPage(); Ui::Edit_page *ui; Widget* m_notebook = nullptr; QColor m_editColor; noteHead *m_noteHead = nullptr; noteHeadMenu *m_noteHeadMenu = nullptr; QModelIndex m_index; SetFontSize *m_setSizePage = nullptr ; SetFontColor *m_setColorFontPage = nullptr ; QLabel *m_fontLabel = nullptr; QVBoxLayout *m_fontBtnLayout = nullptr; int m_id; int m_noteId; bool m_isFullscreen = false; //bool m_ignoreShowHideEvents; bool m_isInsImg = false; void paintEvent(QPaintEvent *event) Q_DECL_OVERRIDE; void enterEvent(QEvent *event) Q_DECL_OVERRIDE; void leaveEvent(QEvent *event) Q_DECL_OVERRIDE; bool eventFilter(QObject *obj, QEvent *event); Qt::WindowFlags m_flags; void setStayOnTopSlot(bool b); void setHints(); void setWindowKeepAbove(); void setWindowStatusClear(); private: void initSetup(); // 初始配置 void slotsSetup(); // 配置槽函数 void btnSetup(); // 初始化按钮 void mergeFormatOnWordOrSelection(const QTextCharFormat &format);// 字体设置 void fontChanged(const QFont &f); // 当前光标下字体格式获取 void fontColorChanged(const QColor &c); // 当前光标下字体颜色获取 void initColor(); void listenToGsettings(); private: SelectColor *m_colorPage = nullptr; QTimer *m_timer = nullptr; // QString color[6]; QColor m_colorNum[6]; QPointer m_lastBlockList; QPoint m_dragPosition; // 拖动坐标 bool m_mousePressed = false; // 鼠标是否按下 bool m_defaultFontColorChanged = false; // 黑白字体颜色 private slots: void cursorPositionChangedSlot(); // 当前光标位置改变 void currentCharFormatChangedSlot(const QTextCharFormat &format);// 当前字体格式改变 void textChangedSlot(); // 当前便签页身份id void setBoldSlot(); // 加粗 void setItalicSlot(); // 斜体 void setUnderlineSlot(); // 下划线 void setStrikeOutSlot(); // 删除线 void setUnorderedListSlot(bool checked); // 无序列表 void setOrderedListSlot(bool checked); // 有序列表 void list(bool checked, QTextListFormat::Style style); void setFontSizeSlot(); // 设置字体大小 void setFontColorSlot(QListWidgetItem *item); // 设置字体颜色 // 调色按钮 void onFontColorClicked(); void blueBtnSlot(); void redBtnSlot(); void darkGreenBtnSlot(); void orangeBtnSlot(); void purpleBtnSlot(); void goldenBtnSlot(); void greyBtnSlot(); void lightGreenBtnSlot(); void yellowBtnSlot(); void defaultTextColorSlot(); void defaultBtnSlot(); void pinkBtnSlot(); void showFullScreenSlot(); void textRightMenu(QPoint); void textForNewEditpageSlot(); void insertpicture(); void dropImage(const QImage& image, const QString& format); signals: void texthasChanged(int noteId, int id); void colorhasChanged(const QColor &color,int); void isEmptyNote(int noteId); void requestDel(int noteId); void textForNewEditpage(); }; #endif // EDIT_PAGE_H ukui-notebook/src/about.h0000644000175000017500000000216214201140431014332 0ustar fengfeng/* * Copyright (C) 2020, KylinSoft Co., Ltd. * * This program is free software: you can 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 . */ #ifndef ABOUT_H #define ABOUT_H #include #include #include #include #include namespace Ui { class About; } class About : public QDialog { Q_OBJECT public: explicit About(QWidget *parent = nullptr); ~About(); protected: void paintEvent(QPaintEvent *event) Q_DECL_OVERRIDE; private: Ui::About *ui; void listenToGsettings(); }; #endif // ABOUT_H ukui-notebook/src/dbManager.cpp0000644000175000017500000004474014174170620015457 0ustar fengfeng/* * Copyright (C) 2020 Tianjin KYLIN Information Technology Co., Ltd. * * This program is free software; you can 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, 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 #include #include #include #include #include #include "dbManager.h" /*! * \brief DBManager::DBManager * \param parent */ DBManager::DBManager(QObject *parent) : QObject(parent) { qRegisterMetaType >("QList"); } /*! * \brief DBManager::open * \param path * \param doCreate */ void DBManager::open(const QString &path, bool doCreate) { QSqlDatabase m_db; m_db = QSqlDatabase::addDatabase("QSQLITE","note"); m_db.setDatabaseName(path); if(!m_db.open()){ qDebug() << "Error: connection with database fail"; }else{ qDebug() << "Database: connection ok"; } if(doCreate) createTables(); } /*! * \brief DBManager::createTables */ void DBManager::createTables() { QSqlQuery query(QSqlDatabase::database("note")); QString active = "CREATE TABLE active_notes (" "id INTEGER PRIMARY KEY AUTOINCREMENT," "creation_date INTEGER NOT NULL DEFAULT (0)," "modification_date INTEGER NOT NULL DEFAULT (0)," "deletion_date INTEGER NOT NULL DEFAULT (0)," "content TEXT, " "full_title TEXT," "note_color INTEGER DEFAULT (0)," "md_content TEXT);"; query.exec(active); //CREATE UNIQUE INDEX 用于在表中创建唯一索引,这意味着两个行不能拥有相同的索引值 // ASC: 升序 DESC: 降序 //CREATE UNIQUE INDEX active_index on active_notes (id ASC); QString active_index = "CREATE UNIQUE INDEX active_index on active_notes (id ASC);"; query.exec(active_index); QString deleted = "CREATE TABLE deleted_notes (" "id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL," "creation_date INTEGER NOT NULL DEFAULT (0)," "modification_date INTEGER NOT NULL DEFAULT (0)," "deletion_date INTEGER NOT NULL DEFAULT (0)," "content TEXT," "full_title TEXT," "note_color INTEGER DEFAULT (0)," "md_content TEXT);"; query.exec(deleted); } /*! * \brief DBManager::getLastRowID * \return */ int DBManager::getLastRowID() { QSqlQuery query(QSqlDatabase::database("note")); //sqlite_sequence表也是SQLite的系统表,数据库被创建时,sqlite_sequence表会被自动创建 //该表包括两列。第一列为name,用来存储表的名称。第二列为seq,用来保存表对应的RowID的最大值 //当对应的表增加记录,该表会自动更新。当表删除,该表对应的记录也会自动删除。如果该值超过最大值,会引起SQL_FULL错误。 query.exec("SELECT seq from SQLITE_SEQUENCE WHERE name='active_notes';"); query.next(); return query.value(0).toInt(); } /*! * \brief DBManager::forceLastRowIndexValue * \param indexValue * \return */ bool DBManager::forceLastRowIndexValue(const int indexValue) { QSqlQuery query(QSqlDatabase::database("note")); QString queryStr = QStringLiteral("UPDATE SQLITE_SEQUENCE " "SET seq=%1 " "WHERE name='active_notes';").arg(indexValue); query.exec(queryStr); //Returns the number of rows affected by the result's SQL statement return query.numRowsAffected() == 1; } /*! * \brief DBManager::getNote * \param id * \return */ NoteData* DBManager::getNote(QString id) { QSqlQuery query(QSqlDatabase::database("note")); int parsedId = id.split('_')[1].toInt(); QString queryStr = QStringLiteral("SELECT * FROM active_notes WHERE id = %1 LIMIT 1").arg(parsedId); query.exec(queryStr); //检索结果中的第一条记录(如果有),并将查询放在检索到的记录上 if (query.first()) { NoteData* note = new NoteData(this->parent() == Q_NULLPTR ? Q_NULLPTR : this); int id = query.value(0).toInt(); qint64 epochDateTimeCreation = query.value(1).toLongLong(); QDateTime dateTimeCreation = QDateTime::fromMSecsSinceEpoch(epochDateTimeCreation); qint64 epochDateTimeModification= query.value(2).toLongLong(); QDateTime dateTimeModification = QDateTime::fromMSecsSinceEpoch(epochDateTimeModification); QString content = query.value(4).toString(); QString fullTitle = query.value(5).toString(); int notecolor = query.value(6).toInt(); QString mdContent = query.value(7).toString(); note->setId(id); note->setCreationDateTime(dateTimeCreation); note->setLastModificationDateTime(dateTimeModification); note->setContent(content); note->setFullTitle(fullTitle); note->setNoteColor(notecolor); note->setMdContent(mdContent); return note; } return Q_NULLPTR; } /*! * \brief DBManager::isNoteExist * \param note * \return */ bool DBManager::isNoteExist(NoteData* note) { QSqlQuery query(QSqlDatabase::database("note")); int id = note->id(); QString queryStr = QStringLiteral("SELECT EXISTS(SELECT 1 FROM active_notes WHERE id = %1 LIMIT 1 )") .arg(id); query.exec(queryStr); query.next(); return query.value(0).toInt() == 1; } /*! * \brief DBManager::getAllNotes * \return */ QList DBManager::getAllNotes() { QList noteList; QSqlQuery query(QSqlDatabase::database("note")); query.prepare("SELECT * FROM active_notes"); bool status = query.exec(); if(status){ while(query.next()){ NoteData* note = new NoteData(this); int id = query.value(0).toInt(); //Qt::UTC 1 世界标准时间,代替格林威治标准时间 //Qt::LocalTime 0 与语言环境相关的时间(时区和夏时制) qint64 epochDateTimeCreation = query.value(1).toLongLong(); //协调世界时间(Qt::UTC),并转换为Qt::LocalTime //返回一个时间日期是毫秒级的datetime QDateTime dateTimeCreation = QDateTime::fromMSecsSinceEpoch(epochDateTimeCreation); qint64 epochDateTimeModification= query.value(2).toLongLong(); QDateTime dateTimeModification = QDateTime::fromMSecsSinceEpoch(epochDateTimeModification); QString content = query.value(4).toString(); QString fullTitle = query.value(5).toString(); int notecolor = query.value(6).toInt(); QString mdContent = query.value(7).toString(); note->setId(id); note->setCreationDateTime(dateTimeCreation); note->setLastModificationDateTime(dateTimeModification); note->setContent(content); note->setFullTitle(fullTitle); note->setNoteColor(notecolor); note->setMdContent(mdContent); noteList.push_back(note); } } return noteList; } /*! * \brief DBManager::addNote * \param note * \return */ bool DBManager::addNote(NoteData* note) { QSqlQuery query(QSqlDatabase::database("note")); QString emptyStr; qint64 epochTimeDateCreated = note->creationDateTime() .toMSecsSinceEpoch(); QString content = note->content() .replace("'","''") .replace(QChar('\x0'), emptyStr); QString fullTitle = note->fullTitle() .replace("'","''") .replace(QChar('\x0'), emptyStr); QString mdContent = note->mdContent() .replace("'","''") .replace(QChar('\x0'), emptyStr); int notecolor = note->notecolor(); qint64 epochTimeDateLastModified = note->lastModificationdateTime().isNull() ? epochTimeDateCreated : note->lastModificationdateTime().toMSecsSinceEpoch(); QString queryStr = QString("INSERT INTO active_notes " "(creation_date, modification_date, deletion_date, content, full_title, note_color, md_content) " "VALUES (%1, %2, -1, '%3', '%4', '%5', '%6');") .arg(epochTimeDateCreated) .arg(epochTimeDateLastModified) .arg(content) .arg(fullTitle) .arg(notecolor) .arg(mdContent); query.exec(queryStr); //Returns the number of rows affected by the result's SQL statement return (query.numRowsAffected() == 1); } /*! * \brief DBManager::removeNote * \param note * \return */ bool DBManager::removeNote(NoteData* note) { QSqlQuery query(QSqlDatabase::database("note")); QString emptyStr; int id = note->id(); QString queryStr = QStringLiteral("DELETE FROM active_notes " "WHERE id=%1").arg(id); query.exec(queryStr); bool removed = (query.numRowsAffected() == 1); qint64 epochTimeDateCreated = note->creationDateTime().toMSecsSinceEpoch(); qint64 epochTimeDateModified = note->lastModificationdateTime().toMSecsSinceEpoch(); qint64 epochTimeDateDeleted = note->deletionDateTime().toMSecsSinceEpoch(); QString content = note->content() .replace("'","''") .replace(QChar('\x0'), emptyStr); QString fullTitle = note->fullTitle() .replace("'","''") .replace(QChar('\x0'), emptyStr); QString mdContent = note->mdContent() .replace("'","''") .replace(QChar('\x0'), emptyStr); int notecolor = note->notecolor(); queryStr = QString("INSERT INTO deleted_notes " "VALUES (%1, %2, %3, %4, '%5', '%6', '%7', '%8');") .arg(id) .arg(epochTimeDateCreated) .arg(epochTimeDateModified) .arg(epochTimeDateDeleted) .arg(content) .arg(fullTitle) .arg(notecolor) .arg(mdContent); query.exec(queryStr); bool addedToTrashDB = (query.numRowsAffected() == 1); return (removed && addedToTrashDB); } /*! * \brief DBManager::permanantlyRemoveAllNotes * \return */ bool DBManager::permanantlyRemoveAllNotes() { QSqlQuery query(QSqlDatabase::database("note")); return query.exec(QString("DELETE FROM active_notes")); } /*! * \brief DBManager::updateNote * \param note * \return */ bool DBManager::updateNote(NoteData* note) { QSqlQuery query(QSqlDatabase::database("note")); QString emptyStr; int id = note->id(); qDebug() << "updateNote note id = " <notecolor(); qint64 epochTimeDateModified = note->lastModificationdateTime().toMSecsSinceEpoch(); QString content = note->content().replace(QChar('\x0'), emptyStr); QString fullTitle = note->fullTitle().replace(QChar('\x0'), emptyStr); QString mdContent = note->mdContent().replace(QChar('\x0'), emptyStr); query.prepare(QStringLiteral("UPDATE active_notes SET md_content = :mdContent, note_color = :color," "modification_date = :date, content = :content, full_title = :title WHERE id = :id")); query.bindValue(QStringLiteral(":mdContent"), mdContent); query.bindValue(QStringLiteral(":color"), notecolor); query.bindValue(QStringLiteral(":date"), epochTimeDateModified); query.bindValue(QStringLiteral(":content"), content); query.bindValue(QStringLiteral(":title"), fullTitle); query.bindValue(QStringLiteral(":id"), id); if (!query.exec()) { qWarning () << __func__ << ": " << query.lastError(); } return (query.numRowsAffected() == 1); } /*! * \brief DBManager::migrateNote * \param note * \return */ bool DBManager::migrateNote(NoteData* note) { QSqlQuery query(QSqlDatabase::database("note")); QString emptyStr; int id = note->id(); int notecolor = note->notecolor(); qint64 epochTimeDateCreated = note->creationDateTime().toMSecsSinceEpoch(); qint64 epochTimeDateModified = note->lastModificationdateTime().toMSecsSinceEpoch(); QString content = note->content() .replace("'","''") .replace(QChar('\x0'), emptyStr); QString fullTitle = note->fullTitle() .replace("'","''") .replace(QChar('\x0'), emptyStr); QString mdContent = note->mdContent() .replace("'","''") .replace(QChar('\x0'), emptyStr); QString queryStr = QString("INSERT INTO active_notes " "VALUES (%1, %2, %3, -1, '%4', '%5', '%6', '%7');") .arg(id) .arg(epochTimeDateCreated) .arg(epochTimeDateModified) .arg(content) .arg(fullTitle) .arg(notecolor) .arg(mdContent); query.exec(queryStr); return (query.numRowsAffected() == 1); } /*! * \brief DBManager::migrateTrash * \param note * \return */ bool DBManager::migrateTrash(NoteData* note) { QSqlQuery query(QSqlDatabase::database("note")); QString emptyStr; int id = note->id(); int notecolor = note->notecolor(); qint64 epochTimeDateCreated = note->creationDateTime().toMSecsSinceEpoch(); qint64 epochTimeDateModified = note->lastModificationdateTime().toMSecsSinceEpoch(); qint64 epochTimeDateDeleted = note->deletionDateTime().toMSecsSinceEpoch(); QString content = note->content() .replace("'","''") .replace(QChar('\x0'), emptyStr); QString fullTitle = note->fullTitle() .replace("'","''") .replace(QChar('\x0'), emptyStr); QString mdContent = note->mdContent() .replace("'","''") .replace(QChar('\x0'), emptyStr); QString queryStr = QString("INSERT INTO deleted_notes " "VALUES (%1, %2, %3, %4, '%5', '%6', '%7', '%8');") .arg(id) .arg(epochTimeDateCreated) .arg(epochTimeDateModified) .arg(epochTimeDateDeleted) .arg(content) .arg(fullTitle) .arg(notecolor) .arg(mdContent); query.exec(queryStr); return (query.numRowsAffected() == 1); } /*! * \brief DBManager::onNotesListRequested */ void DBManager::onNotesListRequested() { int noteCounter; QList noteList; noteCounter = getLastRowID(); noteList = getAllNotes(); emit notesReceived(noteList, noteCounter); } /*! * \brief DBManager::onOpenDBManagerRequested * \param path * \param doCreate */ void DBManager::onOpenDBManagerRequested(QString path, bool doCreate) { open(path, doCreate); } /*! * \brief DBManager::onCreateUpdateRequested * \param note */ void DBManager::onCreateUpdateRequested(NoteData* note) { bool exists = isNoteExist(note); if(exists){ qDebug() << "DBManager::updateNote"; updateNote(note); } else{ qDebug() << "DBManager::addNote"; addNote(note); } } /*! * \brief DBManager::onDeleteNoteRequested * \param note */ void DBManager::onDeleteNoteRequested(NoteData* note) { qDebug() << "receive requestDeleteNote :" << __FILE__ << "当前函数 :" << __FUNCTION__ << "当前行号 :" << __LINE__; removeNote(note); } /*! * \brief DBManager::onImportNotesRequested * \param noteList */ void DBManager::onImportNotesRequested(QList noteList) { QSqlDatabase::database().transaction(); for(NoteData* note : noteList) addNote(note); QSqlDatabase::database().commit(); } /*! * \brief DBManager::onRestoreNotesRequested * \param noteList */ void DBManager::onRestoreNotesRequested(QList noteList) { this->permanantlyRemoveAllNotes(); this->onImportNotesRequested(noteList); } /*! * \brief DBManager::onExportNotesRequested * \param fileName */ void DBManager::onExportNotesRequested(QString fileName) { QList noteList; QFile file(fileName); file.open(QIODevice::WriteOnly); QDataStream out(&file); #if QT_VERSION >= QT_VERSION_CHECK(5, 6, 0) out.setVersion(QDataStream::Qt_5_6); #elif QT_VERSION >= QT_VERSION_CHECK(5, 4, 0) out.setVersion(QDataStream::Qt_5_4); #elif QT_VERSION >= QT_VERSION_CHECK(5, 2, 0) out.setVersion(QDataStream::Qt_5_2); #endif noteList = getAllNotes(); out << noteList; file.close(); qDeleteAll(noteList); noteList.clear(); } /*! * \brief DBManager::onMigrateNotesRequested * \param noteList */ void DBManager::onMigrateNotesRequested(QList noteList) { QSqlDatabase::database().transaction(); for(NoteData* note : noteList) migrateNote(note); QSqlDatabase::database().commit(); qDeleteAll(noteList); noteList.clear(); } /*! * \brief DBManager::onMigrateTrashRequested * \param noteList */ void DBManager::onMigrateTrashRequested(QList noteList) { QSqlDatabase::database().transaction(); for(NoteData* note : noteList) migrateTrash(note); QSqlDatabase::database().commit(); qDeleteAll(noteList); noteList.clear(); } /*! * \brief DBManager::onForceLastRowIndexValueRequested * \param index */ void DBManager::onForceLastRowIndexValueRequested(int index) { forceLastRowIndexValue(index); } ukui-notebook/src/selectColorPage.ui0000644000175000017500000000060214174170620016472 0ustar fengfeng SelectColor 0 0 250 40 Form ukui-notebook/src/noteModel.cpp0000644000175000017500000001721414174170620015521 0ustar fengfeng/* * Copyright (C) 2020 Tianjin KYLIN Information Technology Co., Ltd. * * This program is free software; you can 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, 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 #include "noteModel.h" NoteModel::NoteModel(QObject *parent) : QAbstractListModel(parent) { } NoteModel::~NoteModel() { } QModelIndex NoteModel::addNote(NoteData* note) { const int rowCnt = rowCount(); //指定要插入的第一行和最后一行新行的行号,以及其父项的模型索引 beginInsertRows(QModelIndex(), rowCnt, rowCnt); m_noteList << note; endInsertRows(); return createIndex(rowCnt, 0); } QModelIndex NoteModel::insertNote(NoteData *note, int row) { if(row >= rowCount()){ return addNote(note); }else{ beginInsertRows(QModelIndex(), row, row); m_noteList.insert(row, note); endInsertRows(); } return createIndex(row,0); } NoteData* NoteModel::getNote(const QModelIndex& index) { if(index.isValid()){ //返回列表中索引位置index.row处的项, index.row 必须是列表中有效的索引位置 return m_noteList.at(index.row()); }else{ return Q_NULLPTR; } } void NoteModel::addListNote(QList noteList) { int start = rowCount(); int end = start + noteList.count()-1; beginInsertRows(QModelIndex(), start, end); m_noteList << noteList; endInsertRows(); } NoteData* NoteModel::removeNote(const QModelIndex ¬eIndex) { int row = noteIndex.row(); beginRemoveRows(QModelIndex(), row, row); NoteData* note = m_noteList.takeAt(row); endRemoveRows(); return note; } bool NoteModel::moveRow(const QModelIndex &sourceParent, int sourceRow, const QModelIndex &destinationParent, int destinationChild) { if(sourceRow<0 || sourceRow >= m_noteList.count() || destinationChild <0 || destinationChild >= m_noteList.count()){ return false; } //参数1 QAbstractListModel //参数2和参数3是要移动的行的第一行和最后一行,将参数2 参数3 所在行 移动到 destinationChild 之上 //参数4 QAbstractListModel 索引对应于在其中这些行被移动的父 beginMoveRows(sourceParent,sourceRow,sourceRow,destinationParent,destinationChild); //将 sourceRow item 移动到 destinationChild item位置, destinationChild item依次前移 m_noteList.move(sourceRow,destinationChild); endMoveRows(); return true; } void NoteModel::clearNotes() { beginResetModel(); m_noteList.clear(); endResetModel(); } //负责返回数据项对应于所述索引参数 QVariant NoteModel::data(const QModelIndex &index, int role) const { if (index.row() < 0 || index.row() >= m_noteList.count()) return QVariant(); NoteData* note = m_noteList[index.row()]; if(role == NoteID){ return note->id(); }else if(role == NoteFullTitle){ return note->fullTitle(); }else if(role == NoteCreationDateTime){ return note->creationDateTime(); }else if(role == NoteLastModificationDateTime){ return note->lastModificationdateTime(); }else if(role == NoteDeletionDateTime){ return note->deletionDateTime(); }else if(role == NoteContent){ return note->content(); }else if(role == NoteScrollbarPos){ return note->scrollBarPosition(); }else if(role == NoteColor){ return note->notecolor(); }else if (role == NoteMdContent){ return note->mdContent(); } return QVariant(); } //provide a way for the delegate to set the data in the model bool NoteModel::setData(const QModelIndex &index, const QVariant &value, int role) { if (!index.isValid()) return false; NoteData* note = m_noteList[index.row()]; if(role == NoteID){ note->setId(value.toInt()); }else if(role == NoteFullTitle){ note->setFullTitle(value.toString()); }else if(role == NoteCreationDateTime){ note->setCreationDateTime(value.toDateTime()); }else if(role == NoteLastModificationDateTime){ note->setLastModificationDateTime(value.toDateTime()); }else if(role == NoteDeletionDateTime){ note->setDeletionDateTime(value.toDateTime()); }else if(role == NoteContent){ note->setContent(value.toString()); }else if(role == NoteScrollbarPos){ note->setScrollBarPosition(value.toInt()); }else if(role == NoteColor){ note->setNoteColor(value.toInt()); }else if(role == NoteMdContent){ note->setMdContent(value.toString()); }else{ return false; } emit dataChanged(this->index(index.row()), this->index(index.row()), QVector(1,role)); return true; } Qt::ItemFlags NoteModel::flags(const QModelIndex &index) const { //if (!index.isValid()) // return Qt::ItemIsEnabled | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled; //return QAbstractListModel::flags(index) | Qt::ItemIsEditable | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled; if (!index.isValid()) return Qt::ItemIsEnabled; return QAbstractListModel::flags(index) | Qt::ItemIsEditable; } //保持模型中的行数与字符串列表中的字符串数相同 int NoteModel::rowCount(const QModelIndex &parent) const { Q_UNUSED(parent) return m_noteList.count(); } void NoteModel::sort(int column, Qt::SortOrder order) { Q_UNUSED(order) qDebug() << "NoteModel::sort" << column; // 升序 if(order == Qt::AscendingOrder){ if(column == 0){ //创建时间排序 std::stable_sort(m_noteList.begin(), m_noteList.end(), [](NoteData* lhs, NoteData* rhs){ return lhs->creationDateTime() > rhs->creationDateTime(); }); }else if (column == 1){ //修改时间排序 std::stable_sort(m_noteList.begin(), m_noteList.end(), [](NoteData* lhs, NoteData* rhs){ return lhs->lastModificationdateTime() > rhs->lastModificationdateTime(); }); }else if (column == 2){ //名称排序 std::stable_sort(m_noteList.begin(), m_noteList.end(), [](NoteData* lhs, NoteData* rhs){ return lhs->mdContent() > rhs->mdContent(); }); } }else if(order == Qt::DescendingOrder){ if(column == 0){ //创建时间排序 std::stable_sort(m_noteList.begin(), m_noteList.end(), [](NoteData* lhs, NoteData* rhs){ return lhs->creationDateTime() < rhs->creationDateTime(); }); }else if (column == 1){ //修改时间排序 std::stable_sort(m_noteList.begin(), m_noteList.end(), [](NoteData* lhs, NoteData* rhs){ return lhs->lastModificationdateTime() < rhs->lastModificationdateTime(); }); }else if (column == 2){ //名称排序 std::stable_sort(m_noteList.begin(), m_noteList.end(), [](NoteData* lhs, NoteData* rhs){ return lhs->mdContent() < rhs->mdContent(); }); } } emit dataChanged(index(0), index(rowCount()-1)); } Qt::DropActions NoteModel::supportedDropActions() const { return Qt::CopyAction | Qt::MoveAction; } ukui-notebook/src/noteHeadMenu.ui0000644000175000017500000000632014174170620015776 0ustar fengfeng noteHeadMenu 0 0 300 42 Form 0 8 8 8 8 20 20 20 20 false Qt::Horizontal 136 20 8 24 24 24 24 24 24 24 24 false 24 24 24 24 false ukui-notebook/src/noteModel.h0000644000175000017500000000435014174170620015163 0ustar fengfeng/* * Copyright (C) 2020 Tianjin KYLIN Information Technology Co., Ltd. * * This program is free software; you can 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, 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 #include "noteData.h" class NoteModel : public QAbstractListModel { friend class tst_NoteModel; public: enum NoteRoles{ NoteID = Qt::UserRole + 1, NoteFullTitle, NoteCreationDateTime, NoteLastModificationDateTime, NoteDeletionDateTime, NoteContent, NoteScrollbarPos, NoteColor, NoteMdContent, }; explicit NoteModel(QObject *parent = Q_NULLPTR); ~NoteModel(); public: QModelIndex addNote(NoteData* note); QModelIndex insertNote(NoteData* note, int row); NoteData* getNote(const QModelIndex& index); void addListNote(QList noteList); NoteData* removeNote(const QModelIndex& noteIndex); bool moveRow(const QModelIndex& sourceParent, int sourceRow, const QModelIndex& destinationParent, int destinationChild); void clearNotes(); public: QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE; bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) Q_DECL_OVERRIDE; Qt::ItemFlags flags(const QModelIndex &index) const Q_DECL_OVERRIDE; int rowCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; void sort(int column, Qt::SortOrder order) Q_DECL_OVERRIDE; Qt::DropActions supportedDropActions() const override; private: QList m_noteList; signals: void noteRemoved(); }; #endif // NOTEMODEL_H ukui-notebook/src/selectColorPage.cpp0000644000175000017500000000423614174170620016646 0ustar fengfeng/* * Copyright (C) 2020 Tianjin KYLIN Information Technology Co., Ltd. * * This program is free software; you can 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, 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 #include #include "widget.h" #include "ui_widget.h" #include "ui_paletteWidget.h" #include "selectColorPage.h" #include "ui_selectColorPage.h" #ifndef SHADOW_WIDTH #define SHADOW_WIDTH 0 #endif SelectColor::SelectColor(Widget* page, QWidget *parent) : QWidget(parent), ui(new Ui::SelectColor), paletteWidget(new PaletteWidget(this)) { ui->setupUi(this); pNotebook = page; initSetup(); } SelectColor::~SelectColor() { delete ui; } void SelectColor::paintEvent(QPaintEvent *event) { Q_UNUSED(event); QPainter painter(this); QStyleOption opt; opt.init(this); painter.setRenderHint(QPainter::Antialiasing, true); painter.setPen(Qt::NoPen); painter.setBrush(opt.palette.color(QPalette::Base)); painter.setOpacity(0.9); // 小三角区域; QPolygon trianglePolygon; trianglePolygon << QPoint(m_startX, m_triangleHeight + SHADOW_WIDTH); trianglePolygon << QPoint(m_startX + m_triangleWidth / 2, SHADOW_WIDTH); trianglePolygon << QPoint(m_startX + m_triangleWidth, m_triangleHeight + SHADOW_WIDTH); QPainterPath drawPath; drawPath.addPolygon(trianglePolygon); painter.drawPath(drawPath); } void SelectColor::initSetup() { setAttribute(Qt::WA_TranslucentBackground); setProperty("blurRegion", QRegion(QRect(1, 1, 1, 1)));//透明 setWindowFlags(Qt::FramelessWindowHint | Qt::Popup); paletteWidget->setGeometry(QRect(0, 5, 250, 35)); paletteWidget->show(); } ukui-notebook/src/image.qrc0000644000175000017500000000501114174170620014650 0ustar fengfeng image/1x/ Convert_to_notes .png image/1x/ Insert_multiple_box .png image/1x/adjustment.png image/1x/array_des.png image/1x/array_order.png image/1x/array.png image/1x/array-new.png image/1x/bold.png image/1x/copy_to_new_note.png image/1x/copy.png image/1x/cut.png image/1x/del_line.png image/1x/delete.png image/1x/export.png image/1x/go-bottom-symbolic.png image/1x/Italic.png image/1x/list.png image/1x/new-normal.png image/1x/new-hover.png image/1x/new-click.png image/1x/note_color.png image/1x/number.png image/1x/open_note-book.png image/1x/open-menu-symbolic.png image/1x/paste.png image/1x/recovery.png image/1x/select.png image/1x/Symbol.png image/1x/table.png image/1x/under_line-new.png image/1x/window-close-symbolic.png image/1x/window-minimize-symbolic.png image/1x/withdraw.png image/kylin-notebook.svg image/1x/sourch.png image/1x/skin.png image/1x/menu-black.png image/1x/menu-light.png image/1x/mini_block.png image/1x/close-black.png image/1x/close-light.png image/1x/mini_light.png image/1x/close2.png image/1x/close3.png image/1x/mini2.png image/1x/mini3.png image/1x/sort-click.png image/1x/sort-hover.png image/1x/sort.png image/1x/delete-new.svg image/1x/adjustment-new.svg image/1x/del_line-new.svg image/1x/note_color_new.svg image/1x/number-new.svg image/1x/Symbol-new.svg image/1x/system-search-symbolic.svg ukui-notebook/src/customStyle.h0000644000175000017500000001761214174170620015575 0ustar fengfeng/* * Copyright (C) 2020 Tianjin KYLIN Information Technology Co., Ltd. * * This program is free software; you can 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, 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 #include /*! * \brief The CustomStyle class * \details * 自定义QStyle * 基于QProxyStyle,默认使用QProxyStyle的实例绘制控件,你需要针对某一个控件重新实现若干对应的接口。 * QProxyStyle可以从现有的qt style实例化,我们只需要知道这个style的名字即可。 * 这种做法带来了不错的扩展性和自由度,因为我们不需要将某个style的代码直接引入我们的项目中, * 也能够“继承”这个style类进行二次开发。 * * 下面的方法展现了QStyle的所有的接口,使用QStyle进行控件的绘制使得qt应用能够进行风格的切换, * 从而达到不修改项目源码却对应用外观产生巨大影响的效果。 * * \note * 需要注意QStyle与QSS并不兼容,因为QSS本身其实上也是QStyle的一种实现,对一个控件而言,本身理论上只能 * 在同一时间调用唯一一个QStyle进行绘制。 */ class CustomStyle : public QProxyStyle { Q_OBJECT public: explicit CustomStyle(const QString &proxyStyleName = "windows", QObject *parent = nullptr); ~CustomStyle(); /*! * \brief drawComplexControl * \param control 比如ScrollBar,对应CC枚举类型 * \param option * \param painter * \param widget * \details * drawComplexControl用于绘制具有子控件的复杂控件,它本身一般不直接绘制控件, * 而是通过QStyle的其它方法将复杂控件分解成子控件再调用其它的draw方法绘制。 * 如果你需要重新实现一个复杂控件的绘制方法,首先考虑的应该是在不改变它原有的绘制流程的情况下, * 对它调用到的其它方法进行重写。 * * 如果你不想使用原有的绘制流程,那你需要重写这个接口,然后自己实现一切, * 包括背景的绘制,子控件的位置和状态计算,子控件的绘制等。 * 所以,你需要对这个控件有足够的了解之后再尝试直接重写这个接口。 */ virtual void drawComplexControl(QStyle::ComplexControl control, const QStyleOptionComplex *option, QPainter *painter, const QWidget *widget = nullptr) const; /*! * \brief drawControl * \param element 比如按钮,对应CE枚举类型 * \param option * \param painter * \param widget * \details * drawControl用于绘制基本控件元素,它本身一般只负责绘制控件的一部分或者一层。 * 如果你想要知道控件具体如何绘制,你需要同时研究这个控件的源码和QStyle中的源码, * 因为它们都有可能改变控件的绘制流程。 * * QStyle一般会遵循QCommonStyle的绘制流程,QCommenStyle是大部分主流style的最基类, * 它本身不能完全称之为一个主题,如果你直接使用它,你的控件将不能被正常绘制,因为它有可能只是 * 在特定的时候执行了特定却未实现的绘制方法,它更像一个框架或者规范。 */ virtual void drawControl(QStyle::ControlElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget = nullptr) const; virtual void drawItemPixmap(QPainter *painter, const QRect &rectangle, int alignment, const QPixmap &pixmap) const; virtual void drawItemText(QPainter *painter, const QRect &rectangle, int alignment, const QPalette &palette, bool enabled, const QString &text, QPalette::ColorRole textRole = QPalette::NoRole) const; /*! * \brief drawPrimitive * \param element 背景绘制,对应PE枚举类型 * \param option * \param painter * \param widget * \details * drawPrimitive用于绘制控件背景,比如按钮和菜单的背景, * 我们一般需要判断控件的状态来绘制不同的背景, * 比如按钮的hover和点击效果。 */ virtual void drawPrimitive(QStyle::PrimitiveElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget = nullptr) const; virtual QPixmap generatedIconPixmap(QIcon::Mode iconMode, const QPixmap &pixmap, const QStyleOption *option) const; virtual QStyle::SubControl hitTestComplexControl(QStyle::ComplexControl control, const QStyleOptionComplex *option, const QPoint &position, const QWidget *widget = nullptr) const; virtual QRect itemPixmapRect(const QRect &rectangle, int alignment, const QPixmap &pixmap) const; virtual QRect itemTextRect(const QFontMetrics &metrics, const QRect &rectangle, int alignment, bool enabled, const QString &text) const; //virtual int layoutSpacing(QSizePolicy::ControlType control1, QSizePolicy::ControlType control2, Qt::Orientation orientation, const QStyleOption *option, const QWidget *widget); virtual int pixelMetric(QStyle::PixelMetric metric, const QStyleOption *option = nullptr, const QWidget *widget = nullptr) const; /*! * \brief polish * \param widget * \details * polish用于对widget进行预处理,一般我们可以在polish中修改其属性, * 另外,polish是对动画和特效实现而言十分重要的一个方法, * 通过polish我们能够使widget和特效和动画形成对应关系。 */ virtual void polish(QWidget *widget); virtual void polish(QApplication *application); virtual void polish(QPalette &palette); virtual void unpolish(QWidget *widget); virtual void unpolish(QApplication *application); virtual QSize sizeFromContents(QStyle::ContentsType type, const QStyleOption *option, const QSize &contentsSize, const QWidget *widget = nullptr) const; virtual QIcon standardIcon(QStyle::StandardPixmap standardIcon, const QStyleOption *option, const QWidget *widget) const; virtual QPalette standardPalette() const; /*! * \brief styleHint * \param hint 对应的枚举是SH * \param option * \param widget * \param returnData * \return * \details * styleHint比较特殊,通过它我们能够改变一些控件的绘制流程或者方式,比如说QMenu是否可以滚动。 */ virtual int styleHint(QStyle::StyleHint hint, const QStyleOption *option = nullptr, const QWidget *widget = nullptr, QStyleHintReturn *returnData = nullptr) const; /*! * \brief subControlRect * \param control * \param option * \param subControl * \param widget * \return * \details * subControlRect返回子控件的位置和大小信息,这个方法一般在内置流程中调用, * 如果我们要重写某个绘制方法,可能需要用到它 */ virtual QRect subControlRect(QStyle::ComplexControl control, const QStyleOptionComplex *option, QStyle::SubControl subControl, const QWidget *widget = nullptr) const; /*! * \brief subElementRect * \param element * \param option * \param widget * \return * \details * 与subControlRect类似 */ virtual QRect subElementRect(QStyle::SubElement element, const QStyleOption *option, const QWidget *widget = nullptr) const; signals: protected: void drawComBoxIndicator(SubControl which, const QStyleOptionComplex *option,QPainter *painter) const; public slots: }; #endif // CUSTOMSTYLE_H ukui-notebook/src/noteData.h0000644000175000017500000000447514201136534015001 0ustar fengfeng/* * Copyright (C) 2020 Tianjin KYLIN Information Technology Co., Ltd. * * This program is free software; you can 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, 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 #include #include "editPage.h" class NoteData : public QObject { Q_OBJECT friend class tst_NoteData; public: explicit NoteData(QObject *parent = Q_NULLPTR); int id() const; void setId(const int& id); int notecolor() const; void setNoteColor(const int ¬ecolor); QString fullTitle() const; void setFullTitle(const QString &fullTitle); QDateTime lastModificationdateTime() const; void setLastModificationDateTime(const QDateTime &lastModificationdateTime); QDateTime creationDateTime() const; void setCreationDateTime(const QDateTime& creationDateTime); QString content() const; void setContent(const QString &content); QString mdContent() const; void setMdContent(const QString &mdContent); bool isModified() const; void setModified(bool isModified); bool isSelected() const; void setSelected(bool isSelected); int scrollBarPosition() const; void setScrollBarPosition(int scrollBarPosition); QDateTime deletionDateTime() const; void setDeletionDateTime(const QDateTime& deletionDateTime); EditPage *m_note; private: int m_id; int m_notecolor; QString m_fullTitle; QDateTime m_lastModificationDateTime; QDateTime m_creationDateTime; QDateTime m_deletionDateTime; QString m_content; QString m_mdContent; bool m_isModified; bool m_isSelected; int m_scrollBarPosition; }; QDataStream &operator<<(QDataStream &stream, const NoteData* noteData); QDataStream &operator>>(QDataStream &stream, NoteData *¬eData); #endif // NOTEDATA_H ukui-notebook/src/setFontSizePage.ui0000644000175000017500000000124214201136534016467 0ustar fengfeng SetFontSize 0 0 30 194 Form 0 0 30 194 ukui-notebook/src/fontButton.ui0000644000175000017500000000127714174170620015572 0ustar fengfeng fontButton 0 0 30 23 Form 0 0 27 26 ukui-notebook/src/noteHeadMenu.cpp0000644000175000017500000001536114201136534016145 0ustar fengfeng/* * Copyright (C) 2020 Tianjin KYLIN Information Technology Co., Ltd. * * This program is free software; you can 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, 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 #include #include "noteHeadMenu.h" #include "ui_noteHeadMenu.h" static QPixmap drawSymbolicColoredPixmap (const QPixmap&, QPushButton *); noteHeadMenu::noteHeadMenu(QWidget *parent) : QWidget(parent) , ui(new Ui::noteHeadMenu) , colorWidget(15,161,90) { ui->setupUi(this); setMinimumSize(250,34); btnInit(); slotsInit(); } noteHeadMenu::~noteHeadMenu() { delete ui; } void noteHeadMenu::paintEvent(QPaintEvent *event) { Q_UNUSED(event); QPainter p(this); p.setRenderHint(QPainter::Antialiasing); // 反锯齿; QPainterPath rectPath; rectPath.addRect(this->rect()); p.fillPath(rectPath,QBrush(colorWidget)); QWidget::paintEvent(event); } //void noteHeadMenu::mouseDoubleClickEvent(QMouseEvent *event) //{ // requestFullscreen(); //} void noteHeadMenu::slotsInit() { connect(ui->pushButtonNew, &QPushButton::clicked, this, [=](){ qDebug() << "emit requestNewNote"; requestNewNote(); }); } void noteHeadMenu::btnInit() { ui->pushButtonPalette->setIcon(drawSymbolicColoredPixmap(QIcon::fromTheme(":/image/1x/note_color.png").pixmap(16,16), ui->pushButtonPalette)); ui->pushButtonExit->setIcon(drawSymbolicColoredPixmap(QIcon::fromTheme("window-close-symbolic").pixmap(16,16), ui->pushButtonExit)); ui->pushButtonMenu->setIcon(drawSymbolicColoredPixmap(QIcon::fromTheme("open-menu-symbolic").pixmap(16,16), ui->pushButtonMenu)); QString _Stylesheet = "QPushButton{background-color: rgba(0,0,0,0);}" "QPushButton:hover{background-color: rgba(0,0,0,0.12);}" "QPushButton:pressed{background-color: rgba(0,0,0,0.2);}"; ui->pushButtonNew->setStyleSheet("QPushButton{border-image:url(:/image/1x/new-normal.png);}" "QPushButton:hover{border-image:url(:/image/1x/new-hover.png);}" "QPushButton:pressed{border-image:url(:/image/1x/new-click.png);}"); ui->pushButtonExit->setStyleSheet(_Stylesheet); ui->pushButtonMenu->setStyleSheet(_Stylesheet); ui->pushButtonPalette->setStyleSheet(_Stylesheet); QPalette palette = ui->pushButtonExit->palette(); palette.setColor(QPalette::Highlight, Qt::transparent); /* 取消按钮高亮 */ ui->pushButtonExit->setPalette(palette); ui->pushButtonMenu->setPalette(palette); ui->pushButtonPalette->setPalette(palette); QMenu *m_menu = new QMenu(ui->pushButtonMenu); QMenu *m_childMenu = new QMenu(m_menu); QAction *m_menuAction = new QAction(m_menu); m_menuActionDel = new QAction(m_menu); m_topAction = new QAction(m_menu); QAction *m_jpgAction = new QAction(m_childMenu); QAction *m_pdfAction = new QAction(m_childMenu); QAction *m_mailAction = new QAction(m_childMenu); m_menu->setProperty("fillIconSymbolicColor", true); m_menuAction->setText(tr("Open note list")); m_topAction->setText(tr("Always in the front")); m_menuActionDel->setText(tr("Delete this note")); m_childMenu->setTitle(tr("Share")); m_jpgAction->setText("Export to jpg"); m_pdfAction->setText("Export to pdf"); m_mailAction->setText("Mail"); m_childMenu->addAction(m_jpgAction); m_childMenu->addAction(m_pdfAction); m_childMenu->addAction(m_mailAction); //m_menu->addMenu(m_childMenu); m_menu->addAction(m_topAction); m_menu->addAction(m_menuActionDel); m_menu->addAction(m_menuAction); ui->pushButtonMenu->setMenu(m_menu); connect(m_menu, &QMenu::aboutToShow, this, [=](){ requestUpdateMenuIcon(); }); connect(m_menuAction, &QAction::triggered, this, [=](){ requestShowNote(); }); connect(m_topAction, &QAction::triggered, this, [=](){ requestTopMost(); }); //隐藏menu下箭头 //ui->pushButtonMenu->setStyleSheet("QPushButton::menu-indicator{image:none}"); ui->pushButtonMenu->setProperty("isOptionButton", true); //设置是否自动凸起 ui->pushButtonMenu->setIconSize(QSize(16, 16)); //zybAdd 解决story6496:深色模式下pushButtonMenu //ui->pushButtonMenu->setProperty("isWindowButton", 0x1); ui->pushButtonMenu->setProperty("useIconHighlightEffect", 0x2); ui->pushButtonNew->setToolTip(tr("Create New Note")); ui->pushButtonExit->setToolTip(tr("Close")); ui->pushButtonMenu->setToolTip(tr("Menu")); ui->pushButtonPalette->setProperty("isOptionButton", true); ui->pushButtonPalette->setIconSize(QSize(16,16)); ui->pushButtonPalette->setProperty("useIconHighlightEffect", true); ui->pushButtonPalette->setProperty("iconHighlightEffectMode", 1); ui->pushButtonPalette->setToolTip(tr("Palette")); ui->pushButtonExit->setFocusPolicy(Qt::NoFocus); ui->pushButtonExit->setIconSize(QSize(16,16)); ui->pushButtonExit->setProperty("isWindowButton",0x02); ui->pushButtonExit->setProperty("useIconHighlightEffect",0x08); ui->pushButtonExit->setFlat(true); } QPixmap drawSymbolicColoredPixmap(const QPixmap& source, QPushButton *btn) { QColor whiteColor = QColor(0, 0, 0); //zybAdd 解决story6496:深色模式下,便签页头部按钮颜色显示异常,返回浅色模式后,新建的便签页也会显示异常的问题 QColor baseColor = btn->palette().color(QPalette::Text).light(150); QImage img = source.toImage(); qDebug() << "drawSymbolicColoredPixmap" << baseColor.red() << baseColor.green() < #include #include #include class singleitemButton : public QPushButton { Q_OBJECT public: singleitemButton(); ~singleitemButton(); signals: void buttonclick(); protected: void enterEvent(QEvent *event);//鼠标进入事件 void mousePressEvent(QMouseEvent *event);//鼠标按下事件 void mouseReleaseEvent(QMouseEvent *event);//鼠标松开事件 void leaveEvent(QEvent *event);//鼠标离开事件 }; #endif // SINGLEITEMBUTTON_H ukui-notebook/src/noteHeadMenu.h0000644000175000017500000000271714201136534015613 0ustar fengfeng/* * Copyright (C) 2020 Tianjin KYLIN Information Technology Co., Ltd. * * This program is free software; you can 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, 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 #include #include #include namespace Ui { class noteHeadMenu; } class noteHeadMenu : public QWidget { Q_OBJECT public: explicit noteHeadMenu(QWidget *parent = nullptr); ~noteHeadMenu(); Ui::noteHeadMenu *ui; public: QColor colorWidget; QAction *m_menuActionDel = nullptr; QAction *m_topAction = nullptr; signals: void requestTopMost(); protected: void paintEvent(QPaintEvent *event); // void mouseDoubleClickEvent(QMouseEvent *event); private: void btnInit(); void slotsInit(); signals: void requestNewNote(); void requestShowNote(); void requestUpdateMenuIcon(); // void requestFullscreen(); }; #endif // NOTEHEADMENU_H ukui-notebook/src/setFontSizePage.cpp0000644000175000017500000000423514174170620016644 0ustar fengfeng/* * Copyright (C) 2020 Tianjin KYLIN Information Technology Co., Ltd. * * This program is free software; you can 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, 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 setupUi(this); initSetup(); } SetFontSize::~SetFontSize() { delete ui; //释放内存 for (int i=0; i < 10;i++) { delete list_aItem[i]; } } void SetFontSize::paintEvent(QPaintEvent *event) { Q_UNUSED(event); QStyleOption opt; opt.init(this); QPainter p(this); p.setBrush(opt.palette.color(QPalette::Base)); p.setOpacity(0.9); p.setPen(Qt::NoPen); p.setRenderHint(QPainter::Antialiasing); // 反锯齿; p.drawRoundedRect(opt.rect,6,6); style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this); } void SetFontSize::initSetup() { setWindowFlags(Qt::FramelessWindowHint | Qt::Popup); setAttribute(Qt::WA_TranslucentBackground); ui->listWidget->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); ui->listWidget->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); for(int i=10; i<37 ; i++ ) { int n = i-10; list_aItem[n] =new QListWidgetItem; list_aItem[n]->setSizeHint(QSize(30,27)); ui->listWidget->addItem(list_aItem[n]); list_page[n] = new fontButton(this); list_page[n]->resize(QSize(30,23)); ui->listWidget->setItemWidget(list_aItem[n],list_page[n]); list_page[n]->ui->label->setText(QString::number(i)); } } ukui-notebook/src/about.cpp0000755000175000017500000001476714201140431014706 0ustar fengfeng/* * Copyright (C) 2020, KylinSoft Co., Ltd. * * This program is free software: you can 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 . */ #include "about.h" #include "ui_about.h" #include "utils/xatom-helper.h" #include #define UKUI_STYLE_SCHEMA "org.ukui.style" #define STYLE_NAME "styleName" #define STYLE_NAME_KEY_DARK "ukui-dark" #define STYLE_NAME_KEY_DEFAULT "ukui-default" #define STYLE_NAME_KEY_BLACK "ukui-black" #define STYLE_NAME_KEY_LIGHT "ukui-light" #define STYLE_NAME_KEY_WHITE "ukui-white" #define SYSTEM_FONT_EKY "system-font-size" #define SYSTEM_NAME_KEY "system-font" #define STYLE_ICON "icon-theme-name" #define STYLE_ICON_NAME "iconThemeName" static QString SOFTWARE_VERSION = "3.1.1"; extern void qt_blurImage(QImage &blurImage, qreal radius, bool quality, int transposed); About::About(QWidget *parent) : QDialog(parent), ui(new Ui::About) { ui->setupUi(this); setWindowTitle(tr("About")); // setWindowFlags(Qt::FramelessWindowHint | Qt::Tool); // setAttribute(Qt::WA_TranslucentBackground); setAttribute(Qt::WA_DeleteOnClose); // 添加窗管协议 MotifWmHints hints; hints.flags = MWM_HINTS_FUNCTIONS|MWM_HINTS_DECORATIONS; hints.functions = MWM_FUNC_ALL; hints.decorations = MWM_DECOR_BORDER; XAtomHelper::getInstance()->setWindowMotifHint(this->winId(), hints); ui->iconLabel->setPixmap(QIcon::fromTheme("kylin-notebook").pixmap(24, 24)); ui->titleLabel->setText(tr("Notes")); ui->closeBtn->setIcon(QIcon::fromTheme("window-close-symbolic")); ui->closeBtn->setProperty("isWindowButton", 0x2); ui->closeBtn->setProperty("useIconHighlightEffect", 0x8); ui->closeBtn->setFlat(true); connect(ui->closeBtn, &QPushButton::clicked, this, [=](){ this->close(); }); // ui->versionLabel->setText(tr("Version: 2020.1.0")); QString version = QString(tr("Version: %1")).arg(SOFTWARE_VERSION); ui->versionLabel->setText(version); // ui->teamLabel->setText(tr("Service & Support: ") + // "" // "support@kylinos.cn"); ui->appiconLabel->setPixmap(QIcon::fromTheme("kylin-notebook").pixmap(96, 96)); ui->appnameLabel->setText(tr("Notes")); ui->introduceLabel->setText(tr("Notes is a self-developed sidebar application plug-in, " "which provides a rich interface, convenient operation and stable functions, " "aiming at a friendly user experience.")); ui->introduceLabel->setAlignment(Qt::AlignJustify); ui->introduceLabel->setWordWrap(true); connect(ui->teamLabel, &QLabel::linkActivated, this, [=](const QString url){ QDesktopServices::openUrl(QUrl(url)); }); ui->teamLabel->setContextMenuPolicy(Qt::NoContextMenu); listenToGsettings(); } About::~About() { delete ui; } void About::paintEvent(QPaintEvent *event) { Q_UNUSED(event); QPainter p(this); p.setRenderHint(QPainter::Antialiasing); // 反锯齿; QPainterPath rectPath; rectPath.addRect(this->rect()); p.fillPath(rectPath, palette().color(QPalette::Base)); } void About::listenToGsettings() { const QByteArray styleID(UKUI_STYLE_SCHEMA); QStringList stylelist; if (QGSettings::isSchemaInstalled(styleID)) { QGSettings *styleUKUI = new QGSettings(styleID, QByteArray(), this); stylelist << STYLE_NAME_KEY_DARK << STYLE_NAME_KEY_BLACK; // <get(STYLE_NAME).toString())) { ui->teamLabel->setText(tr("Service & Support: ") +"" "support@kylinos.cn"); } else { ui->teamLabel->setText(tr("Service & Support: ") +"" "support@kylinos.cn"); } connect(styleUKUI, &QGSettings::changed, this, [=](const QString &key){ if (key == STYLE_NAME) { if (stylelist.contains(styleUKUI->get(STYLE_NAME).toString())) { ui->teamLabel->setText(tr("Service & Support: ") +"" "support@kylinos.cn"); } else { ui->teamLabel->setText(tr("Service & Support: ") +"" "support@kylinos.cn"); } } if(key==STYLE_ICON_NAME || key==STYLE_ICON){ //主题框架不能更新 titleIcon ui->iconLabel->setPixmap(QIcon::fromTheme("kylin-notebook").pixmap(24,24)); ui->appiconLabel->setPixmap(QIcon::fromTheme("kylin-notebook").pixmap(96,96)); } }); if (styleUKUI->get(SYSTEM_FONT_EKY).toInt()) { const int size = styleUKUI->get(SYSTEM_FONT_EKY).toInt(); QFont dateFont; dateFont.setPointSize(size * 1.3); ui->appnameLabel->setFont(dateFont); } connect(styleUKUI, &QGSettings::changed, this, [=](const QString &key){ if (key == "systemFontSize") { const int size = styleUKUI->get(SYSTEM_FONT_EKY).toInt(); QFont dateFont; dateFont.setPointSize(size * 1.3); ui->appnameLabel->setFont(dateFont); } }); } } ukui-notebook/src/noteData.cpp0000644000175000017500000000721214174170620015327 0ustar fengfeng/* * Copyright (C) 2020 Tianjin KYLIN Information Technology Co., Ltd. * * This program is free software; you can 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, 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 #include "noteData.h" NoteData::NoteData(QObject *parent) : QObject(parent), m_isModified(false), m_isSelected(false), m_scrollBarPosition(0) { } int NoteData::id() const { return m_id; } void NoteData::setId(const int &id) { m_id = id; } QString NoteData::fullTitle() const { return m_fullTitle; } void NoteData::setFullTitle(const QString &fullTitle) { m_fullTitle = fullTitle; } int NoteData::notecolor() const { return m_notecolor; } void NoteData::setNoteColor(const int ¬ecolor) { m_notecolor = notecolor; } QDateTime NoteData::lastModificationdateTime() const { return m_lastModificationDateTime; } void NoteData::setLastModificationDateTime(const QDateTime &lastModificationdateTime) { m_lastModificationDateTime = lastModificationdateTime; } QString NoteData::content() const { return m_content; } void NoteData::setContent(const QString &content) { m_content = content; } QString NoteData::mdContent() const { return m_mdContent; } void NoteData::setMdContent(const QString &mdContent) { m_mdContent = mdContent; } bool NoteData::isModified() const { return m_isModified; } void NoteData::setModified(bool isModified) { m_isModified = isModified; } bool NoteData::isSelected() const { return m_isSelected; } void NoteData::setSelected(bool isSelected) { m_isSelected = isSelected; } int NoteData::scrollBarPosition() const { return m_scrollBarPosition; } void NoteData::setScrollBarPosition(int scrollBarPosition) { m_scrollBarPosition = scrollBarPosition; } QDateTime NoteData::deletionDateTime() const { return m_deletionDateTime; } void NoteData::setDeletionDateTime(const QDateTime& deletionDateTime) { m_deletionDateTime = deletionDateTime; } QDateTime NoteData::creationDateTime() const { return m_creationDateTime; } void NoteData::setCreationDateTime(const QDateTime&creationDateTime) { m_creationDateTime = creationDateTime; } QDataStream &operator<<(QDataStream &stream, const NoteData* noteData) { return stream << noteData->id() << noteData->fullTitle() << noteData->creationDateTime() \ << noteData->lastModificationdateTime() << noteData->content() \ << noteData->notecolor() << noteData->mdContent(); } QDataStream &operator>>(QDataStream &stream, NoteData* ¬eData){ noteData = new NoteData(); int id; int notecolor; QString fullTitle; QDateTime lastModificationDateTime; QDateTime creationDateTime; QString content; QString mdContent; stream >> id >> fullTitle >> creationDateTime >> lastModificationDateTime >> content >> mdContent; noteData->setId(id); noteData->setFullTitle(fullTitle); noteData->setLastModificationDateTime(lastModificationDateTime); noteData->setCreationDateTime(creationDateTime); noteData->setContent(content); noteData->setNoteColor(notecolor); noteData->setMdContent(mdContent); return stream; } ukui-notebook/src/noteView.cpp0000644000175000017500000001561314174170620015374 0ustar fengfeng/* * Copyright (C) 2020 Tianjin KYLIN Information Technology Co., Ltd. * * This program is free software; you can 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, 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 #include #include #include #include #include #include #include #include "noteView.h" #include "listViewModeDelegate.h" NoteView::NoteView(QWidget *parent) : QListView( parent ) , m_isScrollBarHidden(true) , m_animationEnabled(true) , m_isMousePressed(false) , m_rowHeight(38) { //不可编辑 setEditTriggers(QAbstractItemView::NoEditTriggers); setWindowOpacity(0.7); setAttribute(Qt::WA_TranslucentBackground);//设置窗口透明显示(毛玻璃效果) viewport()->setAttribute(Qt::WA_TranslucentBackground); //一次性定时器,槽函数只处理一次 QTimer::singleShot(0, this, SLOT(init())); } NoteView::~NoteView() { } void NoteView::animateAddedRow(const QModelIndex& parent, int start, int end) { Q_UNUSED(parent) Q_UNUSED(end) //model(): 返回此视图显示的模型。 QModelIndex idx = model()->index(start,0); // Note: 这一行添加了flikering,当动画运行缓慢时可以看到 // QItemSelectionModel::ClearAndSelect 将清除完整的选择 | 将选择所有指定的索引 // selectionModel(): Returns the current selection model. // select(): 使用指定的命令选择模型项索引,并发出selectionChanged() selectionModel()->select(idx, QItemSelectionModel::ClearAndSelect); listViewModeDelegate* delegate = static_cast(itemDelegate()); if(delegate != Q_NULLPTR){ delegate->setState(listViewModeDelegate::Insert, idx); // TODO find a way to finish this function till the animation stops while(delegate->animationState() == QTimeLine::Running){ qApp->processEvents(); } } } void NoteView::animateRemovedRow(const QModelIndex& parent, int start, int end) { qDebug() << "当前文件 :" << __FILE__ << "当前函数 :" << __FUNCTION__ << "当前行号 :" << __LINE__; Q_UNUSED(parent) Q_UNUSED(end) //model(): 返回此视图显示的模型。 QModelIndex idx = model()->index(start,0); // Note: 这一行添加了flikering,当动画运行缓慢时可以看到 // QItemSelectionModel::ClearAndSelect 将清除完整的选择 | 将选择所有指定的索引 // selectionModel(): Returns the current selection model. // select(): 使用指定的命令选择模型项索引,并发出selectionChanged() selectionModel()->select(idx, QItemSelectionModel::ClearAndSelect); listViewModeDelegate* delegate = static_cast(itemDelegate()); if(delegate != Q_NULLPTR){ delegate->setCurrentSelectedIndex(QModelIndex()); delegate->setState(listViewModeDelegate::Remove, idx); // TODO find a way to finish this function till the animation stops while(delegate->animationState() == QTimeLine::Running){ qApp->processEvents(); } } } void NoteView::paintEvent(QPaintEvent *e) { QStyleOption opt; opt.init(this); QPainter p(this->viewport()); //p.setRenderHint(QPainter::Antialiasing); p.setBrush(opt.palette.color(QPalette::Base)); //p.setOpacity(0.7); p.setPen(Qt::NoPen); p.drawRoundedRect(opt.rect,1,1); QListView::paintEvent(e); } void NoteView::rowsAboutToBeMoved(const QModelIndex &sourceParent, int sourceStart, int sourceEnd, const QModelIndex &destinationParent, int destinationRow) { Q_UNUSED(sourceParent) Q_UNUSED(sourceEnd) Q_UNUSED(destinationParent) Q_UNUSED(destinationRow) if(model() != Q_NULLPTR){ QModelIndex idx = model()->index(sourceStart,0); listViewModeDelegate* delegate = static_cast(itemDelegate()); if(delegate != Q_NULLPTR){ if(m_animationEnabled){ delegate->setState(listViewModeDelegate::MoveOut, idx); }else{ delegate->setState(listViewModeDelegate::Normal, idx); } // TODO find a way to finish this function till the animation stops while(delegate->animationState() == QTimeLine::Running){ qApp->processEvents(); } } } } void NoteView::rowsMoved(const QModelIndex &parent, int start, int end, const QModelIndex &destination, int row) { Q_UNUSED(parent) Q_UNUSED(start) Q_UNUSED(end) Q_UNUSED(destination) QModelIndex idx = model()->index(row,0); setCurrentIndex(idx); listViewModeDelegate* delegate = static_cast(itemDelegate()); if(delegate == Q_NULLPTR) return; if(m_animationEnabled){ delegate->setState(listViewModeDelegate::MoveIn, idx ); }else{ delegate->setState(listViewModeDelegate::Normal, idx); } // TODO find a way to finish this function till the animation stops while(delegate->animationState() == QTimeLine::Running){ qApp->processEvents(); } } void NoteView::init() { setMouseTracking(true); setUpdatesEnabled(true); //当鼠标进入或离开小部件时,强制Qt生成绘制事件 viewport()->setAttribute(Qt::WA_Hover); } void NoteView::mouseMoveEvent(QMouseEvent* e) { if(!m_isMousePressed){ QListView::mouseMoveEvent(e); } } void NoteView::mousePressEvent(QMouseEvent* e) { m_isMousePressed = true; QListView::mousePressEvent(e); } void NoteView::selectionChanged(const QItemSelection &selected, const QItemSelection &deselected) { emit viewportPressed(); if (selected.indexes().isEmpty()){ return; } QListView::selectionChanged(selected, deselected); } void NoteView::mouseReleaseEvent(QMouseEvent* e) { m_isMousePressed = false; QListView::mouseReleaseEvent(e); } void NoteView::setCurrentRowActive(bool isActive) { qDebug() << "当前文件 :" << __FILE__ << "当前函数 :" << __FUNCTION__ << "当前行号 :" << __LINE__; listViewModeDelegate* delegate = static_cast(itemDelegate()); if(delegate == Q_NULLPTR) return; delegate->setActive(isActive); viewport()->update(visualRect(currentIndex())); } void NoteView::setAnimationEnabled(bool isEnabled) { m_animationEnabled = isEnabled; } ukui-notebook/src/utils/0000755000175000017500000000000014201140431014206 5ustar fengfengukui-notebook/src/utils/xatom-helper.cpp0000644000175000017500000001374614174170620017346 0ustar fengfeng/* * KWin Style UKUI * * Copyright (C) 2020, KylinSoft Co., Ltd. * * This program is free software: you can 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 . * * Authors: Yue Lan * */ #include "xatom-helper.h" #include #include #include #include static XAtomHelper *global_instance = nullptr; XAtomHelper *XAtomHelper::getInstance() { if (!global_instance) global_instance = new XAtomHelper; return global_instance; } bool XAtomHelper::isFrameLessWindow(int winId) { auto hints = getInstance()->getWindowMotifHint(winId); if (hints.flags == MWM_HINTS_DECORATIONS && hints.functions == 1) { return true; } return false; } bool XAtomHelper::isWindowDecorateBorderOnly(int winId) { return isWindowMotifHintDecorateBorderOnly(getInstance()->getWindowMotifHint(winId)); } bool XAtomHelper::isWindowMotifHintDecorateBorderOnly(const MotifWmHints &hint) { bool isDeco = false; if (hint.flags & MWM_HINTS_DECORATIONS && hint.flags != MWM_HINTS_DECORATIONS) { if (hint.decorations == MWM_DECOR_BORDER) isDeco = true; } return isDeco; } bool XAtomHelper::isUKUICsdSupported() { // fixme: return false; } bool XAtomHelper::isUKUIDecorationWindow(int winId) { if (m_ukuiDecorationAtion == None) return false; Atom type; int format; ulong nitems; ulong bytes_after; uchar *data; bool isUKUIDecoration = false; XGetWindowProperty(QX11Info::display(), winId, m_ukuiDecorationAtion, 0, LONG_MAX, false, m_ukuiDecorationAtion, &type, &format, &nitems, &bytes_after, &data); if (type == m_ukuiDecorationAtion) { if (nitems == 1) { isUKUIDecoration = data[0]; } } return isUKUIDecoration; } UnityCorners XAtomHelper::getWindowBorderRadius(int winId) { UnityCorners corners; Atom type; int format; ulong nitems; ulong bytes_after; uchar *data; if (m_unityBorderRadiusAtom != None) { XGetWindowProperty(QX11Info::display(), winId, m_unityBorderRadiusAtom, 0, LONG_MAX, false, XA_CARDINAL, &type, &format, &nitems, &bytes_after, &data); if (type == XA_CARDINAL) { if (nitems == 4) { corners.topLeft = static_cast(data[0]); corners.topRight = static_cast(data[1*sizeof (ulong)]); corners.bottomLeft = static_cast(data[2*sizeof (ulong)]); corners.bottomRight = static_cast(data[3*sizeof (ulong)]); } XFree(data); } } return corners; } void XAtomHelper::setWindowBorderRadius(int winId, const UnityCorners &data) { if (m_unityBorderRadiusAtom == None) return; ulong corners[4] = {data.topLeft, data.topRight, data.bottomLeft, data.bottomRight}; XChangeProperty(QX11Info::display(), winId, m_unityBorderRadiusAtom, XA_CARDINAL, 32, XCB_PROP_MODE_REPLACE, (const unsigned char *) &corners, sizeof (corners)/sizeof (corners[0])); } void XAtomHelper::setWindowBorderRadius(int winId, int topLeft, int topRight, int bottomLeft, int bottomRight) { if (m_unityBorderRadiusAtom == None) return; ulong corners[4] = {(ulong)topLeft, (ulong)topRight, (ulong)bottomLeft, (ulong)bottomRight}; XChangeProperty(QX11Info::display(), winId, m_unityBorderRadiusAtom, XA_CARDINAL, 32, XCB_PROP_MODE_REPLACE, (const unsigned char *) &corners, sizeof (corners)/sizeof (corners[0])); } void XAtomHelper::setUKUIDecoraiontHint(int winId, bool set) { if (m_ukuiDecorationAtion == None) return; XChangeProperty(QX11Info::display(), winId, m_ukuiDecorationAtion, m_ukuiDecorationAtion, 32, XCB_PROP_MODE_REPLACE, (const unsigned char *) &set, 1); } void XAtomHelper::setWindowMotifHint(int winId, const MotifWmHints &hints) { if (m_unityBorderRadiusAtom == None) return; XChangeProperty(QX11Info::display(), winId, m_motifWMHintsAtom, m_motifWMHintsAtom, 32, XCB_PROP_MODE_REPLACE, (const unsigned char *)&hints, sizeof (MotifWmHints)/ sizeof (ulong)); } MotifWmHints XAtomHelper::getWindowMotifHint(int winId) { MotifWmHints hints; if (m_unityBorderRadiusAtom == None) return hints; uchar *data; Atom type; int format; ulong nitems; ulong bytes_after; XGetWindowProperty(QX11Info::display(), winId, m_motifWMHintsAtom, 0, sizeof (MotifWmHints)/sizeof (long), false, AnyPropertyType, &type, &format, &nitems, &bytes_after, &data); if (type == None) { return hints; } else { hints = *(MotifWmHints *)data; XFree(data); } return hints; } XAtomHelper::XAtomHelper(QObject *parent) : QObject(parent) { if (!QX11Info::isPlatformX11()) return; m_motifWMHintsAtom = XInternAtom(QX11Info::display(), "_MOTIF_WM_HINTS", true); m_unityBorderRadiusAtom = XInternAtom(QX11Info::display(), "_UNITY_GTK_BORDER_RADIUS", false); m_ukuiDecorationAtion = XInternAtom(QX11Info::display(), "_KWIN_UKUI_DECORAION", false); } Atom XAtomHelper::registerUKUICsdNetWmSupportAtom() { // fixme: return None; } void XAtomHelper::unregisterUKUICsdNetWmSupportAtom() { // fixme: } ukui-notebook/src/utils/xatom-helper.h0000644000175000017500000000624314174170620017005 0ustar fengfeng/* * KWin Style UKUI * * Copyright (C) 2020, KylinSoft Co., Ltd. * * This program is free software: you can 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 . * * Authors: Yue Lan * */ #ifndef XATOMHELPER_H #define XATOMHELPER_H #include #include struct UnityCorners { ulong topLeft = 0; ulong topRight = 0; ulong bottomLeft = 0; ulong bottomRight = 0; }; typedef struct { ulong flags = 0; ulong functions = 0; ulong decorations = 0; long input_mode = 0; ulong status = 0; } MotifWmHints, MwmHints; #define MWM_HINTS_FUNCTIONS (1L << 0) #define MWM_HINTS_DECORATIONS (1L << 1) #define MWM_HINTS_INPUT_MODE (1L << 2) #define MWM_HINTS_STATUS (1L << 3) #define MWM_FUNC_ALL (1L << 0) #define MWM_FUNC_RESIZE (1L << 1) #define MWM_FUNC_MOVE (1L << 2) #define MWM_FUNC_MINIMIZE (1L << 3) #define MWM_FUNC_MAXIMIZE (1L << 4) #define MWM_FUNC_CLOSE (1L << 5) #define MWM_DECOR_ALL (1L << 0) #define MWM_DECOR_BORDER (1L << 1) #define MWM_DECOR_RESIZEH (1L << 2) #define MWM_DECOR_TITLE (1L << 3) #define MWM_DECOR_MENU (1L << 4) #define MWM_DECOR_MINIMIZE (1L << 5) #define MWM_DECOR_MAXIMIZE (1L << 6) #define MWM_INPUT_MODELESS 0 #define MWM_INPUT_PRIMARY_APPLICATION_MODAL 1 #define MWM_INPUT_SYSTEM_MODAL 2 #define MWM_INPUT_FULL_APPLICATION_MODAL 3 #define MWM_INPUT_APPLICATION_MODAL MWM_INPUT_PRIMARY_APPLICATION_MODAL #define MWM_TEAROFF_WINDOW (1L<<0) namespace UKUI { class Decoration; } class XAtomHelper : public QObject { friend class UKUI::Decoration; Q_OBJECT public: static XAtomHelper *getInstance(); static bool isFrameLessWindow(int winId); bool isWindowDecorateBorderOnly(int winId); bool isWindowMotifHintDecorateBorderOnly(const MotifWmHints &hint); bool isUKUICsdSupported(); bool isUKUIDecorationWindow(int winId); UnityCorners getWindowBorderRadius(int winId); void setWindowBorderRadius(int winId, const UnityCorners &data); void setWindowBorderRadius(int winId, int topLeft, int topRight, int bottomLeft, int bottomRight); void setUKUIDecoraiontHint(int winId, bool set = true); void setWindowMotifHint(int winId, const MotifWmHints &hints); MotifWmHints getWindowMotifHint(int winId); private: explicit XAtomHelper(QObject *parent = nullptr); Atom registerUKUICsdNetWmSupportAtom(); void unregisterUKUICsdNetWmSupportAtom(); Atom m_motifWMHintsAtom = None; Atom m_unityBorderRadiusAtom = None; Atom m_ukuiDecorationAtion = None; }; #endif // XATOMHELPER_H ukui-notebook/src/utils/utils.cpp0000644000175000017500000000220614201140431016052 0ustar fengfeng/* * Copyright (C) 2020, KylinSoft Co., Ltd. * * This program is free software: you can 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 . */ #include "utils.h" void Utils::setCLIName(QCommandLineParser &parser) { QCommandLineOption monitorRoleOption(QStringList() << "show", QObject::tr("show")); parser.addOption(monitorRoleOption); //添加帮助信息(-h,--help),这个方法由QCommandLineParser自动处理 parser.addHelpOption(); //添加(-v,--version)方法,显示应用的版本,这个方法由QCommandLineParser自动处理 parser.addVersionOption(); } ukui-notebook/src/utils/utils.h0000644000175000017500000000163114201140431015520 0ustar fengfeng/* * Copyright (C) 2020, KylinSoft Co., Ltd. * * This program is free software: you can 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 . */ #ifndef UTILS_H #define UTILS_H #include #include #include #include namespace Utils { void setCLIName(QCommandLineParser &parser); } #endif // UTILS_H ukui-notebook/src/emptyNotes.h0000644000175000017500000000223114201136534015375 0ustar fengfeng/* * Copyright (C) 2020 Tianjin KYLIN Information Technology Co., Ltd. * * This program is free software; you can 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, 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 namespace Ui { class emptyNotes; } class emptyNotes : public QDialog { Q_OBJECT public: explicit emptyNotes(QWidget *parent = nullptr); ~emptyNotes(); bool m_isDontShow; private slots: void on_pushButton_clicked(); void on_pushButton_2_clicked(); private: void paintEvent(QPaintEvent*); Ui::emptyNotes *ui; signals: void requestEmptyNotes(); }; #endif // EMPTY_NOTEPAD_H ukui-notebook/src/paletteWidget.cpp0000644000175000017500000000770214201136534016373 0ustar fengfeng/* * Copyright (C) 2020 Tianjin KYLIN Information Technology Co., Ltd. * * This program is free software; you can 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, 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 extern void qt_blurImage(QImage &blurImage, qreal radius, bool quality, int transposed); QString PaletteWidget::BORDER_RADIUS_2PX = "border-radius:2px"; QString PaletteWidget::KY_BLUE = "#3790FA"; QString PaletteWidget::KY_PURPLE = "#BA7BD8"; QString PaletteWidget::KY_PINK = "#F559AB"; QString PaletteWidget::KY_RED = "#FF4D4F"; QString PaletteWidget:: KY_ORANGE = "#F68C27"; QString PaletteWidget::KY_YELLOW = "#F9C53D"; QString PaletteWidget::KY_GREEN = "#52C429"; QString PaletteWidget::KY_GREY = "#8C8C8C"; PaletteWidget::PaletteWidget(QWidget *parent) : QWidget(parent), ui(new Ui::PaletteWidget) { ui->setupUi(this); QBitmap bmp(this->size()); bmp.fill(); QPainter p(&bmp); p.setPen(Qt::NoPen); p.setBrush(Qt::black); p.setRenderHint(QPainter::Antialiasing); p.drawRoundedRect(bmp.rect(),6,6); setMask(bmp); btnSetup(); } PaletteWidget::~PaletteWidget() { delete ui; } void PaletteWidget::btnSetup() { QString styleSheet = QString("background: %1;%2;").arg(KY_BLUE).arg(BORDER_RADIUS_2PX); ui->blueBtn->setStyleSheet(styleSheet); styleSheet = QString("background:%1;%2;").arg(KY_RED).arg(BORDER_RADIUS_2PX); ui->redBtn->setStyleSheet(styleSheet); styleSheet = QString("background:%1;%2;").arg(KY_GREEN).arg(BORDER_RADIUS_2PX); ui->darkGreenBtn->setStyleSheet(styleSheet); styleSheet = QString("background:%1;%2;").arg(KY_ORANGE).arg(BORDER_RADIUS_2PX); ui->orangeBtn->setStyleSheet(styleSheet); styleSheet = QString("background:%1;%2;").arg(KY_PURPLE).arg(BORDER_RADIUS_2PX); ui->purpleBtn->setStyleSheet(styleSheet); styleSheet = QString("background:%1;%2;").arg(KY_YELLOW).arg(BORDER_RADIUS_2PX); ui->goldenBtn->setStyleSheet(styleSheet); styleSheet = QString("background:%1;%2;").arg(KY_GREY).arg(BORDER_RADIUS_2PX); ui->greyBtn->setStyleSheet(styleSheet); styleSheet = QString("background:%1;%2;").arg(KY_PINK).arg(BORDER_RADIUS_2PX); ui->pinkBtn->setStyleSheet(styleSheet); } void PaletteWidget::paintEvent(QPaintEvent *event) { Q_UNUSED(event); QPainter p(this); p.setRenderHint(QPainter::Antialiasing); // 反锯齿; QPainterPath rectPath; rectPath.addRoundedRect(this->rect().adjusted(1, 1, -1, -1), 6, 6); // 画一个黑底 QPixmap pixmap(this->rect().size()); pixmap.fill(Qt::transparent); QPainter pixmapPainter(&pixmap); pixmapPainter.setRenderHint(QPainter::Antialiasing); pixmapPainter.setPen(Qt::transparent); pixmapPainter.setBrush(Qt::black); pixmapPainter.drawPath(rectPath); pixmapPainter.end(); // 模糊这个黑底 QImage img = pixmap.toImage(); qt_blurImage(img, 10, false, false); // 挖掉中心 pixmap = QPixmap::fromImage(img); QPainter pixmapPainter2(&pixmap); pixmapPainter2.setRenderHint(QPainter::Antialiasing); pixmapPainter2.setCompositionMode(QPainter::CompositionMode_Clear); pixmapPainter2.setPen(Qt::transparent); pixmapPainter2.setBrush(Qt::transparent); pixmapPainter2.drawPath(rectPath); // 绘制阴影 p.drawPixmap(this->rect(), pixmap, pixmap.rect()); // 绘制一个背景 p.save(); p.fillPath(rectPath,palette().color(QPalette::Base)); p.restore(); } ukui-notebook/src/iconViewModeDelegate.cpp0000644000175000017500000003612514201136534017615 0ustar fengfeng/* * Copyright (C) 2020 Tianjin KYLIN Information Technology Co., Ltd. * * This program is free software; you can 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, 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 #include #include #include #include #include #include #include "noteModel.h" #include "widget.h" #include "iconViewModeDelegate.h" #include "noteView.h" /*! * 系统时间 */ #define FORMAT_SCHEMA "org.ukui.control-center.panel.plugins" #define TIME_FORMAT_KEY "hoursystem" extern QFont g_currentFont; iconViewModeDelegate::iconViewModeDelegate(QObject *parent) : QStyledItemDelegate(parent), m_titleFont(g_currentFont.family(), (double)g_currentFont.pointSizeF()/15 * 16), //标题字体 m_titleSelectedFont(g_currentFont.family(), (double)g_currentFont.pointSizeF()/15 * 16), // m_dateFont(g_currentFont.family(), (double)g_currentFont.pointSizeF()/15 * 13), //日期字体 m_titleColor(255, 255, 255), //标题颜色 m_dateColor(255, 255, 255), //日期颜色 m_ActiveColor(218, 233, 239), m_notActiveColor(175, 212, 228), //默认选中背景色 m_hoverColor(80, 80, 80), //悬停颜色 m_selectColor(43, 49, 60), //选中颜色 m_applicationInactiveColor(207, 207, 207), //应用程序可见,但未选择显示在前面时背景色 m_separatorColor(221, 221, 221), m_defaultColor(0, 0, 0), m_noteColor(0, 0, 0), //便签头颜色 m_rowHeight(200), //item宽度 m_maxFrame(200), m_rowRightOffset(0), m_state(Normal), m_isActive(false) { //QTimeLine拥有一个时间轴来控制时间动画和事件 //参数1为毫秒级 总运行时间0.3秒 m_timeLine = new QTimeLine(300, this); //对QTImeLine的时间轴设置动画帧数,共200张静态画面图组成 //Qt默认40ms一帧,也就是一秒可以最多走25帧 m_timeLine->setFrameRange(0,m_maxFrame); //时间轴走的时候,会不断发出frameChanged信号,setUpdateInterval控制多少时间发一次 m_timeLine->setUpdateInterval(10); //设置你的时间变换曲线,即明确你的时间是先快后慢,还是先慢后快,或者线性 m_timeLine->setCurveShape(QTimeLine::EaseInCurve); connect( m_timeLine, &QTimeLine::frameChanged, [this](){ emit sizeHintChanged(m_animatedIndex); }); connect(m_timeLine, &QTimeLine::finished, [this](){ m_animatedIndex = QModelIndex(); m_state = Normal; }); // 监听时区变化 const QByteArray iddd(FORMAT_SCHEMA); if (QGSettings::isSchemaInstalled(iddd)){ QGSettings *m_formatsettings = new QGSettings(iddd, QByteArray(), this); m_timeZone = m_formatsettings->get(TIME_FORMAT_KEY).toString(); connect(m_formatsettings, &QGSettings::changed, this, [=] (const QString &key) { if (key == "hoursystem") { m_timeZone = m_formatsettings->get(TIME_FORMAT_KEY).toString(); } }); } } void iconViewModeDelegate::setState(States NewState, QModelIndex index) { m_animatedIndex = index; auto startAnimation = [this](QTimeLine::Direction diretion, int duration){ m_timeLine->setDirection(diretion); m_timeLine->setDuration(duration); m_timeLine->start(); }; switch ( NewState ){ case Insert: startAnimation(QTimeLine::Forward, m_maxFrame); break; case Remove: startAnimation(QTimeLine::Backward, m_maxFrame); break; case MoveOut: startAnimation(QTimeLine::Backward, m_maxFrame); break; case MoveIn: startAnimation(QTimeLine::Backward, m_maxFrame); break; case Normal: m_animatedIndex = QModelIndex(); break; } m_state = NewState; } void iconViewModeDelegate::setAnimationDuration(const int duration) { m_timeLine->setDuration(duration); } void iconViewModeDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { QStyleOptionViewItem opt = option; //绘制第一层便签头背景 int m_noteColor{index.data(NoteModel::NoteColor).toInt()}; painter->setRenderHint(QPainter::Antialiasing); // 反锯齿; painter->setBrush(QBrush(intToQcolor(m_noteColor))); painter->setOpacity(1); painter->setPen(Qt::transparent); opt.rect.setLeft(opt.rect.left() + 3); opt.rect.setWidth(opt.rect.width() - 12); // 左右间距 opt.rect.setHeight(opt.rect.height() - 241);// 上下间距 { QPainterPath painterPath; painterPath.addRoundedRect(opt.rect, 4, 4); painterPath.setFillRule(Qt::WindingFill); // 多块区域组合填充模式 painterPath.addRect(opt.rect.x() , opt.rect.y() + 1, 4, 4); painterPath.addRect(opt.rect.x() + opt.rect.width() - 4, opt.rect.y() + 1, 4, 4); painter->drawPath(painterPath); } //绘制第二层底色背景 painter->setRenderHint(QPainter::Antialiasing); // 反锯齿; painter->setOpacity(0.04); painter->setBrush(opt.palette.color(QPalette::Text)); painter->setPen(Qt::transparent); opt.rect.setHeight(200); opt.rect.setTop(opt.rect.top() + 5); { QPainterPath painterPath; painterPath.addRoundedRect(opt.rect, 0, 0); painter->drawPath(painterPath); } painter->setOpacity(1); paintBackground(painter, opt, index); painter->setOpacity(1); paintLabels(painter, option, index); } QSize iconViewModeDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const { Q_UNUSED(option); Q_UNUSED(index); return QSize(227,246); } QTimeLine::State iconViewModeDelegate::animationState() { return m_timeLine->state(); } void iconViewModeDelegate::paintBackground(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { QStyleOptionViewItem opt = option; opt.rect.setWidth(option.rect.width() - m_rowRightOffset); if((option.state & QStyle::State_Selected) == QStyle::State_Selected) { //应用程序是可见的,并被选择在前面。 if(qApp->applicationState() == Qt::ApplicationActive){ //返回应用程序的当前状态。 if(m_isActive){//用指定的画笔填充给定的矩形。 painter->setRenderHint(QPainter::Antialiasing); // 反锯齿; painter->setBrush(opt.palette.color(QPalette::Text)); painter->setOpacity(0.08); painter->setPen(Qt::transparent); QPainterPath painterPath; painterPath.addRoundedRect(opt.rect, 0, 0); painter->drawPath(painterPath); }else{ painter->setRenderHint(QPainter::Antialiasing); // 反锯齿; painter->setBrush(opt.palette.color(QPalette::Text)); painter->setOpacity(0.08); painter->setPen(Qt::transparent); QPainterPath painterPath; painterPath.addRoundedRect(opt.rect, 0, 0); painter->drawPath(painterPath); } //应用程序可见,但未选择显示在前面 }else if(qApp->applicationState() == Qt::ApplicationInactive){ painter->setRenderHint(QPainter::Antialiasing); // 反锯齿; painter->setBrush(opt.palette.color(QPalette::Text)); painter->setOpacity(0.08); painter->setPen(Qt::transparent); QPainterPath painterPath; painterPath.addRoundedRect(opt.rect, 0, 0); painter->drawPath(painterPath); } } //鼠标悬停时颜色 //用于指示小部件是否在鼠标下。 else if((option.state & QStyle::State_MouseOver) == QStyle::State_MouseOver){ painter->setRenderHint(QPainter::Antialiasing); // 反锯齿; painter->setBrush(opt.palette.color(QPalette::Text)); painter->setOpacity(0.04); painter->setPen(Qt::transparent); QPainterPath painterPath; painterPath.addRoundedRect(opt.rect, 0, 0); painter->drawPath(painterPath); //当前item未选中 未悬停时颜色 }else if((index.row() != m_currentSelectedIndex.row() - 1) && (index.row() != m_hoveredIndex.row() - 1)){ painter->setRenderHint(QPainter::Antialiasing); // 反锯齿; } } void iconViewModeDelegate::paintLabels(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const { const int leftOffsetX = 20; // 标题左边距 const int topOffsetY = 18; // 标题上方的空格 const int spaceY = 148 + g_currentFont.pointSize(); // 标题和日期之间的空格 QString fontName = g_currentFont.family(); double fontSize = (double)g_currentFont.pointSize()/15; m_titleFont.setFamily(fontName); m_titleFont.setPointSizeF(fontSize * 16); m_titleSelectedFont.setFamily(g_currentFont.family()); m_titleSelectedFont.setPointSizeF(g_currentFont.pointSizeF()/15 * 16); m_titleSelectedFont.setBold(true); m_dateFont.setFamily(g_currentFont.family()); m_dateFont.setPointSizeF(g_currentFont.pointSizeF()/15 * 13); QStyleOptionViewItem opt = option; QString title{index.data(NoteModel::NoteFullTitle).toString()}; QFont titleFont = (option.state & QStyle::State_Selected) == QStyle::State_Selected ? m_titleSelectedFont : m_titleFont; QFontMetrics fmTitle(titleFont); QRect fmRectTitle = fmTitle.boundingRect(title); QString date = parseDateTime(index.data(NoteModel::NoteLastModificationDateTime).toDateTime()); QFontMetrics fmDate(m_dateFont); QRect fmRectDate = fmDate.boundingRect(date); double rowPosX = option.rect.x(); double rowPosY = option.rect.y(); double rowWidth = option.rect.width(); double titleRectPosX = rowPosX + leftOffsetX; double titleRectPosY = rowPosY; double titleRectWidth = rowWidth - 2.0 * leftOffsetX; double titleRectHeight = fmRectTitle.height() + topOffsetY; double dateRectPosX = rowPosX + (rowWidth / 2 - fmRectDate.width() / 2); double dateRectPosY = rowPosY + 26 + topOffsetY; double dateRectWidth = rowWidth; double dateRectHeight = 18 + spaceY; double rowRate = m_timeLine->currentFrame()/(m_maxFrame * 1.0); double currRowHeight = m_rowHeight * rowRate; auto drawStr = [painter](double posX, double posY, double width, double height, QColor color, QFont font, QString str){ QRectF rect(posX, posY, width, height); painter->setPen(color); painter->setFont(font); painter->drawText(rect, Qt::AlignBottom, str); }; // 设置标题和日期字符串的边界矩形 if(index.row() == m_animatedIndex.row()){ if(m_state == MoveIn){ titleRectHeight = topOffsetY + fmRectTitle.height() + currRowHeight; dateRectPosY = titleRectHeight; dateRectHeight = fmRectDate.height() + spaceY; }else{ if((fmRectTitle.height() + topOffsetY) >= ((1.0 - rowRate) * m_rowHeight)){ titleRectHeight = (fmRectTitle.height() + topOffsetY) - (1.0 - rowRate) * m_rowHeight; }else{ titleRectHeight = 0; double labelsSumHeight = fmRectTitle.height() + topOffsetY + fmRectDate.height() + spaceY; double bottomSpace = m_rowHeight - labelsSumHeight; if(currRowHeight > bottomSpace){ dateRectHeight = currRowHeight - bottomSpace; }else{ dateRectHeight = 0; } } dateRectPosY = titleRectHeight + rowPosY; } } // 绘图标题和日期 // 超出字符串转换为... title = fmTitle.elidedText(title, Qt::ElideRight, int(titleRectWidth)); drawStr(titleRectPosX, titleRectPosY, titleRectWidth, titleRectHeight, opt.palette.color(QPalette::Text), titleFont, title); drawStr(dateRectPosX, dateRectPosY, dateRectWidth, dateRectHeight, opt.palette.color(QPalette::Text), m_dateFont, date); } void iconViewModeDelegate::paintSeparator(QPainter*painter, const QStyleOptionViewItem&option, const QModelIndex&index) const { Q_UNUSED(index) painter->setPen(QPen(m_separatorColor)); const int leftOffsetX = 11; int posX1 = option.rect.x() + leftOffsetX; int posX2 = option.rect.x() + option.rect.width() - leftOffsetX - 1; int posY = option.rect.y() + option.rect.height() - 1; painter->drawLine(QPoint(posX1, posY), QPoint(posX2, posY)); } QString iconViewModeDelegate::parseDateTime(const QDateTime &dateTime) const { QLocale usLocale = QLocale::system(); QString d; auto currDateTime = QDateTime::currentDateTime(); if(dateTime.date() == currDateTime.date()){ d = tr("Today "); if(m_timeZone == "24"){ d.append(usLocale.toString(dateTime.time(),"hh:mm")); }else { d.append(usLocale.toString(dateTime.time(),"AP hh:mm")); } return d; }else if(dateTime.daysTo(currDateTime) == 1){ d = tr("Yesterday "); if(m_timeZone == "24"){ d.append(usLocale.toString(dateTime.time(),"hh:mm")); }else { d.append(usLocale.toString(dateTime.time(),"AP hh:mm")); } return d; } //else if(dateTime.daysTo(currDateTime) >= 2 && // dateTime.daysTo(currDateTime) <= 7){ // return usLocale.toString(dateTime.date(), "dddd"); //} if(m_timeZone == "12"){ return dateTime.toString("yyyy/MM/dd AP hh:mm"); } return dateTime.toString("yyyy/MM/dd hh:mm"); } void iconViewModeDelegate::setActive(bool isActive) { m_isActive = isActive; } void iconViewModeDelegate::setRowRightOffset(int rowRightOffset) { m_rowRightOffset = rowRightOffset; } void iconViewModeDelegate::setHoveredIndex(const QModelIndex &hoveredIndex) { m_hoveredIndex = hoveredIndex; } void iconViewModeDelegate::setCurrentSelectedIndex(const QModelIndex ¤tSelectedIndex) { m_currentSelectedIndex = currentSelectedIndex; } int iconViewModeDelegate::qcolorToInt(const QColor &color) const { //将Color 从QColor 转换成 int return (int)(((unsigned int)color.blue()<< 16) | (unsigned short)(((unsigned short)color.green()<< 8) | color.red())); } QColor iconViewModeDelegate::intToQcolor(int &intColor) const { int red = intColor & 255; int green = intColor >> 8 & 255; int blue = intColor >> 16 & 255; return QColor(red, green, blue); } ukui-notebook/src/adaptscreeninfo.h0000644000175000017500000000374114174170620016405 0ustar fengfeng/* * Copyright (C) 2020, KylinSoft Co., Ltd. * * This program is free software: you can 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 . */ #ifndef ADAPTSCREENINFO_H #define ADAPTSCREENINFO_H #include #include #include #include #include #include #include class adaptScreenInfo : public QObject { Q_OBJECT public: explicit adaptScreenInfo(QObject *parent = nullptr); void screenNumChange(); void modifyMemberVariable(); void InitializeHomeScreenGeometry(); QDesktopWidget *m_pDeskWgt; // 桌面问题 int m_screenWidth; // 桌面宽度 int m_screenHeight; // 桌面高度 int m_screenNum; // 屏幕数量 int m_nScreen_x; // 主屏起始坐标X int m_nScreen_y; // 主屏起始坐标Y signals: private: void initScreenSize(); private slots: void primaryScreenChangedSlot(); void onResolutionChanged(const QRect argc); void screenCountChangedSlots(int count); private: QList m_pListScreen; QStringList ScreenName; }; #endif // ADAPTSCREENINFO_H ukui-notebook/src/src.pro0000644000175000017500000000646314201136534014401 0ustar fengfeng#------------------------------------------------- # # Project created by QtCreator 2020-03-17T10:53:26 # #------------------------------------------------- include(./env.pri) include($$PROJECT_COMPONENTSOURCE/closebutton.pri) QT += core gui printsupport sql concurrent network KWindowSystem dbus x11extras greaterThan(QT_MAJOR_VERSION, 4): QT += widgets TARGET = ukui-notebook TEMPLATE = app LIBS += -lpthread LIBS += -lX11 -lXrandr -lXinerama -lXi -lXcursor PKGCONFIG += gsettings-qt # The following define makes your compiler emit warnings if you use # any feature of Qt which has been marked as deprecated (the exact warnings # depend on your compiler). Please consult the documentation of the # deprecated API in order to know how to port your code away from it. DEFINES += QT_DEPRECATED_WARNINGS DEFINES += QT_MESSAGELOGCONTEXT # You can also make your code fail to compile if you use deprecated APIs. # In order to do so, uncomment the following line. # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 CONFIG += c++11 link_pkgconfig INCLUDEPATH += \ $$PROJECT_COMPONENTSOURCE \ TRANSLATIONS += \ ../translations/ukui-notebook/ukui-notebook_zh_CN.ts ../translations/ukui-notebook/ukui-notebook_tr.ts SOURCES += \ about.cpp \ utils/utils.cpp \ utils/xatom-helper.cpp \ adaptscreeninfo.cpp \ customStyle.cpp \ dbManager.cpp \ editPage.cpp \ emptyNotes.cpp \ fontButton.cpp \ headerbar.cpp \ iconViewModeDelegate.cpp \ listViewModeDelegate.cpp \ main.cpp \ myThrow.cpp \ noteData.cpp \ noteExitWindow.cpp \ noteHead.cpp \ noteHeadMenu.cpp \ noteModel.cpp \ noteView.cpp \ paletteButton.cpp \ paletteWidget.cpp \ selectColorPage.cpp \ setFontColorPage.cpp \ setFontSizePage.cpp \ singleApplication.cpp \ singleitemButton.cpp \ widget.cpp HEADERS += \ about.h \ utils/utils.h \ utils/xatom-helper.h \ adaptscreeninfo.h \ customStyle.h \ dbManager.h \ editPage.h \ emptyNotes.h \ fontButton.h \ headerbar.h \ iconViewModeDelegate.h \ listViewModeDelegate.h \ myThrow.h \ noteData.h \ noteExitWindow.h \ noteHead.h \ noteHeadMenu.h \ noteModel.h \ noteView.h \ paletteButton.h \ paletteWidget.h \ selectColorPage.h \ setFontColorPage.h \ setFontSizePage.h \ singleApplication.h \ singleitemButton.h \ widget.h FORMS += \ about.ui \ editPage.ui \ emptyNotes.ui \ fontButton.ui \ noteExitWindow.ui \ noteHead.ui \ noteHeadMenu.ui \ paletteButton.ui \ paletteWidget.ui \ selectColorPage.ui \ setFontColorPage.ui \ setFontSizePage.ui \ widget.ui RESOURCES += \ image.qrc unix { target.path = /usr/bin/ INSTALLS += target translation.path = /usr/share/ukui-notebook translation.files += ../translations/ukui-notebook/*.qm manual.path = /usr/share/kylin-user-guide/data/guide/ukui-notebook manual.files += ../data/ukui-notebook/* INSTALLS += translation manual } desktopfile.files = ../data/ukui-notebook.desktop desktopfile.path = /usr/share/applications/ INSTALLS += desktopfile ukui-notebook/src/emptyNotes.ui0000644000175000017500000002354614201136534015577 0ustar fengfeng emptyNotes 0 0 380 156 0 0 380 156 380 156 Dialog 0 0 0 0 0 0 0 0 0 0 Qt::Vertical QSizePolicy::Fixed 20 17 0 0 0 0 0 Qt::Horizontal QSizePolicy::Fixed 24 20 0 0 22 22 22 22 22 22 Qt::Horizontal QSizePolicy::Fixed 8 20 0 0 0 22 16777215 22 Are you sure empty notebook? Qt::Vertical QSizePolicy::Fixed 20 10 0 Qt::Horizontal QSizePolicy::Fixed 58 20 0 22 16777215 22 No Tips Qt::Vertical QSizePolicy::Fixed 20 25 0 0 Qt::Horizontal QSizePolicy::Expanding 40 20 cancel Qt::Horizontal QSizePolicy::Fixed 10 20 yes Qt::Horizontal QSizePolicy::Fixed 24 20 Qt::Vertical QSizePolicy::MinimumExpanding 20 24 ukui-notebook/src/setFontSizePage.h0000644000175000017500000000241114174170620016303 0ustar fengfeng/* * Copyright (C) 2020 Tianjin KYLIN Information Technology Co., Ltd. * * This program is free software; you can 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, 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 #include #include #include #include namespace Ui { class SetFontSize; } class fontButton; class SetFontSize : public QWidget { Q_OBJECT public: explicit SetFontSize(QWidget *parent = nullptr); ~SetFontSize(); Ui::SetFontSize *ui; public: QListWidgetItem *list_aItem[40]; fontButton *list_page[40]; QLabel *label[40]; protected: void paintEvent(QPaintEvent *event) override; private: void initSetup(); }; #endif // SETFONTSIZE_H ukui-notebook/src/setFontColorPage.h0000644000175000017500000000317214201136534016451 0ustar fengfeng/* * Copyright (C) 2020 Tianjin KYLIN Information Technology Co., Ltd. * * This program is free software; you can 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, 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 #include #include #include #include #include #include #include "paletteButton.h" #include "ui_paletteButton.h" /** * ukui style */ #define THEME_QT_SCHEMA "org.ukui.style" #define MODE_QT_KEY "style-name" namespace Ui { class SetFontColor; } class SetFontColor : public QWidget { Q_OBJECT public: explicit SetFontColor(QWidget *parent = nullptr); ~SetFontColor(); Ui::SetFontColor *ui; static QString KY_BLUE; static QString KY_RED; static QString KY_GREEN; static QString KY_ORANGE; static QString KY_PURPLE; private: QListWidgetItem *m_listAItem[6]; paletteButton *m_listPage[6]; QString m_color[6]; protected: void paintEvent(QPaintEvent *event) override; private: void initSetup(); void setColor(); }; #endif // SETFONTCOLORE_H ukui-notebook/src/common/0000755000175000017500000000000014174170620014352 5ustar fengfengukui-notebook/src/common/CloseButton/0000755000175000017500000000000014201140431016577 5ustar fengfengukui-notebook/src/common/CloseButton/closebutton.h0000644000175000017500000000410314201140431021307 0ustar fengfeng/* * Copyright (C) 2020, KylinSoft Co., Ltd. * * This program is free software: you can 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 . */ #ifndef CLOSEBUTTON_H #define CLOSEBUTTON_H #include #include #include #include #include #include #include class CloseButton : public QLabel { Q_OBJECT public: explicit CloseButton(QWidget *parent = nullptr,const QString &filePath = "",const QString &hoverPath = ""); //Render icon from theme const QPixmap renderSvg(const QIcon &icon, QString color); // change svg picture's color QPixmap drawSymbolicColoredPixmap(const QPixmap &source, QString color); void setIcon(const QIcon &icon); void setIconSize(int size); void setBkg(const QColor &color); void setHoverIn(const QString &hoverIn); void setHoverOut(const QString &hoverOut); ~CloseButton(); protected: void enterEvent(QEvent *event); void leaveEvent(QEvent *event); void mousePressEvent(QMouseEvent *event); void mouseReleaseEvent(QMouseEvent *event); void paintEvent(QPaintEvent *event); private: QIcon *m_icon; QIcon *m_customIcon; QIcon *m_hoverIcon; bool m_bIsChecked; bool m_bIsPressed; QColor m_colorBkg; int m_cSize; bool m_settedBkg; QColor m_customBkg; QString m_szHoverOut; QString m_szHoverIn; QGSettings *m_qtThemeSetting; QGSettings *m_gtkThemeSetting; Q_SIGNALS: void clicked(bool checked = true); }; #endif // CLOSEBUTTON_H ukui-notebook/src/common/CloseButton/closebutton.cpp0000644000175000017500000002155414201140431021653 0ustar fengfeng/* * Copyright (C) 2020, KylinSoft Co., Ltd. * * This program is free software: you can 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 . */ /* CloseButton by David Peng * 2020 10.20 * Version Beta 1.0 * 介绍:该控件是用于对话框的关闭按钮,只需指定父对象即可可自动回收。 * 使用方法: * 1、new CloseButton(this); //这样会直接调用主题的关闭按钮。 * 2、new CloseButton(黑色图标路径,this); //这样会用一个黑色的'X'图标SVG,hover时会渲染成白色。 * 3、new CloseButton(黑色图标路径,白色图标路径,this) //这样会用两张图片来实现图标显示。 */ #include "closebutton.h" #include #include #define THEME_QT_SCHEMA "org.ukui.style" #define THEME_GTK_SCHEMA "org.mate.interface" CloseButton::CloseButton(QWidget *parent, const QString &filePath, const QString &hoverPath) : QLabel(parent) { //Allocation if(filePath != "" && filePath != "window-close-symbolic") m_icon = new QIcon(filePath); else if(filePath == "window-close-symbolic"){ QIcon icon = QIcon::fromTheme("window-close-symbolic"); m_icon = new QIcon(icon); } else { m_icon = nullptr; } if(hoverPath != "") m_hoverIcon = new QIcon(hoverPath); else m_hoverIcon = nullptr; //Properties //setProperty("useIconHighlightEffect", true); //setProperty("iconHighlightEffectMode", 1); setFocusPolicy(Qt::NoFocus); //Initial componentss m_bIsChecked = false; m_bIsPressed = false; m_settedBkg = false; m_szHoverIn = "white"; m_szHoverOut = "default"; m_cSize = 16; m_colorBkg = palette().color(QPalette::Base); setAlignment(Qt::AlignCenter); if(m_icon != nullptr) { setPixmap(renderSvg(*m_icon,m_szHoverOut)); } if(QGSettings::isSchemaInstalled(THEME_GTK_SCHEMA) && QGSettings::isSchemaInstalled(THEME_QT_SCHEMA)) { QByteArray qtThemeID(THEME_QT_SCHEMA); QByteArray gtkThemeID(THEME_GTK_SCHEMA); m_gtkThemeSetting = new QGSettings(gtkThemeID,QByteArray(),this); m_qtThemeSetting = new QGSettings(qtThemeID,QByteArray(),this); QString style = m_qtThemeSetting->get("styleName").toString(); if(style == "ukui-dark") { m_szHoverOut = "white"; } else { m_szHoverOut = "default"; } connect(m_qtThemeSetting,&QGSettings::changed, [this] (const QString &key) { QString style = m_qtThemeSetting->get("styleName").toString(); if(key == "styleName") { if(style == "ukui-dark") { m_szHoverOut = "white"; } else { m_szHoverOut = "default"; } } }); } } const QPixmap CloseButton::renderSvg(const QIcon &icon, QString cgColor) { int size = m_cSize; const auto ratio = qApp->devicePixelRatio(); if ( 2 == ratio) { size = 48; } else if (3 == ratio) { size = 96; } QPixmap iconPixmap = icon.pixmap(size,size); iconPixmap.setDevicePixelRatio(ratio); QImage img = iconPixmap.toImage(); for (int x = 0; x < img.width(); x++) { for (int y = 0; y < img.height(); y++) { auto color = img.pixelColor(x, y); if (color.alpha() > 0) { if ("white" == cgColor) { color.setRed(255); color.setGreen(255); color.setBlue(255); img.setPixelColor(x, y, color); } else if ("black" == cgColor) { color.setRed(0); color.setGreen(0); color.setBlue(0); // color.setAlpha(0.1); color.setAlphaF(0.12); img.setPixelColor(x, y, color); } else if ("gray" == cgColor) { color.setRed(152); color.setGreen(163); color.setBlue(164); img.setPixelColor(x, y, color); } else if ("blue" == cgColor){ color.setRed(61); color.setGreen(107); color.setBlue(229); img.setPixelColor(x, y, color); } else { return iconPixmap; } } } } return QPixmap::fromImage(img); } QPixmap CloseButton::drawSymbolicColoredPixmap(const QPixmap &source, QString cgColor) { QImage img = source.toImage(); for (int x = 0; x < img.width(); x++) { for (int y = 0; y < img.height(); y++) { auto color = img.pixelColor(x, y); if (color.alpha() > 0) { if ("white" == cgColor) { color.setRed(255); color.setGreen(255); color.setBlue(255); img.setPixelColor(x, y, color); } else if ("black" == cgColor) { color.setRed(0); color.setGreen(0); color.setBlue(0); color.setAlphaF(0.9); img.setPixelColor(x, y, color); } else if ("gray" == cgColor) { color.setRed(152); color.setGreen(163); color.setBlue(164); img.setPixelColor(x, y, color); } else if ("blue" == cgColor){ color.setRed(61); color.setGreen(107); color.setBlue(229); img.setPixelColor(x, y, color); } else { return source; } } } } return QPixmap::fromImage(img); } void CloseButton::enterEvent(QEvent *event) { Q_UNUSED(event); if(m_hoverIcon == nullptr && m_icon != nullptr) setPixmap(renderSvg(*m_icon,m_szHoverIn)); else if(m_hoverIcon != nullptr && m_icon != nullptr) setPixmap(m_hoverIcon->pixmap(m_cSize,m_cSize)); else if(m_customIcon != nullptr) setPixmap(renderSvg(*m_customIcon,m_szHoverIn)); m_colorBkg = QColor("#FA6056"); } void CloseButton::mousePressEvent(QMouseEvent *event) { if(event->button() == Qt::LeftButton) { m_colorBkg = QColor("#E54A50"); m_bIsPressed = true; update(); } } void CloseButton::mouseReleaseEvent(QMouseEvent *event) { Q_UNUSED(event); if(m_bIsPressed && this->rect().contains(event->pos())) { m_bIsChecked = !m_bIsChecked; emit clicked(m_bIsChecked); m_bIsPressed = false; } } void CloseButton::leaveEvent(QEvent *event) { Q_UNUSED(event); m_colorBkg = m_customBkg.isValid() ? m_customBkg : palette().color(QPalette::Base); if(m_icon != nullptr) setPixmap(renderSvg(*m_icon,m_szHoverOut)); else if(m_customIcon != nullptr) setPixmap(renderSvg(*m_customIcon,m_szHoverOut)); } void CloseButton::paintEvent(QPaintEvent *event) { QPainter painter(this); painter.setRenderHint(QPainter::Antialiasing); // 反锯齿; painter.setPen(Qt::transparent); painter.setBrush(QBrush(m_colorBkg)); painter.drawRoundedRect(rect(), 4, 4); painter.end(); return QLabel::paintEvent(event); } void CloseButton::setIconSize(int size) { m_cSize = size; update(); } void CloseButton::setIcon(const QIcon &icon) { m_customIcon = new QIcon(icon); setPixmap(renderSvg(*m_customIcon,m_szHoverOut)); } void CloseButton::setBkg(const QColor &color) { m_settedBkg = true; m_customBkg = color; m_colorBkg = m_customBkg; if(m_icon != nullptr) { setPixmap(renderSvg(*m_icon,m_szHoverOut)); } else if(m_customIcon != nullptr) { setPixmap(renderSvg(*m_customIcon,m_szHoverOut)); } } void CloseButton::setHoverIn(const QString &hoverIn) { m_szHoverIn = hoverIn; update(); } void CloseButton::setHoverOut(const QString &hoverOut) { m_szHoverOut = hoverOut; if(m_icon != nullptr) { setPixmap(renderSvg(*m_icon,m_szHoverOut)); } else if(m_customIcon != nullptr) { setPixmap(renderSvg(*m_customIcon,m_szHoverOut)); } update(); } CloseButton::~CloseButton() { if(m_icon != nullptr) { delete m_icon; } if(m_hoverIcon != nullptr) delete m_hoverIcon; if(m_customIcon != nullptr) delete m_customIcon; } ukui-notebook/src/common/closebutton.pri0000644000175000017500000000016114174170620017425 0ustar fengfengSOURCES += \ $$PWD/CloseButton/closebutton.cpp \ HEADERS += \ $$PWD/CloseButton/closebutton.h \ ukui-notebook/src/listViewModeDelegate.cpp0000644000175000017500000004202114201136534017630 0ustar fengfeng/* * Copyright (C) 2020 Tianjin KYLIN Information Technology Co., Ltd. * * This program is free software; you can 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, 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 #include #include #include #include #include #include #include #include "noteModel.h" #include "widget.h" #include "listViewModeDelegate.h" #include "noteView.h" /*! * 系统时间 */ #define FORMAT_SCHEMA "org.ukui.control-center.panel.plugins" #define TIME_FORMAT_KEY "hoursystem" extern QFont g_currentFont; listViewModeDelegate::listViewModeDelegate(QObject *parent) : QStyledItemDelegate(parent), m_titleFont(g_currentFont.family(), (double)g_currentFont.pointSizeF()/15 * 16), //标题字体 m_titleSelectedFont(g_currentFont.family(), (double)g_currentFont.pointSizeF()/15 * 16), //标题选中字体 m_dateFont(g_currentFont.family(), (double)g_currentFont.pointSizeF()/15 * 13), //日期字体 m_titleColor(255, 255, 255), //标题颜色 m_dateColor(255, 255, 255), //日期颜色 m_ActiveColor(218, 233, 239), m_notActiveColor(175, 212, 228), //默认选中背景色 m_hoverColor(80, 80, 80), //悬停颜色 m_selectColor(43, 49, 60), //选中颜色 m_applicationInactiveColor(207, 207, 207), //应用程序可见,但未选择显示在前面时背景色 m_separatorColor(221, 221, 221), m_defaultColor(0, 0, 0), m_noteColor(0, 0, 0), //便签头颜色 m_rowHeight(82), //item宽度 m_maxFrame(200), m_rowRightOffset(0), m_state(Normal), m_isActive(false) { //QTimeLine拥有一个时间轴来控制时间动画和事件 //参数1为毫秒级 总运行时间0.3秒 m_timeLine = new QTimeLine(300, this); //对QTImeLine的时间轴设置动画帧数,共200张静态画面图组成 //Qt默认40ms一帧,也就是一秒可以最多走25帧 m_timeLine->setFrameRange(0,m_maxFrame); //时间轴走的时候,会不断发出frameChanged信号,setUpdateInterval控制多少时间发一次 m_timeLine->setUpdateInterval(10); //设置你的时间变换曲线,即明确你的时间是先快后慢,还是先慢后快,或者线性 m_timeLine->setCurveShape(QTimeLine::EaseInCurve); connect( m_timeLine, &QTimeLine::frameChanged, [this](){ emit sizeHintChanged(m_animatedIndex); }); connect(m_timeLine, &QTimeLine::finished, [this](){ m_animatedIndex = QModelIndex(); m_state = Normal; }); // 监听时区变化 const QByteArray iddd(FORMAT_SCHEMA); if (QGSettings::isSchemaInstalled(iddd)){ QGSettings *m_formatsettings = new QGSettings(iddd, QByteArray(), this); m_timeZone = m_formatsettings->get(TIME_FORMAT_KEY).toString(); connect(m_formatsettings, &QGSettings::changed, this, [=] (const QString &key) { if (key == "hoursystem") { m_timeZone = m_formatsettings->get(TIME_FORMAT_KEY).toString(); } }); } } void listViewModeDelegate::setState(States NewState, QModelIndex index) { m_animatedIndex = index; auto startAnimation = [this](QTimeLine::Direction diretion, int duration){ m_timeLine->setDirection(diretion); m_timeLine->setDuration(duration); m_timeLine->start(); }; switch ( NewState ){ case Insert: startAnimation(QTimeLine::Forward, m_maxFrame); break; case Remove: startAnimation(QTimeLine::Backward, m_maxFrame); break; case MoveOut: startAnimation(QTimeLine::Backward, m_maxFrame); break; case MoveIn: startAnimation(QTimeLine::Backward, m_maxFrame); break; case Normal: m_animatedIndex = QModelIndex(); break; } m_state = NewState; } void listViewModeDelegate::setAnimationDuration(const int duration) { m_timeLine->setDuration(duration); } void listViewModeDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { QStyleOptionViewItem opt = option; opt.rect.setWidth(option.rect.width() - m_rowRightOffset); //678 int currentFrame = m_timeLine->currentFrame(); //0 double rate = (currentFrame/(m_maxFrame * 1.0)); //0 double height = m_rowHeight * rate; //0 //默认Normal switch(m_state){ case Insert: case Remove: case MoveOut: if(index == m_animatedIndex){ opt.rect.setHeight(int(height)); //opt.backgroundBrush.setColor(m_notActiveColor); } break; case MoveIn: if(index == m_animatedIndex){ opt.rect.setY(int(height)); } break; case Normal: break; } //绘制第一层便签头背景 int m_noteColor{index.data(NoteModel::NoteColor).toInt()}; painter->setRenderHint(QPainter::Antialiasing); // 反锯齿; painter->setBrush(QBrush(intToQcolor(m_noteColor))); painter->setOpacity(1); painter->setPen(Qt::transparent); opt.rect.setWidth(5); opt.rect.setHeight(opt.rect.height() - 8); { QPainterPath painterPath; painterPath.addRoundedRect(opt.rect, 4, 4); painterPath.setFillRule(Qt::WindingFill); // 多块区域组合填充模式 painterPath.addRect(opt.rect.x() + 1, opt.rect.y(), 4, 4); painterPath.addRect(opt.rect.x() + 1, opt.rect.y() + opt.rect.height() - 4, 4, 4); painter->drawPath(painterPath); } //绘制第二层底色背景 painter->setRenderHint(QPainter::Antialiasing); // 反锯齿; painter->setOpacity(0.04); painter->setBrush(opt.palette.color(QPalette::Text)); painter->setPen(Qt::transparent); opt.rect.setHeight(opt.rect.height() - 0); opt.rect.setLeft(opt.rect.left() + 5); opt.rect.setWidth(675); { QPainterPath painterPath; painterPath.addRoundedRect(opt.rect, 4, 4); painterPath.setFillRule(Qt::WindingFill); // 多块区域组合填充模 painterPath.addRect(opt.rect.x(), opt.rect.y(), 4, 4); painterPath.addRect(opt.rect.x(), opt.rect.y() + opt.rect.height() - 4, 4, 4); painter->drawPath(painterPath); } painter->setOpacity(1); paintBackground(painter, opt, index); painter->setOpacity(1); paintLabels(painter, option, index); } QSize listViewModeDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const { QSize result = QStyledItemDelegate::sizeHint(option, index); //QSize(0, 23) if(index == m_animatedIndex){ if(m_state == MoveIn){ result.setHeight(m_rowHeight); }else{ double rate = m_timeLine->currentFrame()/(m_maxFrame * 1.0); double height = m_rowHeight * rate; result.setHeight(int(height)); } }else{ result.setHeight(m_rowHeight); } return result; } QTimeLine::State listViewModeDelegate::animationState() { return m_timeLine->state(); } void listViewModeDelegate::paintBackground(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { QStyleOptionViewItem opt = option; opt.rect.setWidth(option.rect.width() - m_rowRightOffset); if((option.state & QStyle::State_Selected) == QStyle::State_Selected) { //应用程序是可见的,并被选择在前面。 if(qApp->applicationState() == Qt::ApplicationActive){ //返回应用程序的当前状态。 if(m_isActive){//用指定的画笔填充给定的矩形。 painter->setRenderHint(QPainter::Antialiasing); // 反锯齿; painter->setBrush(opt.palette.color(QPalette::Text)); painter->setOpacity(0.08); painter->setPen(Qt::transparent); QPainterPath painterPath; painterPath.addRoundedRect(opt.rect, 4, 4); painterPath.setFillRule(Qt::WindingFill); // 多块区域组合填充模 painterPath.addRect(opt.rect.x(), opt.rect.y(), 4, 4); painterPath.addRect(opt.rect.x(), opt.rect.y() + opt.rect.height() - 4, 4, 4); painter->drawPath(painterPath); }else{ // 选中态 painter->setRenderHint(QPainter::Antialiasing); // 反锯齿; painter->setBrush(opt.palette.color(QPalette::Text)); painter->setOpacity(0.08); painter->setPen(Qt::transparent); QPainterPath painterPath; painterPath.addRoundedRect(opt.rect, 4, 4); painterPath.setFillRule(Qt::WindingFill); // 多块区域组合填充模 painterPath.addRect(opt.rect.x(), opt.rect.y(), 4, 4); painterPath.addRect(opt.rect.x(), opt.rect.y() + opt.rect.height() - 4, 4, 4); painter->drawPath(painterPath); } //应用程序可见,但未选择显示在前面 }else if(qApp->applicationState() == Qt::ApplicationInactive){ painter->setRenderHint(QPainter::Antialiasing); // 反锯齿; painter->setBrush(opt.palette.color(QPalette::Text)); painter->setOpacity(0.08); painter->setPen(Qt::transparent); QPainterPath painterPath; painterPath.addRoundedRect(opt.rect, 4, 4); painterPath.setFillRule(Qt::WindingFill); // 多块区域组合填充模 painterPath.addRect(opt.rect.x(), opt.rect.y(), 4, 4); painterPath.addRect(opt.rect.x(), opt.rect.y() + opt.rect.height() - 4, 4, 4); painter->drawPath(painterPath); } } //鼠标悬停时颜色 //用于指示小部件是否在鼠标下。 //hover态 else if((option.state & QStyle::State_MouseOver) == QStyle::State_MouseOver){ painter->setRenderHint(QPainter::Antialiasing); // 反锯齿; painter->setBrush(opt.palette.color(QPalette::Text)); painter->setOpacity(0.04); painter->setPen(Qt::transparent); QPainterPath painterPath; painterPath.addRoundedRect(opt.rect, 4, 4); painterPath.setFillRule(Qt::WindingFill); // 多块区域组合填充模 painterPath.addRect(opt.rect.x(), opt.rect.y(), 4, 4); painterPath.addRect(opt.rect.x(), opt.rect.y() + opt.rect.height() - 4, 4, 4); painter->drawPath(painterPath); //当前item未选中 未悬停时颜色 }else if((index.row() != m_currentSelectedIndex.row() - 1) && (index.row() != m_hoveredIndex.row() - 1)){ painter->setRenderHint(QPainter::Antialiasing); // 反锯齿; } } void listViewModeDelegate::paintLabels(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const { //painter事件 auto drawStr = [painter](double posX, double posY, double width, double height, QColor color, QFont font, QString str){ QRectF rect(posX, posY, width, height); painter->setPen(color); painter->setFont(font); painter->drawText(rect, Qt::AlignBottom, str); }; /* * 已知整体高度,两行字的高度,然后算出具体偏移 */ int leftOffsetX = g_currentFont.pointSize()+12; // 左边距 int spaceY = g_currentFont.pointSize() - 10;// 标题和日期之间的空格, 默认取5 int topOffsetY = 18 - (g_currentFont.pointSize()-11)*3;// 标题上方的空格, 根据字号大小计算 QString fontName = g_currentFont.family(); m_titleFont.setFamily(fontName); m_titleFont.setPointSizeF(g_currentFont.pointSizeF()/15 * 16); m_titleSelectedFont.setFamily(g_currentFont.family()); m_titleSelectedFont.setPointSizeF(g_currentFont.pointSizeF()/15 * 16); m_titleSelectedFont.setBold(true); m_dateFont.setFamily(g_currentFont.family()); m_dateFont.setPointSizeF(g_currentFont.pointSizeF()/15 * 13); QStyleOptionViewItem opt = option; // ` QString title{index.data(NoteModel::NoteFullTitle).toString()}; QFont titleFont = (option.state & QStyle::State_Selected) == QStyle::State_Selected ? m_titleSelectedFont : m_titleFont; QFontMetrics fmTitle(titleFont); QRect fmRectTitle = fmTitle.boundingRect(title); QFont dateFont = m_dateFont; QString date = parseDateTime(index.data(NoteModel::NoteLastModificationDateTime).toDateTime()); QFontMetrics fmDate(dateFont); QRect fmRectDate = fmDate.boundingRect(title); double rowPosX = option.rect.x(); double rowPosY = option.rect.y(); double rowWidth = option.rect.width(); double titleRectPosX = rowPosX + leftOffsetX; double titleRectPosY = rowPosY; double titleRectWidth = rowWidth - 2.0 * leftOffsetX; double titleRectHeight = fmRectTitle.height() + topOffsetY; double dateRectPosX = rowPosX + leftOffsetX; double dateRectPosY = rowPosY + fmRectTitle.height() + topOffsetY; double dateRectWidth = rowWidth - 2.0 * leftOffsetX; double dateRectHeight = fmRectDate.height() + spaceY; double rowRate = m_timeLine->currentFrame()/(m_maxFrame * 1.0); double currRowHeight = m_rowHeight * rowRate; // 设置标题和日期字符串的边界矩形 if(index.row() == m_animatedIndex.row()){ if(m_state == MoveIn){ titleRectHeight = topOffsetY + fmRectTitle.height() + currRowHeight; dateRectPosY = titleRectHeight; dateRectHeight = fmRectDate.height() + spaceY; }else{ if((fmRectTitle.height() + topOffsetY) >= ((1.0 - rowRate) * m_rowHeight)){ titleRectHeight = (fmRectTitle.height() + topOffsetY) - (1.0 - rowRate) * m_rowHeight; }else{ titleRectHeight = 0; double labelsSumHeight = fmRectTitle.height() + topOffsetY + fmRectDate.height() + spaceY; double bottomSpace = m_rowHeight - labelsSumHeight; if(currRowHeight > bottomSpace){ dateRectHeight = currRowHeight - bottomSpace; }else{ dateRectHeight = 0; } } dateRectPosY = titleRectHeight + rowPosY; } } // 绘图标题和日期 title = fmTitle.elidedText(title, Qt::ElideRight, int(titleRectWidth)); drawStr(titleRectPosX, titleRectPosY, titleRectWidth, titleRectHeight, opt.palette.color(QPalette::Text), titleFont, title); drawStr(dateRectPosX, dateRectPosY, dateRectWidth, dateRectHeight, opt.palette.color(QPalette::Text), dateFont, date); } QString listViewModeDelegate::parseDateTime(const QDateTime &dateTime) const { QLocale usLocale = QLocale::system(); QString d; auto currDateTime = QDateTime::currentDateTime(); if(dateTime.date() == currDateTime.date()){ d = tr("Today "); if(m_timeZone == "24"){ d.append(usLocale.toString(dateTime.time(),"hh:mm")); }else { d.append(usLocale.toString(dateTime.time(),"AP hh:mm")); } return d; }else if(dateTime.daysTo(currDateTime) == 1){ d = tr("Yesterday "); if(m_timeZone == "24"){ d.append(usLocale.toString(dateTime.time(),"hh:mm")); }else { d.append(usLocale.toString(dateTime.time(),"AP hh:mm")); } return d; } //else if(dateTime.daysTo(currDateTime) >= 2 && // dateTime.daysTo(currDateTime) <= 7){ // return usLocale.toString(dateTime.date(), "dddd"); //} if(m_timeZone == "12"){ return dateTime.toString("yyyy/MM/dd AP hh:mm"); } return dateTime.toString("yyyy/MM/dd hh:mm"); } void listViewModeDelegate::setActive(bool isActive) { m_isActive = isActive; } void listViewModeDelegate::setRowRightOffset(int rowRightOffset) { m_rowRightOffset = rowRightOffset; } void listViewModeDelegate::setHoveredIndex(const QModelIndex &hoveredIndex) { m_hoveredIndex = hoveredIndex; } void listViewModeDelegate::setCurrentSelectedIndex(const QModelIndex ¤tSelectedIndex) { m_currentSelectedIndex = currentSelectedIndex; } int listViewModeDelegate::qcolorToInt(const QColor &color) const { //将Color 从QColor 转换成 int return (int)(((unsigned int)color.blue()<< 16) | (unsigned short)(((unsigned short)color.green()<< 8) | color.red())); } QColor listViewModeDelegate::intToQcolor(int &intColor) const { int red = intColor & 255; int green = intColor >> 8 & 255; int blue = intColor >> 16 & 255; return QColor(red, green, blue); } ukui-notebook/src/fontButton.h0000644000175000017500000000173514174170620015403 0ustar fengfeng/* * Copyright (C) 2020 Tianjin KYLIN Information Technology Co., Ltd. * * This program is free software; you can 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, 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 namespace Ui { class fontButton; } class fontButton : public QWidget { Q_OBJECT public: explicit fontButton(QWidget *parent = nullptr); ~fontButton(); Ui::fontButton *ui; private: }; #endif // FONTBUTTON_H ukui-notebook/src/paletteWidget.ui0000644000175000017500000000631714201136534016227 0ustar fengfeng PaletteWidget 0 0 200 32 200 32 200 32 Form 80 8 16 16 104 8 16 16 152 8 16 16 32 8 16 16 56 8 16 16 8 8 16 16 178 8 16 16 128 8 16 16 ukui-notebook/src/widget.h0000644000175000017500000003031014201136534014510 0ustar fengfeng/* * Copyright (C) 2020 Tianjin KYLIN Information Technology Co., Ltd. * * This program is free software; you can 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, 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "myThrow.h" #include "noteView.h" #include "noteData.h" #include "noteModel.h" #include "dbManager.h" #include "editPage.h" #include "noteExitWindow.h" #include "ui_editPage.h" #include "adaptscreeninfo.h" #include "about.h" #include "emptyNotes.h" #include "listViewModeDelegate.h" #include "iconViewModeDelegate.h" #define FIRST_LINE_MAX 80 /** * ukui style */ #define THEME_QT_SCHEMA "org.ukui.style" #define MODE_QT_KEY "style-name" #define FONT_SIZE "systemFontSize" #define FONT_STYLE "systemFont" /** * ukui-control-center */ #define PERSONALISE_SCHEMA "org.ukui.control-center.personalise" /** * kylin-user-guide */ #define USER_GUIDE_SCHEMA "com.kylinUserGuide.hotel_1000" extern QFont g_currentFont; namespace Ui { class Widget; } class Widget : public QWidget { Q_OBJECT public: explicit Widget(QWidget *parent = nullptr); ~Widget(); Ui::Widget *ui; //主ui std::vector m_editors; //c++数组容器 int m_isThemeChanged; //主题 void error_throw(); //异常处理抛出 int getListFlag() const; //获取列表切换标志位 void setListFlag(const int &listflag); //设置列表切换标志位 void createNewNote(); //新建便签 void openMemoWithId(int noteId); public slots: void sltMessageReceived(/*const QString &msg*/); //接收socket信息 void textForNewEditpageSigReceived(); //将选中内容复制到新便签页功能的内容传递函数 void iniNoteModeRead(); //读取配置文件iniNoteMode字段的内容 void transFisrtLine(); //便签页标题为默认时,翻译标题函数 protected: void paintEvent(QPaintEvent *event) Q_DECL_OVERRIDE; //void mouseMoveEvent(QMouseEvent *event) Q_DECL_OVERRIDE; //void mousePressEvent(QMouseEvent *event) Q_DECL_OVERRIDE; //void mouseReleaseEvent(QMouseEvent *event) Q_DECL_OVERRIDE; private: EditPage *m_notebook; //新建便签指针 int m_listflag; //平铺/展开列表切换 int sortflag; //升降序切换 noteExitWindow* m_noteExitWindow; //退出弹窗 emptyNotes* m_emptyNotes; //清除便签页弹窗 QAction *m_searchAction; //搜索栏图标 QAction *delAction; //搜索栏删除图标 QTimer* m_autoSaveTimer; //自动保存定时器 QSettings* m_settingsDatabase; //配置文件 QLineEdit* m_searchLine; //搜索栏 QPushButton* m_newKynote; //新建按钮 QPushButton* m_trashButton; //删除按钮 QPushButton* m_viewChangeButton; //列表/平铺切换按钮 NoteView* m_noteView; //listview listViewModeDelegate* m_plistDelegate; QTableView* m_noteTable; //tableview NoteModel* m_noteModel; //便签模板 NoteModel* m_deletedNotesModel; //删除模板 QSortFilterProxyModel* m_proxyModel; //对项目进行排序,过滤 QModelIndex m_currentSelectedNoteProxy; //当前列表 QModelIndex m_tmpIndex; //编辑时临时列表 QModelIndex m_tmpColorIndex; //调色板临时列表 QQueue m_searchQueue; //搜索队列 DBManager* m_dbManager; //数据库 QThread* m_dbThread; //数据库线程 QMenu* m_menu; //功能菜单 QAction* m_menuActionEmpty; //菜单动作-清空便签 QAction* m_menuExit; //菜单动作-退出便签本 //QAction* m_menuActionSet; //菜单动作-设置界面 adaptScreenInfo *m_pSreenInfo; //屏幕信息 QPoint dragPosition; //拖动坐标 bool mousePressed; //鼠标是否按下 QString m_currentTheme; //当前主题名 double m_transparency; //透明度 QDBusInterface *userGuideInterface; //用户手册 int m_noteCounter; //便签总数 int m_trashCounter; //废纸篓总数 bool m_isContentModified; //便签内容是否修改 bool m_isColorModified; //便签颜色是否修改 bool m_isOperationRunning; bool m_isTextCpNew; void kyNoteInit(); //加载界面组件 void kyNoteConn(); //绑定槽函数 void initIconMode(); //初始化图标 void initListMode(); //初始化列表 void listenToGsettings(); //监听gsettings void btnInit(); //初始化按钮 void searchInit(); //初始化搜索栏 void deleteNote(const QModelIndex& noteIndex, bool isFromUser=true);//删除便签 void deleteSelectedNote(); //获取选中便签/列表 void setupDatabases(); //配置数据库 void initializeSettingsDatabase(); //初始化配置文件 void createNewNoteIfEmpty(); //初始时创建一个便签 void setupListModeModel(); //代理列表模板 void setupIconModeModel(); //代理图标模板 void saveNoteToDB(const QModelIndex& noteIndex); //保存到数据库 NoteData* generateNote(const int noteID); //新建便签时初始化 QString getFirstLine(const QString& str); //获取文本内容第一行 QString getNoteDateEditor (QString dateEdited); //获取时间 QDateTime getQDateTime(QString date); //获取日期 void showNoteInEditor(const QModelIndex& noteIndex); //加载便签页内容 void selectFirstNote(); //选中列表头便签 void moveNoteToTop(); //移动便签到列表头 void clearSearch(); //清空搜索栏 void findNotesContain(const QString &keyword); //过滤字符串 void selectNote(const QModelIndex& noteIndex); //双击前选中目标列表 void checkMigration(); //迁移sync void migrateNote(QString notePath); //便签数据迁移 void closeAllEditors(); private slots: void initData(); //初始化加载第一个便签 void loadNotes(QList noteList, int noteCounter); //加载便签列表 void exitSlot(); //关闭按钮槽函数 void trashSlot(); //清空便签页按钮槽函数 void miniSlot(); //最小化按钮槽函数 void newSlot(); //新建按钮槽函数 void listClickSlot(const QModelIndex &index); //item单击事件槽函数 void listDoubleClickSlot(const QModelIndex &); //item双击事件槽函数 void onTextEditTextChanged(int noteId, int i); //文本改变槽函数 void onColorChanged(const QColor &color, int noteId); //便签颜色改变槽函数 void onTrashButtonClicked(); //删除槽函数 void onSearchEditTextChanged(const QString& keyword); //搜索栏文本改变槽函数 void sortSlot(int index); //排序槽函数 void changePageSlot(); //列表平铺切换槽函数 void setNoteNullSlot(); //便签页关闭置空槽函数 void clearNoteSlot(); //清空便签槽函数 //void SetNoteSlot(); //便签设置界面槽函数 void onF1ButtonClicked(); //快捷键F1槽函数 signals: void requestNotesList(); //加载列表请求信号 void requestOpenDBManager(QString path, bool doCreate); //打开数据库信号 void requestCreateUpdateNote(NoteData* note); //数据库更新信号 void requestDeleteNote(NoteData* note); //数据库同步删除信号 void requestClearNote(); //清空数据库 void requestRestoreNotes(QList noteList); //重加载信号 void requestImportNotes(QList noteList); //导入信号 void requestExportNotes(QString fileName); //导出信号 void requestMigrateNotes(QList noteList); //迁移信号 void requestMigrateTrash(QList noteList); //迁移废纸篓信号 void requestForceLastRowIndexValue(int index); //请求返回受结果的SQL语句影响的行数信号 void switchSortTypeRequest(int index); //切换排序类型信号 }; #endif // WIDGET_H ukui-notebook/src/emptyNotes.cpp0000644000175000017500000000667114201136534015744 0ustar fengfeng/* * Copyright (C) 2020 Tianjin KYLIN Information Technology Co., Ltd. * * This program is free software; you can 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, 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 #include #include #include #include "emptyNotes.h" #include "ui_emptyNotes.h" #include "utils/xatom-helper.h" emptyNotes::emptyNotes(QWidget *parent) : QDialog(parent), ui(new Ui::emptyNotes), m_isDontShow(false) { ui->setupUi(this); setWindowTitle(tr("emptyNotes")); setWindowFlags(Qt::Dialog); setAttribute(Qt::WA_TranslucentBackground); setFixedSize(width(),height()); ui->pushButton_3->setFlat(true); ui->pushButton_3->setStyleSheet("border-radius:4px;"); ui->pushButton->setAutoRepeat(true); ui->pushButton->setAutoRepeatDelay(1); ui->pushButton->setAutoRepeatInterval(1); ui->pushButton_2->setAutoRepeat(true); ui->pushButton_2->setAutoRepeatDelay(1); ui->pushButton_2->setAutoRepeatInterval(1); // // 添加窗管协议 // MotifWmHints hints; // hints.flags = MWM_HINTS_FUNCTIONS|MWM_HINTS_DECORATIONS; // hints.functions = MWM_FUNC_ALL; // hints.decorations = MWM_DECOR_BORDER; // XAtomHelper::getInstance()->setWindowMotifHint(this->winId(), hints); // ui->widget->setStyleSheet("QWidget{background-color: rgba(255, 255, 255, 0.4);}"); // ui->label->setStyleSheet("background-color: rgba();\ // font-size:20px;\ // font-weight:400;\ // color:rgba(40,40,40,1);\ // line-height:34px;\ // opacity:0.97;\ // "); // ui->checkBox->setStyleSheet("background-color: rgba();\ // font-size:14px;\ // font-weight:400;\ // color:rgba(102,102,102,1);\ // line-height:40px;\ // opacity:0.91;"); connect(ui->pushButton, SIGNAL(clicked()), this, SLOT(on_pushButton_clicked()) ); connect(ui->pushButton_2, SIGNAL(clicked()), this, SLOT(on_pushButton_2_clicked()) ); connect(ui->checkBox, SIGNAL(stateChanged(int)), this, SLOT(checkBoxStateChanged(int)) ); } void emptyNotes::paintEvent(QPaintEvent *event) { Q_UNUSED(event); QPainter p(this); p.setRenderHint(QPainter::Antialiasing); // 反锯齿; QPainterPath rectPath; rectPath.addRect(this->rect()); p.fillPath(rectPath,palette().color(QPalette::Base)); } emptyNotes::~emptyNotes() { delete ui; } void emptyNotes::on_pushButton_clicked() { ui->checkBox->setCheckState(Qt::Unchecked); this->close(); } void emptyNotes::on_pushButton_2_clicked() { if(ui->checkBox->isChecked()) { m_isDontShow = true; } else { m_isDontShow = false; } emit requestEmptyNotes(); this->close(); } ukui-notebook/src/stylesheet/0000755000175000017500000000000014174170620015253 5ustar fengfengukui-notebook/src/stylesheet/stylesheet_wight.css0000644000175000017500000000041714174170620021362 0ustar fengfengQWidget{ background:rgb(255,255,255); } QLineEdit{ background:rgb(240,240,240); } QPushButton#new_add_btn{ background:rgb(240,240,240); } QWidget#Widget{ background:rgba(240,240,240,0); border-radius:6px; } QTableWidget#tableWidget{ background:rgb(240,240,240); } ukui-notebook/src/stylesheet/stylesheet_black.css0000644000175000017500000000236714174170620021322 0ustar fengfengQWidget{ background:rgb(0,0,0); } QPushButton#new_add_btn{ background:rgb(240,240,240); } QWidget#Widget{ background:rgba(240,240,240,0); border-radius:6px; } QTableWidgetItem#tableWidget{ background:rgba(240,240,240,0); } void Notebook::on_sort_btn_clicked() { if(dack_wight_flag) { QFile qss(":/stylesheet/stylesheet_wight.css"); if( qss.open(QFile::ReadOnly)) { qDebug("open success"); QString style = QLatin1String(qss.readAll()); this->setStyleSheet("background:rgb(255,255,255);"); qss.close(); } else { qDebug("Open failed"); } dack_wight_flag = 0; }else{ QFile qss(":/stylesheet/stylesheet_black.css"); if( qss.open(QFile::ReadOnly)) { qDebug("open success"); QString style = QLatin1String(qss.readAll()); this->setStyleSheet("background:rgb(0,0,0);"); qss.close(); } else { qDebug("Open failed"); } dack_wight_flag = 1; } } ukui-notebook/src/widget.ui0000644000175000017500000002312114174170620014703 0ustar fengfeng Widget 0 0 714 590 714 590 714 590 Widget 10 0 0 0 17 8 8 8 24 24 24 24 Qt::Horizontal 40 20 4 8 4 4 30 30 30 30 30 30 30 30 30 30 30 30 16 0 16 16 20 0 64 90 36 90 36 PointingHandCursor Qt::TabFocus New :/images/newNote_Regular.png:/images/newNote_Regular.png 16 16 320 36 320 36 Qt::Horizontal 40 20 8 0 36 36 36 36 ArrowCursor Qt::TabFocus :/images/trashCan_Regular.png:/images/trashCan_Regular.png 16 16 36 36 36 36 NoteView QListView
noteView.h
ukui-notebook/src/noteView.h0000644000175000017500000000420714201136534015033 0ustar fengfeng/* * Copyright (C) 2020 Tianjin KYLIN Information Technology Co., Ltd. * * This program is free software; you can 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, 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 #include class NoteView : public QListView { Q_OBJECT friend class tst_NoteView; //友元类 class tst_NoteView可以访问此类NoteView的private和protected成员变量 public: explicit NoteView(QWidget* parent = Q_NULLPTR); ~NoteView(); void animateAddedRow(const QModelIndex &parent, int start, int end); void animateRemovedRow(const QModelIndex &parent, int start, int end); void setAnimationEnabled(bool isEnabled); void setCurrentRowActive(bool isActive); void updateList(); protected: void paintEvent(QPaintEvent *e) Q_DECL_OVERRIDE; void mouseMoveEvent(QMouseEvent* e) Q_DECL_OVERRIDE; void mousePressEvent(QMouseEvent* e) Q_DECL_OVERRIDE; void mouseReleaseEvent(QMouseEvent* e) Q_DECL_OVERRIDE; void selectionChanged(const QItemSelection &selected, const QItemSelection &deselected) Q_DECL_OVERRIDE; private: bool m_isScrollBarHidden; bool m_animationEnabled; bool m_isMousePressed; int m_rowHeight; public slots: void rowsAboutToBeMoved(const QModelIndex &sourceParent, int sourceStart, int sourceEnd, const QModelIndex &destinationParent, int destinationRow); void rowsMoved(const QModelIndex &parent, int start, int end, const QModelIndex &destination, int row); private slots: void init(); signals: void viewportPressed(); }; #endif // NOTEVIEW_H ukui-notebook/src/myThrow.h0000644000175000017500000000532714174170620014713 0ustar fengfeng/* * Copyright (C) 2020 Tianjin KYLIN Information Technology Co., Ltd. * * This program is free software; you can 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, 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 #include #define MY_THROW(ExClass, args...) \ do \ { \ ExClass e(args); \ e.Init(__FILE__, __PRETTY_FUNCTION__, __LINE__); \ throw e; \ } \ while (false) #define MY_DEFINE_EXCEPTION(ExClass, Base) \ ExClass(const std::string& msg = "") throw() \ : Base(msg) \ {} \ \ ~ExClass() throw() {} \ \ /* override */ std::string GetClassName() const \ { \ return #ExClass; \ } class ExceptionBase : public std::exception { public: ExceptionBase(const std::string& msg = "") throw(); virtual ~ExceptionBase() throw(); void Init(const char* file, const char* func, int line); virtual std::string GetClassName() const; virtual std::string GetMessage() const; const char* what() const throw(); const std::string& ToString() const; //打印函数栈 std::string GetStackTrace() const; protected: std::string mMsg; const char* mFile; const char* mFunc; int mLine; private: enum { MAX_STACK_TRACE_SIZE = 50 };//最大调用栈深度 void* mStackTrace[MAX_STACK_TRACE_SIZE]; size_t mStackTraceSize; mutable std::string mWhat; }; class ExceptionDerived : public ExceptionBase { public: MY_DEFINE_EXCEPTION(ExceptionDerived, ExceptionBase); }; #endif // MYTHROW_H ukui-notebook/src/paletteButton.ui0000644000175000017500000000140514174170620016253 0ustar fengfeng paletteButton 0 0 27 23 Form 6 6 15 15 background-color: rgb(255, 21, 5); border-radius:3px; ukui-notebook/src/noteExitWindow.ui0000644000175000017500000001052014174170620016406 0ustar fengfeng noteExitWindow 0 0 412 230 412 230 412 230 11 Dialog 40 61 68 0 24 31 321 22 321 22 Noto Sans CJK SC -1 50 false font-size:20px; font-weight:400; opacity:0.97; line-height:34px; Are you sure to exit the note book? -1 50 false true font-size:14px; font-weight:400; line-height:40px; opacity:0.91; Close the desktop note page at the same time 16 26 Qt::Horizontal 40 20 120 34 120 34 line-height:24px; No 120 34 120 34 line-height:24px; Yes ukui-notebook/src/image/0000755000175000017500000000000014174170620014144 5ustar fengfengukui-notebook/src/image/kylin-notebook.svg0000644000175000017500000003116214174170620017634 0ustar fengfeng ukui-notebook/src/image/1x/0000755000175000017500000000000014174170620014474 5ustar fengfengukui-notebook/src/image/1x/delete.png0000644000175000017500000000032314174170620016442 0ustar fengfengPNG  IHDRa pHYs  ~IDAT8c?2ퟴ!,,.K{&G'΂&+c U :FVD0aq6^(3`h.$2S#C}o$lg````g. IENDB`ukui-notebook/src/image/1x/del_line.png0000644000175000017500000000045614174170620016762 0ustar fengfengPNG  IHDRa pHYs  ~IDAT8 0 ?e `&Tu B  `0݀ ,\BIܝ}x暑n<$ > p3zBpr`ӋX7@{H D&,T!0M*Q:Z 1vHUҰu=IxIENDB`ukui-notebook/src/image/1x/paste.png0000644000175000017500000000034314174170620016316 0ustar fengfengPNG  IHDRa pHYs  ~IDAT8ݒQ DݰLuRCuRN.X`B\amGx™0ue`^V﭅E)%ƺ&t8cY/[ Z1$;FaPқIENDB`ukui-notebook/src/image/1x/menu-black.png0000644000175000017500000000023014174170620017213 0ustar fengfengPNG  IHDR;0 pHYs  ~JIDATH CTmm\#`APsw4lE$5CRیM=u_}+t?LHZc3wIENDB`ukui-notebook/src/image/1x/array_des.png0000644000175000017500000000034514174170620017155 0ustar fengfengPNG  IHDR Vu\ pHYs  ~IDAT(c?) Ymo|gr 1ΏŲv9pi000ly&@ ph_ ă,@X\w&#̆ 7Oi(z Ȁ0Fx" @6$`.@Z```=)3ɇIIENDB`ukui-notebook/src/image/1x/list.png0000644000175000017500000000024414174170620016155 0ustar fengfengPNG  IHDRa pHYs  ~VIDAT8c?%_h'?qR|f0001O9%$emB0A@q0Q{4`4<I"IG{IENDB`ukui-notebook/src/image/1x/menu-light.png0000644000175000017500000000022714174170620017254 0ustar fengfengPNG  IHDR;0 pHYs  ~IIDATH ! Db6,۰-TsNI|WTaaa Lcca; P3$OJ0IENDB`ukui-notebook/src/image/1x/delete-new.svg0000644000175000017500000000101214174170620017240 0ustar fengfeng删除-newukui-notebook/src/image/1x/under_line-new.png0000644000175000017500000000033514174170620020116 0ustar fengfengPNG  IHDRa pHYs  ~IDAT8c?% Yoo$BfaBOcPԠ@25`0pR.Pb,hjO2```P\w@r 5`~G ¼x P0|"%-````(IENDB`ukui-notebook/src/image/1x/array_order.png0000644000175000017500000000034514174170620017515 0ustar fengfengPNG  IHDR Vu\ pHYs  ~IDAT(c?) Y]γI{' 1ΏŲpi000l$@ P\ >]3P09"u&#̆ 7<i(z Ȁ)AW84E dC% )oމIENDB`ukui-notebook/src/image/1x/go-bottom-symbolic.png0000644000175000017500000000024714174170620020733 0ustar fengfengPNG  IHDR8G|nIDAT=0D zW#UzMOU,Ȅ'۵UUym{,8b]vقN0"s. ݯŭa%_"HIrx6KtIENDB`ukui-notebook/src/image/1x/number-new.svg0000644000175000017500000000113314174170620017272 0ustar fengfeng编号 副本ukui-notebook/src/image/1x/copy_to_new_note.png0000644000175000017500000000041314174170620020552 0ustar fengfengPNG  IHDRa pHYs  ~IDAT8S 0s0APhL@7d]$'/.ҥ@88;kF(xSċ'3[;_"yψlŠ5xT2(AaiZC\j9[ I «8kam43` 2K?!kVwfv?& Q;6@NIENDB`ukui-notebook/src/image/1x/table.png0000644000175000017500000000024614174170620016273 0ustar fengfengPNG  IHDRa pHYs  ~XIDAT8c?%x4s%o3Q~A` ,@z'GBd6.y:^MN ӉݞIENDB`ukui-notebook/src/image/1x/ Convert_to_notes .png0000644000175000017500000000035714174170620020641 0ustar fengfengPNG  IHDRa pHYs  ~IDAT8R s+ { !2 zTTԒB3qB@O<k~&=`Kj8/h =En ,ΠM"QkP?\eN[?&)֏\|O<],#B3їIENDB`ukui-notebook/src/image/1x/del_line-new.svg0000644000175000017500000000104114174170620017553 0ustar fengfeng删除线-newukui-notebook/src/image/1x/mini2.png0000644000175000017500000000034614174170620016223 0ustar fengfengPNG  IHDR;0 pHYs  ~IDATHc?]γ  Mhdz[>7DR0xQG-zpU83^5/e{Iyj?SQG-xhZp}`,.`u@}:dG)R.pF/4IENDB`ukui-notebook/src/image/1x/array-new.png0000644000175000017500000000033314174170620017106 0ustar fengfengPNG  IHDRa pHYs  ~IDAT8c?%\ Xz'tBqa# dyRC?DfF {¼a7Ȑ @ >)J דḱm R*``H: CIENDB`ukui-notebook/src/image/1x/Symbol.png0000644000175000017500000000026614174170620016453 0ustar fengfengPNG  IHDRa pHYs  ~hIDAT8ch!0ViXc@\,.c$ +`H75 `28~'N4A0 @Y,0005IENDB`ukui-notebook/src/image/1x/system-search-symbolic.svg0000644000175000017500000000067014174170620021626 0ustar fengfengsystem-search-symbolicukui-notebook/src/image/1x/bold.png0000644000175000017500000000040214174170620016116 0ustar fengfengPNG  IHDRa pHYs  ~IDAT8c?%RC=200m@{"l lqa#Xo &000 `jJ P< 0q@rCdy z'rP T. xbh  rb ` d/4d3J^,;3009;?IENDB`ukui-notebook/src/image/1x/sourch.png0000644000175000017500000000045714174170620016513 0ustar fengfengPNG  IHDRatEXtSoftwareAdobe ImageReadyqe<IDATxڬS ,A;BG`Fh7qܠ8#u&w/m虻p O4&8Kdp%hpA% 8J `xGxN )ȕCF %=:y1x6UIENDB`ukui-notebook/src/image/1x/array.png0000644000175000017500000000035514174170620016323 0ustar fengfengPNG  IHDRa pHYs  ~IDAT8Œ 0 D_Q`&Q:A$+DA^F QAP$RA~p_qNwܤXEv6D׼gaFVa |Vd%V1Cuf,!D=[`5%yw* x.4xIENDB`ukui-notebook/src/image/1x/number.png0000644000175000017500000000027014174170620016471 0ustar fengfengPNG  IHDRa pHYs  ~jIDAT8c0 ??Vt>>M0ld?Ѯ XKV@\ ؀I,BX7сA I \@4```ʀ(IENDB`ukui-notebook/src/image/1x/sort-click.png0000644000175000017500000000223714174170620017260 0ustar fengfengPNG  IHDR#FtEXtSoftwareAdobe ImageReadyqe<#iTXtXML:com.adobe.xmp ՇIDATxb4 ?ŀ0(@1DWu EY&a@]4~# D `"S4g2>q4g+DF PLQ:aK2=@< j(uO F!l,Ȗ @b! 4,4?R@mg !L)&+h%' 3U$X B=HfQ > UĤF G@|P9W&%7>=;^pjIENDB`ukui-notebook/src/image/1x/copy.png0000644000175000017500000000040014174170620016146 0ustar fengfengPNG  IHDRa pHYs  ~IDAT8S < .?M'l7rDM|lBp}jZkIX?3.Hॕ 便签颜色ukui-notebook/src/image/1x/new-click.png0000644000175000017500000000307714174170620017065 0ustar fengfengPNG  IHDR pHYs  iTXtXML:com.adobe.xmp @IDAT8T0 Qel@2x:R1[*#PRP|r#Fwj?I{ "SW,= <'" D*'8 @,(͜y1Gv; Tw]wvVLlfHjבj;%7S"1,n7lj~oOޡ(IENDB`ukui-notebook/src/image/1x/cut.png0000644000175000017500000000060214174170620015773 0ustar fengfengPNG  IHDRa pHYs  ~4IDAT8RM0} `  PcM7 a0AУgtrI}0M-[d92`:Fm@0yJsCW:懠Ɨ<  (/J?9T0zrWu6 ܋+u';T֌uֲE߄{dS7mZ6,$ Sԯ J0r2Y&a׳2*kHy;;3ރt{U8n!ˉ{yHqrrӗ.&qIENDB`ukui-notebook/src/image/1x/Symbol-new.svg0000644000175000017500000000124714174170620017255 0ustar fengfeng项目符号-newukui-notebook/src/image/1x/new-normal.png0000644000175000017500000000307014174170620017261 0ustar fengfengPNG  IHDR pHYs  iTXtXML:com.adobe.xmp ^sIDAT8 ENN6a9c }MWsKxPgu[ו3U`T/ ®("&$/$+"?¡ūFj'=B~b2B=0By=~=ԽE}]ɔ*dϖP.B K. |.,nHB5,K8=~;/IENDB`ukui-notebook/src/image/1x/close-black.png0000644000175000017500000000035314174170620017362 0ustar fengfengPNG  IHDR;0 pHYs  ~IDATH 0 řK48M%^*$(L! mC91|pI$Sg=IZ_&,pje-z;܃.]socP:{D1xXmX0TKڦ{;Yg 2# RIENDB`ukui-notebook/src/image/1x/close2.png0000644000175000017500000000052414174170620016372 0ustar fengfengPNG  IHDR;0 pHYs  ~IDATHc?G'  dz[>7DR0x⁷i6 9[kβz@r 5b~l ٱRbc&RR-f992^调整ukui-notebook/src/image/1x/recovery.png0000644000175000017500000000044614174170620017044 0ustar fengfengPNG  IHDRa pHYs  ~IDAT8SQ 0} @0 @åI a@$K)]]u3#`sX\=Ld` jM砈sZppPu;I0MM)Aפ4WM  rN^V/[jRC&<`H"ĉ d)Bv/ OY9*glYz+]LH3PZ IENDB`ukui-notebook/src/image/1x/close3.png0000644000175000017500000000050714174170620016374 0ustar fengfengPNG  IHDR;0 pHYs  ~IDATH10Ʌى2M8pf]]\kʂ/(@q8縇eH*>$08L̾+];9[1h [<(?+vY9lT Y \H5*QEx?E )(vichxHg-XHSpeXʺ},*rH4i5/ FRц,ZxQ5'ˬr2b7 Av!VWTaIENDB`ukui-notebook/src/image/1x/ Insert_multiple_box .png0000644000175000017500000000047014174170620021332 0ustar fengfengPNG  IHDRa pHYs  ~IDAT8 0E?Q7*Mp. &#xIIw墾V ȣ4 :%'^jH%E_}hpdI$]fy>O <^]J4t~ȔSok|lƀ&;[.f›3+/Uºp.H_z*az@ % 0[Ndg)7a䨋sIENDB`ukui-notebook/src/image/1x/mini_light.png0000644000175000017500000000022114174170620017320 0ustar fengfengPNG  IHDR;0 pHYs  ~CIDATHչ Q #ulyBEUXXXXXxrm@tOcaaaa``}e70sIENDB`ukui-notebook/src/image/1x/adjustment.png0000644000175000017500000000037014174170620017360 0ustar fengfengPNG  IHDRa pHYs  ~IDAT8R 0 2B #tL $W#-N.Zq\^M/SwC|}1(XMkbIE;,Wf$8c2o Iv12yrLɇX刹>FǒPh37;I IENDB`ukui-notebook/src/image/1x/new-hover.png0000644000175000017500000000050114174170620017110 0ustar fengfengPNG  IHDR pHYs  ~IDAT8 @?/<ۀh`44 X e1MBffM(X+.@O΁U Ev t:/ŹdX8>ݎo,.v~FLhBF 1UX3>p$T)*=V>T(F*\2ka?Gݺs{ltюG4F־N"IENDB`ukui-notebook/src/image/1x/mini3.png0000644000175000017500000000034714174170620016225 0ustar fengfengPNG  IHDR;0 pHYs  ~IDATHc?q  ή0h~ dz[>7DR0xQG-zp}I6js(@b-&MգZ\ˇZIqk%URVM5Q)xA5t{nΝ/26yqϭr9g|sg<\j,y:JIENDB`ukui-notebook/src/image/1x/select.png0000644000175000017500000000031214174170620016455 0ustar fengfengPNG  IHDRa pHYs  ~|IDAT8c?%"݃RO```8PP\w$/ iӌb@o$IDhN@CvI Ռb@qa!4FBB2 fk3^H )Sf<îIENDB`ukui-notebook/src/image/1x/note_color.png0000644000175000017500000000062414174170620017347 0ustar fengfengPNG  IHDRa pHYs  ~FIDAT8S m0} V-B j䏠cA CEϙIVwλyZQg~_Κ>įE Pb s ."ʜ5@ apkA CIUWՔ aF` [ ur*C!tE$M$Xi{ԁ49tҗ%bM"x_"_`)'/}^6ܗ1S76DZjL N SgAH)lbgH<*{w'EZYjdYuwB>zǤ \#V(ByLD;P's4ʅgF}IENDB`ukui-notebook/src/image/1x/mini_block.png0000644000175000017500000000022314174170620017305 0ustar fengfengPNG  IHDR;0 pHYs  ~EIDATHձ BQ98۸nb9^IVEZ |K#bIڶ=S{10000_ 7ۤjIENDB`ukui-notebook/src/editPage.ui0000644000175000017500000002646214201136534015152 0ustar fengfeng Edit_page 0 0 300 280 300 280 300 280 Form 4 0 0 0 8 10 12 1 10 14 300 34 254 34 227 3 32 30 0 0 32 30 32 30 11 Qt::NoFocus 14 80 5 24 24 24 24 24 24 true 56 5 24 24 24 24 24 24 true 133 5 24 24 24 24 24 24 Qt::ClickFocus true false false 32 5 24 24 24 24 24 24 true 109 5 24 24 24 24 24 24 Qt::ClickFocus true false 105 5 1 25 1 25 QFrame::StyledPanel QFrame::Raised 268 10 16 16 0 0 16 16 8 5 24 24 24 24 24 24 260 3 32 30 32 30 32 30 259 5 1 25 1 25 QFrame::StyledPanel QFrame::Raised 157 5 24 24 24 24 24 24 fontSizeBtn strikeOutBtn underlineBtn orderedBtn italicBtn unorderedBtn frame boldBtn styleBtn fontColorBtn frame_2 insertBtn ukui-notebook/src/noteHead.ui0000644000175000017500000000057414174170620015156 0ustar fengfeng noteHead 0 0 250 16 Form ukui-notebook/src/env.pri0000644000175000017500000000007714174170620014372 0ustar fengfengPROJECT_ROOTDIR = $$PWD PROJECT_COMPONENTSOURCE = $$PWD/common ukui-notebook/src/singleitemButton.cpp0000644000175000017500000000411314174170620017121 0ustar fengfeng/* * Copyright (C) 2020 Tianjin KYLIN Information Technology Co., Ltd. * * This program is free software; you can 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, 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 setFixedSize(34,34); this->setIconSize(QSize(16,16)); pushdelIcon.addFile(":/new/prefix1/SVG/delete-b.svg"); this->setIcon(pushdelIcon); } singleitemButton::~singleitemButton() { } void singleitemButton::enterEvent(QEvent *event) { Q_UNUSED(event); QIcon pushdelIcon; this->setFixedSize(34,34); this->setIconSize(QSize(16,16)); pushdelIcon.addFile(":/new/prefix1/SVG/delete-b-hover.svg"); this->setIcon(pushdelIcon); } void singleitemButton::mousePressEvent(QMouseEvent *event) { Q_UNUSED(event); QIcon pushdelIcon; this->setFixedSize(34,34); this->setIconSize(QSize(16,16)); pushdelIcon.addFile(":/new/prefix1/SVG/delete-b-click.svg"); this->setIcon(pushdelIcon); } void singleitemButton::mouseReleaseEvent(QMouseEvent *event) { Q_UNUSED(event); QIcon pushdelIcon; this->setFixedSize(34,34); this->setIconSize(QSize(16,16)); pushdelIcon.addFile(":/new/prefix1/SVG/delete-b-hover.svg"); this->setIcon(pushdelIcon); emit buttonclick(); } void singleitemButton::leaveEvent(QEvent *event) { Q_UNUSED(event); QIcon pushdelIcon; this->setFixedSize(34,34); this->setIconSize(QSize(16,16)); pushdelIcon.addFile(":/new/prefix1/SVG/delete-b.svg"); this->setIcon(pushdelIcon); } ukui-notebook/src/notebook.json0000644000175000017500000000002514174170620015572 0ustar fengfeng{ "Keys" : [ ] } ukui-notebook/src/setFontColorPage.ui0000644000175000017500000000230014201136534016627 0ustar fengfeng SetFontColor 0 0 175 30 175 30 175 30 Form 0 0 175 30 175 30 175 30 QListView::LeftToRight ukui-notebook/src/paletteButton.cpp0000644000175000017500000000164714174170620016430 0ustar fengfeng/* * Copyright (C) 2020 Tianjin KYLIN Information Technology Co., Ltd. * * This program is free software; you can 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, 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 setupUi(this); } paletteButton::~paletteButton() { delete ui; } ukui-notebook/src/about.ui0000755000175000017500000001571214174170620014544 0ustar fengfeng About 0 0 420 440 420 440 420 440 Dialog 0 0 0 0 0 8 4 4 8 24 24 24 24 Qt::Horizontal 40 20 30 30 30 30 16 38 0 96 96 96 96 0 0 0 36 16777215 36 Qt::AlignCenter 0 36 16777215 36 Qt::AlignCenter 0 32 356 0 356 16777215 Qt::Vertical 20 40 0 36 16777215 36 Qt::Vertical 20 40 ukui-notebook/src/singleApplication.h0000644000175000017500000000314214174170620016700 0ustar fengfeng/* * Copyright (C) 2020 Tianjin KYLIN Information Technology Co., Ltd. * * This program is free software; you can 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, 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 #include #include #include "widget.h" class SingleApplication : public QApplication { Q_OBJECT public: SingleApplication(int &argc, char **argv); bool isRunning(); // 是否已經有实例在运行 Widget *w; // Widget指针 signals: void messageReceived(/*const QString &message*/); private slots: void _newLocalConnection(); // 有新连接时触发 private: void _initLocalConnection(); // 初始化本地连接 void _newLocalServer(); // 创建服务端 void _activateWindow(); // 激活窗口 bool _isRunning; // 是否已經有实例在运行 QLocalServer *_localServer; // 本地socket Server QString _serverName; // 服务名称 }; #endif // SINGLEAPPLICATION_H ukui-notebook/src/dbManager.h0000644000175000017500000000406314174170620015116 0ustar fengfeng/* * Copyright (C) 2020 Tianjin KYLIN Information Technology Co., Ltd. * * This program is free software; you can 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, 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 #include #include "noteData.h" class DBManager : public QObject { Q_OBJECT public: explicit DBManager(QObject *parent = Q_NULLPTR); private: void open(const QString& path, bool doCreate = false); void createTables(); int getLastRowID(); bool forceLastRowIndexValue(const int indexValue); NoteData* getNote(QString id); bool isNoteExist(NoteData* note); QList getAllNotes(); bool addNote(NoteData* note); bool removeNote(NoteData* note); bool updateNote(NoteData* note); bool migrateNote(NoteData* note); bool migrateTrash(NoteData* note); signals: void notesReceived(QList noteList, int noteCounter); public slots: bool permanantlyRemoveAllNotes(); void onNotesListRequested(); void onOpenDBManagerRequested(QString path, bool doCreate); void onCreateUpdateRequested(NoteData* note); void onDeleteNoteRequested(NoteData* note); void onImportNotesRequested(QList noteList); void onRestoreNotesRequested(QList noteList); void onExportNotesRequested(QString fileName); void onMigrateNotesRequested(QList noteList); void onMigrateTrashRequested(QList noteList); void onForceLastRowIndexValueRequested(int index); }; #endif // DBMANAGER_H ukui-notebook/src/CloseButton/0000755000175000017500000000000014201140431015307 5ustar fengfengukui-notebook/src/CloseButton/closebutton.h0000644000175000017500000000410314201140431020017 0ustar fengfeng/* * Copyright (C) 2020, KylinSoft Co., Ltd. * * This program is free software: you can 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 . */ #ifndef CLOSEBUTTON_H #define CLOSEBUTTON_H #include #include #include #include #include #include #include class CloseButton : public QLabel { Q_OBJECT public: explicit CloseButton(QWidget *parent = nullptr,const QString &filePath = "",const QString &hoverPath = ""); //Render icon from theme const QPixmap renderSvg(const QIcon &icon, QString color); // change svg picture's color QPixmap drawSymbolicColoredPixmap(const QPixmap &source, QString color); void setIcon(const QIcon &icon); void setIconSize(int size); void setBkg(const QColor &color); void setHoverIn(const QString &hoverIn); void setHoverOut(const QString &hoverOut); ~CloseButton(); protected: void enterEvent(QEvent *event); void leaveEvent(QEvent *event); void mousePressEvent(QMouseEvent *event); void mouseReleaseEvent(QMouseEvent *event); void paintEvent(QPaintEvent *event); private: QIcon *m_icon; QIcon *m_customIcon; QIcon *m_hoverIcon; bool m_bIsChecked; bool m_bIsPressed; QColor m_colorBkg; int m_cSize; bool m_settedBkg; QColor m_customBkg; QString m_szHoverOut; QString m_szHoverIn; QGSettings *m_qtThemeSetting; QGSettings *m_gtkThemeSetting; Q_SIGNALS: void clicked(bool checked = true); }; #endif // CLOSEBUTTON_H ukui-notebook/src/CloseButton/closebutton.cpp0000644000175000017500000002155414201140431020363 0ustar fengfeng/* * Copyright (C) 2020, KylinSoft Co., Ltd. * * This program is free software: you can 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 . */ /* CloseButton by David Peng * 2020 10.20 * Version Beta 1.0 * 介绍:该控件是用于对话框的关闭按钮,只需指定父对象即可可自动回收。 * 使用方法: * 1、new CloseButton(this); //这样会直接调用主题的关闭按钮。 * 2、new CloseButton(黑色图标路径,this); //这样会用一个黑色的'X'图标SVG,hover时会渲染成白色。 * 3、new CloseButton(黑色图标路径,白色图标路径,this) //这样会用两张图片来实现图标显示。 */ #include "closebutton.h" #include #include #define THEME_QT_SCHEMA "org.ukui.style" #define THEME_GTK_SCHEMA "org.mate.interface" CloseButton::CloseButton(QWidget *parent, const QString &filePath, const QString &hoverPath) : QLabel(parent) { //Allocation if(filePath != "" && filePath != "window-close-symbolic") m_icon = new QIcon(filePath); else if(filePath == "window-close-symbolic"){ QIcon icon = QIcon::fromTheme("window-close-symbolic"); m_icon = new QIcon(icon); } else { m_icon = nullptr; } if(hoverPath != "") m_hoverIcon = new QIcon(hoverPath); else m_hoverIcon = nullptr; //Properties //setProperty("useIconHighlightEffect", true); //setProperty("iconHighlightEffectMode", 1); setFocusPolicy(Qt::NoFocus); //Initial componentss m_bIsChecked = false; m_bIsPressed = false; m_settedBkg = false; m_szHoverIn = "white"; m_szHoverOut = "default"; m_cSize = 16; m_colorBkg = palette().color(QPalette::Base); setAlignment(Qt::AlignCenter); if(m_icon != nullptr) { setPixmap(renderSvg(*m_icon,m_szHoverOut)); } if(QGSettings::isSchemaInstalled(THEME_GTK_SCHEMA) && QGSettings::isSchemaInstalled(THEME_QT_SCHEMA)) { QByteArray qtThemeID(THEME_QT_SCHEMA); QByteArray gtkThemeID(THEME_GTK_SCHEMA); m_gtkThemeSetting = new QGSettings(gtkThemeID,QByteArray(),this); m_qtThemeSetting = new QGSettings(qtThemeID,QByteArray(),this); QString style = m_qtThemeSetting->get("styleName").toString(); if(style == "ukui-dark") { m_szHoverOut = "white"; } else { m_szHoverOut = "default"; } connect(m_qtThemeSetting,&QGSettings::changed, [this] (const QString &key) { QString style = m_qtThemeSetting->get("styleName").toString(); if(key == "styleName") { if(style == "ukui-dark") { m_szHoverOut = "white"; } else { m_szHoverOut = "default"; } } }); } } const QPixmap CloseButton::renderSvg(const QIcon &icon, QString cgColor) { int size = m_cSize; const auto ratio = qApp->devicePixelRatio(); if ( 2 == ratio) { size = 48; } else if (3 == ratio) { size = 96; } QPixmap iconPixmap = icon.pixmap(size,size); iconPixmap.setDevicePixelRatio(ratio); QImage img = iconPixmap.toImage(); for (int x = 0; x < img.width(); x++) { for (int y = 0; y < img.height(); y++) { auto color = img.pixelColor(x, y); if (color.alpha() > 0) { if ("white" == cgColor) { color.setRed(255); color.setGreen(255); color.setBlue(255); img.setPixelColor(x, y, color); } else if ("black" == cgColor) { color.setRed(0); color.setGreen(0); color.setBlue(0); // color.setAlpha(0.1); color.setAlphaF(0.12); img.setPixelColor(x, y, color); } else if ("gray" == cgColor) { color.setRed(152); color.setGreen(163); color.setBlue(164); img.setPixelColor(x, y, color); } else if ("blue" == cgColor){ color.setRed(61); color.setGreen(107); color.setBlue(229); img.setPixelColor(x, y, color); } else { return iconPixmap; } } } } return QPixmap::fromImage(img); } QPixmap CloseButton::drawSymbolicColoredPixmap(const QPixmap &source, QString cgColor) { QImage img = source.toImage(); for (int x = 0; x < img.width(); x++) { for (int y = 0; y < img.height(); y++) { auto color = img.pixelColor(x, y); if (color.alpha() > 0) { if ("white" == cgColor) { color.setRed(255); color.setGreen(255); color.setBlue(255); img.setPixelColor(x, y, color); } else if ("black" == cgColor) { color.setRed(0); color.setGreen(0); color.setBlue(0); color.setAlphaF(0.9); img.setPixelColor(x, y, color); } else if ("gray" == cgColor) { color.setRed(152); color.setGreen(163); color.setBlue(164); img.setPixelColor(x, y, color); } else if ("blue" == cgColor){ color.setRed(61); color.setGreen(107); color.setBlue(229); img.setPixelColor(x, y, color); } else { return source; } } } } return QPixmap::fromImage(img); } void CloseButton::enterEvent(QEvent *event) { Q_UNUSED(event); if(m_hoverIcon == nullptr && m_icon != nullptr) setPixmap(renderSvg(*m_icon,m_szHoverIn)); else if(m_hoverIcon != nullptr && m_icon != nullptr) setPixmap(m_hoverIcon->pixmap(m_cSize,m_cSize)); else if(m_customIcon != nullptr) setPixmap(renderSvg(*m_customIcon,m_szHoverIn)); m_colorBkg = QColor("#FA6056"); } void CloseButton::mousePressEvent(QMouseEvent *event) { if(event->button() == Qt::LeftButton) { m_colorBkg = QColor("#E54A50"); m_bIsPressed = true; update(); } } void CloseButton::mouseReleaseEvent(QMouseEvent *event) { Q_UNUSED(event); if(m_bIsPressed && this->rect().contains(event->pos())) { m_bIsChecked = !m_bIsChecked; emit clicked(m_bIsChecked); m_bIsPressed = false; } } void CloseButton::leaveEvent(QEvent *event) { Q_UNUSED(event); m_colorBkg = m_customBkg.isValid() ? m_customBkg : palette().color(QPalette::Base); if(m_icon != nullptr) setPixmap(renderSvg(*m_icon,m_szHoverOut)); else if(m_customIcon != nullptr) setPixmap(renderSvg(*m_customIcon,m_szHoverOut)); } void CloseButton::paintEvent(QPaintEvent *event) { QPainter painter(this); painter.setRenderHint(QPainter::Antialiasing); // 反锯齿; painter.setPen(Qt::transparent); painter.setBrush(QBrush(m_colorBkg)); painter.drawRoundedRect(rect(), 4, 4); painter.end(); return QLabel::paintEvent(event); } void CloseButton::setIconSize(int size) { m_cSize = size; update(); } void CloseButton::setIcon(const QIcon &icon) { m_customIcon = new QIcon(icon); setPixmap(renderSvg(*m_customIcon,m_szHoverOut)); } void CloseButton::setBkg(const QColor &color) { m_settedBkg = true; m_customBkg = color; m_colorBkg = m_customBkg; if(m_icon != nullptr) { setPixmap(renderSvg(*m_icon,m_szHoverOut)); } else if(m_customIcon != nullptr) { setPixmap(renderSvg(*m_customIcon,m_szHoverOut)); } } void CloseButton::setHoverIn(const QString &hoverIn) { m_szHoverIn = hoverIn; update(); } void CloseButton::setHoverOut(const QString &hoverOut) { m_szHoverOut = hoverOut; if(m_icon != nullptr) { setPixmap(renderSvg(*m_icon,m_szHoverOut)); } else if(m_customIcon != nullptr) { setPixmap(renderSvg(*m_customIcon,m_szHoverOut)); } update(); } CloseButton::~CloseButton() { if(m_icon != nullptr) { delete m_icon; } if(m_hoverIcon != nullptr) delete m_hoverIcon; if(m_customIcon != nullptr) delete m_customIcon; } ukui-notebook/src/paletteWidget.h0000644000175000017500000000265314201136534016040 0ustar fengfeng/* * Copyright (C) 2020 Tianjin KYLIN Information Technology Co., Ltd. * * This program is free software; you can 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, 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 #include #include #include #include namespace Ui { class PaletteWidget; } class PaletteWidget : public QWidget { Q_OBJECT public: explicit PaletteWidget(QWidget *parent = nullptr); ~PaletteWidget(); Ui::PaletteWidget *ui; static QString BORDER_RADIUS_2PX; static QString KY_BLUE; static QString KY_PURPLE; static QString KY_PINK; static QString KY_RED; static QString KY_ORANGE; static QString KY_YELLOW; static QString KY_GREEN; static QString KY_GREY; protected: void paintEvent(QPaintEvent *event) override; private: void btnSetup(); }; #endif // PALETTEWIDGET_H ukui-notebook/src/paletteButton.h0000644000175000017500000000176514174170620016076 0ustar fengfeng/* * Copyright (C) 2020 Tianjin KYLIN Information Technology Co., Ltd. * * This program is free software; you can 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, 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 namespace Ui { class paletteButton; } class paletteButton : public QWidget { Q_OBJECT public: explicit paletteButton(QWidget *parent = nullptr); ~paletteButton(); Ui::paletteButton *ui; private: }; #endif // PALETTEBUTTON_H ukui-notebook/src/customStyle.cpp0000644000175000017500000004204014174170620016121 0ustar fengfeng/* * Copyright (C) 2020 Tianjin KYLIN Information Technology Co., Ltd. * * This program is free software; you can 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, 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 #include #include #include "customStyle.h" //#if QT_CONFIG(toolbutton) static void drawArrow(const QStyle *style, const QStyleOptionToolButton *toolbutton, const QRect &rect, QPainter *painter, const QWidget *widget = 0) { QStyle::PrimitiveElement pe; switch (toolbutton->arrowType) { case Qt::LeftArrow: pe = QStyle::PE_IndicatorArrowLeft; break; case Qt::RightArrow: pe = QStyle::PE_IndicatorArrowRight; break; case Qt::UpArrow: pe = QStyle::PE_IndicatorArrowUp; break; case Qt::DownArrow: pe = QStyle::PE_IndicatorArrowDown; break; default: return; } QStyleOption arrowOpt = *toolbutton; arrowOpt.rect = rect; style->drawPrimitive(pe, &arrowOpt, painter, widget); } //#endif // QT_CONFIG(toolbutton) CustomStyle::CustomStyle(const QString &proxyStyleName, QObject *parent) : QProxyStyle (proxyStyleName) { } CustomStyle::~CustomStyle() { } void CustomStyle::drawComBoxIndicator(SubControl which, const QStyleOptionComplex *option, QPainter *painter) const { PrimitiveElement arrow=PE_IndicatorArrowDown; QRect buttonRect=option->rect.adjusted(+0,+0,-1,-1); buttonRect.translate(buttonRect.width()/2,0); buttonRect.setWidth((buttonRect.width()+1)/2); QStyleOption buttonOpt(*option); painter->save(); painter->setClipRect(buttonRect,Qt::IntersectClip); if(!(option->activeSubControls&which)) buttonOpt.state&=~(State_MouseOver|State_On|State_Sunken); QStyleOption arrowOpt(buttonOpt); arrowOpt.rect=subControlRect(CC_ComboBox,option,which).adjusted(+0,+0,-0,+0); if(arrowOpt.rect.isValid()) proxy()->drawPrimitive(arrow,&arrowOpt,painter); painter->restore(); } void CustomStyle::drawComplexControl(QStyle::ComplexControl cc, const QStyleOptionComplex *option, QPainter *painter, const QWidget *widget) const { switch (cc) { case CC_ScrollBar: { if (const QStyleOptionSlider* slider = qstyleoption_cast(option)) { QStyleOptionSlider sr = *slider; sr.palette.setBrush(QPalette::WindowText,QColor("#778899")); return QProxyStyle::drawComplexControl(cc, &sr, painter, widget); } else { break; } } case CC_ComboBox: { if (const QStyleOptionComboBox* combobox = qstyleoption_cast(option)) { if (!(option->state & State_Enabled)) { painter->save(); painter->setPen(QColor("#cfcfcf")); painter->setBrush(Qt::white); painter->setRenderHint(QPainter::Antialiasing,true); painter->drawRoundedRect(option->rect,4,4); painter->restore(); return; } QRectF rect=subControlRect(CC_ComboBox,option,SC_ComboBoxFrame); painter->save(); painter->setPen(QColor("#cfcfcf")); //painter->setBrush(option->palette.color(QPalette::Button)); painter->setBrush(Qt::white); painter->setRenderHint(QPainter::Antialiasing,true); painter->drawRoundedRect(rect,4,4); painter->restore(); drawComBoxIndicator(SC_ComboBoxArrow,option,painter); if ((combobox->state & (State_Sunken | State_On))) if (combobox->state & State_MouseOver ) { painter->save(); painter->setBrush(Qt::NoBrush); painter->setPen(QColor("#3D6BE5")); painter->setRenderHint(QPainter::Antialiasing,true); // painter->setOpacity(opacity); painter->drawRoundedRect(rect,4,4); painter->restore(); return; } return; } } default: break; } return QProxyStyle::drawComplexControl(cc, option, painter, widget); } void CustomStyle::drawControl(QStyle::ControlElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget) const { switch(element){ case CE_ComboBoxLabel: { auto comboBoxOption = qstyleoption_cast(option); painter->save(); painter->setRenderHint(QPainter::Antialiasing,true); // painter->setPen(option->palette.color(QPalette::ButtonText)); painter->setPen(Qt::black); //选中颜色 // if (option->state & State_Selected) { // if (option->state & State_Sunken) { // painter->setPen(option->palette.color(QPalette::ButtonText)); // } else { // painter->setPen(option->palette.color(QPalette::ButtonText)); // } // } painter->drawText(option->rect.adjusted(+4,+0,+0,+0), comboBoxOption->currentText, QTextOption(Qt::AlignVCenter)); painter->restore(); return; } break; case CE_PushButton: { painter->save(); painter->setRenderHint(QPainter::TextAntialiasing,true); painter->setPen(Qt::yellow); painter->setBrush(Qt::red); if (option->state & State_MouseOver) { if (option->state & State_Sunken) { painter->setRenderHint(QPainter::Antialiasing,true); painter->setPen(Qt::NoPen); painter->setBrush(Qt::white); painter->drawRoundedRect(option->rect,6,6); } else { painter->setRenderHint(QPainter::Antialiasing,true); painter->setPen(Qt::black); painter->setBrush(Qt::red); painter->drawRoundedRect(option->rect.adjusted(2,2,-2,-2),6,6); } } painter->restore(); return; } default: return QProxyStyle::drawControl(element, option, painter, widget); } return QProxyStyle::drawControl(element, option, painter, widget); } void CustomStyle::drawItemPixmap(QPainter *painter, const QRect &rectangle, int alignment, const QPixmap &pixmap) const { return QProxyStyle::drawItemPixmap(painter, rectangle, alignment, pixmap); } void CustomStyle::drawItemText(QPainter *painter, const QRect &rectangle, int alignment, const QPalette &palette, bool enabled, const QString &text, QPalette::ColorRole textRole) const { return QProxyStyle::drawItemText(painter, rectangle, alignment, palette, enabled, text, textRole); } //绘制简单的颜色圆角等 void CustomStyle::drawPrimitive(QStyle::PrimitiveElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget) const { switch (element) { case PE_PanelButtonCommand: { painter->save(); painter->setRenderHint(QPainter::TextAntialiasing,true); painter->setPen(Qt::black); painter->setBrush(Qt::yellow); if (option->state & State_MouseOver) { if (option->state & State_Sunken) { painter->setRenderHint(QPainter::Antialiasing,true); painter->setPen(Qt::NoPen); painter->setBrush(Qt::white); painter->drawRoundedRect(option->rect,6,6); } else { painter->setRenderHint(QPainter::Antialiasing,true); painter->setPen(Qt::black); painter->setBrush(Qt::red); painter->drawRoundedRect(option->rect.adjusted(2,2,-2,-2),6,6); } } painter->restore(); return; } break; case PE_FrameLineEdit: { // Conflict with qspinbox and so on, The widget text cannot use this style if (widget) { if (widget->parentWidget()) if (widget->parentWidget()->inherits("QDoubleSpinBox") |widget->parentWidget()->inherits("QSpinBox") |widget->parentWidget()->inherits("QComboBox")) { return; } } painter->save(); if (const QStyleOptionFrame *panel = qstyleoption_cast(option)) { painter->setRenderHint(QPainter::Antialiasing,true); //Setpen is set to avoid a bug that collides with a white background painter->setPen(QColor("#CFCFCF")); // painter->setBrush(option->palette.color(QPalette::Base)); painter->setBrush(Qt::red); // if (panel->lineWidth > 0) // proxy()->drawPrimitive(PE_FrameLineEdit, panel, painter, widget); if (widget->isEnabled()) { if (option->state &State_MouseOver) { painter->setBrush(option->palette.button().color().lighter()); } if(option->state &State_HasFocus) { painter->setPen(QColor("#3D6BE5")); painter->setBrush(option->palette.color(QPalette::Base)); } } painter->drawRoundedRect(panel->rect,4,4); } painter->restore(); return; } break; case PE_PanelLineEdit: { painter->save(); if (const QStyleOptionFrame *panel = qstyleoption_cast(option)) { painter->setRenderHint(QPainter::Antialiasing,true); //Setpen is set to avoid a bug that collides with a white background painter->setPen(QColor("#CFCFCF")); painter->setBrush(Qt::white); QPalette *palete=new QPalette(); palete->setBrush(QPalette::Text, Qt::black); // if (panel->lineWidth > 0) // proxy()->drawPrimitive(PE_FrameLineEdit, panel, painter, widget); if (widget->isEnabled()) { if (option->state &State_MouseOver) { // painter->setBrush(option->palette.button().color().lighter()); painter->setBrush(Qt::white); } if(option->state &State_HasFocus) { painter->setPen(QColor("#3D6BE5")); // painter->setBrush(option->palette.color(QPalette::Base)); painter->setBrush(Qt::white); } } painter->drawRoundedRect(panel->rect,4,4); } painter->restore(); return; } break; case PE_IndicatorArrowDown: case PE_IndicatorArrowUp: case PE_IndicatorArrowLeft: case PE_IndicatorArrowRight: { painter->save(); painter->setRenderHint(QPainter::Antialiasing,true); painter->setBrush(Qt::NoBrush); if(option->state & State_Enabled){ painter->setPen(QPen(Qt::black, 1.2)); if (option->state & State_MouseOver) { painter->setPen(QPen(Qt::black, 1.2)); } } else { painter->setPen(QPen(option->palette.color(QPalette::Text), 1.1)); } QPolygon points(4); int x = option->rect.x(); int y = option->rect.y(); //If the height is too high, the arrow will be very ugly. If the height is too small, the arrow will not be painted // int w = option->rect.width() / 3; // int h = option->rect.height() / 4; int w = 8; int h = 4; x += (option->rect.width() - w) / 2; y += (option->rect.height() - h) / 2; //When the arrow is too small, you can not draw if (option->rect.width() - w < 1 || option->rect.height() - h < 1) { return; } else if (option->rect.width() - w <= 2 || option->rect.height() - h <= 2) { w = 5; h = 3; } if (element == PE_IndicatorArrowDown) { points[0] = QPoint(x-4, y); points[1] = QPoint(x-4 + w / 2, y + h); points[2] = QPoint(x-4 + w / 2, y + h); points[3] = QPoint(x-4 + w, y); } else if (element == PE_IndicatorArrowUp) { points[0] = QPoint(x, y + h); points[1] = QPoint(x + w / 2, y); points[2] = QPoint(x + w / 2, y); points[3] = QPoint(x + w, y + h); } else if (element == PE_IndicatorArrowLeft) { points[0] = QPoint(x + h , y); points[1] = QPoint(x, y+w/2); points[2] = QPoint(x, y+w/2); points[3] = QPoint(x + w , y + w); } else if (element == PE_IndicatorArrowRight) { points[0] = QPoint(x , y); points[1] = QPoint(x+h, y+w/2); points[2] = QPoint(x+h , y+w/2); points[3] = QPoint(x, y+w); } painter->drawLine(points[0], points[1] ); painter->drawLine(points[2], points[3] ); painter->restore(); return; } default: return QProxyStyle::drawPrimitive(element, option, painter, widget); } return QProxyStyle::drawPrimitive(element, option, painter, widget); } QPixmap CustomStyle::generatedIconPixmap(QIcon::Mode iconMode, const QPixmap &pixmap, const QStyleOption *option) const { return QProxyStyle::generatedIconPixmap(iconMode, pixmap, option); } QStyle::SubControl CustomStyle::hitTestComplexControl(QStyle::ComplexControl control, const QStyleOptionComplex *option, const QPoint &position, const QWidget *widget) const { return QProxyStyle::hitTestComplexControl(control, option, position, widget); } QRect CustomStyle::itemPixmapRect(const QRect &rectangle, int alignment, const QPixmap &pixmap) const { return QProxyStyle::itemPixmapRect(rectangle, alignment, pixmap); } QRect CustomStyle::itemTextRect(const QFontMetrics &metrics, const QRect &rectangle, int alignment, bool enabled, const QString &text) const { return QProxyStyle::itemTextRect(metrics, rectangle, alignment, enabled, text); } int CustomStyle::pixelMetric(QStyle::PixelMetric metric, const QStyleOption *option, const QWidget *widget) const { switch (metric){ case PM_ToolBarIconSize:{ return (int)48*qApp->devicePixelRatio(); } default: break; } return QProxyStyle::pixelMetric(metric, option, widget); } void CustomStyle::polish(QWidget *widget) { widget->setAttribute(Qt::WA_Hover); auto palette = widget->palette(); polish(palette); widget->setPalette(palette); return QProxyStyle::polish(widget); } void CustomStyle::polish(QApplication *application) { return QProxyStyle::polish(application); } void CustomStyle::polish(QPalette &palette) { palette.setBrush(QPalette::Text, Qt::black); palette.setBrush(QPalette::Base, Qt::white); } void CustomStyle::unpolish(QWidget *widget) { return QProxyStyle::unpolish(widget); } void CustomStyle::unpolish(QApplication *application) { return QProxyStyle::unpolish(application); } QSize CustomStyle::sizeFromContents(QStyle::ContentsType type, const QStyleOption *option, const QSize &contentsSize, const QWidget *widget) const { return QProxyStyle::sizeFromContents(type, option, contentsSize, widget); } QIcon CustomStyle::standardIcon(QStyle::StandardPixmap standardIcon, const QStyleOption *option, const QWidget *widget) const { return QProxyStyle::standardIcon(standardIcon, option, widget); } QPalette CustomStyle::standardPalette() const { return QProxyStyle::standardPalette(); } //如果需要背景透明也许需要用到这个函数 int CustomStyle::styleHint(QStyle::StyleHint hint, const QStyleOption *option, const QWidget *widget, QStyleHintReturn *returnData) const { switch (hint) { /// 让ScrollView viewport的绘制区域包含scrollbar和corner widget /// 这个例子中没有什么作用,如果我们需要绘制一个背景透明的滚动条 /// 这个style hint对我们的意义应该很大,因为我们希望视图能够帮助 /// 我们填充滚动条的背景区域,否则当背景透明时底下会出现明显的分割 case SH_ScrollView_FrameOnlyAroundContents: { return false; } default: break; } return QProxyStyle::styleHint(hint, option, widget, returnData); } QRect CustomStyle::subControlRect(QStyle::ComplexControl control, const QStyleOptionComplex *option, QStyle::SubControl subControl, const QWidget *widget) const { return QProxyStyle::subControlRect(control, option, subControl, widget); } QRect CustomStyle::subElementRect(QStyle::SubElement element, const QStyleOption *option, const QWidget *widget) const { return QProxyStyle::subElementRect(element, option, widget); } ukui-notebook/src/fontButton.cpp0000644000175000017500000000170114174170620015727 0ustar fengfeng/* * Copyright (C) 2020 Tianjin KYLIN Information Technology Co., Ltd. * * This program is free software; you can 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, 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 setupUi(this); ui->label->setAlignment(Qt::AlignHCenter); } fontButton::~fontButton() { delete ui; } ukui-notebook/src/noteHead.cpp0000644000175000017500000000237214201136534015316 0ustar fengfeng/* * Copyright (C) 2020 Tianjin KYLIN Information Technology Co., Ltd. * * This program is free software; you can 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, 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 #include "noteHead.h" #include "ui_noteHead.h" noteHead::noteHead(QWidget *parent) : QWidget(parent) , colorWidget(15,161,90) , ui(new Ui::noteHead) { ui->setupUi(this); setMinimumSize(250, 8); } noteHead::~noteHead() { delete ui; } void noteHead::paintEvent(QPaintEvent *event) { Q_UNUSED(event); QPainter p(this); p.setRenderHint(QPainter::Antialiasing); // 反锯齿; QPainterPath rectPath; rectPath.addRect(this->rect()); p.fillPath(rectPath,QBrush(colorWidget)); QWidget::paintEvent(event); } ukui-notebook/src/widget.cpp0000644000175000017500000017572414201136534015066 0ustar fengfeng/* * Copyright (C) 2020 Tianjin KYLIN Information Technology Co., Ltd. * * This program is free software; you can 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, 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 load(QLocale(), "ukui-notebook", "_", QLatin1String("/usr/share/ukui-notebook"))) qDebug() << "Load translations file" <load(QLocale(), "qt", "_", qtTranslationsPath)) qDebug() << "Load translations file" <setupUi(this); m_noteView = static_cast(ui->listView); setupDatabases(); listenToGsettings(); kyNoteInit(); kyNoteConn(); initData(); } /*! * \brief Widget::~Widget * Deconstructor of the class */ Widget::~Widget() { for (auto it = m_editors.begin(); it != m_editors.end(); it++) { (*it)->close(); delete *it; } m_editors.clear(); if(ui!=nullptr){ delete ui; ui = nullptr; } if(m_dbManager!=nullptr) { delete m_dbManager; m_dbManager = nullptr; } if(m_dbThread!=nullptr) { m_dbThread->quit(); m_dbThread->wait(); delete m_dbThread; m_dbThread = nullptr; } } /*! * \brief Widget::initData * Init the data from database and select the first note if there is one * 初始化数据库中的数据并选中第一个便签(如果有) */ void Widget::initData() { qDebug() << "kyNote initData"; QFileInfo fi(m_settingsDatabase->fileName()); QDir dir(fi.absolutePath()); QString oldNoteDBPath(dir.path() + QStringLiteral("/Notes.ini")); QString oldTrashDBPath(dir.path() + QStringLiteral("/Trash.ini")); bool exist = (QFile::exists(oldNoteDBPath) || QFile::exists(oldTrashDBPath)); if (exist) { QProgressDialog *pd = new QProgressDialog(QStringLiteral( "Migrating database, please wait."), QString(), 0, 0, this); pd->setCancelButton(Q_NULLPTR); pd->setWindowFlags(Qt::Window | Qt::FramelessWindowHint); pd->setMinimumDuration(0); pd->show(); // setButtonsAndFieldsEnabled(false); QFutureWatcher *watcher = new QFutureWatcher(this); connect(watcher, &QFutureWatcher::finished, this, [&, pd](){ pd->deleteLater(); // setButtonsAndFieldsEnabled(true); emit requestNotesList(); }); QFuture migration = QtConcurrent::run(this, &Widget::checkMigration); watcher->setFuture(migration); } else { emit requestNotesList(); } iniNoteModeRead(); } /*! * \brief Widget::setupListModeModel * */ void Widget::setupListModeModel() { m_proxyModel->setSourceModel(m_noteModel); // 代理真正的数据模型,对数据进行排序和过滤 m_proxyModel->setFilterKeyColumn(0); // 此属性保存用于读取源模型内容的键的列,listview只有一列所以是0 m_proxyModel->setFilterRole(NoteModel::NoteMdContent);// 此属性保留项目角色,该角色用于在过滤项目时查询源模型的数据 m_proxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive);// m_plistDelegate = new listViewModeDelegate(m_noteView); m_noteView->setItemDelegate(m_plistDelegate); // 安装定制delegate提供编辑功能 m_noteView->setModel(m_proxyModel); // 设置view的model是proxyModel,proxyModel作为view和QAbstractListModel的桥梁 } /*! * \brief Widget::setupIconModeModel * */ void Widget::setupIconModeModel() { m_proxyModel->setSourceModel(m_noteModel); // 代理真正的数据模型,对数据进行排序和过滤 m_proxyModel->setFilterKeyColumn(0); // 此属性保存用于读取源模型内容的键的列,listview只有一列所以是0 m_proxyModel->setFilterRole(NoteModel::NoteMdContent);// 此属性保留项目角色,该角色用于在过滤项目时查询源模型的数据 m_proxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive);// m_noteView->setItemDelegate(new iconViewModeDelegate(m_noteView)); // 安装定制delegate提供编辑功能 m_noteView->setModel(m_proxyModel); // 设置view的model是proxyModel,proxyModel作为view和QAbstractListModel的桥 } /*! * \brief Widget::initializeSettingsDatabase * */ void Widget::initializeSettingsDatabase() { if (m_settingsDatabase->value(QStringLiteral("version"), "NULL") == "NULL") m_settingsDatabase->setValue(QStringLiteral("version"), qApp->applicationVersion()); if (m_settingsDatabase->value(QStringLiteral("windowGeometry"), "NULL") == "NULL") { int initWidth = 704; int initHeight = 590; QPoint center = qApp->desktop()->geometry().center(); QRect rect(center.x() - initWidth/2, center.y() - initHeight/2, initWidth, initHeight); setGeometry(rect); // 设置窗口居中 m_settingsDatabase->setValue(QStringLiteral("windowGeometry"), saveGeometry()); // 保存窗口的几何形状 } } /*! * \brief Widget::setupDatabases * */ void Widget::setupDatabases() { // QSettings::IniFormat 将设置存储在INI文件中。从INI文件读取设置时不会保留类型信息。所有值将作为QString返回 // QSettings::UserScope 将设置存储在特定于当前用户的位置 m_settingsDatabase = new QSettings(QSettings::IniFormat, QSettings::UserScope, QStringLiteral("kylin-note"), QStringLiteral( "Settings"), this); m_settingsDatabase->setFallbacksEnabled(false); // 禁用回退 initializeSettingsDatabase(); bool doCreate = false; QFileInfo fi(m_settingsDatabase->fileName()); QDir dir(fi.absolutePath()); bool folderCreated = dir.mkpath(QStringLiteral(".")); if (!folderCreated) qFatal("ERROR: Can't create settings folder : %s", dir.absolutePath().toStdString().c_str()); QString noteDBFilePath(dir.path() + QDir::separator() + QStringLiteral("kyNotes.db")); if (!QFile::exists(noteDBFilePath)) { QFile noteDBFile(noteDBFilePath); if (!noteDBFile.open(QIODevice::WriteOnly)) qFatal("ERROR : Can't create database file"); noteDBFile.close(); doCreate = true; } m_dbManager = new DBManager; m_dbThread = new QThread; m_dbThread->setObjectName(QStringLiteral("dbThread")); m_dbManager->moveToThread(m_dbThread); connect(m_dbThread, &QThread::started, [=](){ emit requestOpenDBManager(noteDBFilePath, doCreate); }); connect(this, &Widget::requestOpenDBManager, m_dbManager, &DBManager::onOpenDBManagerRequested); connect(m_dbThread, &QThread::finished, m_dbManager, &QObject::deleteLater); m_dbThread->start(); } /*! * \brief Widget::error_throw * */ void Widget::error_throw() { try{ MY_THROW(ExceptionDerived, "error throw"); } catch (ExceptionDerived &e) { std::cout << e.what() << std::endl; } } /*! * \brief Widget::kyNoteInit * */ void Widget::kyNoteInit() { qDebug() << "\033[32m" << "kyNote init"; sortflag = 1; // 排序 m_listflag = 1; // 平铺\列表 m_searchLine = ui->SearchLine; m_newKynote = ui->newKynote; m_trashButton = ui->trashButton; m_viewChangeButton = ui->viewChangeButton; initListMode(); setFixedSize(714, 590); setMouseTracking(true); // 设置鼠标追踪 // 窗口属性 // setWindowFlags(Qt::FramelessWindowHint); //开启窗口无边框 // setAttribute(Qt::WA_TranslucentBackground); //设置窗口透明显示(毛玻璃效果) // QPainterPath blurPath; // blurPath.addRoundedRect(rect().adjusted(0, 0, -0, -0), 6, 6); // setProperty("useSystemStyleBlur", true); // setProperty("blurRegion", QRegion(blurPath.toFillPolygon().toPolygon()));//使用QPainterPath的api生成多边形Region // 弹出位置 m_pSreenInfo = new adaptScreenInfo(this); move((m_pSreenInfo->m_screenWidth - this->width() + m_pSreenInfo->m_nScreen_x)/2, (m_pSreenInfo->m_screenHeight - this->height())/2); // 标题 this->setWindowTitle(tr("Notes")); // 任务栏图标 //setWindowIcon(QIcon::fromTheme("kylin-notebook")); ui->iconLabel->setPixmap(QIcon::fromTheme("kylin-notebook").pixmap(24, 24)); ui->titleLabel->setText(tr("Notes")); // 钮 btnInit(); // 搜索 searchInit(); // QBitmap bmp(this->size()); // bmp.fill(); // QPainter p(&bmp); // p.setPen(Qt::NoPen); // p.setBrush(Qt::black); // p.setRenderHint(QPainter::Antialiasing); // p.drawRoundedRect(bmp.rect(),6,6); // setMask(bmp); // 退出框 m_noteExitWindow = new noteExitWindow(this, this); //清除便签页弹框 m_emptyNotes = new emptyNotes(this); } /*! * \brief Widget::kyNoteConn * */ void Widget::kyNoteConn() { qDebug() << "init connect slot"; // 主界面退出按钮 connect(ui->pushButton_Exit, SIGNAL(clicked()), this, SLOT(exitSlot())); // 主界面最小化按钮 connect(ui->pushButton_Mini, SIGNAL(clicked()), this, SLOT(miniSlot())); // 新建按钮 connect(m_newKynote, &QPushButton::clicked, this, &Widget::newSlot); // 除按钮 connect(m_trashButton, &QPushButton::clicked, this, &Widget::onTrashButtonClicked); // connect(m_noteModel, &NoteModel::rowsAboutToBeMoved, m_noteView, &NoteView::rowsAboutToBeMoved); // connect(m_noteModel, &NoteModel::rowsMoved, m_noteView, &NoteView::rowsMoved); // 升/降序按钮 // connect(m_sortLabel,&QPushButton::clicked,this,&Widget::sortSlot); connect(this, &Widget::switchSortTypeRequest, this, &Widget::sortSlot); // 清空便签 connect(m_menuActionEmpty, &QAction::triggered, this, &Widget::trashSlot); connect(m_emptyNotes, &emptyNotes::requestEmptyNotes, this, &Widget::clearNoteSlot); // 菜单按钮退出便签本 connect(m_menuExit, &QAction::triggered, this, &Widget::exitSlot); // 设置界面 // connect(m_menuActionSet,&QAction::triggered,this,&Widget::SetNoteSlot); // 列表平铺切换 connect(m_viewChangeButton, &QPushButton::clicked, this, &Widget::changePageSlot); // 搜索栏文本输入 connect(m_searchLine, &QLineEdit::textChanged, this, &Widget::onSearchEditTextChanged); // 退出弹窗 connect(m_noteExitWindow, ¬eExitWindow::requestSetNoteNull, this, &Widget::setNoteNullSlot); // listview单击事件 connect(m_noteView, &NoteView::pressed, this, &Widget::listClickSlot); // listview双击事件 connect(m_noteView, &NoteView::doubleClicked, this, &Widget::listDoubleClickSlot); connect(m_noteView, &NoteView::viewportPressed, this, [this](){ if (m_noteModel->rowCount() > 0) { QModelIndex index = m_noteView->currentIndex(); if(index!=m_currentSelectedNoteProxy) { m_currentSelectedNoteProxy = index; m_noteView->selectionModel()->select(m_currentSelectedNoteProxy, QItemSelectionModel::ClearAndSelect); m_noteView->setCurrentIndex(m_currentSelectedNoteProxy); m_noteView->scrollTo(m_currentSelectedNoteProxy); } } }); // auto save timer connect(m_autoSaveTimer, &QTimer::timeout, [this](){ m_autoSaveTimer->stop(); saveNoteToDB(m_currentSelectedNoteProxy); }); // 指定传递信号的方式Qt::BlockingQueuedConnection // 这种类型类似于QueuedConnection,但是它只能应用于跨线程操作即发送者和接收者处于不同的线程中的情况 // 并且信号发送者线程会阻塞等待接收者的槽函数执行结束 connect(this, &Widget::requestNotesList, m_dbManager, &DBManager::onNotesListRequested, Qt::BlockingQueuedConnection); connect(this, &Widget::requestCreateUpdateNote, m_dbManager, &DBManager::onCreateUpdateRequested, Qt::BlockingQueuedConnection); connect(this, &Widget::requestDeleteNote, m_dbManager, &DBManager::onDeleteNoteRequested); connect(this, &Widget::requestClearNote, m_dbManager, &DBManager::permanantlyRemoveAllNotes); // connect(this, &Widget::requestRestoreNotes, // m_dbManager, &DBManager::onRestoreNotesRequested, Qt::BlockingQueuedConnection); // connect(this, &Widget::requestImportNotes, // m_dbManager, &DBManager::onImportNotesRequested, Qt::BlockingQueuedConnection); // connect(this, &Widget::requestExportNotes, // m_dbManager, &DBManager::onExportNotesRequested, Qt::BlockingQueuedConnection); connect(this, &Widget::requestMigrateNotes, m_dbManager, &DBManager::onMigrateNotesRequested, Qt::BlockingQueuedConnection); connect(this, &Widget::requestMigrateTrash, m_dbManager, &DBManager::onMigrateTrashRequested, Qt::BlockingQueuedConnection); connect(this, &Widget::requestForceLastRowIndexValue, m_dbManager, &DBManager::onForceLastRowIndexValueRequested, Qt::BlockingQueuedConnection); connect(m_dbManager, &DBManager::notesReceived, this, &Widget::loadNotes); // 快捷键 new QShortcut(QKeySequence(Qt::Key_F1), this, SLOT(onF1ButtonClicked())); } /*! * \brief Widget::listenToGsettings * */ void Widget::listenToGsettings() { // 监听主题改变 const QByteArray id(THEME_QT_SCHEMA); if (QGSettings::isSchemaInstalled(id)) { QGSettings *styleSettings = new QGSettings(id, QByteArray(), this); m_currentTheme = styleSettings->get("styleName").toString(); if(m_currentTheme.compare("ukui-dark")==0 || m_currentTheme.compare("ukui-black")==0){ m_isThemeChanged = 1; } connect(styleSettings, &QGSettings::changed, this, [=](const QString &key){ auto style = styleSettings->get(key).toString(); if (key == "styleName") { m_currentTheme = styleSettings->get(MODE_QT_KEY).toString(); if (m_currentTheme == "ukui-default" || m_currentTheme == "ukui-white" || m_currentTheme == "ukui-light" || m_currentTheme == "ukui") { m_isThemeChanged = 0; m_searchAction->setIcon(QPixmap(":/image/1x/system-search-symbolic.svg")); //edit-find-symbolic //m_searchAction->setIcon(QIcon::fromTheme("edit-find-symbolic")); } else if (style == "ukui-dark" || m_currentTheme == "ukui-black") { m_isThemeChanged = 1; m_searchAction->setIcon(drawSymbolicColoredPixmap(QPixmap(":/image/1x/system-search-symbolic.svg"), m_searchAction)); //m_searchAction->setIcon(QIcon::fromTheme("edit-find-symbolic")); } } QTimer::singleShot(500, this, [=](){ QList wid = m_searchLine->findChildren(); for (int i = 0; i < wid.count(); i++) { wid.at(i)->setAttribute(Qt::WA_Hover, false); } }); if(key==STYLE_ICON_NAME || key==STYLE_ICON){ //主题框架不能更新 titleIcon ui->iconLabel->setPixmap(QIcon::fromTheme("kylin-notebook").pixmap(24,24)); } }); connect(styleSettings,&QGSettings::changed,this, [=] (const QString &key) { if(key == FONT_STYLE || key == FONT_SIZE) { //获取字号的值 QString fontStyle = styleSettings->get(FONT_STYLE).toString(); int fontSizeKey = styleSettings->get(FONT_SIZE).toString().toInt(); QFontDatabase db; //发送改变信号 if (db.families().contains(fontStyle)) { g_currentFont.setFamily(fontStyle); g_currentFont.setPointSize(fontSizeKey); } else { qDebug() << "获取字体失败!"; } } else {} }); QString fontStyle = styleSettings->get(FONT_STYLE).toString(); int fontSizeKey = styleSettings->get(FONT_SIZE).toString().toInt(); QFontDatabase db; //发送改变信号 if (db.families().contains(fontStyle)) { g_currentFont.setFamily(fontStyle); g_currentFont.setPointSize(fontSizeKey); } } // 监听控制面板字体变化 const QByteArray idd(PERSONALISE_SCHEMA); if (QGSettings::isSchemaInstalled(idd)) { QGSettings *opacitySettings = new QGSettings(idd, QByteArray(), this); connect(opacitySettings, &QGSettings::changed, this, [=](const QString &key){ if (key == "transparency") { QStringList keys = opacitySettings->keys(); if (keys.contains("transparency")) { m_transparency = opacitySettings->get("transparency").toDouble(); } } repaint(); }); m_transparency = opacitySettings->get("transparency").toDouble(); } // 用户手册 QString serviceName = "com.kylinUserGuide.hotel" + QString("%1%2").arg("_").arg(QString::number(getuid())); userGuideInterface = new QDBusInterface(serviceName, "/", "com.guide.hotel", QDBusConnection::sessionBus(), this); qDebug() << "connect to kylinUserGuide" << userGuideInterface->isValid(); if (!userGuideInterface->isValid()) { qDebug() << "fail to connect to kylinUserGuide"; qDebug() << qPrintable(QDBusConnection::sessionBus().lastError().message()); return; } // 监听时区变化 const QByteArray iddd(FORMAT_SCHEMA); if (QGSettings::isSchemaInstalled(iddd)) { QGSettings *m_formatsettings = new QGSettings(iddd, QByteArray(), this); connect(m_formatsettings, &QGSettings::changed, this, [=](const QString &key) { if (key == "hoursystem") { QString value = m_formatsettings->get(TIME_FORMAT_KEY).toString(); qDebug() << "hoursystem changed" << value; m_noteView->viewport()->update(); } }); } } /*! * \brief Widget::checkMigration * */ void Widget::checkMigration() { qDebug() << "当前函数 :" << __FUNCTION__ << "当前行号 :" << __LINE__; QFileInfo fi(m_settingsDatabase->fileName()); QDir dir(fi.absolutePath()); QString oldNoteDBPath(dir.path() + QDir::separator() + "Notes.ini"); if (QFile::exists(oldNoteDBPath)) migrateNote(oldNoteDBPath); QString oldTrashDBPath(dir.path() + QDir::separator() + "Trash.ini"); if (QFile::exists(oldTrashDBPath)) { // migrateTrash(oldTrashDBPath); emit requestForceLastRowIndexValue(m_noteCounter); } } /*! * \brief Widget::migrateNote * */ void Widget::migrateNote(QString notePath) { qDebug() << "当前函数 :" << __FUNCTION__ << "当前行号 :" << __LINE__; QSettings notesIni(notePath, QSettings::IniFormat); QStringList dbKeys = notesIni.allKeys(); m_noteCounter = notesIni.value(QStringLiteral("notesCounter"), "0").toInt(); QList noteList; auto it = dbKeys.begin(); for (; it < dbKeys.end() - 1; it += 3) { QString noteName = it->split(QStringLiteral("/"))[0]; int id = noteName.split(QStringLiteral("_"))[1].toInt(); // sync db index with biggest notes id m_noteCounter = m_noteCounter < id ? id : m_noteCounter; NoteData *newNote = new NoteData(this); newNote->setId(id); QString createdDateDB = notesIni.value(noteName + QStringLiteral("/dateCreated"), "Error").toString(); newNote->setCreationDateTime(QDateTime::fromString(createdDateDB, Qt::ISODate)); QString lastEditedDateDB = notesIni.value(noteName + QStringLiteral("/dateEdited"), "Error").toString(); newNote->setLastModificationDateTime(QDateTime::fromString(lastEditedDateDB, Qt::ISODate)); QString contentText = notesIni.value(noteName + QStringLiteral("/content"), "Error").toString(); newNote->setContent(contentText); QString firstLine = getFirstLine(contentText); newNote->setFullTitle(firstLine); noteList.append(newNote); } if (!noteList.isEmpty()) emit requestMigrateNotes(noteList); QFile oldNoteDBFile(notePath); oldNoteDBFile.rename(QFileInfo(notePath).dir().path() + QDir::separator() + QStringLiteral("oldNotes.ini")); } /*! * \brief Widget::openMemoWithId * */ void Widget::openMemoWithId(int noteId) { qDebug() << "openMemoWithId" << noteId; QTimer::singleShot(300, this, [=]() { m_notebook = new EditPage(this, noteId); m_editors.push_back(m_notebook); m_notebook->m_id = m_editors.size() - 1; for (int count = 0; count <= m_proxyModel->rowCount(); count++) { QModelIndex m_tmpIndex = m_proxyModel->index(count, 0); if (m_tmpIndex.data(NoteModel::NoteID).toInt() == noteId) { m_currentSelectedNoteProxy = m_proxyModel->mapToSource(m_tmpIndex); showNoteInEditor(m_currentSelectedNoteProxy); m_noteView->selectionModel()->select(m_currentSelectedNoteProxy, QItemSelectionModel::ClearAndSelect); m_noteView->setCurrentIndex(m_currentSelectedNoteProxy); m_noteView->scrollTo(m_currentSelectedNoteProxy); break; } } connect(m_notebook->m_noteHeadMenu, ¬eHeadMenu::requestNewNote, this, [=](){ newSlot(); }); connect(m_notebook->m_noteHeadMenu, ¬eHeadMenu::requestShowNote, this, [=] { // 添加窗管协议 MotifWmHints hints; hints.flags = MWM_HINTS_FUNCTIONS|MWM_HINTS_DECORATIONS; hints.functions = MWM_FUNC_ALL; hints.decorations = MWM_DECOR_BORDER; XAtomHelper::getInstance()->setWindowMotifHint(this->winId(), hints); this->raise(); this->activateWindow(); this->show(); }); connect(m_editors[m_editors.size() - 1], &EditPage::requestDel, this, [=](int noteId){ for (int count = 0; count <= m_proxyModel->rowCount(); count++) { QModelIndex m_tmpIndex = m_proxyModel->index(count, 0); if (m_tmpIndex.data(NoteModel::NoteID).toInt() == noteId) { QModelIndex sourceIndex = m_proxyModel->mapToSource(m_tmpIndex); deleteNote(m_tmpIndex, true); break; } } }); connect(m_editors[m_editors.size() - 1], SIGNAL(texthasChanged(int,int)), this, SLOT(onTextEditTextChanged(int,int))); connect(m_editors[m_editors.size() - 1], SIGNAL(colorhasChanged(QColor,int)), this, SLOT(onColorChanged(QColor,int))); // 设置鼠标焦点 m_notebook->ui->textEdit->setFocus(); // 移动光标至行末 m_notebook->ui->textEdit->moveCursor(QTextCursor::End, QTextCursor::MoveAnchor); m_notebook->show(); }); } /*! * \brief Widget::btnInit * */ void Widget::btnInit() { m_menu = new QMenu(ui->menuBtn); m_menu->setProperty("fillIconSymbolicColor", true); m_menuActionEmpty = new QAction(m_menu); QAction *m_helpAction = new QAction(m_menu); QAction *m_aboutAction = new QAction(m_menu); // m_menuActionSet = new QAction(m_menu); m_menuExit = new QAction(m_menu); m_helpAction->setText(tr("Help")); m_aboutAction->setText(tr("About")); m_menuActionEmpty->setText(tr("Empty Note")); // m_menuActionSet->setText(tr("Set Note")); m_menuExit->setText(tr("Exit")); m_menu->addAction(m_menuActionEmpty); m_menu->addAction(m_helpAction); m_menu->addAction(m_aboutAction); // m_menu->addAction(m_menuActionSet); m_menu->addAction(m_menuExit); ui->menuBtn->setMenu(m_menu); connect(m_helpAction, &QAction::triggered, this, [=](){ qDebug() << "help clicked"; userGuideInterface->call(QString("showGuide"), "ukui-notebook"); }); connect(m_aboutAction, &QAction::triggered, this, [=](){ About *dialog = new About(this); dialog->exec(); }); // 隐藏menu下箭头 // ui->menuBtn->setStyleSheet("QPushButton::menu-indicator{image:none}"); ui->menuBtn->setProperty("isOptionButton", true); // 设置是否自动凸起 ui->menuBtn->setAutoRaise(false); ui->menuBtn->setIconSize(QSize(16, 16)); ui->menuBtn->setPopupMode(QToolButton::InstantPopup); m_newKynote->setIcon(QPixmap(":/image/1x/new-hover.png")); ui->menuBtn->setIcon(QIcon::fromTheme("open-menu-symbolic")); m_viewChangeButton->setIcon(QIcon::fromTheme("view-grid-symbolic")); m_trashButton->setIcon(QIcon::fromTheme("edit-delete-symbolic")); ui->pushButton_Exit->setIcon(QIcon::fromTheme("window-close-symbolic")); ui->pushButton_Mini->setIcon(QIcon::fromTheme("window-minimize-symbolic")); ui->menuBtn->setProperty("useIconHighlightEffect", true); ui->menuBtn->setProperty("iconHighlightEffectMode", 1); m_viewChangeButton->setProperty("useIconHighlightEffect", true); m_viewChangeButton->setProperty("iconHighlightEffectMode", 1); ui->pushButton_Exit->setProperty("isWindowButton", 0x2); ui->pushButton_Exit->setProperty("useIconHighlightEffect", 0x8); ui->pushButton_Exit->setFlat(true); ui->pushButton_Mini->setProperty("isWindowButton", 0x1); ui->pushButton_Mini->setProperty("useIconHighlightEffect", 0x2); ui->pushButton_Mini->setFlat(true); ui->menuBtn->setProperty("isWindowButton", 0x1); ui->menuBtn->setProperty("useIconHighlightEffect", 0x2); ui->menuBtn->setAutoRaise(true); m_trashButton->setProperty("useIconHighlightEffect", true); m_trashButton->setProperty("iconHighlightEffectMode", 1); // 取消按钮默认主题灰色背景 QPalette palette = ui->pushButton_Mini->palette(); QColor ColorPlaceholderText(255, 255, 255, 0); QBrush brush; brush.setColor(ColorPlaceholderText); palette.setBrush(QPalette::Button, brush); palette.setBrush(QPalette::ButtonText, brush); // palette.setColor(QPalette::Highlight, Qt::transparent); /* 取消按钮高亮 */ // ui->pushButton_Mini->setPalette(palette); m_newKynote->setProperty("isImportant",true); m_newKynote->setToolTip(tr("Create New Note")); m_trashButton->setToolTip(tr("Delete Selected Note")); m_viewChangeButton->setToolTip(tr("Switch View")); ui->pushButton_Exit->setToolTip(tr("Close")); ui->pushButton_Mini->setToolTip(tr("Minimize")); ui->menuBtn->setToolTip(tr("Menu")); } /*! * \brief Widget::getListFlag * */ int Widget::getListFlag() const { return m_listflag; } /*! * \brief Widget::setListFlag * */ void Widget::setListFlag(const int &listflag) { m_listflag = listflag; } /*! * \brief Widget::initIconMode * */ void Widget::initIconMode() { qDebug() << "当前函数 :" << __FUNCTION__ << "当前行号 :" << __LINE__; m_noteView->setViewMode(QListView::IconMode); m_noteView->setSelectionMode(QListView::ExtendedSelection); m_noteView->setEditTriggers(QListView::NoEditTriggers); m_noteView->setResizeMode(QListView::Adjust); // m_noteView->setMovement(QListView::Snap); m_noteView->setContextMenuPolicy(Qt::CustomContextMenu); // m_noteView->setGridSize(QSize(227, 246)); // m_noteView->setIconSize(QSize(227, 246)); setupIconModeModel(); } /*! * \brief Widget::initListMode * */ void Widget::initListMode() { qDebug() << "当前函数 :" << __FUNCTION__ << "当前行号 :" << __LINE__; // 列表模式 m_noteView->setViewMode(QListView::ListMode); // 禁用双击编辑 m_noteView->setEditTriggers(QAbstractItemView::NoEditTriggers); // 竖向滑动条 m_noteView->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); // 隐藏横向滑动条 m_noteView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); m_noteView->setSelectionMode(QAbstractItemView::ExtendedSelection); // 视图将一次滚动一个像素的内容 m_noteView->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel); m_noteView->setFrameShape(QListView::NoFrame); // 启用项的拖动 // m_noteView->setDragEnabled(true); // 允许用户将内部或外部项拖放到视图中 // m_noteView->setAcceptDrops(true); // 显示当前拖动的项将被放在什么地方 // m_noteView->setDropIndicatorShown(true); setupListModeModel(); } /*! * \brief Widget::deleteNote * */ void Widget::deleteNote(const QModelIndex ¬eIndex, bool isFromUser) { qDebug() << "当前函数 :" << __FUNCTION__ << "当前行号 :" << __LINE__; if (noteIndex.isValid()) { // delete from model QModelIndex indexToBeRemoved = m_proxyModel->mapToSource(noteIndex); NoteData *noteTobeRemoved = m_noteModel->removeNote(indexToBeRemoved); noteTobeRemoved->setDeletionDateTime(QDateTime::currentDateTime()); qDebug() << "emit requestDeleteNote"; // delete from sql emit requestDeleteNote(noteTobeRemoved); if (isFromUser) { if (m_noteModel->rowCount() > 0) { QModelIndex index = m_noteView->currentIndex(); m_currentSelectedNoteProxy = index; m_noteView->selectionModel()->select(m_currentSelectedNoteProxy, QItemSelectionModel::ClearAndSelect); m_noteView->setCurrentIndex(m_currentSelectedNoteProxy); m_noteView->scrollTo(m_currentSelectedNoteProxy); } else { // 创建新的空模型索引 此类型的模型索引用于指示模型中的位置无效 m_currentSelectedNoteProxy = QModelIndex(); } } } else { qDebug() << "Widget::deleteNote noteIndex is not valid"; } m_noteView->setFocus(); } /*! * \brief Widget::deleteSelectedNote * */ void Widget::deleteSelectedNote() { qDebug() << "当前函数 :" << __FUNCTION__ << "当前行号 :" << __LINE__; if (!m_isOperationRunning) { m_isOperationRunning = true; if (m_noteModel->rowCount() > 0 && m_currentSelectedNoteProxy.isValid()) { int noteId = m_currentSelectedNoteProxy.data(NoteModel::NoteID).toInt(); for (auto it = m_editors.begin(); it != m_editors.end(); it++) { if ((*it)->m_noteId == noteId) { m_notebook = *it; m_notebook->close(); delete m_notebook; m_editors.erase(it); break; } } // --m_noteCounter; deleteNote(m_currentSelectedNoteProxy, true); // int row = m_currentSelectedNoteProxy.row(); // m_noteView->animateRemovedRow(QModelIndex(),row, row); } m_isOperationRunning = false; } } /*! * \brief Widget::selectNote * */ // 双击选中笔记 void Widget::selectNote(const QModelIndex ¬eIndex) { qDebug() << "当前函数 :" << __FUNCTION__ << "当前行号 :" << __LINE__; if (noteIndex.isValid()) { // show the content of the pressed note in the text editor QModelIndex indexSrc = m_proxyModel->mapToSource(noteIndex); showNoteInEditor(indexSrc); m_currentSelectedNoteProxy = noteIndex; m_noteView->selectionModel()->select(m_currentSelectedNoteProxy, QItemSelectionModel::ClearAndSelect); m_noteView->setCurrentIndex(m_currentSelectedNoteProxy); m_noteView->scrollTo(m_currentSelectedNoteProxy); } else { qDebug() << "Widget::selectNote() : noteIndex is not valid"; } } /*! * \brief Widget::showNoteInEditor * */ void Widget::showNoteInEditor(const QModelIndex ¬eIndex) { qDebug() << "当前函数 :" << __FUNCTION__ << "当前行号 :" << __LINE__; QString content = noteIndex.data(NoteModel::NoteContent).toString(); QDateTime dateTime = noteIndex.data(NoteModel::NoteLastModificationDateTime).toDateTime(); // int scrollbarPos = noteIndex.data(NoteModel::NoteScrollbarPos).toInt(); int noteColor = noteIndex.data(NoteModel::NoteColor).toInt(); // QString mdContent = noteIndex.data(NoteModel::NoteMdContent).toString(); // const listViewModeDelegate delegate(m_currentFont); // QColor m_color = delegate.intToQcolor(noteColor); QColor m_color = m_plistDelegate->intToQcolor(noteColor); // set text and date m_notebook->ui->textEdit->setText(content); m_notebook->m_noteHead->colorWidget = QColor(m_color); m_notebook->m_noteHeadMenu->colorWidget = QColor(m_color); m_notebook->update(); QString noteDate = dateTime.toString(Qt::ISODate); QString noteDateEditor = getNoteDateEditor(noteDate); // set scrollbar position // m_textEdit->verticalScrollBar()->setValue(scrollbarPos); } /*! * \brief Widget::selectFirstNote * */ void Widget::selectFirstNote() { if (m_proxyModel->rowCount() > 0) { QModelIndex index = m_proxyModel->index(0, 0); m_noteView->selectionModel()->select(index, QItemSelectionModel::ClearAndSelect); // 设置索引index所在的页面为当前页面 m_noteView->setCurrentIndex(index); m_currentSelectedNoteProxy = index; } } /*! * \brief Widget::createNewNoteIfEmpty * */ void Widget::createNewNoteIfEmpty() { // if(m_proxyModel->rowCount() == 0) createNewNote(); } /*! * \brief Widget::createNewNote * add note * save to db */ void Widget::createNewNote() { qDebug() << "当前函数 :" << __FUNCTION__ << "当前行号 :" << __LINE__; if (!m_isOperationRunning) { m_isOperationRunning = true; m_noteView->scrollToTop(); ++m_noteCounter; qDebug() << "创建便签 m_noteCounter:" << m_noteCounter; NoteData *tmpNote = generateNote(m_noteCounter); // insert the new note to NoteModel QModelIndex indexSrc = m_noteModel->insertNote(tmpNote, 0); // update the editor header date label QString dateTimeFromDB = tmpNote->lastModificationdateTime().toString(Qt::ISODate); QString dateTimeForEditor = getNoteDateEditor(dateTimeFromDB); // 从排序过滤器模型返回与给定 indexSrc 对应的源模型索引。 m_currentSelectedNoteProxy = m_proxyModel->mapFromSource(indexSrc); saveNoteToDB(m_currentSelectedNoteProxy); // int row = m_currentSelectedNoteProxy.row(); // m_noteView->animateAddedRow(QModelIndex(),row, row); // 设置索引 m_currentSelectedNoteProxy 所在的页面为当前页面 m_noteView->setCurrentIndex(m_currentSelectedNoteProxy); m_isOperationRunning = false; } int noteId = m_currentSelectedNoteProxy.data(NoteModel::NoteID).toInt(); m_notebook = new EditPage(this, noteId); m_editors.push_back(m_notebook); m_notebook->m_id = m_editors.size() - 1; if (sender() != Q_NULLPTR) { // 获取当前选中item下标 // QModelIndex indexInProxy = m_proxyModel->index(index.row(), 0); // 加载便签 selectNote(m_currentSelectedNoteProxy); m_noteView->setCurrentRowActive(false); } connect(m_editors[m_editors.size() - 1], &EditPage::isEmptyNote, this, [=](int noteId){ // m_editors.erase(m_editors[m_editors.size() - 1]); qDebug() << "receive signal isEmptyNote" << noteId; for (int count = 0; count <= m_proxyModel->rowCount(); count++) { QModelIndex m_tmpIndex = m_proxyModel->index(count, 0); if (m_tmpIndex.data(NoteModel::NoteID).toInt() == noteId) { QModelIndex sourceIndex = m_proxyModel->mapToSource(m_tmpIndex); deleteNote(m_tmpIndex, true); break; } } }); connect(m_editors[m_editors.size() - 1], &EditPage::requestDel, this, [=](int noteId){ for (int count = 0; count <= m_proxyModel->rowCount(); count++) { QModelIndex m_tmpIndex = m_proxyModel->index(count, 0); if (m_tmpIndex.data(NoteModel::NoteID).toInt() == noteId) { QModelIndex sourceIndex = m_proxyModel->mapToSource(m_tmpIndex); deleteNote(m_tmpIndex, true); break; } } }); connect(m_notebook->m_noteHeadMenu, ¬eHeadMenu::requestNewNote, this, [=](){ newSlot(); }); connect(m_notebook->m_noteHeadMenu, ¬eHeadMenu::requestShowNote, this, [=] { // 添加窗管协议 MotifWmHints hints; hints.flags = MWM_HINTS_FUNCTIONS|MWM_HINTS_DECORATIONS; hints.functions = MWM_FUNC_ALL; hints.decorations = MWM_DECOR_BORDER; XAtomHelper::getInstance()->setWindowMotifHint(this->winId(), hints); this->raise(); this->activateWindow(); this->show(); }); connect(m_editors[m_editors.size() - 1], SIGNAL(texthasChanged(int,int)), this, SLOT(onTextEditTextChanged(int,int))); connect(m_editors[m_editors.size() - 1], SIGNAL(colorhasChanged(QColor,int)), this, SLOT(onColorChanged(QColor,int))); //将选择的内容复制到新的便签页 connect(m_notebook, SIGNAL(textForNewEditpageSig()), this, SLOT(textForNewEditpageSigReceived())); // 设置鼠标焦点 m_notebook->ui->textEdit->setFocus(); // 移动光标至行末 m_notebook->ui->textEdit->moveCursor(QTextCursor::End, QTextCursor::MoveAnchor); if(m_isTextCpNew) { QClipboard *clipboard = QApplication::clipboard(); //获取系统剪贴板指针 QString originalText = clipboard->text(); //获取剪贴板上文本信息 m_notebook->ui->textEdit->setText(originalText); m_isTextCpNew = false; } m_notebook->show(); } /*! * \brief Widget::loadNotes * */ void Widget::loadNotes(QList noteList, int noteCounter) { if (!noteList.isEmpty()) { m_noteModel->addListNote(noteList); // Qt::AscendingOrder 升序排序 m_noteModel->sort(1, Qt::AscendingOrder); } m_noteCounter = noteCounter; createNewNoteIfEmpty(); selectFirstNote(); transFisrtLine(); } /*! * \brief Widget::saveNoteToDB * */ // 将当前便笺保存到数据库 void Widget::saveNoteToDB(const QModelIndex ¬eIndex) { if (noteIndex.isValid()) { // 从排序过滤器模型返回与给定 noteIndex 对应的源模型索引。 QModelIndex indexInSrc = m_proxyModel->mapToSource(noteIndex); NoteData *note = m_noteModel->getNote(indexInSrc); if (note != Q_NULLPTR) emit requestCreateUpdateNote(note); m_isContentModified = false; } else if (noteIndex.isValid() && m_isColorModified) { // 从排序过滤器模型返回与给定 noteIndex 对应的源模型索引。 QModelIndex indexInSrc = m_proxyModel->mapToSource(noteIndex); NoteData *note = m_noteModel->getNote(indexInSrc); if (note != Q_NULLPTR) emit requestCreateUpdateNote(note); m_isColorModified = false; } } /*! * \brief Widget::getQDateTime * */ QDateTime Widget::getQDateTime(QString date) { QDateTime dateTime = QDateTime::fromString(date, Qt::ISODate); return dateTime; } /*! * \brief Widget::getNoteDateEditor * */ QString Widget::getNoteDateEditor(QString dateEdited) { QDateTime dateTimeEdited(getQDateTime(dateEdited)); QLocale usLocale = QLocale::system(); return usLocale.toString(dateTimeEdited, QStringLiteral("yyyy/MM/dd hh:mm")); } /*! * \brief Widget::generateNote * 初始化一个笔记 */ NoteData *Widget::generateNote(const int noteID) { NoteData *newNote = new NoteData(this); newNote->setId(noteID); QDateTime noteDate = QDateTime::currentDateTime(); newNote->setCreationDateTime(noteDate); newNote->setLastModificationDateTime(noteDate); newNote->setFullTitle(tr("Welcome to use Notes.")); newNote->setNoteColor(15169356); newNote->m_note = nullptr; return newNote; } /*! * \brief Widget::moveNoteToTop * */ void Widget::moveNoteToTop() { qDebug() << "movenote to top"; // check if the current note is note on the top of the list // if true move the note to the top if (m_tmpIndex.isValid()) { m_noteView->scrollToTop(); // NoteData* note = m_noteModel->getNote(index); // move the current selected note to the top // 当前要移动到顶端的item QSortFilterProxyModel QModelIndex sourceIndex = m_proxyModel->mapToSource(m_tmpIndex); // 目前顶端的item QAbstractListModel QModelIndex destinationIndex = m_noteModel->index(0); // 将 sourceIndex.row() 移动到第0行,第0行变第一行 m_noteModel->moveRow(sourceIndex, sourceIndex.row(), destinationIndex, 0); // 更新当前 最顶端QAbstractListModel item 并添加代理 m_tmpIndex = m_proxyModel->mapFromSource(destinationIndex); m_currentSelectedNoteProxy = m_tmpIndex; // 修改当前选中 m_noteView->setCurrentIndex(m_tmpIndex); } else { qDebug() << "Widget::moveNoteTop : m_currentSelectedNoteProxy not valid"; } } /*! * \brief Widget::getFirstLine * */ QString Widget::getFirstLine(const QString &str) { if (str.simplified().isEmpty()) { return tr("Welcome to use Notes."); } QString text = str.trimmed(); QTextStream ts(&text); return ts.readLine(FIRST_LINE_MAX); } /*! * \brief Widget::findNotesContain * */ void Widget::findNotesContain(const QString &keyword) { // 将用于过滤源模型内容的固定字符串设置为给定模式 m_proxyModel->setFilterFixedString(keyword); // 如果匹配到不止一行 if (m_proxyModel->rowCount() > 0) { selectFirstNote(); } else { m_currentSelectedNoteProxy = QModelIndex(); } } /*! * \brief Widget::searchInit * */ void Widget::searchInit() { m_searchLine->setContextMenuPolicy(Qt::NoContextMenu); // 禁用右键菜单 m_searchLine->setPlaceholderText(tr("Search")); // 设置详细输入框的提示信息 m_searchAction = new QAction(m_searchLine); //searchAction->setIcon(QIcon::fromTheme("system-search-symbolic")); if(m_isThemeChanged) { m_searchAction->setIcon(drawSymbolicColoredPixmap(QPixmap(":/image/1x/system-search-symbolic.svg"), m_searchAction)); } else { m_searchAction->setIcon(QPixmap(":/image/1x/system-search-symbolic.svg")); } // m_searchAction->setIcon(QIcon::fromTheme("edit-find-symbolic")); m_searchLine->setProperty("useIconHighlightEffect", true); m_searchLine->setProperty("iconHighlightEffectMode", 1); m_searchLine->addAction(m_searchAction, QLineEdit::LeadingPosition); // 图片在左侧 // m_searchLine->setAttribute(Qt::WA_Hover, true); QTimer::singleShot(500, this, [=](){ QList wid = m_searchLine->findChildren(); for (int i = 0; i < wid.count(); i++) { wid.at(i)->setAttribute(Qt::WA_Hover, false); } }); delAction = new QAction(m_searchLine); delAction->setIcon(QIcon::fromTheme("edit-clear-symbolic")); connect(delAction, &QAction::triggered, this, [=](){ m_searchLine->setText(""); }); } /*! * \brief Widget::clearSearch * */ void Widget::clearSearch() { m_noteView->setFocusPolicy(Qt::StrongFocus); m_searchLine->blockSignals(true); m_searchLine->clear(); m_searchLine->blockSignals(false); m_proxyModel->setFilterFixedString(QString()); m_searchLine->setFocus(); m_searchLine->addAction(m_searchAction, QLineEdit::LeadingPosition); // 图片在左侧 m_searchLine->removeAction(delAction); } /*! * \brief Widget::mousePressEvent * */ // void Widget::mousePressEvent(QMouseEvent *event) // { // if (event->button() == Qt::LeftButton) { // this->dragPosition = event->globalPos() - frameGeometry().topLeft(); // this->mousePressed = true; // } // QWidget::mousePressEvent(event); // } /*! * \brief Widget::mouseReleaseEvent * */ // void Widget::mouseReleaseEvent(QMouseEvent *event) // { // if (event->button() == Qt::LeftButton) { // this->mousePressed = false; // } // QWidget::mouseReleaseEvent(event); // } /*! * \brief Widget::mouseMoveEvent * */ // void Widget::mouseMoveEvent(QMouseEvent *event) // { // if (this->mousePressed) { // int dpiRatio = qApp->devicePixelRatio(); // move(event->globalPos() - this->dragPosition.x() * dpiRatio, // (event->globalPos() - this->dragPosition.y() * dpiRatio)); // this->setCursor(Qt::ClosedHandCursor); // } // QWidget::mouseMoveEvent(event); // } /*! * \brief Widget::paintEvent * */ void Widget::paintEvent(QPaintEvent *event) { Q_UNUSED(event); // QStyleOption opt; // opt.init(this); QPainter p(this); p.setRenderHint(QPainter::Antialiasing); // 反锯齿; QPainterPath rectPath; rectPath.addRect(this->rect()); // rectPath.addRoundedRect(this->rect(), 6, 6); // 左上右下 // 画一个黑底 // QPixmap pixmap(this->rect().size()); // pixmap.fill(Qt::transparent); // QPainter pixmapPainter(&pixmap); // pixmapPainter.setRenderHint(QPainter::Antialiasing); // pixmapPainter.setPen(Qt::transparent); // pixmapPainter.setBrush(Qt::black); // pixmapPainter.drawPath(rectPath); // pixmapPainter.end(); // 模糊这个黑底 // QImage img = pixmap.toImage(); // qt_blurImage(img, 10, false, false); // 挖掉中心 // pixmap = QPixmap::fromImage(img); // QPainter pixmapPainter2(&pixmap); // pixmapPainter2.setRenderHint(QPainter::Antialiasing); // pixmapPainter2.setCompositionMode(QPainter::CompositionMode_Clear); // pixmapPainter2.setPen(Qt::transparent); // pixmapPainter2.setBrush(Qt::transparent); // pixmapPainter2.drawPath(rectPath); // 绘制阴影 // p.drawPixmap(this->rect(), pixmap, pixmap.rect()); // 绘制一个背景 // p.save(); // p.setOpacity(0.7); p.fillPath(rectPath, palette().color(QPalette::Base)); // p.restore(); } /********************Slots************************/ /*! * \brief Widget::onTextEditTextChanged * */ void Widget::onTextEditTextChanged(int noteId, int i) { qDebug() << "receive signal textchange" << noteId; for (int count = 0; count <= m_proxyModel->rowCount(); count++) { m_tmpIndex = m_proxyModel->index(count, 0); if (m_tmpIndex.data(NoteModel::NoteID).toInt() == noteId) { qDebug() << m_tmpIndex.data(NoteModel::NoteID).toInt(); break; } } if (m_tmpIndex.isValid()) { QString content = m_tmpIndex.data(NoteModel::NoteContent).toString(); QString mdContent = m_tmpIndex.data(NoteModel::NoteMdContent).toString(); if (m_editors[i]->ui->textEdit->toHtml().toUtf8() != content) { // move note to the top of the list QModelIndex sourceIndex = m_proxyModel->mapToSource(m_tmpIndex); qDebug() << m_currentSelectedNoteProxy; if (m_tmpIndex.row() != 0) { // m_noteView->setAnimationEnabled(false); moveNoteToTop(); // m_noteView->setAnimationEnabled(true); } else if (!m_searchLine->text().isEmpty() && sourceIndex.row() != 0) { m_noteView->setAnimationEnabled(false); moveNoteToTop(); m_noteView->setAnimationEnabled(true); } // QModelIndex firstIndex = m_proxyModel->index(0,0); // Get the new data QString firstline; if(m_editors[i]->m_isInsImg) { firstline = getFirstLine(("[picture]")); } else { firstline = getFirstLine(m_editors[i]->ui->textEdit->toPlainText()); } QDateTime dateTime = QDateTime::currentDateTime(); // QString noteDate = dateTime.toString(Qt::ISODate); // update model QMap dataValue; dataValue[NoteModel::NoteContent] = QVariant::fromValue( m_editors[i]->ui->textEdit->toHtml().toUtf8()); dataValue[NoteModel::NoteMdContent] = QVariant::fromValue( m_editors[i]->ui->textEdit->toPlainText()); dataValue[NoteModel::NoteFullTitle] = QVariant::fromValue(firstline); dataValue[NoteModel::NoteLastModificationDateTime] = QVariant::fromValue(dateTime); QModelIndex currentIndex = m_proxyModel->mapToSource(m_tmpIndex); m_noteModel->setItemData(currentIndex, dataValue); m_isContentModified = true; // m_autoSaveTimer->start(500); saveNoteToDB(m_tmpIndex); } } else { qDebug() << "Widget::onTextEditTextChanged() : index is not valid"; } } /*! * \brief Widget::onColorChanged * */ void Widget::onColorChanged(const QColor &color, int noteId) { qDebug() << "receive signal onColorChanged"; for (int count = 0; count <= m_proxyModel->rowCount(); count++) { m_tmpColorIndex = m_proxyModel->index(count, 0); if (m_tmpColorIndex.data(NoteModel::NoteID).toInt() == noteId) { break; } } if (m_tmpColorIndex.isValid()) { // const listViewModeDelegate delegate(m_currentFont); // int m_color = delegate.qcolorToInt(color); int m_color = m_plistDelegate->qcolorToInt(color); QMap dataValue; dataValue[NoteModel::NoteColor] = QVariant::fromValue(m_color); QModelIndex index = m_proxyModel->mapToSource(m_tmpColorIndex); m_noteModel->setItemData(index, dataValue); m_isColorModified = true; saveNoteToDB(m_tmpColorIndex); } } /*! * \brief Widget::exitSlot * */ void Widget::exitSlot() { closeAllEditors(); this->close(); // this->~Widget(); } /*! * \brief Widget::trashSlot * */ void Widget::trashSlot() { if(!m_emptyNotes->m_isDontShow) { m_emptyNotes->exec(); } else{ emit m_emptyNotes->requestEmptyNotes(); } } /*! * \brief Widget::miniSlot * */ void Widget::miniSlot() { this->showNormal(); this->showMinimized(); } void Widget::textForNewEditpageSigReceived() { m_isTextCpNew = true; newSlot(); } void Widget::closeAllEditors() { for (auto it = m_editors.begin(); it != m_editors.end(); it++) { (*it)->close(); delete *it; } m_editors.clear(); } /*! * \brief Widget::newSlot * */ void Widget::newSlot() { // 如果搜索栏有内容,则在新建便签时清空 if (!m_searchLine->text().isEmpty()) { clearSearch(); } this->createNewNote(); } /*! * \brief Widget::onTrashButtonClicked * */ void Widget::onTrashButtonClicked() { m_trashButton->blockSignals(true); deleteSelectedNote(); m_trashButton->blockSignals(false); } /*! * \brief Widget::listClickSlot * listview单击事件 */ void Widget::listClickSlot(const QModelIndex &index) { if (sender() != Q_NULLPTR) { QModelIndex indexInProxy = m_proxyModel->index(index.row(), 0); if (indexInProxy.isValid()) { m_currentSelectedNoteProxy = indexInProxy; m_noteView->selectionModel()->select(m_currentSelectedNoteProxy, QItemSelectionModel::ClearAndSelect); m_noteView->setCurrentIndex(m_currentSelectedNoteProxy); m_noteView->scrollTo(m_currentSelectedNoteProxy); } else { qDebug() << "Widget::selectNote() : indexInProxy is not valid"; m_currentSelectedNoteProxy = QModelIndex(); } m_noteView->setCurrentRowActive(false); } } /*! * \brief Widget::listDoubleClickSlot * 在滚动区域中单击便笺时: * 取消突出显示上一个选定的便笺 * 如果在临时便笺存在时选择便笺,请删除临时便笺 * 突出显示所选便笺 * 将所选便笺内容加载到textedit */ void Widget::listDoubleClickSlot(const QModelIndex &index) { int noteId = index.data(NoteModel::NoteID).toInt(); int isExistInMeditors = 0; qDebug() << "list double click" << noteId << index; for (auto it = m_editors.begin(); it != m_editors.end(); it++) { if ((*it)->m_noteId == noteId) { isExistInMeditors = 1; m_notebook = *it; m_notebook->raise(); m_notebook->activateWindow(); break; } } if (isExistInMeditors == 0) { m_notebook = new EditPage(this, noteId); m_editors.push_back(m_notebook); m_notebook->m_id = m_editors.size() - 1; if (sender() != Q_NULLPTR) { // 获取当前选中item下标 // QModelIndex indexInProxy = m_proxyModel->index(index.row(), 0); // 加载便签 selectNote(index); m_noteView->setCurrentRowActive(false); } connect(m_notebook->m_noteHeadMenu, ¬eHeadMenu::requestNewNote, this, [=](){ newSlot(); }); connect(m_notebook->m_noteHeadMenu, ¬eHeadMenu::requestShowNote, this, [=] { // 添加窗管协议 MotifWmHints hints; hints.flags = MWM_HINTS_FUNCTIONS|MWM_HINTS_DECORATIONS; hints.functions = MWM_FUNC_ALL; hints.decorations = MWM_DECOR_BORDER; XAtomHelper::getInstance()->setWindowMotifHint(this->winId(), hints); this->raise(); this->activateWindow(); this->show(); }); connect(m_editors[m_editors.size() - 1], &EditPage::requestDel, this, [=](int noteId){ for (int count = 0; count <= m_proxyModel->rowCount(); count++) { QModelIndex m_tmpIndex = m_proxyModel->index(count, 0); if (m_tmpIndex.data(NoteModel::NoteID).toInt() == noteId) { QModelIndex sourceIndex = m_proxyModel->mapToSource(m_tmpIndex); deleteNote(m_tmpIndex, true); break; } } }); connect(m_editors[m_editors.size() - 1], SIGNAL(texthasChanged(int,int)), this, SLOT(onTextEditTextChanged(int,int))); connect(m_editors[m_editors.size() - 1], SIGNAL(colorhasChanged(QColor,int)), this, SLOT(onColorChanged(QColor,int))); } // 设置鼠标焦点 m_notebook->ui->textEdit->setFocus(); // 移动光标至行末 m_notebook->ui->textEdit->moveCursor(QTextCursor::End, QTextCursor::MoveAnchor); m_notebook->setHints(); m_notebook->show(); } /*! * \brief Widget::onSearchEditTextChanged * */ void Widget::onSearchEditTextChanged(const QString &keyword) { qDebug() << "onSearchEditTextChanged"; m_searchQueue.enqueue(keyword); if (m_searchLine->text().isEmpty()) { m_searchLine->addAction(m_searchAction, QLineEdit::LeadingPosition); // 图片在左侧 m_searchLine->removeAction(delAction); } else { m_searchLine->removeAction(m_searchAction); m_searchLine->addAction(delAction, QLineEdit::TrailingPosition); // 图片在右侧 } if (!m_isOperationRunning) { m_isOperationRunning = true; // disable animation while searching m_noteView->setAnimationEnabled(false); while (!m_searchQueue.isEmpty()) { qApp->processEvents(); QString str = m_searchQueue.dequeue(); if (str.isEmpty()) { clearSearch(); } else { m_noteView->setFocusPolicy(Qt::NoFocus); // 过滤 findNotesContain(str); } } m_noteView->setAnimationEnabled(true); m_isOperationRunning = false; } } /*! * \brief Widget::changePageSlot * */ void Widget::changePageSlot() { if (getListFlag() != 0) { initIconMode(); m_viewChangeButton->setIcon(QIcon::fromTheme("view-list-symbolic")); setListFlag(0); m_settingsDatabase->setValue(QStringLiteral("iniNoteMode"), "icon"); } else if (getListFlag() == 0) { initListMode(); m_viewChangeButton->setIcon(QIcon::fromTheme("view-grid-symbolic")); setListFlag(1); m_settingsDatabase->setValue(QStringLiteral("iniNoteMode"), "list"); } if (m_noteModel->rowCount() > 0) { QModelIndex index = m_noteView->currentIndex(); m_currentSelectedNoteProxy = index; m_noteView->selectionModel()->select(m_currentSelectedNoteProxy, QItemSelectionModel::ClearAndSelect); m_noteView->setCurrentIndex(m_currentSelectedNoteProxy); m_noteView->scrollTo(m_currentSelectedNoteProxy); } else { // 创建新的空模型索引 此类型的模型索引用于指示模型中的位置无效 m_currentSelectedNoteProxy = QModelIndex(); } } /*! * \brief Widget::sortSlot * */ void Widget::sortSlot(int index) { // Qt::AscendingOrder 升序排序 // 参见 NoteModel::sort if (m_proxyModel->rowCount()) { if (sortflag) { m_noteModel->sort(index, Qt::DescendingOrder); sortflag = 0; } else { m_noteModel->sort(index, Qt::AscendingOrder); sortflag = 1; } } } /*! * \brief Widget::clearNoteSlot * */ void Widget::clearNoteSlot() { qDebug() << "empty note" << m_editors.size(); for (auto it = m_editors.begin(); it != m_editors.end(); it++) { (*it)->close(); // m_editors.erase(it); delete (*it); } m_editors.clear(); qDebug() << "清空vector" << m_editors.size(); m_noteModel->clearNotes(); emit requestClearNote(); } /*! * \brief Widget::SetNoteSlot * */ // void Widget::SetNoteSlot() // { // qDebug() << "SetNoteSlot"; // } /*! * \brief Widget::setNoteNullSlot * */ void Widget::setNoteNullSlot() { for (int i = 0; i < m_proxyModel->rowCount(); i++) { QModelIndex index = m_proxyModel->index(i, 0); NoteData *note = m_noteModel->getNote(index); note->m_note = nullptr; } } /*! * \brief Widget::onF1ButtonClicked * */ void Widget::onF1ButtonClicked() { qDebug() << "onF1ButtonClicked"; userGuideInterface->call(QString("showGuide"), "ukui-notebook"); } /*! * \brief Widget::sltMessageReceived * */ void Widget::sltMessageReceived(/*const QString &msg*/) { int noteId = m_currentSelectedNoteProxy.data(NoteModel::NoteID).toInt(); qDebug() << __FUNCTION__ << __LINE__ << "noteId == " << noteId; if(this->isHidden()) { this->m_notebook->show(); this->m_notebook->activateWindow(); this->m_notebook->raise(); } else { this->raise(); this->activateWindow(); this->show(); } #if 0 int noteId = m_currentSelectedNoteProxy.data(NoteModel::NoteID).toInt(); if (m_noteModel->rowCount() > 0/* && m_currentSelectedNoteProxy.isValid()*/) { int noteId = m_currentSelectedNoteProxy.data(NoteModel::NoteID).toInt(); for (auto it = m_editors.begin(); it != m_editors.end(); it++) { if ((*it)->m_noteId == noteId) { (*it)->raise(); (*it)->activateWindow(); (*it)->show(); break; } } } #endif } /*! * \brief Widget::readIniNoteMode * */ void Widget::iniNoteModeRead() { qDebug() << "当前函数 :" << __FUNCTION__ << "当前行号 :" << __LINE__; //读取配置文件,确定要不要变更视图 if (m_settingsDatabase->value(QStringLiteral("iniNoteMode"), "NULL") == "icon") changePageSlot(); } QPixmap drawSymbolicColoredPixmap(const QPixmap& source, QAction *btn) { QColor t = QColor(0, 0, 0); QColor baseColor = QColor(255, 255, 255); // QColor baseColor = btn->palette().color(QPalette::Text).light(150); QImage img = source.toImage(); qDebug() << "drawSymbolicColoredPixmap" << baseColor.red() << baseColor.green() <rowCount(); i++) { QModelIndex index = m_proxyModel->index(i, 0); NoteData *note = m_noteModel->getNote(index); if (note != Q_NULLPTR && note->content() == NULL) note->setFullTitle(tr("Welcome to use Notes.")); else if (note->fullTitle() == "[picture]" || note->fullTitle() == "[图片]") { note->setFullTitle(tr("[picture]")); } } } ukui-notebook/src/myThrow.cpp0000644000175000017500000000677214174170620015253 0ustar fengfeng/* * Copyright (C) 2020 Tianjin KYLIN Information Technology Co., Ltd. * * This program is free software; you can 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, 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 #include #include #include #include #include "myThrow.h" using namespace std; ExceptionBase::ExceptionBase(const std::string& msg) throw() : mMsg(msg), mFile(""), mFunc(""), mLine(-1), mStackTraceSize(0) {} ExceptionBase::~ExceptionBase() throw() {} void ExceptionBase::Init(const char* file, const char* func, int line) { mFile = file; mFunc = func; mLine = line; mStackTraceSize = backtrace(mStackTrace, MAX_STACK_TRACE_SIZE); } std::string ExceptionBase::GetClassName() const { return "ExceptionBase"; } const char* ExceptionBase::what() const throw() { return ToString().c_str(); } const std::string& ExceptionBase::ToString() const { if (mWhat.empty()) { stringstream sstr(""); if (mLine > 0) { sstr << mFile << "(" << mLine << ")"; } sstr << ": " << GetClassName(); if (!GetMessage().empty()) { sstr << ": " << GetMessage(); } sstr << "\nStack Trace:\n"; sstr << GetStackTrace(); mWhat = sstr.str(); } return mWhat; } std::string ExceptionBase::GetMessage() const { return mMsg; } std::string ExceptionBase::GetStackTrace() const { if (mStackTraceSize == 0) return "\n"; char** strings = backtrace_symbols(mStackTrace, 10); if (strings == NULL) // Since this is for debug only thus // non-critical, don't throw an exception. return "\n"; std::string result; for (size_t i = 0; i < mStackTraceSize; ++i) { std::string mangledName = strings[i]; std::string::size_type begin = mangledName.find('('); std::string::size_type end = mangledName.find('+', begin); if (begin == std::string::npos || end == std::string::npos) { result += mangledName; result += '\n'; continue; } ++begin; int status; char* s = abi::__cxa_demangle(mangledName.substr(begin, end-begin).c_str(), NULL, 0, &status); if (status != 0) { result += mangledName; result += '\n'; continue; } std::string demangledName(s); free(s); // Ignore ExceptionBase::Init so the top frame is the // user's frame where this exception is thrown. // // Can't just ignore frame#0 because the compiler might // inline ExceptionBase::Init. result += mangledName.substr(0, begin); result += demangledName; result += mangledName.substr(end); result += '\n'; } free(strings); return result; } ukui-notebook/src/adaptscreeninfo.cpp0000644000175000017500000000613714174170620016742 0ustar fengfeng/* * Copyright (C) 2020, KylinSoft Co., Ltd. * * This program is free software: you can 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 . */ #include "adaptscreeninfo.h" adaptScreenInfo::adaptScreenInfo(QObject *parent) : QObject(parent) { m_pDeskWgt = QApplication::desktop(); InitializeHomeScreenGeometry(); initScreenSize(); connect(QApplication::primaryScreen(), &QScreen::geometryChanged, this, &adaptScreenInfo::onResolutionChanged); connect(m_pDeskWgt, &QDesktopWidget::primaryScreenChanged, this, &adaptScreenInfo::primaryScreenChangedSlot); connect(m_pDeskWgt, &QDesktopWidget::screenCountChanged, this, &adaptScreenInfo::screenCountChangedSlots); m_pListScreen = QGuiApplication::screens(); } /* 当屏幕数量发生改变时,重新赋值m_pListScreen */ void adaptScreenInfo::screenNumChange() { m_pListScreen = QGuiApplication::screens(); } void adaptScreenInfo::modifyMemberVariable() { foreach (QScreen *screen, QGuiApplication::screens()) { } } /* 初始化屏幕高度, 宽度 */ void adaptScreenInfo::initScreenSize() { QList screen = QGuiApplication::screens(); int count = m_pDeskWgt->screenCount(); if (count > 1) { m_screenWidth = screen[0]->geometry().width() + m_nScreen_x; m_screenHeight = screen[0]->geometry().height() + m_nScreen_y; } else { m_screenWidth = m_pDeskWgt->width() + m_nScreen_x; m_screenHeight = m_pDeskWgt->height() + m_nScreen_y; } return; } /* 初始化主屏坐标 */ void adaptScreenInfo::InitializeHomeScreenGeometry() { QList screen = QGuiApplication::screens(); int count = m_pDeskWgt->screenCount(); if (count > 1) { m_nScreen_x = screen[0]->geometry().x(); m_nScreen_y = screen[0]->geometry().y(); } else { m_nScreen_x = 0; m_nScreen_y = 0; } qDebug() << "偏移的x坐标" << m_nScreen_x; qDebug() << "偏移的Y坐标" << m_nScreen_y; } //当改变屏幕分辨率时重新获取屏幕分辨率 void adaptScreenInfo::onResolutionChanged(const QRect argc) { Q_UNUSED(argc); initScreenSize(); //获取屏幕可用高度区域 InitializeHomeScreenGeometry(); return; } /* 主屏发生变化槽函数 */ void adaptScreenInfo::primaryScreenChangedSlot() { InitializeHomeScreenGeometry(); initScreenSize(); return; } /* 屏幕数量改变时对应槽函数 */ void adaptScreenInfo::screenCountChangedSlots(int count) { Q_UNUSED(count); InitializeHomeScreenGeometry(); initScreenSize(); return; } ukui-notebook/src/selectColorPage.h0000644000175000017500000000320714174170620016310 0ustar fengfeng/* * Copyright (C) 2020 Tianjin KYLIN Information Technology Co., Ltd. * * This program is free software; you can 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, 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 #include "paletteWidget.h" #define SHADOW_WIDTH 1 // 窗口阴影宽度; #define TRIANGLE_WIDTH 15 // 小三角的宽度; #define TRIANGLE_HEIGHT 10 // 小三角的高度; #define BORDER_RADIUS 5 // 窗口边角的弧度; namespace Ui { class SelectColor; } class Widget; class SelectColor : public QWidget { Q_OBJECT public: explicit SelectColor(Widget* page, QWidget *parent = nullptr); ~SelectColor(); Ui::SelectColor *ui; public: Widget *pNotebook; PaletteWidget *paletteWidget; protected: void paintEvent(QPaintEvent *event) Q_DECL_OVERRIDE; private: int m_startX = 180; // 小三角起始位置; int m_triangleWidth = 10; // 小三角的宽度; int m_triangleHeight= 5; // 小三角高度; QTimer *timer; private: void initSetup(); }; #endif // SELECTCOLOR_H ukui-notebook/src/headerbar.cpp0000644000175000017500000001172014174170620015504 0ustar fengfeng/* * Copyright (C) 2020 Tianjin KYLIN Information Technology Co., Ltd. * * This program is free software; you can 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, 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 #include #include #include #include #include #include #include #include "headerbar.h" #include "widget.h" static HeaderBarStyle *global_instance = nullptr; static QString terminal_cmd = nullptr; HeaderBar::HeaderBar(Widget *parent) : QToolBar(parent) { setMouseTracking(true); setStyle(HeaderBarStyle::getStyle()); m_window = parent; //disable default menu setContextMenuPolicy(Qt::CustomContextMenu); setMovable(false); auto a = addAction(QIcon(":/image/1x/array.png"), tr("Sort Type")); auto sortType = qobject_cast(widgetForAction(a)); //sortType->setStyleSheet("QToolButton{background-color:rgba(19,20,20,0);}"); sortType->setAutoRaise(false); sortType->setFixedSize(QSize(32, 32)); sortType->setIconSize(QSize(16, 16)); sortType->setPopupMode(QToolButton::InstantPopup); QPalette palette = sortType->palette(); QColor ColorPlaceholderText(255,255,255,0); QBrush brush; brush.setColor(ColorPlaceholderText); palette.setBrush(QPalette::Button, brush); //palette.setBrush(QPalette::ButtonText, brush); palette.setBrush(QPalette::HighlightedText,QBrush(Qt::blue)); //palette.setBrush(QPalette::Active,QPalette::HighlightedText,QBrush(Qt::darkBlue)); palette.setColor(QPalette::Highlight, Qt::transparent); /* 取消按钮高亮 */ sortType->setPalette(palette); for (auto action : actions()) { auto w = widgetForAction(action); w->setProperty("useIconHighlightEffect", true); w->setProperty("iconHighlightEffectMode", 1); } } void HeaderBar::addSpacing(int pixel) { for (int i = 0; i < pixel; i++) { addSeparator(); } } void HeaderBar::mouseMoveEvent(QMouseEvent *e) { QToolBar::mouseMoveEvent(e); QCursor c; c.setShape(Qt::ArrowCursor); this->topLevelWidget()->setCursor(c); } HeaderBarToolButton::HeaderBarToolButton(QWidget *parent) : QToolButton(parent) { setAutoRaise(false); setIconSize(QSize(16, 16)); } HeadBarPushButton::HeadBarPushButton(QWidget *parent) : QPushButton(parent) { setIconSize(QSize(16, 16)); } HeaderBarStyle *HeaderBarStyle::getStyle() { if (!global_instance) { global_instance = new HeaderBarStyle; } return global_instance; } int HeaderBarStyle::pixelMetric(QStyle::PixelMetric metric, const QStyleOption *option, const QWidget *widget) const { switch (metric) { case PM_ToolBarIconSize: return 16; case PM_ToolBarSeparatorExtent: return 1; case PM_ToolBarItemSpacing: { return 1; } default: return QProxyStyle::pixelMetric(metric, option, widget); } } void HeaderBarStyle::drawComplexControl(QStyle::ComplexControl control, const QStyleOptionComplex *option, QPainter *painter, const QWidget *widget) const { //This is a "lie". We want to use instant popup menu for tool button, and we aslo //want use popup menu style with this tool button, so we change the related flags //to draw in our expected. if (control == CC_ToolButton) { QStyleOptionToolButton button = *qstyleoption_cast(option); //The button has a popup menu. if (button.features.testFlag(QStyleOptionToolButton::HasMenu)) { button.features = QStyleOptionToolButton::None; if (!widget->property("isOptionButton").toBool()) { button.features |= QStyleOptionToolButton::HasMenu; button.features |= QStyleOptionToolButton::MenuButtonPopup; //QStyle::SubControls 此枚举描述可用的子控件 //QStyle::SC_ToolButtonMenu 用于在工具按钮中打开弹出菜单的子控件。 button.subControls |= QStyle::SC_ToolButtonMenu; } return QProxyStyle::drawComplexControl(control, &button, painter, widget); } } return QProxyStyle::drawComplexControl(control, option, painter, widget); } void HeaderBarStyle::drawPrimitive(QStyle::PrimitiveElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget) const { if (element == PE_IndicatorToolBarSeparator) { return; } return QProxyStyle::drawPrimitive(element, option, painter, widget); } ukui-notebook/src/noteHead.h0000644000175000017500000000206614201136534014763 0ustar fengfeng/* * Copyright (C) 2020 Tianjin KYLIN Information Technology Co., Ltd. * * This program is free software; you can 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, 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 #include namespace Ui { class noteHead; } class noteHead : public QWidget { Q_OBJECT public: explicit noteHead(QWidget *parent = nullptr); ~noteHead(); public: QColor colorWidget; protected: void paintEvent(QPaintEvent *event); private: Ui::noteHead *ui; }; #endif // NOTEHEAD_H ukui-notebook/src/iconViewModeDelegate.h0000644000175000017500000000555214201136534017262 0ustar fengfeng/* * Copyright (C) 2020 Tianjin KYLIN Information Technology Co., Ltd. * * This program is free software; you can 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, 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 #include class iconViewModeDelegate : public QStyledItemDelegate { Q_OBJECT public: iconViewModeDelegate(QObject *parent = Q_NULLPTR); enum States{ Normal, Insert, Remove, MoveOut, MoveIn }; void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const Q_DECL_OVERRIDE; QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const Q_DECL_OVERRIDE; public: void setState(States NewState , QModelIndex index); void setAnimationDuration(const int duration); QTimeLine::State animationState(); void setCurrentSelectedIndex(const QModelIndex ¤tSelectedIndex); void setHoveredIndex(const QModelIndex &hoveredIndex); void setRowRightOffset(int rowRightOffset); void setActive(bool isActive); int qcolorToInt(const QColor &color) const; QColor intToQcolor(int &intColor) const; private: mutable QFont m_titleFont; mutable QFont m_titleSelectedFont; mutable QFont m_dateFont; QColor m_titleColor; QColor m_dateColor; QColor m_ActiveColor; QColor m_notActiveColor; QColor m_hoverColor; QColor m_selectColor; QColor m_applicationInactiveColor; QColor m_separatorColor; QColor m_defaultColor; QColor m_noteColor; int m_rowHeight; int m_maxFrame; int m_rowRightOffset; States m_state; bool m_isActive; QString m_timeZone; QTimeLine *m_timeLine; QModelIndex m_animatedIndex; QModelIndex m_currentSelectedIndex; QModelIndex m_hoveredIndex; private: void paintBackground(QPainter* painter, const QStyleOptionViewItem &option, const QModelIndex &index)const; void paintLabels(QPainter* painter, const QStyleOptionViewItem &option, const QModelIndex &index) const; void paintSeparator(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const; QString parseDateTime(const QDateTime& dateTime) const; signals: void update(const QModelIndex &index); }; #endif // ICONVIEWMODEDELEGATE_H ukui-notebook/src/headerbar.h0000644000175000017500000000456014174170620015155 0ustar fengfeng/* * Copyright (C) 2020 Tianjin KYLIN Information Technology Co., Ltd. * * This program is free software; you can 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, 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 #include #include #include class Widget; class HeaderBar; class QHBoxLayout; class HeaderBar : public QToolBar { friend class MainWindow; Q_OBJECT public: explicit HeaderBar(Widget *parent = nullptr); Q_SIGNALS: void updateLocationRequest(const QString &uri, bool addHistory = true, bool force = true); void viewTypeChangeRequest(const QString &viewId); void updateZoomLevelHintRequest(int zoomLevelHint); void updateSearchRequest(bool showSearch); protected: void addSpacing(int pixel); void mouseMoveEvent(QMouseEvent *e); private: const QString m_uri; Widget *m_window; bool m_search_mode = false; }; class HeaderBarToolButton : public QToolButton { friend class HeaderBar; friend class MainWindow; Q_OBJECT explicit HeaderBarToolButton(QWidget *parent = nullptr); }; class HeadBarPushButton : public QPushButton { friend class HeaderBar; friend class MainWindow; Q_OBJECT explicit HeadBarPushButton(QWidget *parent = nullptr); }; class HeaderBarStyle : public QProxyStyle { friend class HeaderBar; static HeaderBarStyle *getStyle(); HeaderBarStyle() {} int pixelMetric(PixelMetric metric, const QStyleOption *option = nullptr, const QWidget *widget = nullptr) const override; void drawComplexControl(ComplexControl control, const QStyleOptionComplex *option, QPainter *painter, const QWidget *widget = nullptr) const override; void drawPrimitive(PrimitiveElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget = nullptr) const override; }; #endif // HEADERBAR_H ukui-notebook/src/listViewModeDelegate.h0000644000175000017500000000537014201136534017303 0ustar fengfeng/* * Copyright (C) 2020 Tianjin KYLIN Information Technology Co., Ltd. * * This program is free software; you can 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, 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 #include class listViewModeDelegate : public QStyledItemDelegate { Q_OBJECT public: listViewModeDelegate(QObject *parent = Q_NULLPTR); enum States{ Normal, Insert, Remove, MoveOut, MoveIn }; void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const Q_DECL_OVERRIDE; QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const Q_DECL_OVERRIDE; public: void setState(States NewState , QModelIndex index); void setAnimationDuration(const int duration); QTimeLine::State animationState(); void setCurrentSelectedIndex(const QModelIndex ¤tSelectedIndex); void setHoveredIndex(const QModelIndex &hoveredIndex); void setRowRightOffset(int rowRightOffset); void setActive(bool isActive); int qcolorToInt(const QColor &color) const; QColor intToQcolor(int &intColor) const; private: mutable QFont m_titleFont; mutable QFont m_titleSelectedFont; mutable QFont m_dateFont; QColor m_titleColor; QColor m_dateColor; QColor m_ActiveColor; QColor m_notActiveColor; QColor m_hoverColor; QColor m_selectColor; QColor m_applicationInactiveColor; QColor m_separatorColor; QColor m_defaultColor; QColor m_noteColor; int m_rowHeight; int m_maxFrame; int m_rowRightOffset; States m_state; bool m_isActive; QString m_timeZone; QTimeLine *m_timeLine; QModelIndex m_animatedIndex; QModelIndex m_currentSelectedIndex; QModelIndex m_hoveredIndex; private: void paintBackground(QPainter* painter, const QStyleOptionViewItem &option, const QModelIndex &index)const; void paintLabels(QPainter* painter, const QStyleOptionViewItem &option, const QModelIndex &index) const; QString parseDateTime(const QDateTime& dateTime) const; signals: void update(const QModelIndex &index); }; #endif // LISTVIEWMODEDELEGATE_H ukui-notebook/src/setFontColorPage.cpp0000644000175000017500000001052514201136534017004 0ustar fengfeng/* * Copyright (C) 2020 Tianjin KYLIN Information Technology Co., Ltd. * * This program is free software; you can 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, 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 setupUi(this); initSetup(); } SetFontColor::~SetFontColor() { delete ui; //释放内存 for (int i=0; i < 6;i++) { delete m_listAItem[i]; } } void SetFontColor::paintEvent(QPaintEvent *event) { Q_UNUSED(event); // 系统默认 255 、 248 深色模式 30 34 QStyleOption opt; opt.init(this); QPainter p(this); p.setBrush(opt.palette.color(QPalette::Base)); //qDebug() << "paintEvent" << p.brush().color().value(); //p.setOpacity(0.3); p.setOpacity(0.9); p.setPen(Qt::NoPen); p.setRenderHint(QPainter::Antialiasing); // 反锯齿; p.drawRoundedRect(opt.rect,6,6); style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this); } void SetFontColor::setColor() { m_color[0] = QString("background:%1;").arg(SetFontColor::KY_BLUE); m_color[1] = QString("background:%1;").arg(SetFontColor::KY_RED); m_color[2] = QString("background:%1;").arg(SetFontColor::KY_GREEN); m_color[3] = QString("background:%1;").arg(SetFontColor::KY_ORANGE); m_color[4] = QString("background:%1;").arg(SetFontColor::KY_PURPLE); //监听主题改变 const QByteArray id(THEME_QT_SCHEMA); if(QGSettings::isSchemaInstalled(id)){ QGSettings *styleSettings = new QGSettings(id, QByteArray(), this); QString style = styleSettings->get(MODE_QT_KEY).toString(); if(style == "ukui-default" || style == "ukui-white" || style == "ukui-light" || style == "ukui"){ m_color[5]="background:rgba(0,0,0,1);"; }else if(style == "ukui-dark" || style == "ukui-black"){ m_color[5]="background:rgba(255,255,255,1);"; } connect(styleSettings, &QGSettings::changed, this, [=](const QString &key){ if (key == "styleName"){ QString currentTheme = styleSettings->get(MODE_QT_KEY).toString(); if(currentTheme == "ukui-default" || currentTheme == "ukui-white" || currentTheme == "ukui-light" || currentTheme == "ukui"){ m_color[5]="background:rgba(0,0,0,1);"; m_listPage[5]->ui->label->setStyleSheet(m_color[5]+"border-radius:3px;"); }else if(currentTheme == "ukui-dark" || currentTheme == "ukui-black"){ m_color[5]="background:rgba(255,255,255,1);"; m_listPage[5]->ui->label->setStyleSheet(m_color[5]+"border-radius:3px;"); } } }); } } void SetFontColor::initSetup() { setColor(); setWindowFlags(Qt::FramelessWindowHint | Qt::Popup); setAttribute(Qt::WA_TranslucentBackground); ui->listWidget->clear(); ui->listWidget->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); ui->listWidget->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); ui->listWidget->setSelectionMode(QAbstractItemView::NoSelection); for(int n=0; n<6; n++){ m_listAItem[n] = new QListWidgetItem; m_listAItem[n]->setSizeHint(QSize(28,27)); m_listPage[n] = new paletteButton(this); m_listPage[n]->resize(QSize(28,23)); m_listPage[n]->ui->label->setStyleSheet(m_color[n]+"border-radius:3px;"); ui->listWidget->addItem(m_listAItem[n]); ui->listWidget->setItemWidget(m_listAItem[n],m_listPage[n]); } } ukui-notebook/src/closebutton.pri0000644000175000017500000000016114174170620016135 0ustar fengfengSOURCES += \ $$PWD/CloseButton/closebutton.cpp \ HEADERS += \ $$PWD/CloseButton/closebutton.h \ ukui-notebook/src/main.cpp0000644000175000017500000001226714174170620014522 0ustar fengfeng/* * Copyright (C) 2020 Tianjin KYLIN Information Technology Co., Ltd. * * This program is free software; you can 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, 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 #include //#include //SDK统一格式日志 #ifdef KYDEBUG #include #endif /*! * \brief myMessageOutput * 日志打印输出 */ void myMessageOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg) { // 加锁 static QMutex mutex; mutex.lock(); QByteArray localMsg = msg.toLocal8Bit(); QString strMsg(""); switch(type) { case QtDebugMsg: strMsg = QString("Debug "); break; case QtWarningMsg: strMsg = QString("Warning "); break; case QtCriticalMsg: strMsg = QString("Critical "); break; case QtFatalMsg: strMsg = QString("Fatal "); break; case QtInfoMsg: strMsg = QString("Info "); break; } // 设置输出信息格式 QString strDateTime = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss ddd"); //QString strMessage = QString("[Message]: %1 [File]: %2 [Line]: %3 [Function]: %4 [DateTime]: %5") // .arg(localMsg.constData()).arg(context.file).arg(context.line).arg(context.function).arg(strDateTime); QString strMessage = QString("[DateTime]: %1 [Message]: %2 [Line]: %3 [Function]: %4") .arg(strDateTime).arg(localMsg.constData()).arg(context.line).arg(context.function); // 输出信息至文件中(读写、追加形式) QString url_filepath = QStandardPaths::writableLocation(QStandardPaths::HomeLocation) + "/.config/kylin-note/output.log"; QFile file(url_filepath); file.open(QIODevice::ReadWrite | QIODevice::Append); QTextStream stream(&file); stream << strMsg << strMessage << "\r\n"; file.flush(); file.close(); // 解锁 mutex.unlock(); } int getScreenWidth() { Display *disp = XOpenDisplay(NULL); Screen *scrn = DefaultScreenOfDisplay(disp); if (NULL == scrn) { return 0; } int width = scrn->width; if (NULL != disp) { XCloseDisplay(disp); } return width; } /*! * \brief main */ int main(int argc, char *argv[]) { //自定义消息处理 //qInstallMessageHandler(myMessageOutput); //SDK统一格式日志 #ifdef KYDEBUG initUkuiLog4qt("ukui-notebook"); #endif if (getScreenWidth() > 2560) { #if (QT_VERSION >= QT_VERSION_CHECK(5, 6, 0)) QApplication::setAttribute(Qt::AA_EnableHighDpiScaling); QApplication::setAttribute(Qt::AA_UseHighDpiPixmaps); #endif } SingleApplication a(argc, argv); a.setWindowIcon(QIcon::fromTheme("kylin-notebook")); a.setApplicationVersion ("1.0.0"); QCommandLineParser parser; Utils::setCLIName(parser); /* 处理命令行参数。 除了解析选项(如parse())外,此函数还处理内置选项并处理错误。 如果调用了addVersionOption,则内置选项为--version,如果调用了addHelpOption,则为--help --help-all。 当调用这些选项之一时,或者当发生错误(例如,传递了未知选项)时,当前进程将使用exit()函数停止。 */ parser.process(a); Widget w; if(!a.isRunning()){ a.w = &w; w.setProperty("useSystemStyleBlur", true); // 添加窗管协议 MotifWmHints hints; hints.flags = MWM_HINTS_FUNCTIONS|MWM_HINTS_DECORATIONS; hints.functions = MWM_FUNC_ALL; hints.decorations = MWM_DECOR_BORDER; XAtomHelper::getInstance()->setWindowMotifHint(w.winId(), hints); //w.setAttribute(Qt::WA_TranslucentBackground); //KWindowEffects::enableBlurBehind(w.winId(),true); QObject::connect(&a, SIGNAL(messageReceived(/*const QString&*/)), &w, SLOT(sltMessageReceived(/*const QString&*/))); if (QApplication::arguments().length() > 1) { if (QApplication::arguments().at(1) == "--show") { QString arg = QApplication::arguments().at(2); qDebug() << "main" << arg.toInt(); w.openMemoWithId(arg.toInt()); } } return a.exec(); } else { if (QApplication::arguments().length() > 1) { if (QApplication::arguments().at(1) == "--show") { QString arg = QApplication::arguments().at(2); qDebug() << "main" << arg.toInt(); w.openMemoWithId(arg.toInt()); } } } return 0; } ukui-notebook/src/editPage.cpp0000755000175000017500000011542514201136534015320 0ustar fengfeng/* * Copyright (C) 2020 Tianjin KYLIN Information Technology Co., Ltd. * * This program is free software; you can 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, 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 #include #include #include //#include #include #include #include #include #include // Necessary for closeApplication() #include #include "widget.h" #include "ui_widget.h" #include "editPage.h" #include "ui_editPage.h" #include "utils/xatom-helper.h" extern void qt_blurImage(QImage &blurImage, qreal radius, bool quality, int transposed); EditPage::EditPage(Widget *page, int noteId, QWidget *parent) : QWidget(parent), ui(new Ui::Edit_page), m_editColor(0, 0, 0), m_noteId(noteId), m_lastBlockList(0), m_mousePressed(false), m_defaultFontColorChanged(false), m_notebook(page), m_colorPage(new SelectColor(m_notebook, this)), m_setSizePage(new SetFontSize(m_notebook)), m_setColorFontPage(new SetFontColor(m_notebook)), m_isFullscreen(false), m_isInsImg(false) { ui->setupUi(this); initSetup(); listenToGsettings(); slotsSetup(); installEventFilter(this); } EditPage::~EditPage() { delete ui; } void EditPage::paintEvent(QPaintEvent *event) { Q_UNUSED(event); QPainter p(this); p.setRenderHint(QPainter::Antialiasing); // 反锯齿; QPainterPath rectPath; rectPath.addRect(this->rect()); p.fillPath(rectPath, palette().color(QPalette::Base)); } void EditPage::enterEvent(QEvent *event) { Q_UNUSED(event); m_noteHead->hide(); m_noteHeadMenu->show(); } void EditPage::leaveEvent(QEvent *event) { Q_UNUSED(event); if(!m_noteHeadMenu->ui->pushButtonMenu->isActiveWindow() && !m_noteHeadMenu->ui->pushButtonPalette->isActiveWindow()) { m_noteHead->show(); m_noteHeadMenu->hide(); } } bool EditPage::eventFilter(QObject *obj,QEvent *event) { if(obj == this) { if(event->type() == QEvent::Close) { // if (ui->textEdit->document()->isEmpty()) { // qDebug() << "ZDEBUG " << __LINE__ ; // emit isEmptyNote(m_noteId); // } } } return false; } void EditPage::initSetup() { // 标题 this->setWindowTitle(tr("Notes")); // 任务栏图标 //setWindowIcon(QIcon::fromTheme("kylin-notebook")); //setWindowFlags(Qt::FramelessWindowHint); #if (QT_VERSION >= QT_VERSION_CHECK(5, 12, 0)) // 高分屏适配 QApplication::setAttribute(Qt::AA_EnableHighDpiScaling); QApplication::setAttribute(Qt::AA_UseHighDpiPixmaps); #endif // 添加窗管协议 MotifWmHints hints; hints.flags = MWM_HINTS_FUNCTIONS|MWM_HINTS_DECORATIONS; hints.functions = MWM_FUNC_ALL; hints.decorations = MWM_DECOR_BORDER; XAtomHelper::getInstance()->setWindowMotifHint(this->winId(), hints); // 配置按钮 btnSetup(); initColor(); // 获取字体按钮状态 m_fontLabel = new QLabel(this); m_fontBtnLayout = new QVBoxLayout(this); m_fontBtnLayout->addWidget(m_fontLabel); ui->fontSizeBtn->setLayout(m_fontBtnLayout); QFont dateFont; dateFont.setPointSize(11); m_fontLabel->setFont(dateFont); fontChanged(ui->textEdit->font()); m_noteHead = new noteHead(this); m_noteHeadMenu = new noteHeadMenu(this); ui->verticalLayout_3->addWidget(m_noteHead); ui->verticalLayout_3->addWidget(m_noteHeadMenu); m_noteHeadMenu->hide(); ui->textEdit->setFrameShape(QFrame::NoFrame); ui->textEdit->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); // 右键菜单 ui->textEdit->setContextMenuPolicy(Qt::CustomContextMenu); connect(ui->textEdit, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(textRightMenu(QPoint))); // 设置字体大小 m_setSizePage = new SetFontSize(this); m_setSizePage->hide(); // 设置字体颜色 m_setColorFontPage = new SetFontColor(this); m_setColorFontPage->hide(); } void EditPage::btnSetup() { ui->unorderedBtn->setIcon(QIcon::fromTheme("view-list.symbolic")); ui->strikeOutBtn->setIcon(QIcon::fromTheme("format-text-strikethrough-symbolic")); ui->orderedBtn->setIcon(QIcon::fromTheme("ukui-view-list-numbe-symbolic")); ui->insertBtn->setIcon(QIcon::fromTheme("view-list-images.symbolic")); ui->underlineBtn->setIcon(QIcon::fromTheme("format-text-underline-symbolic")); ui->boldBtn->setIcon(QIcon::fromTheme("format-text-bold-symbolic")); ui->italicBtn->setIcon(QIcon::fromTheme("format-text-italic-symbolic")); ui->unorderedBtn->setIconSize(QSize(20, 24)); ui->strikeOutBtn->setIconSize(QSize(20, 17)); ui->orderedBtn->setIconSize(QSize(20, 14)); ui->insertBtn->setIconSize(QSize(20, 24)); ui->underlineBtn->setIconSize(QSize(20, 16)); ui->boldBtn->setIconSize(QSize(20, 17)); ui->italicBtn->setIconSize(QSize(20, 17)); ui->boldBtn->setToolTip(tr("Bold")); ui->italicBtn->setToolTip(tr("Italic")); ui->underlineBtn->setToolTip(tr("Underline")); ui->strikeOutBtn->setToolTip(tr("Strikeout")); ui->unorderedBtn->setToolTip(tr("Unordered")); ui->orderedBtn->setToolTip(tr("Ordered")); ui->fontSizeBtn->setToolTip(tr("Font Size")); ui->styleBtn->setToolTip(tr("Font Color")); ui->insertBtn->setToolTip(tr("InsertPicture")); // 取消按钮默认灰色背景 QPalette palette = ui->boldBtn->palette(); QColor ColorPlaceholderText(255, 255, 255, 0); QBrush brush; brush.setColor(ColorPlaceholderText); palette.setBrush(QPalette::Button, brush); palette.setBrush(QPalette::ButtonText, brush); ui->boldBtn->setPalette(palette); ui->italicBtn->setPalette(palette); ui->underlineBtn->setPalette(palette); ui->strikeOutBtn->setPalette(palette); ui->unorderedBtn->setPalette(palette); ui->orderedBtn->setPalette(palette); ui->insertBtn->setPalette(palette); QPalette palette2 = ui->fontColorBtn->palette(); palette2.setColor(QPalette::Highlight, Qt::transparent); /* 取消按钮高亮 */ ui->fontColorBtn->setPalette(palette2); ui->fontColorBtn->setAttribute(Qt::WA_TransparentForMouseEvents); ui->boldBtn->setCheckable(true); ui->italicBtn->setCheckable(true); ui->underlineBtn->setCheckable(true); ui->strikeOutBtn->setCheckable(true); ui->unorderedBtn->setCheckable(true); ui->orderedBtn->setCheckable(true); ui->fontSizeBtn->setCheckable(false); ui->insertBtn->setCheckable(false); //变更btn的属性,hover态,蓝色变为灰色 #if 1 ui->boldBtn->setProperty("isWindowButton", 0x1); ui->boldBtn->setProperty("useIconHighlightEffect", 0x2); ui->italicBtn->setProperty("isWindowButton", 0x1); ui->italicBtn->setProperty("useIconHighlightEffect", 0x2); ui->underlineBtn->setProperty("isWindowButton", 0x1); ui->underlineBtn->setProperty("useIconHighlightEffect", 0x2); ui->strikeOutBtn->setProperty("isWindowButton", 0x1); ui->strikeOutBtn->setProperty("useIconHighlightEffect", 0x2); ui->unorderedBtn->setProperty("isWindowButton", 0x1); ui->unorderedBtn->setProperty("useIconHighlightEffect", 0x2); ui->orderedBtn->setProperty("isWindowButton", 0x1); ui->orderedBtn->setProperty("useIconHighlightEffect", 0x2); ui->insertBtn->setProperty("isWindowButton", 0x1); ui->insertBtn->setProperty("useIconHighlightEffect", 0x2); #else ui->boldBtn->setProperty("useIconHighlightEffect", true); ui->boldBtn->setProperty("iconHighlightEffectMode", 1); ui->italicBtn->setProperty("useIconHighlightEffect", true); ui->italicBtn->setProperty("iconHighlightEffectMode", 1); ui->underlineBtn->setProperty("useIconHighlightEffect", true); ui->underlineBtn->setProperty("iconHighlightEffectMode", 1); ui->strikeOutBtn->setProperty("useIconHighlightEffect", true); ui->strikeOutBtn->setProperty("iconHighlightEffectMode", 1); ui->unorderedBtn->setProperty("useIconHighlightEffect", true); ui->unorderedBtn->setProperty("iconHighlightEffectMode", 1); ui->orderedBtn->setProperty("useIconHighlightEffect", true); ui->orderedBtn->setProperty("iconHighlightEffectMode", 1); ui->insertBtn->setProperty("useIconHighlightEffect", true); ui->insertBtn->setProperty("iconHighlightEffectMode", 1); #endif } void EditPage::slotsSetup() { connect(m_noteHeadMenu->ui->pushButtonExit, &QPushButton::clicked, this, [=](){ if (ui->textEdit->document()->isEmpty()) { emit isEmptyNote(m_noteId); } this->close(); }); connect(m_noteHeadMenu->m_menuActionDel, &QAction::triggered, this, [=](){ this->close(); requestDel(m_noteId); }); connect(ui->textEdit, &QTextEdit::textChanged, this, &EditPage::textChangedSlot); // 调色板菜单 connect(m_noteHeadMenu->ui->pushButtonPalette, &QPushButton::clicked, this, [=](){ QPointF position = this->pos(); m_colorPage->move(position.x()+30, position.y()+34); m_colorPage->show(); }); // 调色按钮 connect(m_colorPage->paletteWidget->ui->blueBtn, &QPushButton::clicked, this, &EditPage::blueBtnSlot); connect(m_colorPage->paletteWidget->ui->redBtn, &QPushButton::clicked, this, &EditPage::redBtnSlot); connect(m_colorPage->paletteWidget->ui->darkGreenBtn, &QPushButton::clicked, this, &EditPage::darkGreenBtnSlot); connect(m_colorPage->paletteWidget->ui->orangeBtn, &QPushButton::clicked, this, &EditPage::orangeBtnSlot); connect(m_colorPage->paletteWidget->ui->purpleBtn, &QPushButton::clicked, this, &EditPage::purpleBtnSlot); connect(m_colorPage->paletteWidget->ui->goldenBtn, &QPushButton::clicked, this, &EditPage::goldenBtnSlot); connect(m_colorPage->paletteWidget->ui->greyBtn, &QPushButton::clicked, this, &EditPage::greyBtnSlot); connect(m_colorPage->paletteWidget->ui->pinkBtn, &QPushButton::clicked, this, &EditPage::pinkBtnSlot); // 字体颜色大小 connect(m_setSizePage->ui->listWidget, &QListWidget::itemClicked, this, &EditPage::setFontSizeSlot); connect(m_setColorFontPage->ui->listWidget, &QListWidget::itemClicked, this, &EditPage::setFontColorSlot); // 文本格式 connect(ui->boldBtn, &QPushButton::clicked, this, &EditPage::setBoldSlot); connect(ui->italicBtn, &QPushButton::clicked, this, &EditPage::setItalicSlot); connect(ui->underlineBtn, &QPushButton::clicked, this, &EditPage::setUnderlineSlot); connect(ui->strikeOutBtn, &QPushButton::clicked, this, &EditPage::setStrikeOutSlot); connect(ui->unorderedBtn, &QPushButton::clicked, this, &EditPage::setUnorderedListSlot); connect(ui->orderedBtn, &QPushButton::clicked, this, &EditPage::setOrderedListSlot); connect(ui->insertBtn, &QPushButton::clicked, this, &EditPage::insertpicture); connect(ui->textEdit, &QTextEdit::cursorPositionChanged, this, &EditPage::cursorPositionChangedSlot); connect(ui->textEdit, &QTextEdit::currentCharFormatChanged, this, &EditPage::currentCharFormatChangedSlot); connect(ui->fontSizeBtn, &QPushButton::clicked, this, [=](){ QPointF position = this->pos(); m_setSizePage->move(position.x()+227, position.y()+273); QDesktopWidget* desktopWidget = QApplication::desktop(); QRect clientRect = desktopWidget->availableGeometry(); //获取整个屏幕(不包含任务栏)的rect数据 int listHeight = 194; //listwidget 原始高度 int heightListCrossPeny = listHeight + m_setSizePage->pos().y() - clientRect.height(); //listwidget 超出任务栏显示的高度, 不超出时, 该数字为负数 if(heightListCrossPeny > 0) //listwidget 超出任务栏显示 { int fontButtonHeight = 27; //每个fontbutton高度,当前为27 int keepNum = listHeight - heightListCrossPeny; //listwidget 未超出任务栏显示的高度 int realNum = keepNum - (keepNum % fontButtonHeight); //最后,实际显示的高度,应该是每个fontbutton高度(27)的整数倍,小于27时,为0 //listWidget 向下显示,高度不够,此时,显示到set_size_page的上面 if(realNum == 0){ m_setSizePage->move(position.x()+227, position.y()+53); m_setSizePage->resize(30,194); m_setSizePage->ui->listWidget->resize(30,194); //set_size_page->ui->listWidget->sortItems(Qt::DescendingOrder); //倒序,但是数据会混乱,暂缓 } else{ m_setSizePage->resize(30, realNum); m_setSizePage->ui->listWidget->resize(30, realNum); } } else { m_setSizePage->move(position.x()+227, position.y()+273); m_setSizePage->resize(30,194); m_setSizePage->ui->listWidget->resize(30,194); } m_setSizePage->show(); }); connect(ui->styleBtn, &QPushButton::clicked, this, &EditPage::onFontColorClicked); connect(m_noteHeadMenu, ¬eHeadMenu::requestUpdateMenuIcon, this, [=](){ KWindowInfo info(this->winId(), NET::WMState); bool b = info.state() & NET::KeepAbove; if(b){ m_noteHeadMenu->m_topAction->setIcon(QPixmap(":/image/1x/select.png")); } else{ m_noteHeadMenu->m_topAction->setIcon(QPixmap("")); } }); connect(m_noteHeadMenu, ¬eHeadMenu::requestUpdateMenuIcon, this, [=](){ KWindowInfo info(this->winId(), NET::WMState); bool b = info.state() & NET::KeepAbove; if(b){ m_noteHeadMenu->m_topAction->setIcon(QPixmap(":/image/1x/select.png")); } else{ m_noteHeadMenu->m_topAction->setIcon(QPixmap("")); } }); connect(m_noteHeadMenu, ¬eHeadMenu::requestTopMost, this, [=](){ KWindowInfo info(this->winId(), NET::WMState); bool b = info.state() & NET::KeepAbove; if(b) { setWindowStatusClear(); } else { setWindowKeepAbove(); } }); } void EditPage::mergeFormatOnWordOrSelection(const QTextCharFormat &format) { QTextCursor cursor = ui->textEdit->textCursor(); if (!cursor.hasSelection()) { cursor.select(QTextCursor::WordUnderCursor); } cursor.mergeCharFormat(format); ui->textEdit->mergeCurrentCharFormat(format); ui->textEdit->setFocus(Qt::TabFocusReason); } void EditPage::fontChanged(const QFont &f) { qDebug() << "font Changed" << f.pointSize() << f.bold(); m_setSizePage->ui->listWidget->setCurrentRow(f.pointSize() - 10); m_fontLabel->setText(QString::number(f.pointSize())); if(f.pointSize() < 10 ) { m_fontLabel->setText(QString::number(10)); } else { m_fontLabel->setText(QString::number(f.pointSize())); } ui->boldBtn->setChecked(f.bold()); ui->italicBtn->setChecked(f.italic()); ui->underlineBtn->setChecked(f.underline()); ui->strikeOutBtn->setChecked(f.strikeOut()); if (ui->textEdit->textCursor().currentList()) { QTextListFormat lfmt = ui->textEdit->textCursor().currentList()->format(); if (lfmt.style() == QTextListFormat::ListDisc) { ui->unorderedBtn->setChecked(true); ui->orderedBtn->setChecked(false); } else if (lfmt.style() == QTextListFormat::ListDecimal) { ui->unorderedBtn->setChecked(false); ui->orderedBtn->setChecked(true); } else { ui->unorderedBtn->setChecked(false); ui->orderedBtn->setChecked(false); } } else { ui->unorderedBtn->setChecked(false); ui->orderedBtn->setChecked(false); } } void EditPage::fontColorChanged(const QColor &c) { qDebug() << "fontColorChanged" << c.name(); QString _Stylesheet; QString _BgColor; _BgColor = c.name(); if (_BgColor == "#000000" || _BgColor == "#FFFFFF" || c == QColor()) { m_defaultFontColorChanged = false; if (_BgColor == "#000000" && QGSettings::isSchemaInstalled(THEME_QT_SCHEMA)) { QByteArray qtThemeID(THEME_QT_SCHEMA); auto qtThemeSetting = new QGSettings(qtThemeID,QByteArray(),this); QString style = qtThemeSetting->get("styleName").toString(); if(style == "ukui-dark") { _BgColor = "#FFFFFF"; } else if(style == "ukui-default" || style == "ukui-white" || style == "ukui-light"){ _BgColor = "#000000"; } } } _Stylesheet = "background-color: %1;"; _Stylesheet = _Stylesheet.arg(_BgColor); ui->fontColorBtn->setStyleSheet(_Stylesheet +"border-radius:3px;"); } void EditPage::list(bool checked, QTextListFormat::Style style) { QTextCursor cursor = ui->textEdit->textCursor(); cursor.beginEditBlock(); if (!checked) { qDebug() << "unchecked"; QTextBlockFormat obfmt = cursor.blockFormat(); QTextBlockFormat bfmt; bfmt.setIndent(obfmt.indent()); cursor.setBlockFormat(bfmt); // QTextDocument *document = ui->textEdit->document(); // document->setIndentWidth(0); } else { qDebug() << "checked"; QTextCharFormat charFormat = cursor.charFormat(); qDebug() << charFormat.fontPointSize() << cursor.selectedText() ; qDebug() << cursor.anchor() << cursor.position(); QTextListFormat listFmt; if (cursor.currentList()) { listFmt = cursor.currentList()->format(); } listFmt.setStyle(style); // QTextDocument *document = ui->textEdit->document(); // document->setIndentWidth(15); cursor.createList(listFmt); } cursor.endEditBlock(); } /*! * \brief Edit_page::listenToGsettings * */ void EditPage::listenToGsettings() { // 监听主题改变 const QByteArray id(THEME_QT_SCHEMA); if (QGSettings::isSchemaInstalled(id)) { QGSettings *styleSettings = new QGSettings(id, QByteArray(), this); auto style = styleSettings->get("styleName").toString(); //if (ui->textEdit->document()->isEmpty()) { if (style == "ukui-default" || style == "ukui-white" || style == "ukui-light" || style == "ukui") { ui->fontColorBtn->setStyleSheet("background-color: black;" "border-radius:3px;"); } else if (style == "ukui-dark" || style == "ukui-black") { ui->fontColorBtn->setStyleSheet("background-color: white;" "border-radius:3px;"); } //} connect(styleSettings, &QGSettings::changed, this, [=](const QString &key){ if (/*ui->textEdit->document()->isEmpty() && */!m_defaultFontColorChanged) { if (key == "styleName") { QString currentTheme = styleSettings->get(MODE_QT_KEY).toString(); if (currentTheme == "ukui-default" || currentTheme == "ukui-white" || currentTheme == "ukui-light" || currentTheme == "ukui") { ui->fontColorBtn->setStyleSheet("background-color: black;" "border-radius:3px;"); ui->frame->setStyleSheet("background-color:rgb(217, 217, 217)"); ui->frame_2->setStyleSheet("background-color:rgb(217, 217, 217)"); } else if (currentTheme == "ukui-dark" || currentTheme == "ukui-black") { ui->fontColorBtn->setStyleSheet("background-color: white;" "border-radius:3px;"); ui->frame->setStyleSheet("background-color:rgb(77, 77, 77)"); ui->frame_2->setStyleSheet("background-color:rgb(77, 77, 77)"); } } } }); } } /**************** Slots *******************/ void EditPage::cursorPositionChangedSlot() { qDebug() << "cursorPositionChangedSlot"; QTextList *l = ui->textEdit->textCursor().currentList(); if (m_lastBlockList && (l == m_lastBlockList || (l != 0 && m_lastBlockList != 0 && l->format().style() == m_lastBlockList->format().style()))) { return; } m_lastBlockList = l; if (l) { QTextListFormat lfmt = l->format(); if (lfmt.style() == QTextListFormat::ListDisc) { ui->unorderedBtn->setChecked(true); ui->orderedBtn->setChecked(false); } else if (lfmt.style() == QTextListFormat::ListDecimal) { ui->unorderedBtn->setChecked(false); ui->orderedBtn->setChecked(true); } else { ui->unorderedBtn->setChecked(false); ui->orderedBtn->setChecked(false); } } else { ui->unorderedBtn->setChecked(false); ui->orderedBtn->setChecked(false); } } void EditPage::currentCharFormatChangedSlot(const QTextCharFormat &format) { qDebug() << "currentCharFormatChangedSlot"; fontChanged(format.font()); // fontColorChanged((format.foreground().isOpaque()) ? format.foreground().color() : QColor()); fontColorChanged(format.foreground().color()); } void EditPage::textChangedSlot() { qDebug() << "emit textchange" << "note id" << m_noteId << this->m_id; emit texthasChanged(m_noteId, this->m_id); } //textedit右键菜单 void EditPage::textRightMenu(QPoint) { QMenu *m_rightMenu = new QMenu; //定义action QAction *undoact = new QAction(tr("undo")); QAction *redoact = new QAction(tr("redo")); QAction *cutact = new QAction(tr("cut")); QAction *copyact = new QAction(tr("copy")); QAction *pasteact = new QAction(tr("paste")); QAction *textfornew = new QAction(tr("copy to newpage")); undoact->setIcon(QIcon::fromTheme("edit-undo")); redoact->setIcon(QIcon::fromTheme("edit-redo")); cutact->setIcon(QIcon::fromTheme("edit-cut")); copyact->setIcon(QIcon::fromTheme("edit-copy")); pasteact->setIcon(QIcon::fromTheme("edit-paste")); // textfornew->setIcon(QIcon::fromTheme("add-files-to-archive")); textfornew->setIcon(QIcon(":/image/1x/copy_to_new_note.png")); //定义action end //action使能与非使能 connect(ui->textEdit->document(), SIGNAL(undoAvailable(bool)), undoact, SLOT(setEnabled(bool))); connect(ui->textEdit->document(), SIGNAL(redoAvailable(bool)), redoact, SLOT(setEnabled(bool))); undoact->setEnabled(ui->textEdit->document()->isUndoAvailable()); redoact->setEnabled(ui->textEdit->document()->isRedoAvailable()); cutact->setEnabled(!ui->textEdit->textCursor().selectedText().isEmpty()); copyact->setEnabled(!ui->textEdit->textCursor().selectedText().isEmpty()); pasteact->setEnabled(!QApplication::clipboard()->text().isEmpty()); connect(QApplication::clipboard(), &QClipboard::dataChanged, this, [=](){ pasteact->setEnabled(!QApplication::clipboard()->text().isEmpty()); }); textfornew->setEnabled(!ui->textEdit->textCursor().selectedText().isEmpty()); //action使能与非使能 end //action绑定槽函数 connect(undoact, SIGNAL(triggered(bool)), ui->textEdit, SLOT(undo())); connect(redoact, SIGNAL(triggered(bool)), ui->textEdit, SLOT(redo())); connect(cutact, SIGNAL(triggered()), ui->textEdit, SLOT(cut())); connect(copyact, SIGNAL(triggered()), ui->textEdit, SLOT(copy())); connect(pasteact, SIGNAL(triggered(bool)), ui->textEdit, SLOT(paste())); connect(textfornew, SIGNAL(triggered()), this, SLOT(textForNewEditpageSlot())); //action绑定槽函数 end //action添加到menu m_rightMenu->addAction(undoact); m_rightMenu->addAction(redoact); m_rightMenu->addSeparator(); // 添加分割线 m_rightMenu->addAction(cutact); m_rightMenu->addAction(copyact); m_rightMenu->addAction(pasteact); m_rightMenu->addSeparator(); // 添加分割线 m_rightMenu->addAction(textfornew); //action添加到menu end m_rightMenu->move (cursor().pos()); m_rightMenu->show(); } //拷贝选中内容到新便签页 void EditPage::textForNewEditpageSlot() { if(!ui->textEdit->textCursor().selectedText().isEmpty()) { ui->textEdit->copy(); emit textForNewEditpage(); } } // 加粗 void EditPage::setBoldSlot() { qDebug() << "setBoldSlot"; QTextCharFormat fmt; fmt.setFontWeight(ui->boldBtn->isCheckable() ? QFont::Bold : QFont::Normal); QTextCursor cursor = ui->textEdit->textCursor(); if (cursor.charFormat().fontWeight() == QFont::Bold) { qDebug() << "current cursor charFormat QFont::Bold"; fmt.setFontWeight(QFont::Normal); ui->textEdit->mergeCurrentCharFormat(fmt); } else { qDebug() << "current cursor charFormat QFont::Normal"; fmt.setFontWeight(QFont::Bold); ui->textEdit->mergeCurrentCharFormat(fmt); } } // 斜体 void EditPage::setItalicSlot() { qDebug()<<"-------setItalicSlot------------"; QTextCharFormat fmt; fmt.setFontItalic(ui->italicBtn->isCheckable());// ? QFont::StyleItalic : QFont::Normal); // mergeFormatOnWordOrSelection(fmt); QTextCursor cursor = ui->textEdit->textCursor(); if (cursor.charFormat().fontItalic()) { // return boolProperty(FontItalic) fmt.setFontItalic(QFont::StyleNormal); ui->textEdit->mergeCurrentCharFormat(fmt); } else { fmt.setFontItalic(QFont::StyleItalic); ui->textEdit->mergeCurrentCharFormat(fmt); } } // 划线 void EditPage::setUnderlineSlot() { qDebug() << "setUnderlineSlot"; QTextCharFormat fmt; fmt.setFontUnderline(ui->underlineBtn->isCheckable());// ? QFont::UnderlineResolved : QFont::Normal ); // mergeFormatOnWordOrSelection(fmt); QTextCursor cursor = ui->textEdit->textCursor(); if (cursor.charFormat().fontUnderline()) { // fmt.setFontUnderline(QFont::StyleNormal); ui->textEdit->mergeCurrentCharFormat(fmt); } else { ui->textEdit->mergeCurrentCharFormat(fmt); } } // 除线 void EditPage::setStrikeOutSlot() { qDebug() << "setStrikeOutSlot"; QTextCharFormat fmt; fmt.setFontStrikeOut(ui->strikeOutBtn->isCheckable());// ? QFont::StrikeOutResolved : QFont::Normal ); // mergeFormatOnWordOrSelection(fmt); QTextCursor cursor = ui->textEdit->textCursor(); if (cursor.charFormat().fontStrikeOut()) { fmt.setFontStrikeOut(QFont::StyleNormal); ui->textEdit->mergeCurrentCharFormat(fmt); } else { ui->textEdit->mergeCurrentCharFormat(fmt); } } // 无序列表 void EditPage::setUnorderedListSlot(bool checked) { qDebug() << "setUnorderedListSlot" << checked; if (checked) { ui->orderedBtn->setChecked(false); qDebug() << "show list set false" << checked; qDebug() << "text_edit_page->ui->orderedBtn is checked ? :" << ui->orderedBtn->isChecked(); } list(checked, QTextListFormat::ListDisc); qDebug() << "text_edit_page->ui->orderedBtn is checked ? :" << ui->orderedBtn->isChecked(); } // 序列表 void EditPage::setOrderedListSlot(bool checked) { qDebug() << "show num list"; if (checked) { ui->unorderedBtn->setChecked(false); } list(checked, QTextListFormat::ListDecimal); } // 字号 void EditPage::setFontSizeSlot() { qDebug() << "setFontSizeSlot"; int num = m_setSizePage->ui->listWidget->currentRow(); m_fontLabel->setText(QString::number(num+10)); m_setSizePage->close(); QTextCharFormat fmt; fmt.setFontPointSize(num+10); mergeFormatOnWordOrSelection(fmt); } // 调色板 void EditPage::initColor() { m_colorNum[0] = QColor(SetFontColor::KY_BLUE); m_colorNum[1] = QColor(SetFontColor::KY_RED); m_colorNum[2] = QColor(SetFontColor::KY_GREEN); m_colorNum[3] = QColor(SetFontColor::KY_ORANGE); m_colorNum[4] = QColor(SetFontColor::KY_PURPLE); } void EditPage::setFontColorSlot(QListWidgetItem *item) { qDebug() << "Sender" << sender(); qDebug() << "Item" << item; int num = m_setColorFontPage->ui->listWidget->currentRow(); QTextCharFormat fmt; if (num != 5) { m_defaultFontColorChanged = true; fmt.setForeground(m_colorNum[num]); ui->textEdit->mergeCurrentCharFormat(fmt); } else { m_defaultFontColorChanged = false; fmt.setForeground(palette().color(QPalette::Text)); // fmt.clearForeground(); ui->textEdit->mergeCurrentCharFormat(fmt); } m_setColorFontPage->close(); } void EditPage::blueBtnSlot() { QColor color((PaletteWidget::KY_BLUE)); m_editColor = color; emit colorhasChanged(m_editColor, m_noteId); m_noteHead->colorWidget = color; m_noteHeadMenu->colorWidget = color; update(); } void EditPage::redBtnSlot() { QColor color((PaletteWidget::KY_RED)); m_editColor = color; emit colorhasChanged(m_editColor, m_noteId); m_noteHead->colorWidget = color; m_noteHeadMenu->colorWidget = color; update(); } void EditPage::darkGreenBtnSlot() { QColor color(PaletteWidget::KY_GREEN); m_editColor = color; emit colorhasChanged(m_editColor, m_noteId); m_noteHead->colorWidget = color; m_noteHeadMenu->colorWidget = color; update(); } void EditPage::orangeBtnSlot() { QColor color(PaletteWidget::KY_ORANGE); m_editColor = color; emit colorhasChanged(m_editColor, m_noteId); m_noteHead->colorWidget = color; m_noteHeadMenu->colorWidget = color; update(); } void EditPage::purpleBtnSlot() { QColor color(PaletteWidget::KY_PURPLE); m_editColor = color; emit colorhasChanged(m_editColor, m_noteId); m_noteHead->colorWidget = color; m_noteHeadMenu->colorWidget = color; update(); } void EditPage::goldenBtnSlot() { QColor color(PaletteWidget::KY_YELLOW); m_editColor = color; emit colorhasChanged(m_editColor, m_noteId); m_noteHead->colorWidget = color; m_noteHeadMenu->colorWidget = color; update(); } void EditPage::greyBtnSlot() { QColor color(PaletteWidget::KY_GREY); m_editColor = color; emit colorhasChanged(m_editColor, m_noteId); m_noteHead->colorWidget = color; m_noteHeadMenu->colorWidget = color; update(); } void EditPage::lightGreenBtnSlot() { m_editColor = QColor(110, 207, 67); emit colorhasChanged(m_editColor, m_noteId); m_noteHead->colorWidget = QColor(110, 207, 67); m_noteHeadMenu->colorWidget = QColor(110, 207, 67); update(); } void EditPage::yellowBtnSlot() { m_editColor = QColor(144, 101, 255); emit colorhasChanged(m_editColor, m_noteId); m_noteHead->colorWidget = QColor(144, 101, 255); m_noteHeadMenu->colorWidget = QColor(144, 101, 255); update(); } void EditPage::pinkBtnSlot() { QColor color(PaletteWidget::KY_PINK); m_editColor = color; emit colorhasChanged(m_editColor, m_noteId); m_noteHead->colorWidget = color; m_noteHeadMenu->colorWidget = color; update(); } void EditPage::defaultBtnSlot() { if (m_notebook->m_isThemeChanged) { qDebug() << "白色便签头"; m_editColor = QColor(255, 255, 255); m_noteHead->colorWidget = QColor(255, 255, 255); m_noteHeadMenu->colorWidget = QColor(255, 255, 255); m_noteHeadMenu->ui->pushButtonExit->setIcon(QPixmap(":/image/1x/close_block.png")); m_noteHeadMenu->ui->pushButtonExit->setIconSize(QSize(20, 20)); m_noteHeadMenu->ui->pushButtonMenu->setIcon(QPixmap(":/image/1x/more_block.png")); m_noteHeadMenu->ui->pushButtonMenu->setIconSize(QSize(20, 20)); m_noteHeadMenu->ui->pushButtonPalette->setIcon(QPixmap(":/image/1x/more_block.png")); m_noteHeadMenu->ui->pushButtonPalette->setIconSize(QSize(20, 20)); QString _Stylesheet; QString _BgColor; _BgColor = m_editColor.name(); _Stylesheet = "background-color: %1;"; _Stylesheet = _Stylesheet.arg(_BgColor); m_noteHeadMenu->ui->pushButtonExit->setStyleSheet(_Stylesheet); m_noteHeadMenu->ui->pushButtonMenu->setStyleSheet(_Stylesheet); m_noteHeadMenu->ui->pushButtonPalette->setStyleSheet(_Stylesheet); } else { qDebug() << "黑色便签头"; m_editColor = QColor(0, 0, 0); m_noteHead->colorWidget = QColor(0, 0, 0); m_noteHeadMenu->colorWidget = QColor(0, 0, 0); m_noteHeadMenu->ui->pushButtonExit->setIcon(QPixmap(":/image/1x/close_block.png")); m_noteHeadMenu->ui->pushButtonExit->setIconSize(QSize(20, 20)); m_noteHeadMenu->ui->pushButtonMenu->setIcon(QPixmap(":/image/1x/more_block.png")); m_noteHeadMenu->ui->pushButtonMenu->setIconSize(QSize(20, 20)); m_noteHeadMenu->ui->pushButtonPalette->setIcon(QPixmap(":/image/1x/more_block.png")); m_noteHeadMenu->ui->pushButtonPalette->setIconSize(QSize(20, 20)); QString _Stylesheet; QString _BgColor; QString _Color; _BgColor = m_editColor.name(); _Color = QColor(19, 20, 20, 0).name(); _Stylesheet = "background-color: %1; color: %2;"; _Stylesheet = _Stylesheet.arg(_BgColor).arg(_Color); m_noteHeadMenu->ui->pushButtonExit->setStyleSheet(_Stylesheet); m_noteHeadMenu->ui->pushButtonMenu->setStyleSheet(_Stylesheet); m_noteHeadMenu->ui->pushButtonPalette->setStyleSheet(_Stylesheet); } emit colorhasChanged(m_editColor, m_noteId); update(); } void EditPage::showFullScreenSlot() { if (!m_isFullscreen) { this->showFullScreen(); m_isFullscreen = true; } else { this->showNormal(); m_isFullscreen = false; } } void EditPage::setWindowKeepAbove() { KWindowSystem::setState(this->winId(), NET::KeepAbove); } void EditPage::setWindowStatusClear() { KWindowSystem::clearState(this->winId(), NET::KeepAbove); } #if 0 void EditPage::setStayOnTopSlot(bool b) { //m_ignoreShowHideEvents = true; bool visible = isVisible(); QPoint old_pos = pos(); Display *display = QX11Info::display(); XEvent event; event.xclient.type = ClientMessage; event.xclient.serial = 0; event.xclient.send_event = True; event.xclient.display = display; event.xclient.window = winId(); event.xclient.message_type = XInternAtom(display, "_NET_WM_STATE", False); event.xclient.format = 32; event.xclient.data.l[0] = b; event.xclient.data.l[1] = XInternAtom(display, "_NET_WM_STATE_ABOVE", False); event.xclient.data.l[2] = 0; event.xclient.data.l[3] = 0; event.xclient.data.l[4] = 0; XSendEvent(display, DefaultRootWindow(display), False, SubstructureRedirectMask|SubstructureNotifyMask, &event); move(old_pos); if (visible) { show(); } //m_ignoreShowHideEvents = false; } #endif void EditPage::dropImage(const QImage& image, const QString& format) { QByteArray bytes; QBuffer buffer(&bytes); buffer.open(QIODevice::WriteOnly); image.save(&buffer, format.toLocal8Bit().data()); buffer.close(); QByteArray base64 = bytes.toBase64(); QByteArray base64l; for (int i=0; itextEdit->textCursor(); if(cursor.atStart()) { m_isInsImg = true; } QTextImageFormat imageFormat; imageFormat.setWidth ( image.width() ); imageFormat.setHeight ( image.height() ); imageFormat.setName ( QString("data:image/%1;base64,%2") .arg(QString("%1.%2").arg(rand()).arg(format)) .arg(base64l.data()) ); cursor.insertImage ( imageFormat ); } void EditPage::insertpicture() { QSettings s; QString attdir = s.value("general/filedialog-path").toString(); QString file = QFileDialog::getOpenFileName(this, tr("Select an image"), attdir, tr("JPEG (*.jpg);; GIF (*.gif);; PNG (*.png);; BMP (*.bmp);; All (*)")); QImage image = QImageReader(file).read(); dropImage(image, QFileInfo(file).suffix().toUpper().toLocal8Bit().data()); } void EditPage::setHints() { // 添加窗管协议 MotifWmHints hints; hints.flags = MWM_HINTS_FUNCTIONS|MWM_HINTS_DECORATIONS; hints.functions = MWM_FUNC_ALL; hints.decorations = MWM_DECOR_BORDER; XAtomHelper::getInstance()->setWindowMotifHint(this->winId(), hints); } void EditPage::defaultTextColorSlot() { QPalette pal; m_editColor = pal.text().color(); emit colorhasChanged(m_editColor, m_noteId); m_noteHead->colorWidget = m_editColor; m_noteHeadMenu->colorWidget = m_editColor; update(); } void EditPage::onFontColorClicked() { QPointF position = this->pos(); QSize size = this->size(); qDebug () << "Current size:" << size; m_setColorFontPage->move(position.x()+size.width() - 168 - 8 , position.y() + size.height() - 70); //m_setColorFontPage->resize(300,30); //m_setColorFontPage->ui->listWidget->resize(300,30); m_setColorFontPage->show(); } ukui-notebook/src/README.md0000644000175000017500000000001414174170620014334 0ustar fengfeng# kylinNote ukui-notebook/src/noteExitWindow.h0000644000175000017500000000246414174170620016230 0ustar fengfeng/* * Copyright (C) 2020 Tianjin KYLIN Information Technology Co., Ltd. * * This program is free software; you can 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, 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 #include #include #include class Widget; namespace Ui { class noteExitWindow; } class noteExitWindow : public QDialog { Q_OBJECT public: explicit noteExitWindow(Widget* page, QWidget *parent=nullptr); ~noteExitWindow(); void exitImmediate(); protected: void paintEvent(QPaintEvent*); private slots: void on_pushButton_clicked(); void on_pushButton_2_clicked(); private: Ui::noteExitWindow *ui; Widget* pNotebook; signals: void requestSetNoteNull(); }; #endif // NOTEEXITWINDOW_H ukui-notebook/src/singleApplication.cpp0000644000175000017500000000654014174170620017240 0ustar fengfeng/* * Copyright (C) 2020 Tianjin KYLIN Information Technology Co., Ltd. * * This program is free software; you can 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, 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 #include #define TIME_OUT (500) // 500ms SingleApplication::SingleApplication(int &argc, char **argv) : QApplication(argc, argv) , w(NULL) , _isRunning(false) , _localServer(NULL) { // 取应用程序名作为LocalServer的名字 _serverName = QFileInfo(QCoreApplication::applicationFilePath()).fileName() + QLatin1String(getenv("DISPLAY")); _initLocalConnection(); } /*! * \brief SingleApplication::isRunning * 检查是否已經有一个实例在运行, true - 有实例运行, false - 没有实例运行 */ bool SingleApplication::isRunning() { return _isRunning; } /*! * \brief SingleApplication::_newLocalConnection * 通过socket通讯实现程序单实例运行,监听到新的连接时触发该函数 */ void SingleApplication::_newLocalConnection() { QLocalSocket *socket = _localServer->nextPendingConnection(); emit messageReceived(/*message*/); //### (might take a long time to return) if(socket) { socket->waitForReadyRead(2*TIME_OUT); delete socket; // 其他处理,如:读取启动参数 //_activateWindow(); } } /*! * \brief SingleApplication::_initLocalConnection * 通过socket通讯实现程序单实例运行, * 初始化本地连接,如果连接不上server,则创建,否则退出 */ void SingleApplication::_initLocalConnection() { _isRunning = false; QLocalSocket socket; socket.connectToServer(_serverName); if(socket.waitForConnected(TIME_OUT)) { fprintf(stderr, "%s already running.\n", _serverName.toLocal8Bit().constData()); _isRunning = true; // 其他处理,如:将启动参数发送到服务端 return; }else{ } //连接不上服务器,就创建一个 _newLocalServer(); } /*! * \brief SingleApplication::~Widget * 创建LocalServer */ void SingleApplication::_newLocalServer() { _localServer = new QLocalServer(this); connect(_localServer, SIGNAL(newConnection()), this, SLOT(_newLocalConnection())); if(!_localServer->listen(_serverName)) { // 此时监听失败,可能是程序崩溃时,残留进程服务导致的,移除之 if(_localServer->serverError() == QAbstractSocket::AddressInUseError) { QLocalServer::removeServer(_serverName); // <-- 重点 _localServer->listen(_serverName); // 再次监听 } } } /*! * \brief SingleApplication::~Widget * 激活主窗口 */ void SingleApplication::_activateWindow() { if(w) { w->show(); w->raise(); w->activateWindow(); // 激活窗口 } } ukui-notebook/ukui-notebook.pro0000644000175000017500000000021614174170620015607 0ustar fengfeng#! [0] DEFINES += PLATFORM_TYPE TEMPLATE = subdirs SUBDIRS = ./src/src.pro \ ./uNoteDbusServer/uNoteDbusServer.pro ukui-notebook/README.md0000644000175000017500000000303514201141077013546 0ustar fengfeng# ukui-notebook 麒麟便签是ukui桌面环境的一个组件,提供便捷的文本记录和灵活的界面展示, 具有使用方便,界面简洁等优点。欢迎各位下载并试用。 ## 目前实现的功能 * 便签列表 * 实时按照修改时间倒序排序 * 显示每条便签的修改时间和部分文本内容 * 新建:列表条目增加并打开一个便签页 * 搜索:匹配列表中所有便签的文本内容进行搜索 * 删除:删除当前列表选中条目,删除后自动选中列表中上一条便签,若删除时,对应条目的便签为打开状态,则同时关闭此便签页;若无列表中无条目选中,则删除无效 * 支持双击列表/图标条目,打开或重新激活置顶便签并获取输入焦点 * 便签页 * 支持文本修改自动保存 * 支持用户自定义便签头颜色并保存数据库 * 文本修改后,此便签页对应便签列表中条目自动置顶排序 * 便签头颜色修改后,此便签页对应便签列表中条目自动更新同步 * 删除此便签:删除此便签,并删除此便签页对应便签列表中对应条目 * 打开便签本:任意便签可重新唤起便签列表 * 新建:在任一便签页新建会创建新便签页,同步到便签本 * 关闭:关闭当前便签页,若当前便签页文本内容为空,则删除此便签,并删除此便签页对应便签本列表中条目 * 支持加粗、斜体、下划线、删除线、无序列表、有序列表 * 支持修改字体大小,字体颜色