pax_global_header00006660000000000000000000000064123655160130014514gustar00rootroot0000000000000052 comment=6b78810400d053f283020a6b8f8d874976fa66c6 shaarli-0.0.42~beta~dfsg1/000077500000000000000000000000001236551601300153775ustar00rootroot00000000000000shaarli-0.0.42~beta~dfsg1/.gitignore000066400000000000000000000001731236551601300173700ustar00rootroot00000000000000# Ignore data/, tmp/, cache/ and pagecache/ data tmp cache pagecache # Eclipse project files .settings .buildpath .projectshaarli-0.0.42~beta~dfsg1/COPYING000066400000000000000000000016621236551601300164370ustar00rootroot00000000000000Shaarli is distributed under the zlib/libpng License: Copyright (c) 2011 Sbastien SAUVAGE (sebsauvage.net) This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. shaarli-0.0.42~beta~dfsg1/README.md000066400000000000000000000067441236551601300166710ustar00rootroot00000000000000![Shaarli logo](http://sebsauvage.net/wiki/lib/exe/fetch.php?media=php:php_shaarli:php_shaarli_logo_inkscape_w600_transp-nq8.png) Shaarli, the personal, minimalist, super-fast, no-database delicious clone. You want to share the links you discover ? Shaarli is a minimalist delicious clone you can install on your own website. It is designed to be personal (single-user), fast and handy. Features: * Minimalist design (simple is beautiful) * **FAST** * Dead-simple installation: Drop the files, open the page. No database required. * Easy to use: Single button in your browser to bookmark a page * Save url, title, description (unlimited size). Classify links with tags (with autocomplete) * Tag renaming, merging and deletion. * Automatic thumbnails for various services (imgur, imageshack.us, flickr, youtube, vimeo, dailymotion…) * Automatic conversion of URLs to clickable links in descriptions. Support for http/ftp/file/apt/magnet protocols. * Save links as public or private * 1-clic access to your private links/notes * Browse links by page, filter by tag or use the full text search engine * Permalinks (with QR-Code) for easy reference * RSS and ATOM feeds (which can be filtered by tag or text search) * Tag cloud * Picture wall (which can be filtered by tag or text search) * “Links of the day” Newspaper-like digest, browsable by day. * “Daily” RSS feed: Get each day a digest of all new links. * [PubSubHubbub](https://code.google.com/p/pubsubhubbub/) protocol support * Easy backup (Data stored in a single file) * Compact storage (1315 links stored in 150 kb) * Mobile browsers support * Also works with javascript disabled * Can import/export Netscape bookmarks (for import/export from/to Firefox, Opera, Chrome, Delicious…) * Brute force protected login form * Protected against [XSRF](http://en.wikipedia.org/wiki/Cross-site_request_forgery), session cookie hijacking. * Automatic removal of annoying FeedBurner/Google FeedProxy parameters in URL (?utm_source…) * Shaarli is a bookmarking application, but you can use it for micro-blogging (like Twitter), a pastebin, an online notepad, a snippet repository, etc. * You will be automatically notified by a discreet popup if a new version is available * Pages are easy to customize (using CSS and simple RainTPL templates) Requires php 5.1 More information on the project page: http://sebsauvage.net/wiki/doku.php?id=php:shaarli ------------------------------------------------------------------------------ Shaarli is distributed under the zlib/libpng License: Copyright (c) 2011 Sébastien SAUVAGE (sebsauvage.net) This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. ------------------------------------------------------------------------------ shaarli-0.0.42~beta~dfsg1/images/000077500000000000000000000000001236551601300166445ustar00rootroot00000000000000shaarli-0.0.42~beta~dfsg1/images/50pc_transparent.png000066400000000000000000000011271236551601300225430ustar00rootroot00000000000000PNG  IHDR@8sRGBIDATx1ðqsDBV C-``````````````               ``````````````              ```````````````              ``````````````bϤF!IENDB`shaarli-0.0.42~beta~dfsg1/images/Paper_texture_v5_by_bashcorpo_w1000.jpg000066400000000000000000003707311236551601300262030ustar00rootroot00000000000000JFIFHHC    &"((&"%$*0=3*-9.$%5H59?ADED)3KPJBO=CDAC A,%,AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"A !1AQaq"2B#Rbr3C$4sD 1A!2Qaq ?3z].AQc!#3 ~PDKG_gGi ??.Kݯf 3'7+8c qO:N-洼G{p?[azmuASQ8a$ؑ⏔?V#ÀΏ:=2H ꫧ/.=.KrH_ Vt?-sǥ'CwX5nF9z߂oT='[Bٟ?KZ:'~`<_d`31~"EܮS@IidGC=4[7pD Zk#x ICb3wM"Z 0?~tZ>B@#T$ݩtméEHz+%hXTa–I19$ +F17zqk"e#]/!3C8$? 2X@sE5? _GhsZWKhcS7i3T'07OSt';wt ӗ;foѠ /7O:o@& uv׷tZ5Z։~m'_(ài%>\}Ml1-2K  \M/ =CmsXQ2 ?@2 LROzս/ó[DΏSђL0o[0Ew@aS$T`M +^k`Q}goAqqO63Iz}0 (sβ p`'uGP9s3aws跨z-{@ѧ@@02J?@$n7]3JI9:sL^k?cr??kIh@xyw.3ꉃVG5g\>SMKoQ߈M_5HC[xZçoId ݎӿVzJ;V^O#t?=Fl5I`GEC)F*T,T?=>1;GOS騠ӀsYKɑ=t5HL~$ tZ1# @"gdQʨ:=?_XS4`8Q0oHY0I<1U /kf6UzN=7:H`TcnC M4zOtt {]&'K@\..IwouwEf4ZChuF3U@)'i53 :t<0HeXzz=]I-N,wp&?=&3<o!`캙hn$}x[1'1\z?x O:='tOOKphpe%͆./ǪI~*3~?W d@$[ ^Ų=s%@ mg/L oʓ?#&#NhlXKPN 'v4HL"D.wS&'-Ȉdb ,GzX:ޛ ،ltc+7tX^d`԰t&gE4O Rޖ `cw a7;aQ#upyJ[pv+g:F;ޠhفG][0&i!ڥ6'0r?,:eM"ޣIIZ'v7:Mԝ#acMy޲ s2?G $nF}t-k(~k::685GOΙ(6L lijހ&M[03c*<9c|= Y֝'h:cz9j';&jgC5!Kn = 6n6LwLEsZ" u ?JYS{ 89|9q6/&0~ @3#Q-{XxkY::a9 E+6YaCZE {qt]G].;HNB":`phpvt >mn=R}A#tHI2OS.9[C>L파 ~K$Ȉ0`y Q|*/((go`o 糖d)?q`j9;dt!mU ÄQ);WS7o8%0NrosOk_ds ΓH `T5Z7?t{TYuu"*\:atsHͣɛNf7?YuZz7'Ul ə7ni l484{tMhPǺL@9SIsdH3I44b뙍m[8PSIk4!Iy?Jth Sԙ It ${cp&ɨZL7m)tbvJ wL.<^e tIsJ.@ ,8iZdyXu sb(*(.Thkme Nou>cD6|\0F„-%rEǿuu47xh$# 2{I;{)flbEP5a&"u<DnA"nCjo38PDNbsLe6t[DWu4u,2݃\]!x1P~sz[6 w,@yZX'#cT4 dˍ@7ئ$ .2cF: *Z,U"Ǵ M4H-W8U+f45 nDH(3 hCZv#ZH3A` `B!4 RM@# Vޙ?7` iH^[$?i(I@un' ;ـ#RՠAX%Oqo-+Xn({1SZ. 7Y꿢34Z1yi+ÒòSkQ?Z5y"> V`dMN|&2u{ePN&H8LXbϙYǓ 5L 3K.P8i)?2G&)u=#0@pSD^zmh"͝Bzlv@y.KoHt P&&$8VBD\l7VAi5dsbu\]dYS{LϯCSA dEʰZZDgU wB(mH0Ke߲վ=YfqVDzA\o+k0$آl1#3Ձ' l3ud0o° >1>5{Q%QtPϛDc+Ƹz enJ:S~Pa%6IhڦVLPP%,*cbwa(ѤLO'! Ĭ2B|(@"';Y%2EMQȐ4c[0e0CDvI$N}!k` L5,5kQ $bpdؠv=Ɇg)iPl;mRi K@b DSxt7CIM&XHꇆ7._ u`)0 VY0 y!~3W F`GDV$MnU0T9Iy8)6!ĸAW:`\4j;Z* #Lw\4n I1ŅE(PCLD)}qK`ʃ3#^B{AL8nd\"v?Ii0Fdzz=D 'I2 XQL d|4g4WtՃr$Hm=?"`Bk5 sVN@p+QH\ %)g4BkAM; N {+ @dxRY[4#d%w)$üb $ 7tC8"cƵSRDWn a/$MTJl8 Q짤֘rPT.P䝧emfD^pXT0vD Vd-[wEkoMpЅ.64ih`{(3c\jhTpIL(&ˀw+X38pͭ|u5@ #Hr=?S dfV:: oŠǢ㭓I@Nʿ =GkO(05i̊Ӣh ~FkV: ԁpvZBLWCע.dW`؉~{z,.G&1K@{sk^+ "a9sIhP_ael 0%87(3 yFNM]cQ-tmfAjLcZ[)/ .KM@d~$fƵ` T(L6d(ك+p-ݟ{z@O8 wA2]Q~|z`t ,#ƷCX )P@G}C8L@7CEMEpaFQht@=G=.k'TěșW8Cր] i{*764+;-n ngL605DYHuGL:%ς)ߌzc_Ss 9?-EVqLhX֍F0#IlI:]rr-~ dIىi$n3iTdzd1m356΃Z:L8k ݸ$tIB CZHi9hå^ޟsX1I&ÌQȓ0w.Xi& ʠ4z!ݿcKB̊F0dg+M mD[$.2iۘJN:?8#:M"0 ? iΐIJ؞Z%6hbeOY lb}@@:2*&E^`(m²i9# LAu"?_gĩCI85CyN&SH3$[K#`e ܢhR ҐG@yU T0˒GyQZG Z:xvj{T U2$zi0&\eӢa ͕q"+NִC8g*?u1fdw{O*GiÀ"#˅T}B[KH'tcDy+>-hs[IO*)A1 :,O ֩" ]WGu@f't8x†1A}AsJL)b$Cpu~aLm_ҢjF is@X8(( _m8AȁctZBMZۂdw`p3$ .-*:wTetpAf|cKDǘSi݊DĎ30#O9x cռ8ҰAf8?dɛd Tn~b 9"L ۞)0wʚua8ā;ʂC}[whNh$@P7>Ƒ o :f `X&2 Cu'yJZ|!֙> py)#,lEɸA'#Se; u$}P^)c#Hx H3}j`')'7I7Z +BaS ) ЈlH$sMa ۦ_' FA!bSOX-3;0^v.D+-=Oͺ?b`2jBz%~%2&(JցS&d 5 @H=C]p')\,* Rq i?D4~(q>4$ao A 0+!^[=ցP"&r3 K\GWsdbW/? =,r0tlˤ<&R,PEO%K I0GӶNċ:`v 1x c- g )i."ɋȵhb) dJ&֏26r$H&⎭Hg~J@4[J#H53dO=.{-W8(snv!P\#ѠT7 l צaNo%Mv'?&- @ #>kD*p3f08$eQ:\"NMEd,wND2} I(ȬnM{Y \!["a%bq! ۳-:r5 :uX 8 (((AC^Y&#" N'fydz4ŽAsA4ܦ|WM{INpqctuzٿ|.s;NNASDࠀᥠNMZlA4PgSkkK] g:OC >>z:8N!PG\s8Lt%8 @4;lDgFN_6HnHtp"OH.5}hEǺBdFT=DH2qROM&&sh h0'Iޑ_1>&=2Lo*!c~SuCL;[vf MH33q͛sD:jd65E߲K8c7$($i60U@k}QԲ, L 1$ !(OQEAoO F#ɟSt(3:쵠wL6/{*u{{!xQ 1`я@*$f*4 Y̒' 1&f*1?dN{ ?) gss2jDLqa6N<$Nlň jkA}V9!NH"n-1OZb"Tu LT@=Qy%N($&=& НfD"7 *B sS33" 1<*-:P"#ObmI!i2/Ve@`\|M(E=;]ÏI]& QL /LS.2q\-j|R2HwkLm{\l:5Fni>4:"*ZZ(10ȌDy"@ '>PQnS`p'UUFNh-pvHC@!KL~ ZFq?LŚLm#3o& 7tI0MD+kL|Ӥ0 cFDI$ZDWc"Q9! cn5j5z8G#(LNs¦Tj| DzAٯ9J}85%Ed p"*Cn>P]t 1IG$F4JOR>ctff{2[ AܬA0lR [#a$&| eBp19Tw3QQ"PSdM 49n7r?!b HJO/pd(h0OdÏxNt|(6ANFd0LNJ@'I !^ \t!: }i@+ $U\mv )!QRI uzm{ )Cd1?U_؁;|Z/SS.@d-6ZCW'C> &U{v)!ՙD+HQ`kL7 XMN~?@HB}S# tEyES\ Ǻ.uQgY6u Zz6bguO D?BƫFot<~Jo gQF|j?oHvci tC""X]5sZٍ&`ABDs-҃T543ޖYtYbr!jPx0ёRR $^02%X&~-R$'{ _ʨmdC6 892R@lu 0fw?P$?o )ttɂ"Vp&/^ G@tn'?%u23?d+9ose йɔ[FA$Uz* ؊[VGr0b3rd(tj D.8ս 38LI#f(f@פ h;2ZCf%iCh Ϭ$".ӢCKWQӬ@$ǸY<1:W-[ʃ9ԦCIHlL)$`!ߘto0=".{H C-l<$쨶@$AfQ-.]6\C(5h`G6MDaD: IRl%OiEsJӰXu:'.#6ڀ+Өyw[ֱ$T'YkrJ :(T~&Zڮߪ!eoP;a&I1ϲz|7TDqՆʶ  8¦[P3? {vNA 24>B6 rP% fcA7؊?ʧ@$8|JN.:@1BTEIocN@#5k0ި5]ceS(hdL}U6*O >x"EFo\' #[A$d*3A5bv@a{aF7`Ս13ji$L62 &|N9U0lma&h{@ZfؓD=d˜2&DžU%TDcVMpH$[]$E$MR0,mAG8;}7899 i-$@@?-q6 Q-cDI%W]kt}:A3b~.WLsʞkM7KIu@ǔ2|~Nv]q%ȬMhp?+.t)p2)"g- h隠 +*yu6$Z NV73bݒRƳex7'F{fBbmjQ#my E4 T 7 UZi']8IZ >®7JNK.J?!0ٳs *?@ ^63<8yk8\["D1/gsXFSLm~>:ZL k-H!eӂ`{Z١'-8u8$m6k\E!eDjsELNDkr2 Għ"1 촌N"ms#qk C&6 S4v7E0qocHM~:osn٘QZa, PqWhP)AcsD{}O@IDStC4 -3sG43H#HJz7ӌ@hSh&D1KC&~"Z2cZM*7HiDQuN<\cFACsiS!&vl ֆ84d" wKuKn @nGzDOx2$1 z:)u 8 ֚p6"7AC}Ff?_) "O~ʚr8^i` 'kYꉝ9@XBk\(pM%tup nH 'ΆiND L:[w4F7Ei_m i h, 1_`AMݠDžQD뛣$Rh%'Z@7WR4I0cA˻}TzDR5 vD(AE'HQe <h dĂ9@lA59άP Tuzl9\" BkEi삦w vIv5$%Z/­0D$ )@1ەfg$ 5^2 kM0ZUhkΤP{7@o8e,!i)<R,Ƙ 5h3%'Ttd?B“2DE|6 @njq \⻨2=i.Z02w_ )hB!͑s;H&2#ZbH5 dggtkPCdȯomd$|~'j/]i`zoP=@C\H<+X@f _M"e\6d,18* o~1BۚD8 J4@p$j't =3#MlOT kcjT:' 0}n =8a00{KAsd^fmX V\^Xؗ K["$ѣď󑄁(ۋU ,%A38MN*<ݨZPꀁqRDVh^"2G:]5F%S?O_fcIZkCH ('S/f;hN}v+Fƀ:/68rGܐ4XWnM{M'Vo8VH-`T}HAەD,纊obGtul֓S1I8 Œ/Uo#etL&IpMARq Ƙ0(tE BXL0 ϨGA'*0Lĥ8#fΡA&\aؑI길$E_V t0V (TZGL&9ҷ@1¹:eO?Ё$6Ime~A4xt& IAl ep9:sIk59x $yç'3 ^h'SۄZ "fn@\v F8ZIIJMFٍ1* :`젰U`g tI3#4.#KAA\~OAq%θ`+?Ž9#&R,hF/u[~{)?[?2EE@.#' I bv/$Df=CsښMķCHli>HKޥ\Btkiq?0H'!7c(irUDj _66aIפN)3 ƋkP ~qh$w2}'=50I0IDT͏24}HDjFb}0F!#V6=ӑ>J 5ndDMYC{ʗKZ[^o6`>b!KZ| DjcbΣ";|% )ѦѬ8Q_QsPHPC8 L}V48zTXv-PϞt;E l:Rb(ODJ$Dz!?[LE"(8e'/ /L&$ *? A McEń6 )PtIvNL'H(/!LXSi/2fAG Hd8ARv3 m TH#@xApoɖڣ.}>Q#cR N- uǞ=BFw)d^M8bG8p`(m :OhLc)hH=IfsGJMqsH(dR uADphA :N#–;wQZA1It7>$ Q.${M['>a<`KA:G n%b5fIi f ;cn1,nA | FE_+4>R#P-{}\nf'oe`]2Njִ@ 9zh.i##I [&  KCKy;* ,b\np ">6ISU ʗxh$[ٍ#L-H 6#QPu2c7!bPb6xP$ƛ2vr88 wĺB.KÃrV{4LUq %PH7I[#%,U #̄&VNh&Ab#I =z[HQl0\XQ,4oP49^oU7kcdDȌes閑 K9-z6E^ȲFU7?, D(kL}B+x,}\&l8E,tIkL0I'ܙ*:f0É# w#K~&wkQ=U@MGش :7ǤcCkI-6INؤ#} !3[.02׿fmCy/li=G/`4iå[5 YLb1\ad״zTâ(-k6,THS4dOU:G=n#^*FLit2{j69Iް@ㅘ ȉ}@ L48A/Kŭ$`¶@Ael K];m0\ 6t@mX SR.ELL9OR v& cNE<,FYtx1l*4$ a0Jhl(x6>Y>j@ ~=Ӝd>S`陛@]VdJ@? <)8+Xrp#OB: wPk|Kny -G(*}\`]Խޓ281*453SkUÁIҧ0@#D?L5$4j5qM' o)="3w+H7hPTY%cin  P1$LQ(pnc`4I4d&wȰ>ff"`Xt# ~b`6 ȓ 1`Ȑ3TA`St!."7KL8Tl@VFH> O3qir DHdOtZFʅF{|) ֟xD5NDʡ ULB@EiyY^ZC`hI|xLT uu$ʑ@& p=@:{D@'@QU7 ALl8V_) p.\m@7WdK}$?aFFL '-&V"@_{ (7 m@@Gh%3`DdԤ=dKXAl10QI#T^eVnCh J^6A}@;U3E?@+`d`)GS n@3 FpH@[q;H*u4tnA gXD^spa :GQg zmjEbxJ@}2:AIvDbȺB03`F E-[߂B <) ̦Fc< 3o 1BIH)$S|GEj#s'u.'B4IfqXA@ͦXo*-klL|}qXt͙M!z{-@g$ J[絬A#Tuz FZq vR-t~H +V80mdfF*&/{I@Ykl}W?ლ4 ]NlI+2-А =ˆ/92Lm 5mUQ V:4{_%f%FN#GuzE$5@Ix.xhjܬXC+bd&yQ Qt9OSM=p{Y-dN dHd\Kb>R,Q#B}I <n:֗;$?ncG^ u:$xNE81,I:O~Š91[($ :nF (48^T',ˀ.&KG*}@Xm sdG;'9>3/UJPો7; fMG)d&qlPH2ʙ;:IT9& ʚKڔǤ"-"Ga9]^ʇ {!iߺFr{A$!8Nar;wXuChV>u>;)P?\fgZtu{ 7WEoP|nhvrrG*Ok< G&$nMmk AA>Dh u5 &4P5DW7d@ ?K\ڊMw?ʖ$G*o.Ջj*mDPF\;ꛞ{%[hM4x&A 1Bo.OHY!$@#+Aϴt n8A3 %'^Epr"|, Wt ; dN;Oܢu Cb' ةDK-Zc)fwP\EyS0OUI22"6*$;-.@ahڔj (իg蠱è o}V= w@$#d 8ge= #xL :DvSdzDW7ڣxh.Ž6%WL4nS?\Lʙ g ?X"ADs3ֶǺ..o`A&RתKZpk'VDznБ4utH.ƙ5kN\dYwIKfA~ E.@Ze@'* j|$D bZ`+= Aˤ?-NJj4h;hG["QJ D@AuQH= ąF n;DX0MŌVEo(`"c舎& %FwM9';F?ÞI/u] &H1Fesk\^ ]XoTu, hL:HHhя (lo*IQDfwZB$dNN!WQXG4T"7-Kh|&^5F,=S'+vK~!Med*J'X."gxZ= [A!P}B[ephh pԱ D3߲&`58l0ۥ'xh4D] gæ@q.gLR@ r''AWX"73-Dxe"&n2W^(3/9efn+p2 ǣoq=P`–QhoPiZncVQ`4KCu] G?4ix{BC:@4bI"LL%EK !)U_0? {+xThֳQ$Cs͘Uf  0o}2UIx¢v78DKo&?R5r _4Wt@ ߂:FL4nHi) @ag̕Ẻʟ&8A:t-%aeh_H ASHUx-AO!5zD5X]4E+A kAnU5H,$\#dj _tEt4Q쯥{tAK[HsZ*g: M(hkM2ؠBb 1>"Zw!X]P 9Dh3鑪IegH>T\#"v"q,V2!QpT88DwPZ̪tZlJNn6 "*!ĉR&"kS kM VU,W6DɁ74P`TT$?d~0&z[72/'f<9"7@1!RmӟaHo2$!$LEx@ݬi>  w#^ѤGrDYyR[mE.e)#H<)b$ag"vZ 5# \Ѭ@@V>2`y@;t9Z lPJwIhh>y 1'`AǕ:f #*(ji3p ;pg_UqRhA 67[Q2IN )EeAfxV {U0((,U,>陛Ds:\WO_DS2%t7 _l GG;Ip VN`t47Q.sKxĎS|S%[z)Y3T? HxrFu&A*"!V6$o"@) A'諦OL 3Rfu inYc \}&Drj|1vU 9Pxf -; ')MNS7A%qUm\ǭ :]-ÍBfw4b' V6zDzbZ8>H$BϪ"d@[" _ xRniUQ'U . Dy$$שžOV.U 0 S@kN*.vR@rI w+`e,mUN rP MeKۨD\1d0# c̅$Tq^:ٛPdč\HUcA^T Co58&$.9i5=2G64v&Q 68nֈ AT D}_Id!ǘJ? sGt??sl-t@t '۔FqCim+L6C|FԀ|ӯ!D"VdI ($42E0 )-l{TZab'"{zzkT[1ĔˢAQgyTi? ` 9QDI?1DPmSto i6#cnYBéS ˹04Kug--s$X.ATp02=ԐԖ^{h.HsZ$XLqyH]Z Q8` A[z@ \#R=Sd5'GbrLYɅ/؋P;wU ?ui"'*l ʰ"5:6YQFBmpp;Q? 54~C{׺ LfTZu/ [ (BU)q5JOSI4ox鰹D]ȋ#c쯦I# \Y0&# f7B`A g٤1.^zbwWHIM+LH:s lLcc1*$Q|*"x[e i/tH= iඡTX"@tOI1 TMlp!Hms4Ln..o:x0i'6h >،vA0%쨆!{l9UfE9'M4@s(b7ϥM5dO%X|[""dXI0h{Od B?6*7(R8i&hl| k\<x&ǐ#MGVD K $\)DpNjу )ʩh]"*@k'4I*hk(ꆴu%hUVJD֘98{AC)B7 /wGeA"ȑQ1> H +l- C1`1ӰN69KALLjZh@FM ɐ fBMi' ƉɎBw;߄AkbJ "cPz*jěDD$ p=ᙎlȃ €'5P !lB5$` }Bh 2MӐDJ'w(w$T[g&l 3tdہ@ 4IRI)ƑFeU͑TGZY~ fAHq?tw@5hiՍ 4s $7D(4/y06~0xwN;B:wА}@l7"` Z !rR|$ g>7 ܓ= d򐚢ch=nh~$Vqj0nnvdz D?68-7U4(\iii[ ̈GuR>mH7DUl3ʇJ ƒ)0uXu$ ?JZ l^R- LJ"quw•K!M &I&g|Ejl$ Y&32UC8R[;nQ LZ5q۔iL{;TѬgumi*8HU@H1 (EۀiGQAu`Vo`ahzcHoQXau4hx9F>12-fll3I0ʶ$ f- FJ!-:HwL;N ;I 7 8[ V@eC<9 2L=Q~QZhWcY:I Qfo..zOY OStN-'eOzzDB3Cl6o=N QYO̊!ᦌ ?V!¯T hT/̈(ʗP&w":H2a-@Șpɏ3uDNI`{ǫ-($~f]7W3`v"$ TCg}tF6w^t`nLfn+Lt궛DLVBzU@꼩ŊhA$H|GEI4}UcOLE H"s2GO4aa{;IX7ź}ϦާPaCElJd=(xZAN{$ji?'`߄]1cM(n*UL%aDㅣYT>VI!pMvi:s3UAu&KH<|Z/l`j1XTIarin*2sH Dn7PX.px$K 5S?:.wOP@~]_~9Fb]XWq$@AEL]q?lA䏸+Mz۬ŀ+n֎]>V;zEz]P nxt1cId ذ ^h]FOR`ݟ* d2`pw s@p|%ck븀@I/o=435eI+Tc$ NHkHZ@0g_k@t4X cLQࠑrvB@S€)0zI&A= Ba#mE}2*G#tp;PÃbpgG8H470b" %&`ߺ$\@} mp8:(J}DV}:bd7A"L&%7Tr uN A$ :"dRknwŠl0H<$&@Lˁ q dLR WX'S[/M,ײuL:WS+JMqtaNiXt2gei? d/A d w'8D'Ls/;dTc+N`ؑ~`&B9DZ?>V؂!YZU AeAڎ6ӌY4L> U8ɶ&,|4cZ pã s]Nf ;PcA:pRge wQ@e2g걵F \'V}/@cJ /IP'E:|580I 93VH4]lD1 l*d;F9ȤA): d| 5XS pBe7"wq#W ny6ĈN/'ؠ'0c!"3'kvJNҪ*9X'2b#=@3+7id~W6ȃ}8RԶHޓ[K!:2 <)yvԳZ6 ̂#<ㅯ呓0rC,:'Xӧt Cd qSX1 J`8YVƷUA)dH,ha<{KA!+g7(54 QSG-i͘PD/t09I7P/ s\X(k%0cʣf64h ]lktäEH&dd&\o:w LI1bSE 9oCt'b% eT? qnuQ4b.?w,Mèo) odɭɴD1T %HDfKMr2bb84YZVkZaVn A"' "M]Nө;U2`g'E6.PSd@-pç`dnT؈vLw ,Q p@Yue"TFàk4GL@b1vƽҎ1'q ;%҈  fs*,%Ǩp;JM\ 8Vo2@g(,?IOQ+AUQ# F?D6s}2A&@#*~)QmzZ@- C}4&D r,KN| ({ k&62ˢ MkM' )2MȒ';+3L(nDDŽt@. H7{$#H}DkHlꛟddT- @t3|ʓJ7RvT0+#:n@d$"C'9Z>ZِM &&6Vw8jtD~ؚyO6l |,K(WktjL&gyY~_M4lRzmfF04r{SWS5qL(D2nU#$ܤ J7( UT8g4r s$dTN6XCt~P!!7‚#a6:@DRTY&#hL9TSLn_]N>e{GŅw+7$ mh7rH1@dʂ+ˆ:Θ3"_IA '1(ɆAKen)KgT7uT$TNCwFq?*I:4i";A-! 5n%'#$}FD э( 9@ `M$`Q0h* RQAK@ړ== psDIqV"+\^@Q@`5z`Q1-tLu-jCQuc#2ɕ3 : CYDm>Pt$IZD>Jbh"A>A ̑Y? QK~t848h@4ͩ'iei$20"I%\]bze" z}2.xoTH~Rp V҄/aH\/t#I;Gt oǤc}.-n8.iQSHZ#?b@ۺ3oKCtvMPh flAZ4 Aj:?=iTɕQw`aPH0KD zzI#i달Pe5s)@$yF! bI& kSmʣPx]&,w[7Hr9d (kk<&~%71FE2LNyA .&q tLp4f"c yQpO;&Q6 #Ag3h ]B`*t@'$ޠG2l)j@#NuPZ 4g)HNP=>"{J E`hbEdKԝRD?'?BBͥ#MՏt84pOԪ",aG"ts>J7B ~ȬƗ9MqEIl!Dg-@[7Vrz==$n# F`ee`KbNb1R7U'eQeG x$LVACS DLGr1# 0dD1 fO(LP=R O:H| 4@iLP"P$Ɉ*zs24  ~bLna7 5H_l&H}h{_qz9H1[ KwZdf"db C52F&09D#>KGЁ>wU8>i"(Ċlf>kNL򨣘#ꑡ_`ו:uA$r3{RNhhlʗAn( ؙQVZFP"'Qcjd@I.MHHAx $sAQ DKEV"ǎQH#CYWb=YAEݥGT[-36g©;&(0bĎ-]iR4 @MElN)q16/¢素1 -82FP.ퟄ(͇_T#l(&4n&r7pK8@Lę.531$eK\bKL 5jL8mE u@@2|nQR"d^Tʒd9\~(7w]:gD'tQB;r0IoOKKXKpmA6@̒DviC]@LFf(Z'OvZHI )`ZIKVz$s- '7LTřEOή${rI?T @vi@ dJAsJ2'4y`Z\4>*WqM? cnL^W`#Oq_e:|ϊWPq1[RIž}$ r {dTuі:`UK` ӱpQbr #bˠF>f$42 L6FIT7Q̪h-mPI;Ͼ@'b {=Nl7)6jZHÝ2aE2u@d>8{)Њ%k&QbbQPdfiQC'DA@%Yq dt9tlA#0Ak3OL=T:"'dRnkmsgK nԒcՙӞP@s <p,!>Whi& ;!#&$(,b{ VdyI~B8"ꗴp~xSh"iQ`(\D&{ ] D3{l?ENA.F#A 'd~X'~!2&ȤC`@Q1'vEqfn$ 3}BF_CmrJ$T9ϲ5TZhQpBA'{_ؠ #*Q~ʥ8ਂ(WWj0< O'0w=Ծ^I2c?DLikp@UT}AP>" P᪤V8 ѲDFM%8_(e}QWoxOS"¢Z , IZ<~\Q}79tbR$n#a(| ^cU١NT 8PIcA3\_Bg9o~nZ5ڄlyYlJ >"B`4sV` P.XqRAӥPVPg,F~R=ʊΝP-ׂsE`4"AtITir+tHCu0 LmEVD! "`hpyp s7>{ޑq1m1'#.O &oM.DO8Ӛ8vII;j46Ly]#4\6&n`mV8h5;*ߦ4,bdE0ȉ ޡ`QC陒c"Wo$s4NQi.OZN\hC1 [cVEII0 8f=̨{H""" |3xJ I b`E*]%Uv}3DnFN|MgžDlDTJQ`y­H&ǐ3H=D706,ˢ3c)fw = Gd4 \8S6 nܕQĥ *U*u,'ndIP' Rn5DzR6(yP(Lo' P$(p'%p0C  DjH;Ge7'TbF{ ٛxA/pD`6ɴMndxʡJQ3ZE[$x?xJug|  lL~R'g<  4xLds=Ia)``yAP(;}6~lP M"g4 )ORҗIܞSqf( $(=R]0 ?d/|>I j@`KkZyET`}YsDɛknh9HQHC@osQ£[sULғ ͒jHA"R/ X@?E2kV&LF.hXaA|\fA7 86Ł0,9nR@<҂zQy % 4:=3[3Z~`x hu~ = 0$GuTiC Ҟ fոF~`#u]ԒVi@L#A'M"ez 8F;&Ƈb;BnveaLزgQMsQ`ς(rLB u|6,#&g!PwA7!HCZ w>6L.!@"56s;H7AnL$5UX"| `Gf j#T2 mQlB0"1:p6DzbNaF5w*9 #n[OIp06A?Ggz}>KcCA&ɮRsD"TT iR# >$KIp_ C RA. tP&$h3U " A$Ǖ $Pȍ^3P&,IMplEl#hD6'emUH&AȉwQn `&`v@]-.2ߢ4MJ;E 3A3Wӫ9(!q=   qLы@cW) A7eB!>HNR< \G)τ o7ࠚ)8oI@]w@>-r C'k]Cx ы2gbMwi A 'P?d7'̄L\q| ۘIYiL8#b9@PXgt(ioF{ Y$nM+M2K*Vb~xA1Q})nQ@"*n8$%jU1P#n `\ɘD HYӃ1&*7T[lP@&S,$ cRfg&$Ybah%j!%' }0j $JB ͑f{OGC HuF {bsh"GʇqG$`6bSG LF4L@Tm7@(5 LP^\*:uE80QF'~RH;(* aH:H#UL$_]3 5x eB9B$aAn32PTTFRr="GYD.R{J$EQL޼7geBM\+NiH EX-i .v$Qv' ODPm )0AwUtv'}Q<}70U\N@8̳BEYXY++AEª"`DzO.>.'쑽d&Od$iq% +N`hRbg.Ιih~JOO ,u  D/G^{z!AKֺ"ʏRDRe2+7jj -gq"v=2 qI' !*)$GeM"aT&Mi#} 8?A:qT-0n&1dO"H@19H$}p$Lsn&lr 26AGРHon B4Ӵ_ ELD TKH&BxAH;&}Dj ̪Zn)tn h}cuIRp_dSx!;Q9ϺoާtAd "Xm3ik47#iP>$v @0S$ Ay2Kӽ%:ݫ 37@P%S8=;JM|LUPaKڥ w$Lo3dR5~ɴ`dAQ 0 L5oq%)s{t wˋLJFf&E? v-Ej4ASǺ͝F \;= $E S 0c ݦ${TW v 6 36A:b D_ry2 *Dj CUw̝=pv'+;"$|ePt:1Cx1BPw .-%bhFdsJ*`=RqX aܙ:M=75&;;ts)IhbTiYJRTpoxZyȄ uB|)&&8L:@ DMpSJMjJV/G"g|J(B MyAo€$@fp <ԯP e,#0>[f;c!W\aU +ߗ$t[hΦj9?+GI2\6EW7͇NG.0wV8{:ʂ鸈{Ѐr>mltV]$'Qbh *CԜv,ə YJ VkyC ¨͠ !p.%hJ _8=bC ~SI *e@ʌ:pFh3RӪDjT<;"'bSlo4;;pFJ'&=u3KLIv@u`Y:m 'mn78L;UA-N3wS[wlJO IRZI88}>g [3PKY0r:1pdG}JL&o~>lfPN7T>J$V|CJ`9*\ޯ4K]."dQM%S uTfc[Yj@Éʭ^Ud!j0'431잭D#hABkg$<'^|KIsAp!85ryIURO>s#H?D6d@iξeDoʀQM QZ`?Iܖz]2ޣݐ~՝fDM  DgK#?uBϲ[W# pu0(%>P$e #([%bw'~qzC@2KC#U@CumVx@5&N1Pd H ";821C $F& 8EḐ hu_iAhHrL!;) *{ & 'DGa̤Ae\q2y#; 4k삤oW;Cf آ( ǔ NON7 *E% EoT*Oݍd甦$v VagZ˾ 삜 xux~f*r"3@I1$fbUi J* #SUI@r )  "d`((YEP!@ /A5QU'-TiməR$hZz#QD $ѪLE VZ 6%A/)Dc:72 q?RD#(.o7$4$G38YLu=&FM"/jtgj9\'ph&2+JSm-iTZ bGET:0,Z`%(!"EA# vT`MxV )Gڙq:ݏ>p xE78P@]ep (f e2`#kNONwtS50ӼDvei y\H8iW:i k-Z"<^Uz(━+7 DD,KHَ$V cyhcè"5"I t$y6G9YtMU[7PO,@2qVU l5wKRs$&$Mo1æRG4$tU> F;Ab Fc @Y|ʀ"jA#Ml~pKO6A8&Pe^R#dJ{v \ +ItP=)s jH&;(iwV$ (7@i$;)O@\opJ?jRKFn7"M ;a%ALP"A} !77nwRZsP@pϲ?G76#7ʗYTD‰,' BE 0|¦DVTR hN@CA#`U9hc@hlO1v?7SzgkaEv'/~) -$ɩ=P2%CZC Z&p۠'RlmCiL(k;ZNdLBHU6@? !79LZ@:,GM{s`> 0.Z'TUjX0k6cԵ` D8U9"H%RAYq9<ª1Yu69<̭_ r=A[shˁ{H(YAءe4^S-"y__.nOKsNsL $[ ;'HhwS6ZB)bt=ĈĄbl 6vyLATK&fn"~"(C|+kvX+7)ܔDLPψH{"@ _#;*AT&| ȎIl ˛{"1T%frAOfd ΙNp̑ rRhA(UJ5A~܍Hc`d93JHqv{!ͫ4&05LI@$m"H3?U.&` {?Q'&%p.6iScEUĂtp6DShSeSG$TM;DLl:kVUվ3iY;晲&*cFxX.>TtyZdtC 7u0)6ʡa  {N!Ai+9Pry(x5UT"Pc lēI d+)jx|(zʃu+LKE~*dem"@z|{} )df>T='ucZI4@tbOcߕ2I\i\A7B:ߨ YWlZZH\{u8gy\I,Dv[:.R187h08*:MnA;-?[Ҡ` $@LThZ&I@7?Tzet 8 hEbow¨`AFMRM%2(Gy@7L"g*dTYw{HOmhIAɇrOk@mD1B?@ah( }`"R@"Yh0kʼ۔<(p$]:r't@?T~QHɰq)f H sIi 6?Yqx( tIŌjvNX2!Wcp{2ȌE %Y zO̤P2# 3{ o `Ȩ견"Ѫ2,&A$d|@;ҷD+6t20PH2<*oQ?tH;aWce:oSLok\ϺdR#S #?D8qHl|ҩHj8Z:vDGP1 LR~?G좇 t=T#™;3(qb~T#'U @ CH"*_2@lL~4'8m&A I,;i)+$yHYTmnldU{*g N@zD >U= [c u :`BHPIĔMa:"tJ^{'D%) qd{DME @@czLvPd=P;L"vHXJ{2S#}J  H4ԧ0H‡7]\I~8a9@k ĉ bר)"r 0 PǕP7I-sI@L"PIb*AՊ()A߉C@{!F$<c$";/#p@#T\Pu F $p1쪥~O~,%0&7ONH@QQPot"uZ^`{;bI~Zzm=788=U^@=7F8`iYO3S zhִC`;*h ߴAl)|1 $A"aVoc#sX<d=idS`8%+~PMVW# k9R$vNb'6r)HĤlx(z@@>:1pHG ŤBњ@q&h!ML"or)C;&IR ϚDUXi"mڍ gu5VI~#"WDA"B]BMH9NƓA - a-&e(Q@n@FH Oʃ7 1ʢ۟*KA vh2I|ѓxAm("e44j N :s'A3 h^3B䩊rL"&PHthP ԓګ |!0vb b?$I`7 ?KHI"ʡ3pAԙQۉ*fǕNB(:Ni- "I 1#ؠ1ڥLPr31 3i>Nj’He0ryW?S!g|72q(O[CdMmze4ԯ3;. q78, :n"Lv${'d󱢑 Zf uQL9W7=Sv=¶C'cKPu@DѫRH&s¦Hc$=Vb&,I۲G #!)KnMTW v S@lvPH#q J'Q8J"XؼRD{VnV!2Ms it c6e82t O(7 BgeS"̨<|(:dDQZgn߅K{&֒MȈxvRD*x0&'Rd$cT'u"ݪ Yq^h6`U@FDPE"=^@৴EH a5 \ ;{lJ*su6 EPdwLA"5}@jDl=MQDfQRsw̤?`$ dqU]vSz h|R'c'rfn8A}xH ;@ 2DEm?jp@$BfU؛Hټ@VԢ l"m36D{)1=F"iǦ$yJ@#dDF3$DJ#nRI(+yGac 3`)xTqJEx}&ot4ț/9Pe&;H4{ h2 Vi~S:2H!(`w: qD$u$q E@j3{)sq ̄ WP '?{"d9w +E`~S`bPUjyGPs"pltUwyAH 2& fgQ86' u$o}[ g($‡wI0\EW[!gMisu rm|Tcvr*!DuFx "yeD5?T|Ȝf3qVt7&2d?u2P. 7۫OL~gR'KjGޓ/-Nk(8OȜ?5R>7E`f~!clǀKX]@,?tz GTF%51=G &??œYgt8ZOX]F c2.F^jT#HuLU@;VT${+kN¢Hi8Lbc@JP&.fP?dTB74o`kb~RqJ60RXd L`K&G)Ɉ(G'|$]yR`0N6SLM FLFd wQg@M!MCl{ 4T4lqldbHKK1 i>p $Q?لArb "V8' !Ph& '%K T&m1$`0nA@L|"'8fL3ndyJlg13 7SG~a:EJd ;MnQ2"L';yJKBpwPzdlcP&$1rE}6O(f+%#ʳQ1p2 |DA j"|!1Ub pUE$ S#8|fvKMIy@[/h $]X&{'RP'@oDo-ƌMn̔BPI55Bs hmP}Rt̀8 ;% I2ر#RI@N{$bH5Q Po2&';ħOT'GDqqdrdd" UXyD vA7*cn-(5~7?UBDpZ c%0[&#Sjɟ)@F n#&膰2@$g'9.'&pD*l 87:h3(DiLѸwA:}Gj쯧M߱H4V$lrn>FMR "b~ID'W9k! A0Ml83+~}}~ cBF.F!IPD5&`aÙY9Gyd_ES\bw 6IMo)Z$=R*@ TERӶwRlhVNdA9P"H9&6RsvBIheLH$( Idi0i<}ԑ-c'}6d?) +6;DI8I'N@VVH5ʁ8r rM쨒lLe:nA3 m~U9N"@UeF7)ɮ(#p'c&'n t7pV,L.SUj0NSi3$H? hSK7^&C")g}¶F2HA%3c2B@}&$  :AV;㈔D`Ci~5'2bŋ1wL = H(Tf9U x=xDPI#&aH}TH8#"1JLد(V=V9oS( L6 ALBh0̂ASPL Dܪ*$dR(߲V| B"C@j ~w;7Qi -iE*)8{+Im&P"8ѹEUEe\db~cJ3.6hGY픈p L8)LD}@MrBhY-)g??Nw q&u2 Q*$BÍHYu{B^L"N#*=Դ&ǸC"x3 ;(d3) PQL!-* $#THhq3Q: 72A06AN!̠236fk" QC\0cc2N]PlRN<;"MDT87w ~ZZLL sD@PA 6ZuI!'NF䬩 `E@JmU~2LY$sN26LNi#;cIl]Rs?dSCo ,Gc+8!xTs!=$7@ ®t ȩQl3.!:*rHFP oLQ$#Z6*tqܸE^ESQ#Y,I;֍aLgdFdՌlTcHKA;iT09E@`R"@i `d1)LD0|"c)A [^S9Ad@A(;$HA!duP'*\XEyW2T:KbIEV *b&4n18H>>d"2 FÁ8xi, '[$-|Il#p$ Eru2~=}N90.S,W6|g%gZϧdV׃uúZKgI0gG9}n[_/Θ,>[9;鱝6сkcV%7<l6ppq#P|A {JN>S7p(v#C@$S` G&hbX6lt|ZMXCI 6YwJ )2t4pys)IJ1-Rޠ$QP3DN2t{ʢ7LD 錦ӨzOʧ4S)k`ZyAPHcǔ=P1$t%@F&j@<631n$yD +5O%e:nl9)D;"P[fR' ?3$vDG㲁Hq" {clP$4Wiz]N7P>v@OmI:}&J90n؎p@1jI '2y84"]>B WU!}@{AdQx ${>T D41Յ8&LBz0f 0 DP/ȀPV A  FF1K`2L~R"#"R-I2ؙ"\@rmAHpLHʛ$A HTM 4`4G|)h$ɲ" =59FDi":hth "(GPji$R 2 ujڪ֌懕 "MT8Gī ]_EDRt`^؜Q\pLA#$ًB8ӺZ5 1]' ~^_Aie^Nzi=Z~N><C0:v٘$^럢(oP Rb[Cl }H=vc8j3TIN$,@͙;Qn!' 1D|O ɀd&BrI@H𕃋H2 WDb,@SHy@ǤW|dHxRATT}N$|zFlm+K ܴKO(k"7  Q@ 8"Y?%Do_+@JyA-.$0 6(DYH4THلQ~(~7(pi5Zic #BH~!PzD^"F$l{DB,"QF)~̤2@['1EyA3(XF(4k 0OT[&?ԂdMHFdT4₦w4v~ɜcn^A$8*6H"tzP$91 vAq#E{m 0 Mi$_ *o^̊6Ǻ ( @$Л'L䧑%yʪ( @Im#iI`yisdLLďr6I&i+LvDf{ ;<&TQ'bL05T"T:2 YzN$\s1 ˟HV7 A*OQL~ok vRgh3?(.'&9L 6( IEf5#ff`Z%tRNU61AA%H2D9Zf2$ @I"L# Jxt*"=1rۋVb5O?Bd|I"Cqa@;:I$yL Ff H9L ~䠬#^R3[I6$){(AZ ͩ, ǒﲂ0  Dw* "O%q£FHM G8A:Z1JȘ7 xHBGL1*. 4 " vK3${I~8%, *=' 6A"3(*NkXqeA&bO-$NN-Vj6S'6%9τmmEtE|ʓe_ЂkezCZձ}>ӏxT,M`$¨*t~!0 -n粂_G~xʠ 8?qt2 D+d@Gy$3'w1+&L4$[) oT(&@IMe gŠD(F#g;JI&"3 3CP vFɁe*f?q;&#dVDN؞  9@czC?Oc] =sH>+&k m A):0x%T*;$y۔4 0 x DdhcChh.&PIǕ%Ĝ('I&HA=WltԨ " 7JbMYqDR77"E DyMfMh2?kHFv 2/1$074$LcP7bvIOF'D{ H))Π ǚF&7l̈FP2F"<!¡Iɒ&.B<(yc{ϨEAj>d涢&g rhQ&#8*dAPS7B0M3Gvus!g@{-+76̴M{-L $8Hc@Ym!dH 6Z"H)GQ2lp` Md4 %_)H(9RB& 6QTD̙e B$>ԳToe[Q3Y̡.=? s:^i{`(wZӵ'$ `o+g¯ I2fVuNi[Ox'' fTW#5> u8GT=$.Ksq87)Ncq<Np H8L2RtVww~PU"'{Lv P -QR32e˪~m(Œ( ɾҙ#=Ra-@mm&s@D ڸ@ōI`ktDg[O`rk4nAEJA3KB`J@ MNs"lեl qR3@HZ`i Z}XְqI6@('1T LJ0f*084U<! I_Q@dĤFeDNpd)OPDwQYt ĕ3u}DAjɋR ")"9=B>HW?T٘] Nge&R&!>Fy(Ec6]cU4~F:A""k@8:igIP=@f2 @Ds$7` AwZ e `TjMIII'膙 D۩&2;Ǵ8 n<wTLHH**]tH ܝ\Y7ʋǥA!ڮX!L*H4Jm4Hq 5A&9O,ߺWc}BGj zl\Av|+dĞb"L:/ ,#c9T'UsaQm#"b~I0,=8T{۠A)L *+O5q/ie &ׁg$DқkT,ApQ"/NSx`֍=`&:\be >F) pC`8c%Ii#$Lv K4ePNJ&nWD oq6@𢇂A;p@S9Ʊ5PUH$P4RvA d$3C(&fZPF w|58BfDǪBK@j0.2Dܟ) }MA+?~vkِ!"LYsQ` u_d] P0`| 2p?uq5h%F?DGP)@VGe2$j@)"RQ?;ą@.|QbL 3O%@Zp~ȚCG$ PA.S6JoSG[@7.${*@I[z߽ SpH$q訒Ly['[D 1#ꘂ`87h gR<1sqp R6)c( O*aDz&n+# !v S&"}I$b>@d\A6IʷL.oMno0zC&& 'k@nDO/-PLBD>TMDPIu. 0wQDE{@1?Mm8 U7K67f%ӓ\"$Y'kV@RI3k)zKJ8Տ|3cJDQU @ dܒ$b.pwH_u H#X=իVSnr3nE|)ZOP̀I9ICB/OWDh@]Lf긿:`Z]6Avh~TL.{+f";v~`:OP\{gLf~QC + }ՈǼ7 ~2D=7K 8L 3Y, N %,D &fHR_Qf'D^&yOq0k"ǔuN㲒 Hn@ ?)9/0;! v)UbB v Tʼn3DE0zf CI+Ī@s?ʃP=WHCH7dA;oZ S30wQ2c#U& vuO+;lAE$IFGx@0"(2b@pc`@X-ni;"+`3_ 4wݭTI$XI'h@x,J}QQ H0IOPvi oPNxWqa@d;2hTTF4Y#f`꫔C :i"W Z"}:R#"@q5e9h6iT &QKU(P&ԸHA Fo{|QAc\,w*XJ;amt{~7B "}Uy!Aw& h `QL=S7@I!P3r }ʃZ}JG 7<} -[p? FT=}QR1UI-d`rbO0"[P`(Sͦ;ڂ @xJH> 1dCpl P)*AASd XFf!" A M;#"J Z`< $PP<G)8(l4A'~$:I2kʖI0U >5QFeE=HhTA0TKcv <N B,_TU5$yNbD6}*,DžV` F[9@"$ ^efɅHv2$YSQID _ bR!D`T'qjt$D{&W;#Op\ z\rVkQT0 $8tqIu2@;/!`l'pI1e0o̗`H ͅBdڒ R  #H> TGxR$sq0xX9C@-';@q ~ۨ/I,:OA: 鸈(1^e"N&E2DReL q`>{eT\ɝR?T6% ֒l"87} '1$s L 0 2dlgꂳ=@diOtOYi5 wP\G Gef :>uEWnZ'oj.rǸJIQHMjP{'{銙[gieP&"j#u- v@OQQp~ײ#'9=BH=DA&U<& RtUL#iRF$(;YϤI0wV7( d+"~ 6typ17=B=1`Qqx۲!N'>AxEP<]GF'+Qm0lwDLcM1p@$ #yE\H9?p@;beT Up|,kH'*K{ZG2jJ$'(b{"=7JdbiHșn|@.xS0H9DElAP3qshܩ'qA\\*C31#d$F3AbUcܕA>긊AF&7N;(`2+$2dw1$O\HJ4dMLC$MY6$M-vJl]ws䧱 IRr&=l9쓝wYqZdEf hdbbԈMd2V9ǕsAEokA u$m8\&`7UREs:p # A agkZWpBFE}вO=7EVyz-xay_t_cO@fŮ-q-i5)ǢNՂDdl<&;V#۲-Zq*Hy* n7@dLa^LF cP#5>R P/WIEm 9WI3g |+qtI s3*`|T./X85 A@n3O ^\xazfH=^YR Ơ;hh]-v)<R-JNoQZZ,NȲ19xR\I k쳿o ADIk#P~JV?sV9ҍR})G2 YUD(62bGqUh>͉'ag @uLSTrbgaIsI촍q071Lۺd5DJeDTKϪ V{62A6?uoT..B)&2b1Q2lO&? \ ոTWyHR Y Y*cH2yV]pʢI0d'Wu8">TgʪeX6rYHJp8 KOWk; 8C{R?yz6 Qۏ/A{ZCDYUX6f\s LCfL$Av9 j9M~ɶl,ˋQK?eQ@2FЦC5P 5U D*l~c-0 T ~I#aP[ZE;L$ܘUӚE,Y(3M9X0ItNFP0%k@i]0 X˦熖> oV89 #S $OKMPCHC\ؙ8M y 2+*C: =8ic75 2f E8$@@zvTAG'8pXV4LssܦDPA6JdO/N6Ak* ;@$PМ-Ym@ii' pCyTb@Zq3AaIR&BFfDv!0 44ILh L*+E@V6Iͪr"${D$ZgN(vKA'y4 7\ :m(Z0P&6AR!2A}Di2yP%]  /[ \fKx6EDŽ}"O͠FFmK[e0u<Š ȸWuO&w̒A`I7m1DVuc< n SS5h%jimt#IvQZV))*0o PR1ǽj@a{JclvHRi{ &yA%nࠨ n=0$q8'Q0rB6Xky#hI/?m*@[LS)a1w-XH*jm9 #nɂbtA葎#S4S#dLb%Y>T^T go-@".c fQ\@mds֠@Bnk T!0` $h^Le}3W5^rMIp>mSOj6p?(ANVxR"0/L 9PuTv*`}@nJY<{$p&%Q;{DŽ .m1  Z<}p;τ>T MJ!"& oڊה1s;\a$H&Am'(4P$O{AtI% ȕakpO&f£Tʐ"u%*AD",H>sdWYpD+]|ExߌptENMkZKU_WZAFsYހ6 cEktF9ыDPw>~T]@pIq[\LXP \fGPT sb4L#IK5bU-sPfH35@v$tEzjHd2@w @ÜD6@672F֥(H:LD8Mhk0pvKn Zť" HPӳ?߄DXuza1in`Z0 pq'꠨ϧԎK@{p9Za豽04D M75"c;'̀N7Vh*5vKp~ $sD6NRZg5opsX =>6HA2 D)TR m7Nr1qZ`i')A&L&`}&RwMǎa&H7*=3zGcH$L#TH862e>B3DOMg| abfv ÈI3A(4k5޿tMBt7q3`.&8f("RN:b]0HdSv$@Tf |$(;*l~VPd+j# ٠&ĕ>">2G?*Hd |&zN$_d ğ ]21 dxTTϔ~葋SȁH,+U"$W~["(N@9܏gȘg#L @&N;rBdm G( BU~R'xLy>% 3B &*0^PD}׽xpv"1d G] ""8&澊3 ῴ+Fɍʩ1`:7ʡ#Q" |)5U 5o<7\NDp"Mب~E@QNJAh/ hhL D "n`@5Ɂ#"( ˛@‘2OT#*]1&HH5P-s 38#Ғ(€,ONT}fPА 6NJ@ Tl2I <:O얞1<|(S0LL@$Op)I57EU ";@!OՏ2=J &(!b#t3j,ڭfu;Ouwv* V P0",,nE⌭,4I*Cwϭ ۬JI2b2dTsD'ԧ흐_FztsΫq'}n x'ηWQ$[{/gmCa,I6F?C4#}6Hպ %mѵb_ 5CQKH0uc|h*a3q!\4v^aC!@iDi6{ $O2cA3jXKF[sOLܬCs}@4?PȜ҆iLw *I4 C]PDo5rDc"4\NUKoŤtȏT숶ˬD;Ij A *5IAOFęPMb \ߎ8;SF(5iJe 'VA&*`J  ^}1c(pÐU;Hy@81kv+&|(.RD%*0q?ERfG h@*$H1|e2=43 QQKVk;! ' 0aXJjp~  j &@HWKs0;%z0AEK7`K[beW{J$Afd.@TZE [@@"$:dQC̉?ʗ̝wQQ$47 #T6]}& *$ 1Nn@>r¡BA?1M}Bc?"q_N P"G *3L{IؔQs pe0|}E$@IW*E{})?!P21$x)H) 7("gJGl@3X /$\}P';="M؁JeE=c?%߰@&fwE@8E)E"*\f'B&bG0T3LmN'F~t=4^UV#&"+9G4bXDP&8B2-(8Nk *_e@[yUD2 ۄE e@U<Gah37`|NS-'x 31"* rNqD~=M6*Df3' mwI IOW!)1,ˉmdneg$HLt 58')L i jӼK<-8kt:nO"@R LB@>PǐR03ϸCAP8,xYH2aY^TEru8U_(RN=k hOgW--ww.AA0:t$HW@tl-A^ F  0`L5mcLI0V6LNQMn1=x"n $ .$LJdOI:B6L ǺPlHj4geyvtsj+nˮtqd`DxEITI-4|/;=>^ ^DZoj3"gU@w-"f+c@I )q#u jCħq6 U$R qbBNXt5-0D"jhIFAIW6b7}`TΓ5‚K lȄͭ'Va:#kV2+&$dPfOAxQ 2qX0"f; :dDF ܐD 0y?w(h=L T-?U@WdIV`'°v5OnUӳspqPʀ`nNꇉ0 +A ?V /HuP0 BF@`C(dPEP20~覈Fpd紩Ns O"jC|@B'b,~$O ~I4ɂv Nh+&Ӱ A2 0>+D:f IH=E{GrS-98t ,&{ q$s$dȍ/ A"qN0d2?"oE8#j3Q9d8YZ4>QL@H~PQ5dHkA_tܓ 3s\W* !(V2&\E1ꟷ!7JA>(6E )o(1Hn{#P 2*6$)95"a@2LNJ5Y%(Da"dws;]i")"tsEA.xžN%XO l)0h K@imb&h>&+43FՃn8qyRMӽ\L# IaNPJfD-@1B =;OFޓiQDnH4s-F a]V \&'uz}F. I Hhqp~ CvZ6oV@  xSV "$a;ĖeQMj DO:#(-'1JoRb6@7%TP^bn& $` kXpf2?FbJ@gm} .cHshtݑDY$ 3áx0uț7"nTO:nt3ƒ:]<+iʗy n=.Zn6vVƸHmf }qP 4 @ 91IlT"D@- SFzf;f#֍Ȃ $д$Aհ?t ܬZY~",՝A`gqw9Xt-t]KtRk@6fΟH7ZU ctEGdMsiT}Q1 ;rDNG#\QN)(~; Q*!3$TNu٨̪tDʩC pIA*AP @ ^ rS2/ا0d( ו=Cg0 )Di'BߤcabI&"g~$&d %~#b9hʖʴQ2sU va0.~D $9 $M6l{&D'DE9AF8)DT}L?+{C])2>̛Sg#dT}ԑȚRIP7A1\X**JAMkXXn"&;)N&ZFbqirXg1H mWBNLyUϹ4U/@dۺ@)HI#  %|N&@'{1ؐ h!ȻH<'4 H؛RfMc O1A H& DJF3̂;."s.y$A'@(4Jɋpl`TOA#ҹ3I쩤TP=#UI#h }y#s0(pq APQ"`Yr;Lk?r!ܥ5 Rb 15[ p]þH)ù @`P7 >CDHwPjK?T Z4$چӉxWD; ">TI!^ ,0A&1nIB-*-ǬqB+9!GRIBP*A8˚Di16L Ef=zM oGN)Z4kh8F1Qj7KH&[Et`[ #Ө << LGU${A8iL(EdEĴA IoKvUy7m&s7Vjh sOm6$,zH*@I(q’bVUHiL@dߔs|T.s>R$xPfY$@r$47H= "!&M:lf\ %,Qh QID7c06]F#!' gk"`QYFL2e:N;UB7I0Dbt5 HQru+&ۼ|[o S D\*"/dEBj8n"LҊb#L"{aI!\F@c*V<ϱ0Scb0 hi MbP6>#6" LlE!$3D8_!l$DML& 2}1dP"1~RAcji0L4Meh &3ORTA_BqibaeI2A!(R(,F'&08x#3HDwJlhY@f%Ð<⑁5H$=3O^dEvPpG)@ oS;>JO1{7(>A=Z4:dI Jaڅ M0l U %3ꢀ?0c9L h)aOpj-DNe'Nn$c$qHD]yvR3=D#M1E26"mQR;#ؚP]Lԃ@>8PCsuSeD|DA&[#s:5 IAA`*&# z&#"/5dh*h6{qBأ01A Hď\sjpL8}֔I?)v#KIA ;)TH(GNovKK3Ph@15|sE\'k̥O!Z8uOX匲 xAcNv<@93&g#}" JLf+$ ND m -H4H#ʼnMzrA17 U I+'7ПI\q"N HϪLxB˨K\(7B:znӀ'vED;{,X؃!dikҖƭɴ[_PSLʱl{*khЫ"];.srPSE8*ěGC>ךCwr*9@QX@{C&q3eG 7&*mA2f[YpR[ʝQ3@1GDޢP\OD "@t㲡ƌrU"DBB@Y ҁ9Ȏ$v3(7aOHu{fS-@6gɛ"OܩAjRZ&̄QDŽR{{! n2Ι0H6zXJ6O.H5^TPlDx3v*p'PSdri19t' 7 jH>uP\]@vS[t Mr! [sED'Lzd|JJ,'2L’F.>6H۔ǒgF]NYf'yQYA-~T9s Fo?u%tsp cOl&R r@Z#2. ޥ"AKL'LF '-a_!9u?R~(&&31zʂoD6{f9[Jq/Ձߔ&Oc@t,7L43Ūo,({t;H*\MK_>ꃉ`+044E@Y'CFU aQc UBnTu8xq+i`i*.10$h/xB kbI4WS@, %I1>UV8*ցu>aAAۺѦE٤8#’x졙h&@YbLB$LL*ҢgĠ9ڏׅ5It˅h|v OPJ"IAbԖ"vNmdILF{n\f06(in Α$K2,A1dX*Ya*/;{6߱Cx f^6)c^i DjxL4 EnpFodVsL-K蘢 =dx b@1IuD7דpq$q|bd8O(f|Gȉ[OFHjy?)=yT.DPڐ)Ђ4 ]H#t9,m\&L8Db =(5A''d ]I Mz ̃"õE'Rт@ͦjm+.!\: x,xq-1jp:fյEY$ 8@ˌآ")ϊV[ʪ5H- Ta . Q UB@B}a&nq (=FDZbw?Q5eVďPBjgSn D~cA}9QŘyO(310^6@dd@0r10~R%"錠Ncu.f$d`ctEwbwQ˙&ZV\@?t@j˱*+I$PNa"CGeTP=)?򜑼EH9&>$N=$T DH+B'}"!* 40Ĭr?`]4)ޘ2Pmȿ)bw!g Q[>j\ A)PvH,#@B jy$)9l۲{8՞gq>U.\q# qWg94Hu)G)MgS9;dnć$IpFr}'AEL L**?MPs"'GM.ﺶ"P@.$fditUu:Z9)kH5TH F@RAN~>TH|ThMJ)F dbCu$9(#­b37@g@^eDHA=9s#l Lו!(Tx dtG=<`I<cHAt M[Et @IZ<&-P:m(.oY}dD2Dn1DNSt4i#o*dd$sWE;Pg'a6U,0,R52weND ʠpqv;R(@98=UgZ`hg'0]{B xLE0H@i0;U0jLGzOCӹ'ʨcC\HA&H:+D`Z *Vnl7y"këV1@*Ǟ2vRD3 mv w$pObe0NTIU55u}>;KD+3v v@ȇ @IZ F0ٲ}ąNn.LDa Z'jU%[(%ߧ7K`ÌGQJ򃦍:/zN7;#h" ELiϹHi8y dX>R-R͉Afj 1?Hk2 $JAD@U%I9;so)@$ Y3H&.򤷟TM\dP֘ #؀ ChXRIv@<’I$'>+ɮxL7.8g݊? %ܞed闌3Z kDA±XSG%trL\@@aI!>UW>ҤR ͨsuG3j)D3鸇+@l!gcu25{$i +RgRO'q& D@ȟuQ-kDA>oHlAE'tM @tHHO(H)&gꘆ;#>2#HIKreŦ){Q@ I0'S0}hmM QPHӨp&?Z(&32Q >v'?ZQcT̊20A@ v ¢!Hi4G핖x[FSHQXdBE v[8v$)sZ J.9R$ ̭tMpnhXZ7Uԇ:^X̰:.?}N#f0.vI[;Ek~4C` Ub1甀TSDH?S ׅDu ȽpptoK:[ˋD"扅LfDLX$vXs!dkcj]iS?f'Y!hH0Ry$2Lc ] 6HHnl沃F*9H ">hQ"CFd UsPy2u;JǪGU%Dq&)2P;m@ 9Zwu웝b:tsD qDTtZ"'EʊA3blŤd\R{o*^POH '(0dHiTt׹K ءwPE7AFJ 𤓉?A( TV}C7f!1#@JsILQHnf2|Z\8@GLV$bNV`^ӵ*2 *&7uzk9^&l9ò"!E`bnVbd &mLap-2?&&)bFZ j&&c@[oH*3UDY!! <ԠA~S_UwVٝA2Q9|`䚌h%=&|#Iq>зh|J#YȄ)&~(6LnTb!L ;H0 |''6_ʣ>5:0",Td'裧 {J+GKQ&TNACrs&?d@T&HNvH{*"#&L8H9O fèꐛMa揁  8DH*1y2+w*LX'XqFZ?GUQ&E-;i$pU=X!tǺ =BMrO xE6gfb%i&d^5$@ Snv?)"Q.UMS櫄; gpx@I='<.7Ak 1yLɃ7idQG)q'6 8L0̌N0p/uM5 ə۹p3&1)L\I48H"@'#gR.gYPؿH#dөdvJ[R 8* md&}8漠:6pHRB(M@Kݚ#!?af6UۚY!(pFV$ DHNʹc wBg┙F]Th J%>" =6p *CD^IL%ُ DR B:'T2y 7A' $m+P a@Qj@T@3 ;GASd6##e ʤAghu;KUtC -9@کu884AѾ\$A܏v1ΘEi'd!OakMlV>ꀰKm?YTC(f85:\ o42LSP:}@!&6@q-@Զ܄ˉ8E2 0S$E}eɑ1;BXRgu ꤓB7 YGbI or@Pd`nLSG(?AH\LTj O0lMe: >.7DۊI@aK\*OcI7=ME_MleL!Q5E $L ;OHp& :}VfNF& ,Y# DD7<^ b Qo3'g@6*izxZypn,Ya"諣Q6'Tm% &; x '–0>؊2<pT'R #=8Ll~ oVbU[ 41d Hu¦ `D,G'F$sh4so7K[iӚ'J@hKgHժkb@ج0i m@!C NE1wyAHLDd#ȯ2 j MS%&Lc|8r"" eAS??Js~3U8T"cDL(#OTL`l'PAZ$ g 9(h)Lht#5*k;l 04[ B 닏{Nk 9DN E2RFSeU$ +7*\7D 'D$bB\HT?U&H  SC*bhLzv2s*l܅"| "?ϰF9N"B6V;q5< bA>ʶN.fͺ $,Ѵ)"lA$i:L ILp DN$ ͌LϽ(&LȈ&dȬP uFn#TC1Fʜ wʂ]}Q@(2| 3w"/ ;TX `A14( 60~6%Z@ QcCLo 8;>:DSSW*ɑ D;h8D]\Q(cDG[czn`0JNTE8M&;-Ĭ#m4h`kg̠:.sFkwtzwhGˁJY.8h!bqmق{M#]$;DjoutM`6o7 }Z˦ vI+ e14eװV0 Oi#jy,5BnrDRXhmV;eTc '8!p!Qz5ޞi~Sd lqK-.V10F}j{I2< ·FT>H:ZE$N{VH q[%НߓR`.Md'(q?u1]؉qKfO}RdㄋC"D@8Z75prkb-UH88W&surF.0hS$m0J"Ț@ @_.*ۼN E RCI±A!i6d#R(DYMaGu$IlDG ꀈR؞sp2 d X#7#d*O aBO((2Iy&1&= *bTմ$ #P="R@L)|E-KgCݣ{-$gu.t(2g`b;R bp.#} *2L_dpH (m%C%3HhϮK qp3CηM~p=-GW`muq9PbȌI@9N6ѶԪ(7M)Ozf~1&yTLmvBKfA P0LަD m&&8Nq87<yW VB8*'HO{?EsdcMS k ۟ez9H~+͂fb> 8Њ?:h˚[~zx=A'WGI7V#zGW;):JѤ8(>TƚܦN%\0MxB‘G []6y@{_<-M+7 @2AqTٍ@i.{zC?#ZAӒcLzW1iH: WQhUFBA xl="t A|,P4 `+D`3-$rb)i$ѣh#DM^wO2ym̤f,A?P5]:"fèK`I*H,шbNđRM Nqi:cCFgQ-IGyn =C>^& I:d6.!:##.o×EIؙ4%!IL#02b`iDbp h It}=3Fc3 Phn9ʽ>n3 G 4qTQeL9~Pj=d8546u :o lO8I6ZLbqDh@3F(y=U5 nl"Otl LXmϔ#`a&2ɕA؂#ʓ;O$Q^'Iv `afPHY2ci$ J04d)Se$@ 4hٞipn6Ar g(0s5}"D0>u60~Uj$d#֬!"2{{*rBADU$C@%Ol Ew*fŠ7#7gJ LvR@F`D >L$@sYOj i@"cQAM˜/'GnQF@% g°g14( LS{DJ.?AbI0Zc0v)$DvMbH {T#Ũ;vdON'l)Spܢ+yij \DOl h2h#@AR AL{$s+ `O'OKk>h㈌z1C,02Im=V@pvN44 c*_DOQIXa7 0Ppy a9-.D h@'!hG蜄$֑PDd @2Lͅ@`˜ B*d($M_kZe/͉{eQ-""Mr F[uG1ڔB >v}U%")7&G5ӒP$ q\~HQ\4Wu3Tiw9\d $.17R o&$[8[h{-2/`<  LhT@!CL\bea1 -BZ`h3ZLie9 $ѯ,AϨNF 5-Lo*hhLAq]ڎ3?TZ$'DT#$_ 8o½m ,m2 3¡ "&0a$@QOʝL sJ ~`Kzb.q.UC,s&sh)FLgC#DZ QH2DSQp&"ʠ~kH 2B˺Nu@ 5740行Hi '!@ĆDvY~%v!j}0b Tf)R NI< [ k'?D8oosC&Dꔎ# Td ɑȄ  V'@4FbI=;;1@I;€vJrr2$Q#1GO?5|ID82b#PcPT(#6";TĩR3D(2쐲`{@&̐H&J<aHmEQI3CZ+$%63$#dAtݔh>!q:`4A&琥Iptl`ez{k}dFv@"7U c1D A1AA-S@ئLHh,IA+SuzD&6V0LyLMzcCMb|&O &ܦ['W*:38Tq*NI Ox!e)CWt"EG&NbH$KLV+GwDa :NV{)Q[RE}֑թD| kKGrIDw9JIhDwc^4#86It+p"d9pLӈ* 8(] 鷨_dK~t >fUۈ.)ƌDIq==S18wAtiQlΛK0(`#p@6$IRkp3> GP!/ty"4BCpTt8v*34fWLcu"CIF[qۺ*2'.˶WyhjH,1sˣz-:t=/c4#@HpsAȵL~-y!&DGE"^\wUЋtF/`u4Ԝ+ d F\LR- `GV5Z ZP@jlyY@h# ON+PA& Lw@2(@zt 2E}PF@3(plN}LbQ3| d]Ti3=*i7HרaD3IP܉UsfȊ*A9"&>'IAciGcOIL F7qU7P1bA.c27&w(=p"b&s:@(;JRDWD1ߔԸP'M~ JE 8ݔ 1dt i9ڕEZR0>aN1m˜"VPʀؠ&$2DZFa&Ȳ7#tmGif(yl Ri I1BH򖙴 ϺSmNۢ" 8ب93LNx)4r%~Q5t߄wASx"10j,.iHC>*}O{Š](f8 =%൹B{r18䍅R4*OMŚZL}I;'M'n]6A,.N}8Ʀɓ&4#Ab*{.pX[0-JZLO Ӊ) uQ}PGΚTY@T$ eΠLFz*g~srQfe&p6L,uR"vdT9畛ONkl3I f < gdR $!ڲ&&{\d{죬R?zǠCή4,pfG#3f3m]'tb "A fd l[c@!2HH4EܟxW1F$$s0@2DZ"BH2w$s8H h@QY w5Q?Ӱ}F}+p#gL'%41q!H3p~]>AںfF1@ q(*j䠶QO1AG-->DOD2lI#4s SA [ 4O Fq>GPDϐYH( H"DN6HBbgzBBbA/o&<8Qip"$xL,o(F+F2cl"q71/ ^ @H`Aā\FJ-CU`]{"f~05SFhߺN`"!?20|n,em 'UW(%^! BLk~Dj8dM$Q0 20xR?Tip|]a6v<8ABG5}&(.NvjAR]ci1&8 fՅih@&#H/1h?QdB) Rwȃ tChsɻDŽǙy߄ S"?,zh"Jr~ d{.ִ*Ej$X!Xi~Ɏ0L"y6u +C9uo?yDhD4g8 s#_t B\.:y aJlPO}2MDK4Cʦ9Γ$ܔ QܕQaИ>fI&4Si4$g ]\ib{B$-OA1(0vʂ O~eTS>;HF }7D꥗t/f-\vZ=k8EGhkA?}V=.;a7kbf ._~#o\5;3`b 푤ɬ 2H1X20l8=;DjMZ*$|10$ʨ_͛#P3\)i:lq)4DtdeKHHpڻ8h ߐmAɹ(nxA@ *wLtB 12I58N9H6'd(hʁD4W{fE53Bj̑Ahш2\ =ոT6kI(@:`ObqHh^QyU0 6 1U TVùr(NP)@_u}Sb?+IVؠrӒLȉ("{H"*Qa0ڟB{iGhE @C##Ae.iT >eJ]@[H:d+b dܤw!FĤ6$!C'P?'"n $bl QHQ(@9阄!5nyR WP~0t[`I,Y*ҫPEQ?P=P1coesB9&@&,%IPDaH@4GA>tE|!o9A3IaͫT 䢤Df>e8[I rLT!F@[ sZ\&H Q>Y՜8S 6"A) * BI{*, 2PTUl'm0Ly@E@Mgdl}>PfdJ v3DP߅ܘ=UuJ}T%A s n$ yU I$; ӰD0f[P@~7MăS}~ԖTL;yHAS7 :A=4F,И숖 :™ H>Vneؿdv~UDd @}R@RCZl Y J"& Kl՟+9ѫ?+n6[<"@n>7tKCC"Z#"#W=ɑi@ry#" ^H %gEAitA–KP6]L  @@ǵҙAjM\wD Ө 4 t 'l'4L1Gߺ l͎@vYH ppsD O ; @ *J)LBm?? ,o_G:6c.ԏIߋ0:ߓ%$c9h+4m1} m=SDzMAt#aQRgi7(P46]@ Up&䠀@$$m7N}Rx@` ;F 1'H# Idv ,?wZz8xl;-ɽ$} =?CZCbw B.>q 4H1ey8VhMlb5LA;*N >SqkH*j$9"g)pOPH))ꓬI;DEPtL]"InM q)Š #5L|`scN.M  _ ɵ@2E|-Z7vC9&}U4R #3rē 3[%>P$ `EhjI))3v@(gׁKhg;5UQ5tt PRg {}$PNߺB @l2?T5AR2adQ-4&c 2t:5G"IM+hI5 AڐLX6I*&H`P D<'`3]B& %F@6" 32ߢ51Mx0P P`_Dw ǾT1ĐT5M=@' _)8 >QI'(p$ n" gdPK$qj-r;A8>w `"Bi5@9s ¹܈I3"'P*Oǃ.*$v?I7u(Q~67_\.MEatQR+a"V ~AivL>s;lNdc)F,9Ruk ^5Ѽ`zH* Px dؓ^a.DyZ:Zu> fۼDL&96I OD4,L-NX$aeX1* 1t _Sq#ʩy)$ 4!}T?#N f5N {;,>,ɖ}GT:KdmSzYNA#uN.oPtFCb`).:JC1Vd7>ɮV`Pb Ä d";Hi5V8CDžEfjaT"tƾl$f)"mOl{EFj| ΝR@. >u8٨4@4mU(-y{Z V?@v,a@u?}}5ב01쑻wRLI1ƛEI'7`b~ST%'X@:H:7:@k7U@ڮiKq (8>LPb|#I 4k ~>vT=5ҾJoSdE AeS@w4. ¦tLc\ x;-<ǔl~acp3}EEURHP74hʞ1!TIBC4@v~8X$bL9&;#%ĂG)ɒ2X4ag'JAq0&PY~Hd@$ G 5q𡽤5c7Ax'9Ԗ`ށU@]8m<mFcQCN 4ݹ5 %D6QS 3$WxAS)JC9H1@ r2 k.vDI@x>ʣnt<6' WFuc"(J A (&K3Te*9CNmN!" is[D–j$q]Ղf[7{QQ\BL6NV`$vZ| %&,P05@HDs7Ik;c32ăP$DX, *. 1] 0jZ^A9oMDF%m _C5iGd~{qđDX;QCDAMZmQuEʢߐ–ȓvO/it! ;(!֑f<-Y #Ap& ZMى Њ${Dx{%OrV%= $Hӗ"h3`*ÂK 7H` E=30bh@J=$q8OA$8dW5{r͢ RtuP!"$,I 5Hq_P=DEѫ׀@ M`O Ei[gQIn1)$ \zp EV e'>S-S '&@GeM$샃$f#l6DQAs '!τ u!F \}Y*$P؄A#{)"(tLFJa6x@LLq($ 3̪k `Tt!%Ph p N` ! f+DcI*$0q$ T:xɿsC:$d} NwPcGP(7#hL d2T@ۺ@ȉNK&TRIFcY?_@Ә$Lo-s '<eA2b77a4H< UÑʽ!D (i2D4G{E3fkY/tL%L1@[DLp1Ct"6[&ZћU&CIdÁڐ}o!{!p3wAhLgQ07>T|!$L_A; ]ah` ` 0x&?Šẗ́ F}@C8)> Pfh|xYKBLt@戸8S:?t3@Tin&^@P@܂bDDB3 B^6̪A2 9*zM&L%jLbYU4s|BKO}D J6mJNMND# D7Ρ"AA+ i$хɇhj3;$mK=R ĂT˅Me cj'[D@}ME_QkCZ$bĠsDܺ 3VlAp2Ij*PDpg]3Im2Cg;Ӄ]2&Mi gqY$*@VLg?"掣F~[L DF$q%5qL9[" er^aiJ?kxpO2lϼTR:"A@XVZt[L,}Dęۦ J iڿsmw }dep{I2>Ȉ XwQ"Dn0$GSf1ťEbV*iFn`pHV5, F O(ۨA; b'0;@LFȓ U |u VBo;2h(p-ytěbǺDBђR2&ZD;ԉ|a~,)Sm t@0xJjxS āN14MrdMAN190NkdfFxGUh an?H}ְ5c*#Y+LLMk(g \cnPL1GiND>-7I)9,E[mII:,51p8Q-pCLi%`Mv(3o Aϙ("GZ$SsI۝mO'(pP BOa 't}` s¨jgDjB"wJ(|O)*d|h |!8A#IQe2d(kʊ I1S $i}sASRo ;8iʒ*jCq8 7 4,IjG$];_Q * | ߱Ho F 3>֘ha.@-0 U\F?1j4"ERp3t >;Jn6= g̤H&;8HCLBZGv3TTS.3H~`Ou `5=F{LDp$Wt`Ole) 9(<j^dxR]=FNrlw 1R 0d=EX ePYZAx8 @@ _!$&(2<ւ(B=*3"w8eZ0eb-Z32feH1qX&R'zʇ>5Q$\ˬC[$4]\絲LzDzZjh k@ip:hBR9Z]xu`Ř";:ly8ԹF9i1&TYryXv42=Wi,ZFq6PIn&ldّKzpTk G-t ȩd4u El>'u4*.l:`i3Nk-d ##?-=D rl;-}d*`3%0րpʡ="UֹgEw)U>KDbȩT?D6"Z@zAqZ7#J/35tIkHtVmDId0tC`U  jEKk{Dl'A"("4GT}2F(6F+N3>o7J+qDD>}'ș=b4R.}m'8@&xCD5H9TSHBf+GOѪ+"1&otD6jA (m)5A%=i"M@ ^ Dȯ郱I6Ĵ&bLi*%@ };PI7eTMUy ?3q>{H:`@[*]97rU d@>:,oOƱZvoA@؏ܞ!gJLA(;*[&Zjnm%=$xR'Lp!9fӟd vY@@#;`T@#;}f0\`VJ Jioɕ ZoACfE]"ء4GtHߤĢPbdOL:%EC&y!S 0&==&aH7yTcHD@"\$7&9L1t7IlrQH4 |bmPkG$^1'Fm򜝏_) T̟S#Cj/dN;yt{$9D2-uB8" + yY2V偹`09R-3.v(hm֚{J D$Hi;4&=TU@Ә 7L8`1{My* #~8A5D$s9)XQi )emqͩ$IdɈ`I$vr&  t%tL;%k(,[xK\?TKbrbtr%IiwJu߹A;RI$"aD5 "!yA9} Hiv0A;kIgJ44*sI'W/SK[D4 & 8?ҬSycFi4!S["&҆\IL~`˄DM-uW5a&HT9 qXa2 b2l" P6FbRF(dv0}*E^mW“ B 'G5b, $di&hc JI E}LՍz xhʡqlIO#3Ly0`pR@yKqQ0`1T I'WPIdC$+fn! Oh8Zub!InО5N$&@&y@,P⁙Cd;hϔugGN `vuLF' ')INA14q@> :UL@ILDmi6_Qw\kp $ %L -F8Ⱦ0lf |H<)8HU5I 1d ʱ[\s '-Dgmx&2& wL{J3*Lrf)A%H?DA޶VMJQTA. B Q0U%T ;4$p(21!@ص 4j`*oB4> sD| I@ ) s( 3IFrP=ɜ'UY~Q}?.n jzHED7n7HȒP&P鑿Tn h B . 3DОDLm(h"خaIGjAqkH#uV" b (i.iu KZ%g:]a%sXLx@%Űw|$Z(oL=-'+z`AG̈V]`\$D l[7S,"hiffϚTpGu{"h:LpNs?z6v6Dme-s@; G$bf;S.HxjA>R,"D` -~X tGuܸM dcs&:PJD3!߮#2[,d@ul!nU ֙"0C$}% vD8ᥤ'Iŏ9T7?TLT1EDvH7o 506s"&D*'&xSi5$(R VZK'(5h;EV&f( k6}Hj/9ʒ*@ *f# kH+ڡ4  EE?ZM  Cs57  fЈ {BȘxCB/;:hnUL֓QyK[t&p` rFT8o*C<$HhPf=& $L oOH$ ]'#(¡fd (tyNFNx3E) $৶BO?d$zI&3XQL#LO%P0~sMy@~UXXp NT~Vb.8IIg* 0 FWdsyT䠏U(?T?LQ LڶwՀLOM82(R雛[WjpshP%8TGu5AohP^6! Šz^@֠D?֘ $4l;@Ƕ8H3Cߺr44*[ԙ.AFG*+> [hk؎P G(j-򘽾-F` {{ŠX E UM&sޕD$l9R=0( c"8=1bt ޒ#HRkT#N$@& \dQLd9{S 9)KG d')dݞʡ; &(P`(l;ςCϺft;e"HSHDz ia`M ނ°,CшT7J`$EAxCbmh"|8>$ =:{:S7Tay I}kdutupl |Bۡ/IsH!y:A9/SGI_;Z\ ޿gcUb#unXaxr47H7821jE9QQl:.$ȓ8ĐHp0("1!ei xv[Q-e_LNHȄFQyl@rC >0)>G ]e$8A3hw-ӞPH8nt7Swkשăs 4`쎙 ;pɜvi QvnӅm kmh{,7P$D AIAJSw2ִ7&YB5Ψ'`|xDP"*Nd 5?eQvIՙAP;— &:|aFA%@̓i0QxNor$<M2$]d6}Ŋ)APhɹU`YP'W{NrG{ʀĩ9(LElp*idP>|*"陚;O&(w [!9UFu`FJ/mI&3Ɏ9'A``@srAf7*AJ$"!x*9Lo;DTkq1ǺGC@s8f2J&qLH[I |0N>DH9A]dؑAd~%x¯IdO{* *A$!1xJ?+ |A AgLZDoł#Ka‘W6\MŭI08+0Ꮲяq.hPue$(ci8I#>jQv* F00 NF*阝TK部"tN&jlLOB?1Ũs d4~eI$~IsOPH"lL}1_< <#96F?G@F>`b]Ai)L 8M> <)nQ7H,:GK9Hqʠ,@Pq$E+EKlZ*Nv6븎wHx vH42x0,pc#9DžT0$DLtDmiW]MTP\]q# 6S AxAy @'A Q$8@| TIJ}LtiF "$FΙǜ"N| @ LeP2cyFan84(:/t;n= wPGUXۃL2FȝHDDY?M0˦8jCGAb1" S[2?7$,x0fO§1L-X &mhǏ-NU 7ө9jM'8jy Z7Yhra)TL**Z 9 {tY-hEn.a'Tȹv+"iA&EV+J "gTD(n"he1DR$ \ڨefg .(˛ͅC-qT~uK4i1~k2'N@)0E&lQ'cg2DO2+ըJ#t"h\T8P <3A3Vi*wR\nh=Il+y:b(Iڐʒ RLg蛁9H c*‘ .l] V $5C9,'` Vs8@'M5[&d"PCD ~c@tN·E'0H>e#b#ZTgl3~f̐qL8N RV-TfwJ@8xT/d@3&dTu`b~F1INBӲN vT- Wr`IQ>rtդI(&> N f{BѪ{+m`s`vTNFv*  4 IĊAx0J76&cCP> uG44+$. Qa"hH @8iU<؆5 V Rm ly? FNJD7 fw-D ZO &Iq=Io8"P?[@Ǐˡ?iE,t }GkA"$'.k!`;-#BSֺȐ0SG)"DsAQ.tq7Wb*Cll$CJ BL7#YNxE\e7bD)A'2?$i"@tT? v nT>" )?vQSsq1PXï;6gfǗg~"m ;&>Ƀq"qM)9ըfjsʷ$/,tr)e[#e4 a0g6>阓12$ZS@TP#GOPiw:wZ6pGɮ.n#t`Q9@b@&%?t n$RqDM'Z]P3AĔȞ %N؄PRBH܅.h"Mؑ80`t1!=I?"g|$ yP>ӓ\ )s&!`&?\RF3 (rsPۺ"#b'ͦ/ A;zC?ݓk@&DdW)@89!bLh"1>7YKq)E]뀗J HjMyI%uHB 6HRLюT6i!6>)S4#+ň v_= 4 @ $N|@~l?;'0r't>BdcYEƳbdp5e6HPސKb"`29F YII"LIF ddqсI$FQcbg@1ңziI1BuEܜ򖘉@sTh q̞Rv+Q2u#108qϮ^u(-+|j&h* 2w = %Xfd;L]d Ao}7lO!>`SPb"o~Uڨ{p7b`Sf8@2n x7P108!E7{.3&#NPA}Dh$Q**BH9Eq" A 'D'ŭFFt]uv.a1.a'jkpP鍥_K*D*4/IA((j=- NJτlOC >..1B{' >rDFn#ALYo&( <g!T6D {V_܏տ*6itT1R#8D0 'oe4# I)nX5'h \=f9^˵\Ru0s+5aǧoem,DͪQ@GQaw7Yڨ@eb7&9b@Mi$ʣ %SD o@=U*& 4I Gdx"L(8Ǖf"X .~!Β;nn!R ¸~<9*t)r>聏#{Nr"L+g6&17'ZD " 6.OL ?Q DJ;L"c|~7OW@#7q ¨y@؁ 7 +1ZBD `& LJ`#>b Q@wM܀F pQnPPDA2&OMf;7TEH6["&HvS7<~ 9d^pPG#-ujvZxe˦F BLp8DP| o}T :YC:r )L:;+g’jӕD4fM%NAaHA۝ԞHB uK1 mD&잢%oHv[1.'jPe)'a\(jd']$H2S ;JsU1JLkZ MUD}U4|'1m(dOP5I&sq F?^K\ >w6-!䊑C(_()3#HtPgIUX'x9 ¯AE-&7$ ]ߔIdUiA!͑DF HFz/m4lmKG: '14tfTq[$bjDIpNLeC^OP <+7A$T`-OxP @QKTS{4Tanm78 :Mv$Z;RtEjH^25CZl֝9`- H1*hrZeMZptv DLʪaXɀD(a$!$d;r1K D.v(q7$qʭ'8D *=f}5vTGeQ)@ #2pc( #N&I9(S;QBe7k EnXZd&{$$"S8[-]W|-](& A"o"9uP;(Bq<<&=C" ARv~, B dH.s`fBE)I;*dbbc9I<6U7TñPN>r0m0g'DDHp ]G U鎘dp s|fE)NoLLA}Cq#Py"c'ܨӾgĂq'3S$%x9=3J4`|-E6wM#ʑyMDImDǃ @ "z@ <KMMD-Hpl EČZ `Q ^ɨP31_@mS1*<*H'00&j UU) 4q1"DLȀ$0$*lA)DiPN>R-NvUyC Σ1B=BQP(3  $!Chlj&ΠhP&tIp)3TI$Ksjr e@(9C_ԤD;$|"E` afj J\EzE20G? l$a${mPHHu$} F#dXǂa?G6 VO]SvTD" 'ﺑ`=q"Us2Lה${OTz`UT2ФY @8do%YrZ+{5'9 tnN–o L #L^6@|rql% ŅTDA@&xOdJs;("f8KDjRkdTl%&d&x#W)Ms֑Q$`@*HU䄌ʩFrpu  26@iD-IFUP"2!}qػy͑"yA2Nm+"i4iK0OD{ F*+&\AII𠜷UGI:IڐƑ$Ul`V @q|fu -mhVv]#Q2HALN?}  ظLYxJDmd5*-M=J"F NԐ0w~3s&DSdIP= 6.MtIgd yCGڟk쩢wBădMO"N5 4N"!H \Nw>S3Vu>UD t)Dخȱ:dU5)A0qHqJPIˉ {AMB<" tE$|d&P6ďT$L_$AA% PLDuD\A 7DT6nx${ pf>f[._ Q+ld#_|z`rhvj聜)^>EۄmAsC>PǤK6Mu8LI0 ~8`fgcU:ގ*hp `N!'NJ\cYVM.ޛi8YVA԰4?,XIߑA6PeSHo RD䥤ju XS#Ht1L#%nLȶ _mXTI8OHh){UQA!N=dT*G<78DLU"h웠 +"4>M]$ɡܔVdb6&cV pDTd_ ZT q -p؞8UU C3;NjH 2AF0AQV 5)-F?U̐6>QM[h(!‰)TmQn*0c U#t" 9@L~Hb05bޑ9;C wN9)D}TA@tܣI3c5[ (-bl @I VN=TL{xZnUmOfAq{?m-k nq 7oa6wR"dd"LTLt nepQyt7Sz g)ie-12UF60'  Θ@7)s" ESD"TQ7*)Ȍ&")T@(qMDӑ7'AB'w{AL5P_LPGQPH&ʴј! @ 3ZI$BwtwA$I,6́[My!{pح]$gF q#25>}P\($\ DOŻd=v D`7IH H" APL/d83j#$ꘓCowL;"@0G@VgaV%(3="It5hlP6D62ȗI;*3t,դ[2[Fy 0NK ~ɋĕa)uz@zE @  :5ʨhi$-#:*d( _efs8Y%'(8ITQ [4 lՓ8A1̂A''L/N0C~4b Ne͎ |A=M\sLoVr: qv4&6`vH71 RI & frzc AI!PnfʀfL  FG 6GD LDPυRY'˪ & #*+"}3 HgNYvwqǎy]_y ~ eQ鰵H2oIV!Ƣ@6Ū j_|?@+W"hRIu2㑨JܩqT;[Hpq$sj (:dg;"q(*@2~ cJ&PQZ9>0LP(f(Dt쨀o3zF"3 4JY@ϯbIW[hQ 6 7TŤ;q I  w)G@>bq`N M;/EDʁ# uG,rG5\I<*v>ɸgFH1?v?TFG6 !`TOYs 6{¸JdB><0#AG%dޣJ : lL@>:1D*+b$=%IZG?8x=`IoAdm '&f5HN'C_P~ Ъ("HJ9396BfZ'YO!Q!h⊂i+ WdP;HRg)ϲ "P&@vuyE )qy@2*EЀL#Oi0pw-{g4(e=/ r;Z@ vf\IԃE S"$~CFDˍ Viw@ mY$$~`ڨ $c8% Ck I𧩒#bp!" dM 4ح o@W| Rwb FQ"$vHbpMgyH]#NR b6B L7>p I0{ȡ_EB6T#v/8pP09ѻgWVqkM'wH$ &$ʎ aPq$Aud Cbf 2ux 7t]l򛬈tĠWEN3@'#MPhP1fxT('kRIʱi;'2(5iN:}P#!'F@LA3L*>k8P93Y2,HL^"VM5N$H3az:HI:…)} (m*2, ٱ?DLy𢤏oxP?U ,ELA$ lEq~5.p"t  D '/eitHZ]ću hlM B+L 97Ie`6'\sd! sZeF >IX @k 4HF)*[7bP_#€̒'ʡ ~ A Oqand'VȁIUځl 2XʇC7R^3ɛY %j@tA $JhQY\6 xYP T(rɔIPTfvS9#Sv 'yL KVo SH6ft?=1@zJs{'nՌ]º;Pdh$c֓7VkQtg\NvZ8H"< b|8{ʞxߕFФZwըA 0ɁҒL'ܘ=0zf̟;&CP&M.s~PoqH5L@CfX */$<(pIx@]0v&j@ 7h~, 53jb潂+GU}QSV[1c$:f*6fn/;c5=մs@s 5 @& cޓk.1&} y ܘfH6ܚT]"$L쪀Dz A Fpbe ˠ&(sdHaU^/ d F |^|b3( .O b 'nʀ;$hd${xF;ٴ $)hq}&9Ai! G1uEwJ! }d ШAhG4'UDP2؉m0$Iqi 8 -e09w+8=ğ 紨-`iV9>%?^t`@$!ָ4`-Kk.h;ʊvH3VN*ln"; @9Iq+G779T 4LVb>ș(`_uH5(0y+qtlU驟z.dv Q3*dLt7E>Z3 Ht=.@uPf1> FRi58@''-Y&Jm ⽑ ]4H$v!QPg(mpԾ ! EO ʿW#D9 Ӏ/"40툐K D@)@@"J p+(l h=wISSsSJ4ȞQF&&XFrDCP@쨟? hB)uD+桤V~$L" eFB Zw8EIH$L.'ԓ <##y VwA-󟔆oEIm5fƒ2I ]2uA&  ; &M դ.HTkI!zyN|:LP #z6!Q$`Wq0kA`()Q꓌HPv!R ApL*m "S.%?({HL '{[&8MtI foM46 No{@0? rx1"wUs Sڶ9AOx@AcT)$hS D (' `Tݪv8" k֬<D WSe*>S}Fq"Lzc E؂0Q0A2"S!?dQH6)2ᴢ q3@.5!'DIޒda7 {$'%јP"#ZLL?Q#L>E`i9܃y*d + 4LuX2hGغ9Hič&i8i 56-x366U VrH?҂:gi(A"6;ghDd̩ >PI;IǼ[&}0QLI&vȄė2A'hl*''Ҧ" ;(.YL )3q=I{UxP*O QE *G[LRa WjAʛC z:@Gy䍖OZ=1 [%S ^Y8\w -#dFVJɏd.! *lW;_о 4)knRULE F`{%$dD96W7.⺠t1BvM(:H<X½cد\~Tv*uF#''dBu\<H*L jU>­QǺ3 b & p0'A~!3d 4eHNt9ܫ$RiB/U @;xA&-h,Гb+詥|cphЅQ$APD\,z iOR>N8}Xӓϣpk ncxK1ib[*[й Z;`Tg'e8A8T10ϙ@&}C;I1o` q *A`KmfA%Ydm \IRGNߘVƟP#d8bahZ4+3fL=փo F h54g(3D \Ln `r@ "ۅr,"EH'T?D}îm8 daCd8 s[BΚ*1**#$ē1fi @1i#U )&#MAAS$A"$̑#'hHr<yh7 OQPtDoϾSPF 2!g=Dj F@(mY"1NJ RN{ST8| s^Ӕ&QS&y!-H5Vf$ZbrLIZGxtH- ]A3+`$ T9Q YHA@u(idH)3a1^wV'nHA9_twDž Ad6HOh fJcA:fd{@RDͪmJNTYc6HH4F y(]’ZL rug:kphs]4/Ө 'g'C}7tgQM bY9V\0qS`+SF⬓ ӎd&:DK``DNt4KP6V鯲 *1 *R.3\NL#H@BOL;eGUM 'EeMYP ,2H2ȂuJM6漮OMY(Y&kL";Sn4 Z? Rb>wlc&LmG ` K:1̸N}Vד(*4dBՀ:4*#-fC1Ԉ?EQ%r>T3";kyTNK-sd;2$HDr? Cqho$`ʗA \aZIA@cꉊ('xCua*)v@qb~!3:tpi 䠃dXT ;%#PmOQ4'ڐVn""2< @ H4[LO3I\yT DhPNgʯP}ZT;KPQ$ d.WQ8ъUi,f1&T`@"1 + 숰M~&e3A1T/I6 TK%H¹j2}[Iht')Fh4 ާ* g*n EBv<DKAt2`e)m ~$Cn>U_emgkHMNGMߦw?t6xU5#' 7$@Q f\2dSր;'_8‚E]wPp*9MIq IƆ⹫D lA<*ZH"LwGOי-&'3 tqӵ M4{*Q   `ne2o? ʓPV(3>wӤIr;@= KHV,$ v80ă75@Ax'裚*\F vn"-t$$DDvG!Ԣ #9N;.J1J=AFA  ܒ$<{BlI IRC"l S CA(/V/Z\A(1 S:Dh|3DQP;Mcd4(D=R" bb%Q2uDbN3dI(ݨE:&R "AH2~XRNTN-E "ڥl5Y [փ0BDQbGbX FCվ<[zdܔH3T* 1"@1ja/)LC ꃷuikKI- 0D8T5@bi"? RۢYE7~|J]C`j쥧q¦m Vնd Yi LP!}kHX AdiB0@6AQؠf tQgBH<{PCHlcvǍP9BZj_dP#FLͤ HlLa:bg8R6RD՝Q[6$A 0OisNFX |lA=|($HٿlؘIMl`HD6S[ t +襸BM膜|A:FnQ b>¿r~eCB S?OI.&>:aW> P]^̤2I9H#*nqʢFo6F~sD숲Ld&#QlwA$;P`Vq"@mUo ܃ F*dci䐈M$ >T D@ HvAp!Q$EDfgrL&B7- FIUztR@ , &;ѓT4= }ӽ1s  Hr0$_2ꁑ&aPq*Tj;Bn6 f({*^<|Z6{Й0LBs(lloP䁒.|-b:㲱A~ii{tMIjn9gQO\3b~Zd'"4 )tF?6 xZ.hrVL $:+fSD#FA3 LbBA 4hA% `"@{B-"w518k]ar")E7@R:f7=P)$E¦8 H}Bc*peI&P>R @>ȨS 0LIg(*h2}11?E:0aB. y&<)lO*_~1Jsrp<MJe*P5chQcZI'NGKm6H:F|F}&bVMB@(ˤJl"x1^VPVFnKP(&A~IRIy6ջDbKMIwY#T6N{q߅}U6 xU6uQzX@<FpHuIdabw>ЬP88V +2Hm B@D ɸ#I>5@o P ui lO L uGP>\'O6gu[?D<*POtrFI)r2eٍ1:ʙA:L 5 ! T{*qT.gR;GU8jl* cUkIڈ Y\"1-\tZD 6Vl#pp@U&<CiMψARKKj>H8sM$Ey+M/p&RiAHv»ugpib(*E ~_P9)WY5r P'8ŋ7 [>Q;pT #U vlGmc֎;i^ElyA72e pUIqO0syQn nVB.'o29P5qH;{@G-GQʢ.p%",yY,L ,LȓŠqlf0|OLil斀gEX 쐌ɘ j&#V~B: 8t͂%0AP"7i38L 0SycZ&]"MNm;M8!' 5)Q2;BN?&9!fբ(0E<|&kVD`A> u&gho0`Uߴ%&.&%5bAR0 SY( H `zAg@4֪촋)ə%&r42w(_`AvR fOUUeg~aCO"}$A*]1fw Pƛ#bZeV)4(q f3 ?8L$8ͧӑn졊f8;INuQ*  1#"@c8SĦH5^!=QXb0 r"H2hSؐ"7YI0'Nu  o$1m'IW D{wExT#nWUS.f{خdAto[ "[ગp:LtzMtzm ckMF Lʀǝ8yYF 7UnPI".I nA"ЅR(qHf{T5):3R \ 29>L-2 jOO@z&^GoR5+9MW.-Sl6^-mLH&?Et$ x]B :|I#1,m̪i0#j<${)tM& QeT[haPꣵ,(QQB8ՈknjzD*/eĚ9!0"FP$DkI쥲M8yT!.tT'H"fc7-& *Ff  EV6I ju*hnHWK DeAhO6 DCQ c+- @'Jf;R$gL: U? 'nZ`q6u]pqwT@sJ0FnUX'TY w²w \#=pkRkD:8Z6AH ;@ 0Ȇi`oCi4 .+핥PI& d!8dɓ? '$Ğ *#Q` {yY` T&+9ɤlT D{JoG&)hN8YԚ8$kD2;eS/yh*6;"`$l򈫀9D?E͛=f}C< 8HU~\(P` 7aQQ.qU:ﲊ(s07AA8 Œ'|ĥAP`Dz(hmr@ T#r~pqg(3O-e?tY @NtCJ"/kDH#XgњI 0H`Q\ik눮R7 >ERz#I©'FUċ;=t6P{J&%i"Dr{Ӳ؁ #L `xE #nm #32x0w|6 HH 8(U NP"c3F'*{"$t;4#8~i'#Rqdg.TF4G[VpC!e{-* 06{fHt8!'=˶`DvR6+ԀQLV;- Tk}=tD,րm31'ؠN`om<ԗDj$A2㟄oq}d(~$(l~F8U%|q H0G!cxDxA4N>ȘQ)sMQT"aAd |RQҠgS J3YAV>T4ĀU8MI&sN-l}EDjxN 5^7X7-z=8xkb _ƆWW\s}9/$)p͎OPd'q8.Y]#&"Zߕlrysu_FvV.9lF BílYFq=QYsIih$l}P@?򁙋K@fv!)㘘MA:DĎ)ո'3hQH#QNrI$=Ѫf#.P ПS2H"Ga("}웹i9 9T<1i@xCq1]@pc`(3#~&ӰD(oH$/ M $D[ܪk`*qbG!" \>UH"ŠhBDzAhB^F{LmoTF֠>'N=1@P2%S#f&n487E\Ip/8" Ll0"}8ךHN B; @p8uLq"lFdIg;+#N'<9Pf2 LtH1gP]ě®DWV0# &"FEf.ICDžf'+'8wQY~%ߗ=X8H-!A7HYQXfѢ$^F#Ik[\K ~ÈɩkdZ ]#+9[XY[1 Q.tyH& ޫE8rlـ!T2$X~s@ d;Erk0d'7B0jd B s,.i]fG9#tVm;elmU(O!\r|$@8LGϓL'nRwP &7"!!3TAۙ.$2 J 4'IvA2K蛾E"jgZOdMNgpHNb#͠6n'H3dap>xDldIZf7R6VGؼ (S"qԓfK# n|wR]9 (p92~ʁK"$󒢦MBIVPg0czY 춡u`HJak0><8 `. {Z+#c.NSq\+8)e_*($j|Lu.$P.X#Tj4Aj`Y7IP )i"Dpq"fk]63 8AM).e$J$!*Gle@;d_2OI8W \3AK6T ܂O *$w(q n<6b#ɄOp/xY8 ܫ&&I\;IeSBɻ Fېu_^7_Pg~Jt݆8PXxt;dJ0< o pS <nv"&h(GT\3rE^OQ }38As$ @mof|f%aAˢTf &hxH3&b^։$?J U`Y#/4)i $k2< ݮeAM*kA1;k4L@&c)dMAh4y3+9=^Ң$f 6E4Y;1QԂ eu#eyoLZ/߫~3 oP92&31C^wGSZOv~ $ˁf<+Yq*LM``kA-A*5c yVa EDq&h~_ܨ[T,ۅR| 5'm~AJdqKHF5qM@.'IKEsH.T).RK.ʠ$H0~TAAH48liV R -pcR* 35)I0+ȼB`cxEڼ)oz@8>Tp$-N~ C$D:Gn8Pv !A$4IȒhOaJMB.5p"MH9 @*U"l"1 $Vy=wP@i8g}*\dpcE􃊺E-Y;pU5(tG]/ɟuo=F~Tz!KӤl'GU!e7\t\0ӑ ~"OFYG+#Lid쯦c g;ֽ7TOj\(>T3.0LuN !B& ]! Ő .Mĉ=Sb8Bc#i%ޟ6@9`"wUҀHLWSA")X]?ZkSj1JyԬNhꮦ!d$)y$QثsApggXnHPBsz ujt gՅ:K98R鹲 Zi=3nJZ DI~aӘ?Ml~*G&U!o#Aɍ0oQdw;5eNMc1H42 E#*ę6F<,Fkj3_@!$Yg-?20nM gHkTlLaEڂvIr e@f {B$ThKS%f^'#Hyiʺ7uS?U :G 4 LH!M͕` I983-:hx1i?I1*+EY6oRoif9짬l8 u#nPǺ.2<:jg*`dHψNL7Yʇ HgDsd=Pq4F#fvH @ Lrq4q$OW'S5 1\-mxM1#DŽŀk"dyTY2b/H\e=T(yWe-sN7S$BVntx@/V I4kwS"< &$!2"6cq:R tqL^`x\cMzd3 Y}'\6~P 8L?8Dܟ!$ # I,}CmsMPS{Q>P͠0o&%Ri R"(@RD `z HPuؠ:O8L{MA 6q ܝ1d˄pK9C \/I R&,}Pqg=հ}$|)k@Zo&}lj ފ&D| 2e89 QP2kDMNkd|);3E6bjLnb:9;ҦF}Z7ڎah59$106LD'Ma);r2yPզگ$.0-72Bj.7G."dTA5HOj?c nj@ǎHg@DMZd3}ԇ*\;myQVs2@ͨqDG \HܸO(sG(H ˀ @Ps=!e 0#$Eh\)s$‡N Ny­.sFsFP\I3AXI&$ ?.+^1 \t +-ӆ p?7PIoM 5/?;BOzz]?e~]u†2oPo5ut?IBgu?O!ߥ! Bo!?Ҵ?)K0B g!Q_y σBtЄf[TY}Є %#(v[+ɍأd!=K]ob*xBVMg)vYTWGݹo!Db?7߰Z9T!`HLPc#v[)Hc)?(B?{!?;=d!PyH@~~Bg?e?գ?d!fُ|(~t!T}?ΧSџW&~ )w!T/F > :!~GoDm l˼Od!eO?PBMK!& 螧WS쭙 nYPEZP%d!E_O%\%>~7d!mt!&~$ ~B:4o>B d BT7lHP'꺟gHVN®KYm)EdٺSOY3uSP]o!R7shaarli-0.0.42~beta~dfsg1/images/calendar.png000066400000000000000000000012431236551601300211230ustar00rootroot00000000000000PNG  IHDRagAMA7tEXtSoftwareAdobe ImageReadyqe<5IDAT8˥KQQs4B$[U;i6h&h["jբMBFQ&2 "!!2l{NWY /=}*;9![\v*D'`EpNpX'UpVq"Sw.Djw7{|$W@q`Lt/d~W[%BH L l>/`xl xD$"q[d(o FjeUU}.Ex toJU5"0NUV UM2r7P3.&"ZP JTS =EݤqB=kJ V"x\.F@D],#X=ZycIgڒTt[<_~H%Q qQ mXAKu1|/M@!F>"
>9Qv7aY8:]X9u #BZ=pIENDB`shaarli-0.0.42~beta~dfsg1/images/delete_icon.png000066400000000000000000000002261236551601300216240ustar00rootroot00000000000000PNG  IHDRa]IDATx C// V-h'!D:i} )2n3ŶBf  'wHQS_aoIENDB`shaarli-0.0.42~beta~dfsg1/images/edit_icon.png000066400000000000000000000006121236551601300213060ustar00rootroot00000000000000PNG  IHDRagAMA7tEXtSoftwareAdobe ImageReadyqe<IDATxڔS;n0}$Oݶ\9663GX_!m:@$e9c xH#O. &#ͥ >3w9x22О `93KEIENDB`shaarli-0.0.42~beta~dfsg1/images/favicon.ico000066400000000000000000002262251236551601300207760ustar00rootroot00000000000000 .. C( 00hh% 005 h  E00 %PNG  IHDR\U0PLTE;/pStМb+z`` tRNSةyqEIDATx]=lI:at  DсxTvt pn)<.m︹0 3PD88&24jvBvbY+iR3\W^u^aEvW^JJJm(n03[Yi2mBzʄO}?lSr>8 -{R|t\ѻ,}X9W2]2AR/ 5ϭ0 u){_c,xӶӦY0<-fsLSq 2| 4vH%Q@|%)h Аǧ'O +aMuv)P)5>d;Bxf10 g|s 2Acot0 1?~i-Syf4̌M a|̂a9adCx, @,| 2&H`g n2Z$M}a YL1L۷5@^9Lb!xaLL,SWt<7RY7`Fd`T,!v"<- (1Vx|/N4Jn˂q3r^ :h07ȢbS_Wɗ \+@{MB̿$Za-0+ee`*p"~JqoG`dpQNI^8o#Ѐ s4xdggxdONOO YQ<}`^8~c؞4+ S;mG~O ){ L n/@/,t0 d!j٣Oc`7&GOӋ-B"M-+=23 M[ _Z:z(mibl`WudBN`ha =@nn" Xs)<od'p@>̹wŵ0#05cu<=UxTaHde6;'VS;N=0q̢-(pF{N/U/lbmxs U -0ێpcsk9b{PI-sЏj8~#?  lPZK Y3 unmpKT{\k>A4BEC=ׅPk9`Y@b7.5;3 p(@Xd(({}r 8{SX? p&Ew\Ԝ  HΙ6"`O`C;q̿/p1Z <"a7]C.nq?0l.:`n.hV hp0dFxt쳶4r n^o#`~toAJiva.N-?+6?o$ߍpX&5#9u00lIڐXKIHLOfAġ  5*(֮tRX;r96Na=S%<5S @$FMDɩSEVT5JRv>;܆x{A#L_K&7'rkVWDǜһ忁bB9+u\RQѽ#e87{5TWƑ-է>Ȉ`E1LSQM^e`@|!Q HfLKTA7B>~6vX QxG^\'D_8>yCs0-d!pH69E~fJ (6PG S++3$"iΞ<{ aIE>+tT_0>̻_HLn)K.u0%BT> Ư]9q.匈N#]F5:CT{ć+u=r^Zt0kj\wBqrpun rB:|o`|zSHJc:Y~ ͷpv,MAĴr,Re$CȘV (4npF|wDWN`ѻq2|@jsSO¯|=3P2qo +7>0g'wWb Gp:zWD!* ;H9ҍ>!K|S+06]0:f;@>` f._= ݈ѡ, +uo!ܶC2NX"Z? ^J;|˦zilnyxL~C<` `IsK{cNuoͪնoQ70N5( OOm#ȴIi&iR( O!ͧDw\%Sta`%+H `R⑍r )bg>wLZzu%V `~ @Dz,']v9% *.M `CA."jLP5"!d5 Tf(h U^?ı8AUUX*u@ E.NMS`U`(/,P){[r &P>xkj[XJANfhkɘp:_]+Lg,p6K;'ek ҝ>DQ& 8gdsjYy: řyY*C-x#X'6PxS\B < YN‡˅5@tcel, 1r U`^7AJqxN<;s5e1xK5#o3h}I{ )AkOU[:fw3|U?'qhǐUSԠ ljv$hi]o)uPxES"C bfc֏wE;:밆ヰ?i0ʾ" Gx-~e/`/Tg LxD~:Ƃ1V|!|@`3DcW0##.庛b0 L\bRpħAk0v8wB\C4]haxIIw_^(8R+ :Ffǽx.H92 [Ϥ@5ّ+mIQ7q8ؠ@ =XN AXO dqOW8TK(u n:Haoij yd>Qge>~*vOrM+Ȱ&>ТF)`t ~sYFMq HkKi6Ѡ_")nOs\sR;hllȄAtXH&4g1;w*MM1-eG y_Itr>V-;b\Cd@m$:_z_z*Pf_"e@2ɐT) A 28'_D" y .l+U!wy%Ɗo+tmy0[It>C[Mmse 'M@< WZJR0[ @:&Z{ud\[:Jq@nҘbF-: TSLgicH&#;fN Tt悼D N' $%YlD X~w~V.I]+u@E:6jaV4]h>OS47-,ivȒhMwA0ӵN0^% "M+ s\J0~t+L0moWr%Wr%Wr%Wr%[ŕW^IENDB`PNG  IHDRkXTPLTEvty[}W-./+0*S)1(^3'6&7P:<$?wsxBz{LF\#|Z]IYX~`,V됕rn좳rКUO)#q7^q8NQ4lQnm̢1gaedQ39 $?kiL5L;8;"qqq=O>NFAGLCEC 777OOOddd...h(s8tVKk!(((IFFFXXXpF===[o1""" lI곟bwwwmk,v |gA&sV"Xrrz:)I}\D*ZU5(ͯtRNSFaOMt, "& % v?U8 IDATx} l#ɕ\z/q|d/Έ$@e{#?C^3HAR.{0BLx4{$F9D1FII$RDZcX{Y 55lTMI-kd賱vzիW]p+\ WkfE>'ZqOMCtэ{rJu#^J\ DUkݥ@ v^;4^KS"R KpPOHD)N^RRy> ,BhlKH$RЉ4ĈC"]tcSQ).LIhnf^!@*!ׁv2x@ySfG [Ʃ;_WN.EqtxS? ފ]pFtfǔ#:N9>c% ")&w)' t $6@]h.SwHH8-߼cANѨrفf uhIkYДi'$SgvtD-X28>OH J).%$G5aDR 0OI XPsԬNYAkG Kp/hןtTC`'ڙ\:4Z 4os0Ou>~Ɔ;3RQKfRHHh(<>&P W}| `4)%H$:ZwņtI1e $1l>X4 X?^tʡM?Q KNq`Iu=_*Gr4I@5l0OiHڥ.u$1S柱b*It)w0  "2XRB@J?0@yI-wX 1 TOG`AWpKM@d.t=Zb `%"+xe-@Bnu57,w Fӫ_ KYbQl1X\Ό6!7T%bq;8HrJ7v(ra~ 6ܣ'jXtz0x(*̬`]w)0H@+F|U(`paq[[_&=7+ơRJ.%-Jp< tUr Jz}[<9qb֣r>% Kl%oZjy^ -b 2MRH$Tln`1+YI)tĘCLI-3a9@ܞPH&%"v:Aobt:/ `<;BA S DNz 6O6 {\-0C<$ɔ&EcZ*U*6 R:L!`Fal&YNiPEo=d ۉ3IG%0Lb w5>È>x 2f۳f F^J-z)+́7*)Jc۶46 ؒ ^}gvFBJ#r8x3m-{ |`xfF. 8/INabX`!NN{D px#L?@=$$ci*y` `ɧ&>frm,@5+FJO+n G'Ц)ʣ IA-x܌#΂y} D34>#ؓ87 E:8Pm ;L3/p#`_, 6Tc.L2mZy-!"@8Duŷmӎ?V٘=CO+bh4j?AB}ԠPjF+ h `FVK[NθB/@HWŃWVM3yr u/Wj:`ǵZc0bZ_i&*6Op=+|ؔ  +C4jdqS{#pF)| @]ӧ[ xWlVP?vR7A`J^u`y: crO$Ju1K>.!E _Ŏi?eGzi7UbvF IAiu%/4hqoЁZvY"G?KA[é&opK0\S4v\;UQ^lcĢ@'wlh;tx)yOf PYa ISe֧<K V;&͸ n4*UY(NLk0-A~Jug0EV[GI`o94R+m΀%xLFbǪo @v;՞Xbc>%5҄y_z5C9*|$D#][K|*q7nu3%q4`I:L dعn/(XDEϾzsfJ0py90lE,n,aQ>PNؕe |c nVwvnnUN@gzv'hRN`)Hs`.>ϢeKd`buM9Exuggu#hm@_&3fV8%f qs}ͱOJݠd|0raggcr`P #x$Xf!8>&(܀?@N0ʝ藄߈۰RBv7Mʊxp,S@``:6QZ x*AR bad4^v2C:eg{V`HNz%Sn; -ލa]Z TH=B޼v݋|>I8gυlՎ4u,ߪXS$d;! vLz9 r^'=.gl ՠQW܋i'?إq W.56SG\b'krLl:J7OF97sZ V3#@[Rc:#$&Ml:qaIe0e0IIo q\\Ёz `- LdPH:: υ8jE9C4`\92x0-UJaqC${;$F ^XZWq(#00-9 nq]Ҋa0-GѠ-ZFJ:\Z.WWd`g܋ڡ7ז,_2` 'ƽ =XUЎ/$gJpc`@d6Z I4 x;)>G) 7iVz)ڽη2UqCZ:pddI{]ݰ (2W[o9lhte`X-U %%vsWZ`ߥFE^Lz]{-RbvaC ?"tĀauE FZeJe Nu:y<2f0Ɛ0E _FG|VXE_/_J>u-εh e`H#J=n`ocr),)ݎL\Fc#i݅V`wr<)DŽx簦׵QkZϧͪdr,8:j(Ӡ.c{H/hM6@yr"KcS6,SG(Ep/ܳj(n6aH%45#J&4*]n׺<: B@Ugc@G=ϛ&N?oM.Y @ax\޻|cUWuPVnxxB13,l-Y nB&7ej@6] K :G"a`׉j7 L>g΀5Z)P!̟'gݸbx*)a<סJֿv7o;4챔&{/2,m |6J^ol97Cju,;Ǚ:Н#`oY3'{WF쥖Wv{W˭mMORfYnqDNtD\#r6hgC0b/1$$K` ]*Et4nj]H,G?{{]$?6j8#qǐ\3mx8ˡۨpmy4맖0$"= -ОF̿u-&m[cܓs=;@ab\A=V8f]*wZ  ̦~̐X~0נwF:,`Yf@7yu8ve#6%6lW=}!o1q&_x#Kҁ-"/\ŀ_3X>ǁW1G#/r3do0vF.)Dx# 6!.otܻ(W+>|Mȷuʜ"? jcLjvW\?I["5.=,^O\  6 ;+ikK2G~hsHE uA&wmĽɀW]B֌!}vy+i.1=?(w ozeUՉ&"r"=e /p'6oLlB G히ALC{vz₻Ѻ؋$M(1Po]L$&BM-ڣ!vnYv{]nLGA{2:qs܅PxH%w0έ +9vyhAE4ѴV޼Ynތz2ІwzbCDSԳb@@-+; [*Ȃ'CZj%ւNsG}`-"r+\sٳpQBCjo'y+n݊T}`wQO0M Ct z?eCNx(;m8ᖞ>]5vǀ=)W@j]'t[F Shz&Z`&.ƫP *6%?f | /bU,$L-j2Nxq ,d@7 ox/DC&V旬 zLC$-2pK@U\ \D (!#"kàsL:`ч ,,(x>tY޺lxBN},שE09>PqSy7tn .t% wf.RUk9$#߳p8 +339ƀVnN@GMxNOBw蹈8y vb!2DQ~F)$ x8Ky%!tB $Ήlw]"B uϟs#2/B3.+BXmޒ%? } QtrS9W44OO=SDޟE + Z 4`&b[=z锡@"0]"l"𧛤}JS@fDDV&XBd_E!D#)7%Fl@?>t@?G"K$ 2ʆO00zEƂpP~m0U=YZ9 Mvfs!Sx(6|܌nD@xq" |j3;oi (GS_HMI_mCY:&@tz/^:#m;`_S&qՖBN%02 H%O;%8!4u2 Laa>Aӊ+Wh+MЦ (l#Bt`!$G6 S ' 㘿i :&W{2jZj;~ m~%uhڵ<~d*8ׂ""!u1#έ8'@Q["P?iU+R#Su\~w'ѫ7 &E9Y=4:Enmiۀ @F$lːOL@x~59y('3UXRG o ps+2A㏴}8ݟvدNW$W8g[x9?!=evӶaZN0 EZ vL__r3Z{|xKI3CP]}uE,ܑ^ǟ:W) wr#0t0))ȠcNbZ1ez73(t= ܽwBeu\ ڹoh `\FXrDhHЁbU'P3[Px-?c.b P + K VFUS3YU1m@Vx9@Q_We6K qDe& !v`GNEMU1첅y`.@0 Bp@ϽwIOU>痄E?*EbH67VZ_*1 LVִ199 2* D;naPa3$i04½/1Nj{GfW'D<2$D1L96{+65;f,:+{l'uQmPrN@+hX 3Coǟj:6c`vXjwr̵۬i0q{O ,~_EŁrQ>Dm-!Wr.-XiX@aF6 >|*.[+ዋcw=$|Vʋy:'|!O{4᳜0QdƜzWׅK"V g(pܓ5V,.n ,rWp+\ Wp+\  WIENDB`PNG  IHDR\rf IDATxi\yܵ}_AE"HQRvX))NJ9Ur%r˖TEb)eR1bH } f{0{v}=!;[}===~ȥ_0Jg[:wq_w B}/c]QoxIy^%_}&~m@|K,//~.x~u]\wEd&ıcDzk=4Mêi*>C뾖6u瞙{g.gfff˗/Oif&1MtVzn3_җl lڴ{]~? D3.)i`P($;6{+ɳgϞ^pBj ^ϣx-(R[[[1vؿ`'0lue~sСC&oH'Ԕi۶$E,[P(o~;=[o gWl`::uj(H~__NdY&\,[}Æ ~IpO>y>?ȭI~x~|3LfuK.5p q+D#4;E9꡾1걿=@߃>xeYoض/x-'}}}]v=[8SQ}AY8Iq n BPFGCHKpmmmڶ;wn(L~˗/+{<֎[u&+y6ˇ8t(zQ|X㻮0Y $3$CSddsd+nc: F"Ҋ抲ӰSͽ{gŋӧ=kgDZ[[|Pj68p`;644܃_vnI` L'妱rsn 4;㚸 YFG[Q0'Mr#Ԉ.7˭Z$)Ғuzw͏xMHoo}-tС?v!CcY 8i4i 99k=΂L>8皟_^BdJu[NL۳(F?D~W~ٶm[=xK@,S~ /wÝ5M(IR#KfMIǙ1`x(qZۣi,7CŪpמq\`83rer%,7$$iȒ^r"I_4Eu_0,B쬝NgOi^|xhGkpu78I#ϙ1&gS wÙ#m@ ]t>GAQ@rjDK/eΝ;gYvU^|kb8aI[gC L'E=7m7O`:y{u'Qb|rQEdvF/?EyO$IR$񵶶㈔`GnM7c,C'NryWobј%e$"oH$UEzt]7?bt†#@@{os( rmz 8IL_ex}MbA]j8Eg!@b HOuw. .^rRxP'[nm^xX,hwqq^3t(ş2kEMB_ asI/wH~)XMd͛7ۚeGs\!ͺ^ @xٳh405kRdx.IÉ㸷Xn3LPGFCj ۶m;d?#4oݿN3===ƍ'xbӓO>(p W\\l Y{LBpfy+um,a,',)m4 =,lѱEUU!*y33R6l tKbؓUbEgyL+o -b8q|J AIQq0.ڶmMOOxw%3O<(^DJoU:xUfN2nZ\,,rRIR(mmm;pl?y{W-։͛7R*8#]]]ca8W\Ȳ(($=lʺq-L'EֺĴS%N%iDB!Ҡm8ڧ> |0{7U;`ٲe>OTأk$qXŹfYnJ/N`/p~x 300_ݻw7`sčHu{go}N2g|DPA"] okT~-Xc6mO<~A矋dI[縒ƇNzT݁DR%(dI g7n84;;kxuטLN'*q\3IڼHƺHޞq{qM2%̏nZSP?6lPk` #7UX'a`xww.hby{-T{/%DBr<X#"r}ަp8܅h]ar3̙'I1d/&"2 'I&[ g.4O4ϑ'):q_sפQC*mZZZ"_Z#H;S`xzD_U&oM`9uw)No?hӠm'7H@qq ;4i C1 0k|@ںDorI4ϢQ49D[SGuqj`hv}Y6Т;JG-b:IT),iXn&Hl:iBj/u#R:bwraw81^8qu4ѨB% M;&7Pg)r>Aw%mkj`@ ܔ3GtVh$m#P5H(ڋ$4#gO7N`K,2y}: Q}Z)i8? &:"tU[Nu=-&+/4J`ʽ+/Jb1 1#U-^U)L@i/Yi""!5Dޞ\Ek`rRƎ oݾ˗/۞OV$IRccc^oIuEJ+MnJ{LAVKS$dIC;a1Y{Y*0$@&UUu;OVXj'Nu3kNoj=$pp~nn* )lD!t9Zˉ@캴! fi {[ۻf T)BHkF쟧a#)@H&v Kz—M'K'l'#/*[ OVGYK"~r҅&t 7JoU:Q.JOY{vqx*<X9K^$͋y Q7Hg7ej'*-nKɒ&X(= 7oHvjDu (!{.ܰifb(WQ$r]‚M'G_b_X% e]fQU!^ɓlygs9S dt4U bYu6L'K֜%@=`q) uz~Y(jRZe, }ʕ+b>}˗@)RsͰ<91Lt_`xPGC$IGc(\_z$B rב`Eg˩"/CxmW'u`a9FBE*:5^qeX@+( ђ)b6pҥe@>#@ ?{lѶm/"pxY/ܫ~5=JϽ# nT - qM,7S}uW^m-Vq#N{ݲROZ^ ,id XۥhȘE%b<,ա!DVZXnǵǃ5?@yQC.@ i^$muZٌ7OVYnKZZ?+b>9>u''Q =BadeGnbb"k/\)>O4V8҂ ?*!R( h Ъޥ2*\z Jwz ߿100O8rJbrr2OIWJG{u]0 4>@4|STF,T(.H>%TߠiZC=ѯj]MRHnf-z ;y'YЇ .")_g?4*fMӜGEQhllᰌf1 (>O}駣_Wb-*h0y}[CwQo&`#P꺞߹s,B$&ovoo w\7[F垞gO9RwjIV݀\ #"u(Q\yXlv8g]\(޽{{᪅p}4=|jjj,y۶ mle{Qկ:;;]v:KGklA3p(umlHekVXk,@N`է[ uD 3/`?-[(>CEhGGGK'W@!>Yk "'G֞$e 3YyY><"or 칺u&2?P{{{}a |ИaSc HdϜ9cbPwD"үʯ}V`'F{ZfZqufeZN5ʕ?r1#f'1,k6z0) ,.b~0|>_瞛{G )oПɟmQ.j׮]={4hGڽ{waъn.tsN"oϒIL3^8FޞvkƳg\"3S\ 2f]K!Y蕰;M:2,݅4Zi ~>`q[r.c5 [QݑHd*-&ť$|8T8 %Oj4h=(>W\jj6n4O'Ǐ`ӦMCEbX3`WW "nѐoZ! XNNZ-R_v&80 E'Eў#gϒ&H#di {z^" (hRMEt%s3\\!NGhrMP ȍrM#hr]+ (SdTDya~k[[[CV>%Jm{X,[}Q|.k׮kpps ""!.`'ۉy[9̸.hϑ(82ϰ"'cM&a>P-hQ!u~SOU+R?\r,yP [u?QPe?~IT'm$u:i5M3`ϡC2=P Tg/wIO>uV`۶m۶wttlu} UowKv3GNPr vZ4t Xn)`r n-,p\ `9GBEk{/ `EՀR:*p$ ۱])r]cFJ#ik@i"RP%}W EQH$x___y+W.?t:m-Ϊ@$~߯گZ<< J߹Z8,0g698)kqy5NގSZdIfY*3_N=|wRTbV,ƍ#>e IDATOnGt y.`b9,IgI$$ˤQڙaw%NɒAo3Mf-4i ⓣJTXjʔ-!ⴷ>usxXK`E I&i^&kMR(y ;-fdk3g\&o',|_RZim36N}[Q%,.l>ggow,Yz{{۶mkx'v?裇[|U){3$ikx33L~tkuͽK̼ ť(+r9BNIWJ \uSmb===ROOOphhHI$20fgϜ9cLLLi\owm۴igN5qJ)_r>ckܕkʵĝg_n,ax9h]Bj;]}ͿoR=S˗/]z{{} =3x(ڇ筊鈠9cYwueѸn7kp29#o'H#$Z/aMTyX۷w!:9 Ν;۵s}@ ̧s\S5:ajԫ@cyb<ihoeSIBQ;PEw˛50Dh~DC}ɑ&R r01{+~j3ހK½XRtLa '$a{hoAFױd >C>o^[\޻EN).d^wɘ+ =X" vV&c FTTُ"UO|Ę^rsf4#cN9IWp/".ITe@_Ć GWVU3F/s{NW"*NO3y0.<$(h@7|[o-?kȟ e\!mMRt2VR#rݭϯϜ9d2|>ZKp?"'X=LDA6^t3FHx֬{zgPŷq7Fe@TZLOpis܇8KZFJZNTڈhtͿ?|;_kqSItDk^ ċμCZڡJ~Bj+--6QL",E@Dn{H73QY vqM)`:& ';MȒ\i9Z{7[EDeQI4e\g>J|7aj1!i0.WyE%Jۍ* !Vf6K@U J;6,599yCG}d|߶e׮]iy~%_bMTOoservZW4t9,iB@P<,U| Xdc9E\l{߆hK ׾-#Q N,2U8X8;A)8zVZ _|;BP1oN9Nƚ&oϕ+{ D (1"Z{/x?QELb#'z?a.0=ڵEҼ|D.lv rqs02JFHfjvik=U)s1S$6'qi\e4]!,|uTWKbV=x] ˲DZ ??$^"ga߆$$dIEPŚ$ChrYR3$IFTt9XӽT$Zw^hr]WiDj\ md29H$*~P\\.'ߣ>صkW3.͇8rӌw4ُ_e,W>ap\*Ւg"k"6Eɔ:5sv-g(آ,]T BL curw~G9z(ޒBC?5lyk]K_պ}2 z' UJ:':/Ghm$ƖrU7[8 ,4+|_nڵkv6\ھB{w)S3/4[ $)s[M cfjBn~G_~]s5 N1N2>t9@Xm%H">>6S*TG~rb$?>%\q]B'ѕ`žr2U @lxr:}ꫯ~R|ɢ[4뺎]}1D{kbևߵd?Q P_eK;1XӤM! )sζca8YRsAjaI$ H4 R"*b8śn6I(*h%FHmͿVV4ُO V|OPb}nLrw̢*Ắf?)UU`0(ڄu~(NXm#V][8ӌ?a( Yk#:Eq\ .6'HK]U+S` !LDfSi? EhO ; զyϸ"HEyIU[o._}{ob9fwԉ'.?شiә^xa6ӲۼrLG`G)f cYp%w5SMqH[ċiкWOߋ"`|9k걥A`MMaGims'"@&H|8==^{|;dB}7sof߷o߅@ niit]@ڂCEXk'*:~F=xcZk"ΐ6D:됵$qD'y+e,@Ç GDk+5ko__-Է/^|饗lBu |E- 1t9H  up>uO5gK"P?\Űb9~DL|6[>DoթvMv&$_AbC ݨիX~b_DD"5<<<~ Oz?ƂWcvvo\7nx؆%:5MkKŕUI{xxضδh4J5WKe?Ze^zkםdI'S„VbxI s\ Cɑ_,m0gQ3uOQeDLٷ^gc) /N?KCCC+W2k5'Gdҵ|Lluccc~9C&̼??-f2w}'o}d-kBGXy m.=֌ eX#v)d4d]w$\,g-ͭt 䬹">Bj3\5\a&bVOu3ror] MMM'O$J]ґAO"b';6~+### Wܱc뺎(F!C8\2`|>_cccQ{QH$p~.p=VK wKWg|y-ǒ׊ K"j;mOVElZXXUQ\2 "[>kc:J~~|qR|S]qS^?-MDUJoW=}ts]{BbL&cLOO-  ht/E1 \:փ>lܸѱm^߯y mmm Ek=yj\ \<&xovN@AĜ\?ֻ"osB%IF-ԨVl qJ1(B@ʃ8]:2裏;6ke?ʕ+򇬆y]vmB{=S 1*:abX 0RqK׾uT/,>7˒JaJ"W.u˒Yfʈ&ɪrYpdO#`\:o;̎;~wwΝ;"|Dr)sj2҂c[E.JK=aZ9r\=: otm6 L0:{ȑ[NѣGMoӣ<'xbpbR{ƭD, mE֚e4{x2N_uȚq8]3ZV&ێI֊fn*Dz{{_ w_|AV_>x&)DuiHjH ecpuk6gGZdͳPl b;=hm$c͒Y LqYj3~v#@߾}7@6?qg?ZD}~yKrd80c g19ޜ{X(<GܐDia&: IcL3Y8GDk٧ˁ5Їؿعs瞝;w? i?~jlInq@?`੧?X~٣G~ajʚšh\qiXr\[Ÿdϑ/}Z )s1I¸Bܸ\{o.'-6^iYz(GU}U (~Ӓ gSobaIA,(Ruİȑ(!#g.] ~F`Ǿ}ϝ8qr@u侾@ @xo..c0[&iCUPP+U& ?P$'b :.kfx53Nʜ"mM]$Ry+U%LLdpY`:WrGʹiRMզR1 g%ZU30~%O U^B9k79U/~ȑH+BnCr*3@0SL'5\N BjA%*7fIvY5)Nj{1J%®=N)c@I (Q"ZboYD%׀> j * 8|YS\"iL4&)3UH-j $vWq-,HN1gW]5VF6W"ȼ(*H,ɥ D~tEtC_TU޴i';>44dήkp8,?~8T,`:y4Ok>gل k-TL IaڸUr\lVIq-v`:~%BXkFj&]IJj_ 0-^I"Z M}˔Xq Lq=-Wdc;w ^5U(}hDubzMz74-]`Z~??|oѣG׻aS$Iv~um $I2V|"1+H:2 uROF_ǵJ-ͬۮ.(Q/YRz `E ho ɁRɤmm:ELHM0!M: Z;1f_M^bz'1&_7A5&+6\`_IlPãH\+<:,e ZzV%2r 0MW¨NDk%D[)7YnE 'eHHHFPdM)!bz'={4hmS9ݵawcĪ&a%w*$Q[i{UWۼ-Zz!P* UlhhH=}}}SkZI~|tw1;MZC]tf *34hhrP*'Zr!J:00Gb{p `nnO~Re9}ϵgP$'D1M)s#;h Ϻ$0D6ol6w]ԩSo~}}}#OtEvod]EJ0U1j#+Gq*"K~ _Ѝ(e"fQ`f,|v.\P79ޞ@7'C#4&0kXШw߼hu.ld2Y4 rɺ*J}c$1c3^lR`8hdUS#~\x$Vğԧ8lhii޻wo)p=6b1>$9B `fvvv_?N eM <נI>f8|۶߭HN#1j D̎{ͽβB+=cuq.ɲ|_I4z%Sɣ(μcȨۇ5i.b'!IRSOu" DD՜:9>rHMMMxV1?`T`~Yex(X:z7]hכ@7H2 SSSogFGG۟yO TV$eCd?+ΙL.-Z$IwfCYSswf߾}gy&> ,<\JdW- ,,o"aөH`|^!K*=Gh:}8Y~_if TH%?t/S`0LrL\ MРIg`s5 \+BCž</?d|DF"V*8I%5®QP8zǻVH_h7{1G]c |h%Us\jhhxooos{{{[5˒BXm)`g][ @unP=$8ov|jjj3Tj~J VȟpuAûyTԑBp{}ԩS ?bf^2:‡PGEP}~%LWp{lĩ䛜N[Y ozB;{чiu/μ_|Yϥo}_qhHY3?{o}`W.ex[%dneT9)S|JMTS2VxeMJ\DqE$ ݍ i$%%?C@7]Q*OHQ:&j}5b晞cǎ9pXkoom۶?H-t۵(bt %ee!]GfDr{|QF'u"Z ..266)kxqP>U%%VR79,*^ۉ_* ;1 }w#~&w  {{vmL~!ER[h Ro§E1|(_o{饗vֶpa,c0Lܘ$m#K*>5DJs5c@,lx/(-8FO(cv3 haWwR؈lxr܉{;s94n߾}i]d/z#. vBW,Iӟ&YRu!1C\2=8<#*|J@6ERo+K%ժ@.\-{dʕ+_؟ɟ|٠is0˨ԛ[%jm:M7y )CFɿ͑gh^:>|x6???O{]pq)8Y #X(SKݚ$ԛxObrt5bYp~ir=1Ce{Y] K2!:_''i ٿ $OjAw]v绻rڋ= @6٬}ĉ5555LSESCHz_վ6*1ymvvܙ3gν.]~}7={vg߿?>szbTy9ȅ8Dg<1j|Ĵr e"oMYUUUyol׾Qt&ߓ2f%FPpr\a8*$ًRz%jB<3`Ep -:Ynf>$)7^%HBZo;]wT+[>ޛ. 8o`m}ر>MӤCz)qChdIFF#:ۢѪ3`0L8EJ<BFBo*̜={vѣ-=Y}@`g0|'iLHg0/W_ݳ}em~d=wY(L<S,'L_$&gg&)ym1D]:h!.ّ葽l ?*kh 1 @ 1i LSkeI~4ŋ&."w!ϟ/{އ.}\?~|իz{{ ]=r]%GE J2 +LIdkb֒ڏtxP˭t:ݛN'7 I|+'B+.-ka&S?XƹخMҘ$۵y*eߊSELsܖXa):=U=g۶/|=OL5iL3La?֣drȒ"yHE~Zߏ]@āa0ECWĊ9L_[۵YΑ1cRk'rĉW_>qF \pa:>( Sg"|mmq{8K@R4GB1h*klj'Y4۩%a1][6c>B7YRH6+7~򓟌OOO/ٳ'GGk;% )O3D$% TQm'FJթueeJa9MQE`X41% ƜfvaE"4 cHP44issëiu47J@-[)NWelGʜM.a: c>@q]Gg[94lr+ B^A,[)>Ѫ<^9: g.3x$ry;ǵd߅<ǁLiq>d' HNLOOa#j bEr2D~5X\n#og''Y(N,R"q]2kxTCs`3QTbx<>388xo0 I[[[7 @ %ΛYi {٩vAҘ:*lYPAT$QV 8M"K*;GƌyF1⒄`n6+O۶LXwPH]9sfck~2w]# ~ovBQٴ@}Tꍄ=U47-% [/S$o1sb"@ڟUz#{+^5\2}}}ׁgNiW_Uo꭭Jɲ_X`4{+yZInfz*j-U-p,o^ë0"731<(2V{dE$d6E؂``Ycj$BscbaaaG?Qѣ L&ӏt:^zFXT8N666N,ˉ;vwuu 2ѥ ˥Rz`g0cՈJ«j5A@HL&{{{{gruuu5kSU1w\a8Fo8c> ÎMt sx:!TcJҖCrI*J4 -_ 'GRtd̵ 2"2*>5Z(J]x?pƍ#=== J{3w}>{#[U!3gd ,/(rϻ6!Z9Md\ah6YRHdsi6Qmů0 }D ogE6^S`:7Ws0IH~Z mi"fN!z'1U)YnfzMp˜{mV1o)ZvA)"r:;37nԞ~i߁6Ȳ M~܁b:?XY`8E pU[Y$d"Zur?@ӄud3uh(3͹U8X~F8M#%D*5a|_ j8/ٷ~{e?iiii6#͈x1'2&y;La ;$ ^o[Z.0ɱ}{DPp0o}K)0Mqn.0#gLg4dn*\{H ׹V}Tj &iXL~Ec`C9# n$X,-NX-2٬qʕSǏ>~p6rUU~#bऀ8(+a8X1f!O%ۢϰE{XOǏ[nܸ.{mמFX8Үxso1DҜqFFW|:dEIE_R@.3"#w髁:%B@YQd{"6܂m..k!!Q%Vzd 444$m۶GGG X3ࣘq~[g߷o_P6|A&IR(M,\]%^b,Ϣ1$aO%;bϳ=VDuݔmL<8NbiGRY#j+¹E;Bqn&sKZ k L3(WQ`Ie݊\@PZSG6ZSCdERRXKC* ])"{)9{eY*ǎ+9r$yȑ#G 9rJooDUUUCUUU %nn-aI:()>OP"&vn&º)z']<]AiGė_ _Sz[!^5\G8#kt6 1ϥq$$|{m+{#}x, S.vl$BS6W¨J:hB,"1@dWƪ!U+Z5'oet~)BX@"kRmBǯQK?튢87o-..>rŔ n&DcL6In>$Q]P;HFJμp"(BiDtɂ=, k> SFVIS, ׵Q =5DEl~˵0!q\rM}Djt[.4-vnƍ#$IjnnصkW+E^.&  !2VrU+⩦I ~f;1799y7sN~-[F8x\kS\r$ vn JKLr=Qj-l ?Ȉ\ !EL'(%$I!Ԏ#6Cp%qAjb1/yfKR t]oܺ0 #6+]c8"Ic[d_ b:.&p[=K%*+n.,XG[d0}$9;C@L))-oXW-VgRl>E.0JTk$Q2\*k6."*)~gJblHL_a&?&VGP7kY/_|ӣϟO˲TVVv555=( Sf*7@2#~#x8`繒8G;ޥf=b D€nD GHDBI"uF&a2taduv EL~Sݸw6@ 0ziQL>.`#eH S&N3Yxes'OD&^ xA YH~Dn.>Vl Fml&1CJn% ?`7bB+K߯DT<mNJ1_`I#X:Q%VSԿWE.܁{/zD2d=e.0BXVE^OyiԷl?3 Z&yڗ_~'xa*(gi3p @0s IDATč_K)`[6'p\ȦR9ea  „ +ܿ$SDQXaEsn*6GD[9!((>I׻(r/"XS[ //j_UHqF$sĴ6F.%yL\m{ܲz^W^i?}zkI Ƴ7J2yG] ۶It~o-MT O)̓~ˈJHJT{1"5OIRhw1=cE_+UeZq %e)څU * =C˒͋/^7Ғ$oW8p9O ck .ql {eǁPI οxrk`ѝB @ٯX>Uezm$YG`8Ef \IƦ#aʴ@&Lc{e0|qZ{%J͑'6{y<::z㭷*Ȳ\oͿٵo߾'ar#!fXC>G d=91 {HsKS}%-],}A5o"YW$BP%fݟCj3/Lr%yPZ@UTT芢-)=lFC+&#$Nq-yuU"PebGOMU|ꩧ544|Um&S"^a.%N2zdˆY)v^_%HT 65 @ܕqXċ3 .Ƴ.2Ty ,'.麞hoo4-wdPXvaPYY644huuuՔzخjBXZhe mmm]"gFl;t vL?2D,o \rNa8EbZ52^,qi 1<ԃWX$IHh}IgdLRLX(Nk wc 544O?M`Ԛ`~:/ſ޾}{IPHL1|~Jt}UJ1ހ,_ Dm6 p%yt/4i|orL8^$^'n\Qᑴ{QoG*e(!<~/llv8} twd>\w9|Сp8\G -<1ԁf+L1SBZhUH R""b~+6Sd&?)3W} NYRjtSk-U>["e&֤9p]$Djڃ%?D[g \͔Q&rCLGYi,ZUN|]QTK+"vD sEqLB738;CӼS$Y/yey+D5\8ArBl~K F#Yz4;T22d Q 8uZ>%X1"V:DaW.33\g,;@jJUˈjUwͯN49kmlNU֐$ tS$ kSsL憸[{!kd8MLRP{{{+Ϟ= aY2 1Z*!.TY#艢++zˈ"T.(:M0ϸE31ݕRF'ȮXF)`g?P*~]Qky``9&Y+XvUO(EL$a2_B]ȀwpGGGTOOOβCaS:x /BHӴ ck0 #!!S 2d%˰]J,3F˜[A'FSU%yl+ѓK<|qzzDTdcx'uU#{1"s)L e$Wb,+8h D͏s):_ *y^3q/pisuafM6Oe&֍@$̚ɿM/NIs-v}pm\8c dGѪtϼv$WI,v`..r&Rװ9ڃ[osVF}2f6 )#d@Iчd_e3EcdqAkd9$ժ mC~JMʒ^8Aq/^d8K+AY%L^^LQ$,^n- iq(姸8+f9S$ȃ( =uVJZ)S)C}XoZqwrMRfD"i,з!MNp?%i5V/&ʍpz0SX}! *U E@R~`ou],rR3;I2,g)XeED1hWqqmrK)kyD0R|jm'م*kV`3qnfYFBg !FmٿD-Ch"K2īMLxӿ\פE;OLbX]~l4x=)al"mHI5+:FT/#z\B~%"rL vf$sknzgMYe9E߉]ecEa 3$WYzѨz2Gu2-q&r&o=Lcbc6P`BhmBљ^Wc;$3;K-rJk)`YOۢC-7fk#N]d:mͨFa8r$U>O[<~u=$H*u|K*=wJ#v-j~I;3PY)vbK^rG3sTCK ETF7Hz\+纂mesd71z%;QD@cK yz*$ 7%;pO{v=bAtW#{kɏ^ K25Dl#\`;;[~0<>>_vttDPP*^Zp\ ˉ\M^ e$:C@ QKPvHFz29K*{iUTxd i]4ڬ'5&DsTC0Dt:]L&[o5577Wlkk3j=L6mSk§+AJfA6ֺh~j ղ xlN|=,T{5PeMBGh OT>ǦN* (¯~'˗/ߊ=o޼w{chhO?El)Ё$IOpf(F^czvjIkM%JgH$9EQMMMyEQ5oa9Qjn0hBW|?]~r7 o52??_:" FkpRjA]Uœϲ9M%D ,.,,;ӿ{H$ܷzF/Lmܸqzǎ,5ŧe5ThFVCïh&Y5_ PC4UcW~eǰM`<^||>HVuXLNN./yuDRd[BB$tK^Kkp#;5L`ш?#{bw/6ƁCG[pQT.z77'V3_,..:.]*=ztѣ}m۶3U;$dwȑ#7N:ucCԔ555e9EQ&:::͛eJ$I::bzfu :}H,^ŷT>vVcKt7rouD.>~7񞞞Gf `Bq\<o۶ͩ6ԲV9Ngx3[i +):LDDjo=m.6Fv klxU~O[G@ _5@^_ J!ORB&!WW<[yF M6m[M/i.\8uԩ'O988ȳk7hB!_zӷ͟!ka;kb;'J*ɒ,)H")Ȓr,毄9w9|ׯ_lJ뾑^eBT{o}[{Gkatc҈(3a27\a4sy")3I\,;s K "Tuh #:_5zQ\2ṝO|;T:. G}IDAT=V2 ðrgϞۿ[_tydz؂ &;IY/M|pYĔ'WfffRx㰸,1.]rD瞛D"NHYqalY%E,E^'EL2=*$J'BT+R#PC{ȳS?~؉'>}$(o~ӛNc߮s]|K/E'`c>44u]g?rv[Z67˵˵{7?]t]˿WUUeY^Wm]޽{Cꫯn,y7JFQ~mY[[cJ|8 {XLTňhj!x@! [,|jlp8].WwGGzcG{RSfv]W&;99)j#fX0d XAAy<^wke~r[V-3ZFqZ,z}OXl?WocA8S(z^xg!'_ZVvՇ;|F+ y-NrBekk| @EZ22 ;c<f BABbЅ[N.zTo$,IJ2dF/.\.usu40<<v=/I [__7`15H'sR6=Ba D~ XE畸V ||V@j]r~OReqgg磪մ}pgf~'7( 4QcN[bј tvn;t3]W'&-n'T=k>xO"R^?F*rZe2RQ mD$I\qJ%E xu_|=G?‰zp{@3 1c,zS|i?nvYբt]KWe& r8;;,B!B!B!B!B!B!B!B!~~ȶw IENDB`( ٽjD'ςTٟ4ݢyӡsDDGtCO$DNsTO#7 F$)3OboC?c2&b/S{c\"hb"UzUUUޱ w-qݐ֠ ??( @ P0pӆqߩCܟܚwwwwpwUWwwfewwjhwwjgpv32gV33p#332u333*a3333!a333!\#<3,34#3!Q#1#2C23Av<33,2pv""#B$pw_"Z",#ApQ""!ZB"pu333<#33Mpz$KMVjKDB"pQB+gq"paDMhpzDpZDKjDpzDDDlDKpuDDDNDDDNڨpZwwUewpqugܦpvgpwxww?(0`E|([ޜ>ۜq2"""""""! !_Q""^ !R /ffӹ "ffc ^fffff"ffffO! %mn%ffffff^6fffffi/n/ݾ}%=ӛמ}R333==3333>"Yff"Yffff4fc33>R^s333s33 //_>"!_ws"wwNwws%^s33~Ys7339"33339Ns33KQ".wwwww{.wwwwwwYwwwwwww"wwwwwwwywwwwwwt"""wwwwwwwwwwyR 陙陴www̾"̾̕U"!U̞DD{ "tDLLDKN.KKKLR/̾RDDDDDDDI/DDDDDDDI!^DDDDDDI/DDDDDIDDI/DHH"!DK/DK "/ "DKDI "."눈 鈈 .興R.鈈 "Q* ?@@?   ??( ;Q? ڟIz5`Ӆ!uԲXԎ*҅wީgՒ{9WU%VoԣЪп)M&gφ5fߩٯ|1V Y&`wՠy=ߤKݳڹ&w҇El ҂:9,Ѝ ׏5wр3tݿOޤ+xyύ)d^0OۼӣѭEܟhщ-J1ֻ g-R@ Y<_eҋݽBӖJئ"tц?gWqD R[OU _22 U }13L]!T1x5'{+'.hF3f)[ !vjAa%<82 =pw(=Jq";l|^[dQYUgK$B 5Rb*&6nO>o#k\zeCy~ r9Ic_H? 0iGmS sDE_M@Nt/4[] ??( @|S+0'u5:@hZFoߟaӂMiۡ5k E5]؏ < 5' S#֋'ב-` Ji%Ԋ:)rpՉH,o xIrݚڕOMcڜ,R(iY֒L٘Nޣyyט\Ӄ"ܛ(ީt6vUFޤoՒ=֐ޠ\z1\EG`u; Չ2ߥt֕Bڙm2}`ު9-ԋ׏[pۡٝMޣOؕN۝#p;Yi֔LZ5%؏a .vԄN 1YK1 1pHQQι!K]`,0]H h,,5H|w(=Z¥Kw(wKO'==Rw'0`C&&niG'00CeZ ! & &! wKHU n {B ] {VnB9!˗g K[!/BKF`jfnԄߞݚՈ׌ِܗڔ'TEՏNߥ"k9Me+߾7Սwח*ՌrӌY֋w.ݞ 0mK}-(ۚ؏Ck'dӇNp5V҈9߬qިX#ؒh΀Olt6a ӄ Iޜ-Wt [; y*\"H&#oܛ[s։1Ӂ+ە<4;bLFՆcIIIccIIIcI*bbbbb*Ic*bbN|̚E̻I6TTT۩?1Ŷ55+9II$6555oIIkIIV9̼ I9k kEbcI1L*9)8II+ E9ETII+E3oVoLI; 6 ;3 w3o wI) 9i3; uE )9cỊ y1 oV9*N L/N<<[âgo6ϺI/̛Le3)zzW>I*SWE鍘njgȨ<̂ccb11+yrr1WWỤWiIvye$1yrVrLx1Icbzyz$UV̙7rNbI@I9871gMR-ݭNV9̏c|V@SSxSy7xN@260(c1HS@-n161II''/?́H\-`~~\\UI16VzU`HNOѫssH11OHHOOOYsZ|@$O2NIcb8`($]Xc9Y ($] Y=1RI,X~Z=2]Z̈$]mY]=\X̢/I6D =>$] 2̻tcJJ//l!!!=>$]!!!!=$GM]"""$]""""̄c$C!!!}nJv!!!#~}]Dc=D6}̟}}vcd~NcN}qqqqqqqqqqCvcXddDDC&&&&&&qccnXCqqqCDzIbNKIA…(?@@?   ??(  @eF $Ǵ* vUo-:t͈½lK̤0O&9W;/T;^9ϛЛ?-R;@ {5`eЇ>g RDeυ%Va00 :|֔Np702<_H000 J\W+W551[55 O3^ =5 >۠555:cI3V|::ٜޚE:;<:Aݦ::@rՒ˫$ȌܥK@Sjvט@@@DܢV@@ߦןT#ۘ؏"ݞ֥>؏؏]&ڕޟȵ0ڕڕѫKݚ ޞc~ߡݚݛs٧ߟߟ5ߟߟ2R u ڹ?[4ڼkHFpϏ-t׶ظh &' (0` %'(( 8KPL5%ҝ܏3ۏS i OuІgzqσRҍ[q:#"" .'ESjG(n΂=#"""&;VC>2$$$$$$$$&i~,B;$$$$$$$$RjѪ!C'''''''''''Ql%ei΀+''''''''' 0.***********,~Փ׏`.Q+***********ڠ,<ܣ.----.9.-----82V-------------wԏ0,30000c΀D00000@e:_10000000000000}֕/93333I3333 :[|333355]Hl333334# P6666 >6667B76666Jq66666#R0ݧ::::Yyڟ<:::::::>>LK0c>>>>>>>Bo'\>>>>SˊYЄBBBBr͕ؖJBBBBBB Z#\BBBBFFB҆KFFFS6K|FFFF7nWFFFF OSцaLKKKK b:UKKXZKKKKK~ $UӊROOOOOOOOOHҧZԌO'iYOOOOO#gmڛvܡ<q۠^SSSSSSSSSSSL҇ݭ3hSSSSSSSSSSW itܡ'm[XXXXXXXXXXXX ^'ZiXXXXXXXXXXXXXXzި{o\\\\\\\\\\\\a3}, C0vB҇\\\\\\\\\\\\\\\``````dݴ lSהlb`````fffffRٖi<ԉfffffjjjjj@Տ;<햿=ՎjjjjjnnnnnoDؕ}K ߯9֏onnnn sֲсrrrrrrrrrtv x z}рс:ؔ~2֎-Ռ0֍/Ս*Ԋ(ԉ!Ӆсzsrrrrrrpsl {wwwwwwwwwwwwwwww֠'֌wwwwwwwwwwwwwwwGܜ) ҁ{{{{{{{{{{{{{{{֠'׏{{{{{{{{{{{{{ӃU]֋ ԆӁ}"֠'ٓҀ ԅ֋d=рodYT+ۙԄԄԄԄԄt-֠'ڗԄԄԄԄՆ֌׏7ݞ]ˀ%Z։ՈՈՈc@֠'ۚՈՈՈՈLZ4Qit~LJۘ׌׌׌c@֠'ݞ׌׌׌׌aܝ{M ײݜِِِXOԪܛِِِِ}_٩&ڔڔڔ9{ `Pj`8Pi#p-[o(-Tp@ p XgT:` 8ncZXiǀ5Q@)}S ռ:hH>͚̏lC{P?&@Bl/.8!ꀥtv+G ; }S iS_6f$ j?%fG 7/LNs=(N_n EAg@Ϡ~c1J-%ۧ701F41<eA@T07!\ ~-= u&77@`秂wJ ZKQ9oc )JtF^&w!,f g/MG44h+ De6}`,b_#u.nL9AKi5:4#Cn;]@Owqdqs@V{`.so|E 82xh%A*F7X[GAK9|؆joo*fKBϗ(@E`n $~*N3)Dj ^>q24eL;)<5XDt\<<¦LVߜ" Vt -mb# .5H_Fm(09)s޶#~7FV؛dk+;5yS;q]i~C^`aPCa'ٸ^>A`W?z|`V]v}eo{\lqVEDZfftvN-p;C`GOjv;)y ɹys}RNH ,z\d?P89(R@w \潿!)W^M\ Gt(9Ewo)[{p2jD˶G)bgds|odYD'׀u#]CvQm tP؀|y A69w+{6}9{?<=Xlc:@DL[}!'Á@O@Y?D.3A*dEιD]F&a("uzW F|K(g3=j܋({RHU'Nm50dRTc݇t` 2:7ED &\`ݕcP8g#sOVى?h'G.3}8>@i`.˷$ŦRKl^PZ܅H Zslbn䟼!d$O}͜sDes(bҸ]ȸ{Y&F$y+C9R\K=+Dzд7^nDojb;jZ!\Z@y!}UƉTgZd{k7z1(ƾoquE4 /ׯwK1 ڋcs,'}Y/z~ JAl"5wjtf3FNy.\6腞۩@t"ʎ&lkrm9$ۘ(q9wOQ56솒ٓP ̺Nn5 P3FʺQT͟_H `O6 oc(ܪ`x; r(#SߔϾd BIENDB`shaarli-0.0.42~beta~dfsg1/images/floral_right.png000066400000000000000000000046171236551601300220360ustar00rootroot00000000000000PNG  IHDR32sBIT|d pHYs B(xtEXtSoftwarewww.inkscape.org< IDAThŚ}tWu_ߍ #aG" V:ȀDJPS ,(v&'K(%hQ]sys"™sWkD┈/z@GN;'[.P`0THcNݴWo 뜫n>{9ڊi>1Q1[{kA40f*x xc~d`h[ˁ[AEv0:E_=ވ&g@z e;0?+w.Ykjqv1qY{;` 5,Vyb$C)ֺP93mFE_d,N/w$BQ?<#R"4rsyZzl*Y{cd7 \ó"mz-mpv n6{ 0=Q`0 :A؀1;|= #guțxz7wfgGx;y[⤺7GB\pmqg*0sM~d-e~4( ~@7߷5cрGg5j7ʁ@^`n$WZ[F4 C4Ɏ&oc5&狁>;ԛ7؎ﲾ9 Eufa¹'cyF6{]rjzь)6!৘k͍sM, =^<.V1t>KtEY0疤`}6Tq_)&:q0^zG_ۉ=V/oLb  [L,ꑷy̔ZPݼs&$@|0SD{~`)&bc3ÅA¨AbRL6S}3"㍨o $FLk0")`'68dَJ{HQ_D.zWMD`" FF1kk @8W1 10NĬHTݪ$"ι✛ AKAu@p97U| tGMlp \(MsI xvGyKw#7[M9c0_?9F UVM9WKG3DFU"R㜻 =Z*TZ[=m@MgP]8F v PVsEdNZΝT'3jtfn7Nn$zy[1u׍1@E|5@ɉht/ 1`__I&4˿.Ew;3,~5hXp;1Fz_PKx%*Vk1Xii̲c+k:{QE^iʺ?4j`U%Fg.īH&4}֢80kQ'6x`1aLU8_գt;'t&|0_ 4q`~IL6F'ZZg7x S-G !k_!IOhn9-HtEߤD> FsfE-C@vͥ:[ըsΕ:9rlU=_e@|*1e}?Y&Dz_u #c/=y2w*9b7_lsqoowT@?$݇>ZA԰Gk{>(§Zo¨ȸoQ `oFNP`Ed-zE=<Т _EA%s % -Uy UF!:IjkEo姿&sRIy3$@d'PT ªj '6f'm,h4Hi NCؓ@>zfۙib7GG[ۓ^l4^\n$bzx#P% Ohmz<#1!Lf5MS]b>9Fי\E{ kιЏVhпcιlT,}eHy19P_XŸGoheh RD˯/Dbv*jG)mBs1%=v} V f@@# s+h]nBO ^- 全|ś?hO+:&19M6~ @~;/ZVZj`'"o$Yύ,VIENDB`shaarli-0.0.42~beta~dfsg1/images/logo.png000066400000000000000000000125201236551601300203120ustar00rootroot00000000000000PNG  IHDRi7dIDATx[ pU, {A!Ä"kBp-:*RcMXu@=,@0,"/@p|iNb^,S{wݷihW]_!F(n}b$y6~'kD~MT{*"-Q=_#$1 ɄfjkoRXÉƈjm=XXQk52.}54)غEca'c屟d%i8lٲIeʔytLB-(sؤIL ƲQj#6ŠOjZ7|7{N9? 5.WI0, HEɆN5f͚7Gc;3z$;K[k׮=}X3ɓ l6o|Tah`XUGTҾN: 6l6$s+W܇ljժD˗/{+xrZbmM ׷Ƅ诣^ g˨bL9lAy`l3)bԀ[\+6|9T̾7[p>sd΢g3S1GpȐ!ի͝;wgΜq\3--￯泳&Vh1ܡZjHO;=iGSNU6ѣG>oV_3tPyf|Val.k|vqvC"рg8v옹k.80͛Ę'͠Kv: -7o]X}91693 3ff,l|ǾBRV50;?yyݻwCu%ӣGsڵsqSNJ>a 9ۚ6m]me˖yR>$t;lY2y3B{dz$2XK&y … C{;V٣d{̑ӧlB_߲XarHi2w$%f*:Zfοs}Le릅܊M3 fqƙ.]R1cаa (cb ޽{(s|rG{]vUr@ƴuVWX'lCO*}K{<<)o6>l?Kilxخ()zƲ /_6?s%гgORwÆ on5sLG۶m+}l-A_~Q+Ήa{\ Kb1-ZI}vիsJz`.| ͆$ MoY3,xV3oggŋk׮wݐG0k,sǎ@|22/=?l1s؆8w>YFɸz ^~+ÓP}z;j(`;9x$`7+ddoi.9@l߫IH]|aCzY(7)';w8 й@,DCK/QN^\`.P}1.صGxS./>}kG˯&I2pl7eW_8 sJ[oes68S\MIk@:Q/_~ ;6~{O 㳨L/}$r Mk.ݏ^=F& }G!NI9X8\5x ^s}ցoܹsO? //y܀n~_bh- hWfۛڵS-|@i.^;ֱ6G蛺o$OjJ]}Ey´t_Lɳ mH!p!-Ze3111PHw ~˖-:E#4q B%PKt9ؓq/}Ν'{8OFn?և6AjYykf͚WM_y@#>Y\?F53_O6N@ָq wS1;6*ek|&M_ j]ݝ0tFԨQ#Aƿ ե84j-{6! / AνHNSxъ%GAA} M]`F5Sm:~&|?ZOV?ԇ괈;ZmX W"7#ر^*~:\ J  ^"Gv)gMhavfΏC ʕ+W$"=@HePaSWXJ;T zSI&J }glQTԾ}t>|Xd.a(1F<9O2Z xOEgm驸ɓ' J-1hkݾ}{.]}ڠ{-z`U,*}j>rb]5hߊ,ΝGtƭ#$&$0⋄SN%\2Kׯ_c0@MMp`ml.'mlƍ.߰s>xE9 |#ΏVֽ+|1''Ǯ^ǒCW" Qqyyyq;vc?=e}ǐ <ؖGKKKQ1lժU}c: TM615;jRM$Ԧb6lذ0kΡ{SW[.9sĻ~C{ 6N\<) 5<lA,rssm;w*>cѣ]9@l˼Zr8>|22/=?쥗^ X_6d933ѣDW~OxѣCϟݻԩCrZ1C:l̟?ߥ?=Öcgڵ.0vX8^apA^(ƺu.\uСӧGB$سgR@'lt!cP2.}>B(m@qǵG!G=_Q&Æ +{%:ʲ 3fP[ڲ{*>YF %'ۅ} ޸qߵkWT}e=/_nY~='s\؞Α2ޡzvx .|r$=E ÇW9sfmy9fRorq'@r xŘkTޒs<ܹlOƧsڂj@p %ڻzjIdpi%oy 'z[hR._Sl09ؕ2>5Fj@78F/^8ڵku g9SЫW/ݿSey#l_f͚刕1D_cIt؃䯼V2"cR|ܗ&Lvuٳg<333lɒ% w5'=>>uM= D_Ɗc׀c's=8vXzXv:BpŋCoܸJ;459 P<`ĉJFI5'clϙ3e2ևHe9⤢{ڠq|ǵUu6CҥKCn޼@[ڐ#Gw![lQڙ*91lkܹtu{ Yz Ǹ(i;lIvrÑ;׋sZ@^\kXۤ Q k֬ u떍: 'Otȳl=CNɪ1cs)`C H&JПBR91693 4if,acϺX%ma_ĨQ> ~ݾ};(==ݡC{~5C} o8]8M`.P} @Kzike8PChX&?-۩hZIENDB`shaarli-0.0.42~beta~dfsg1/images/private.png000066400000000000000000000012121236551601300210200ustar00rootroot00000000000000PNG  IHDR%&C RtEXtSoftwareAdobe ImageReadyqe<,IDATx̗_DCQ6#"%((=DRʞ"b(CĈT!bLK"FXsg;S>߹~SRk #*,Hu ́€WX(5TK0eSj K<'ψKYATeɤ(c*sL< .N-FABBj+E *)rNDbL3M&ˌjSJ&^J10 q¦R [$,q&S/d}5FŤ`b#\&:թѧY)Uƙr˜0{'Ic$%%*c3r첰.&oA T(3˖tkQoB:R.&'B:sDtFU^R9n[RnR1ý, BCJ EkIJfJ&%e-F& .4n&._%Zs;=uz{.TXlF؅-RJ%E{݊j '@ IENDB`shaarli-0.0.42~beta~dfsg1/images/private_16x16.png000066400000000000000000000006671236551601300217020ustar00rootroot00000000000000PNG  IHDRa pHYs  ~iIDAT8ҿKQ=~bQ(%AHIc4476968C΂CCHD73-  <_[9s9f586@*z)Tl Xr>YG?\.V?zD~Zy o3Mhn@_- XBٯ+bw&Hx?{?v2ǰ#w!UJ;kQ_6fC0>9TA _K̄‹v 8$^}oD ubHOṷa$vep`:dD?_D#\C34=GWGW s^q7 ,ahS0BZIENDB`shaarli-0.0.42~beta~dfsg1/images/qrcode.png000066400000000000000000000003321236551601300206250ustar00rootroot00000000000000PNG  IHDR r|sRGBbKGD pHYs  tIME :*& ZIDAT(ϝ Cw6]N BxOÕg顋3pfbR ׽JbE~:(,EAg+ 2e*IENDB`shaarli-0.0.42~beta~dfsg1/images/squiggle.png000066400000000000000000000016661236551601300212030ustar00rootroot00000000000000PNG  IHDRB}sBIT|d pHYs B(xtEXtSoftwarewww.inkscape.org<3IDATHSsw Md,h"&Zͯ_Rf"m4lYf̯"&B2lrq}qGN}ss9y?ωR{t. "Ne:"fDġpDFD.Rʠ?\;1- 0ce+s7\R 9s=<J)ð1 gڰF<ؘ/ K);yt5b&>j 莈.\mX$P$_pF5bޠpa!06"`n:'p7&di06]Ek"5y[֯S sp/sw{ UpLk򠭘k3K Pe8)؎~\~Ɖ Ftg}6U ˵ؐeV00k"f6ՍH)e{'bhD6UqXՈxU)s<()L3H" @K+2KWYMl93 {#hd U՗7&us_uϹ(GDD(}08`6}dzDĹ v4-|Q ?"aNtV`a7N-\Tk m#x">` j?=ۜГ 1kQJrpSD49<%)5.EH330qC tj&GDQդJ4)%Y# X\JUJHݏn*NFk\Xzc'>ES|_/rvuG9INi}Iv.H^,8fKݹ;l # 8.`KVfۙvq ix:Je5తLk8#<3wvOURR>ʚ)؏w17hFKF6Z]>lgkVmx/hB1N& :~#܇k4;4:'21-nO!lfzTvB2>r97Vdj¶ʼ%@Eceo 4H K+N|\CɉRJECR)".;R'1]9ŵ8 Oږ[;aIENDB`shaarli-0.0.42~beta~dfsg1/images/squiggle_closing.png000066400000000000000000000054761236551601300227240ustar00rootroot00000000000000PNG  IHDRB= sBIT|d pHYs B(xtEXtSoftwarewww.inkscape.org< IDAThyԟUqM^@RHa цE U^J-iAi)KBOԄMEQ%(4pH-4As_/]ss}{Ν;w;s["B+*l٘]11/b5)I<N RD-kp?_-ßԱ{FER\lQ_NAW15?Lx 7\R7(uj>SJNz"BUƿ:ٯao}ub 9;7ux{_Ƚ@Ep0 bnj3kܞa>4|8fq/eC^WEu NB޷U[1x7q,CH>+j)e!b?Oڙ`{oGfcC"'R#ƥ-R$Igtj] #ʒd#~+ǗRIU2NǞx B܃2JXYJ?"fz$BPϬDx Lc8E%!7F J)_/WQ\[J'Eo;鄶~30iNx|${@g.ӅQU/aH'3\uǽr+_Ix;U L~ #q#QQq ~=]ݢD ፽UBvZJE;W; ع*laUj+'cjS?KSfmuZm5b- [;\)4#ӧ$t_fQ-\߅oeme8[vSCCz_nM/ '@ҙaeu$nk:ی3=YYʪ2VҼo~n S02Fӭf`ߪ8? GyY幥9 +C4{ֈxN *l sJ%3V\F 䎑Es"sSETi Y.CXO~U.rۼGZ/|ܯW+LD| |3j '>Xh$xk/aOyX~S)ez3åu3`ϫdtΊLDqw)gx5 ]DXN֓[V"X:27N{w"bu)ew(#qE?x:_FKڿ~TDepFy}p%lvI) v:M: XՂƲNiqɭLV&_Z(kBmՃ˱u}8/H ͒q31+(1Gb;dz\T?)YOAiZ6ߖIPDtuڵsD)D)<*3MފoEҗS|֘֕FK)Rm\J{,;^*i'WΖ5g0Y߮N4\^%B=_~#iӭZ[O1m_Z=me-Oh/IG>' .Ѣہ$K> qV89"nkg,(ׇ;<{j\0|Kc}&wQh1a<qc&(U"%m?$'*j'M x_MDw1o> Wʻϡ>R㢈MDSfO/՛yAfeb#Y {DSQ a 8_d)V4j;G4ڇ1/MqdJE<-`TƲDJ)&X"KE VJ`)V])esO..Y1#\QJF2Wo(]LCtvj}cY? \# "۱2:,C!Ws>2.i"}B)K 1+4xܳ&E-)yLR5C#!jN8K}%68Ϛx˵Q'x5HZdU s}JC"zd;W.oq4hPlZ70zP:Տ,Ê,JXm*1ҙ!/^?2 ++Eod5眗? #>R=W+44*,j2Å$lPK#j{ QJyDJXC Ƿ2, FE),~d}*Q`y#!h^E#F"zH 1⊈E8d+:qET:KؾFiK){F""l[J9g奯aϵ-/5xlztyt8A d!6rIENDB`shaarli-0.0.42~beta~dfsg1/images/tag_blue.png000066400000000000000000000011121236551601300211270ustar00rootroot00000000000000PNG  IHDRagAMA7tEXtSoftwareAdobe ImageReadyqe<IDAT8˅يA%6<] dL.3C(((*n=n=.5fl{)qŹ:4unvV fAUU4+RNqj:JHZaL0d2q!t&RT*0LFz]5MmsV*FF!~ ˲0m~mcEr##]f3Yc{7(jMs|=KpH)]joČ|\ʦʖw|{< JH$"!R.1#_,;}ր-Q B+wB|>?|Mނ٦H&^ŢdY>\;$FmaZO/wdT*i mہe~}SˑH$X,iw@|@F9-X?) `0I<'Wp sZ:{)IENDB`shaarli-0.0.42~beta~dfsg1/inc/000077500000000000000000000000001236551601300161505ustar00rootroot00000000000000shaarli-0.0.42~beta~dfsg1/inc/shaarli.css000066400000000000000000000414321236551601300203110ustar00rootroot00000000000000/* CSS Stylsheet for Shaarli - http://sebsauvage.net/wiki/doku.php?id=php:shaarli */ /* CSS Reset from Yahoo to cope with browsers CSS inconsistencies. */ /* Copyright (c) 2010, Yahoo! Inc. All rights reserved. Code licensed under the BSD License: http://developer.yahoo.com/yui/license.html version: 2.8.2r1 */ html{color:#000;background:#FFF;}body,div,dl,dt,dd,ul,ol,li,h1,h2,h3,h4,h5,h6,pre,code,form,fieldset,legend,input,button,textarea,p,blockquote,th,td{margin:0;padding:0;}table{border-collapse:collapse;border-spacing:0;}fieldset,img{border:0;}address,caption,cite,code,dfn,em,strong,th,var,optgroup{font-style:inherit;font-weight:inherit;}del,ins{text-decoration:none;}li{list-style:none;}caption,th{text-align:left;}h1,h2,h3,h4,h5,h6{font-size:100%;font-weight:normal;}q:before,q:after{content:'';}abbr,acronym{border:0;font-variant:normal;}sup{vertical-align:baseline;}sub{vertical-align:baseline;}legend{color:#000;}input,button,textarea,select,optgroup,option{font-family:inherit;font-size:inherit;font-style:inherit;font-weight:inherit;}input,button,textarea,select{*font-size:100%;} body { font-family: "Trebuchet MS",Verdana,Arial,Helvetica,sans-serif; font-size:10pt; background-color: #ffffff; word-wrap: break-word; } input, textarea { background-color: #dedede; background: -webkit-gradient(linear, 0 0, 0 bottom, from(#dedede), to(#ffffff)); background: -webkit-linear-gradient(#dedede, #ffffff); background: -moz-linear-gradient(#dedede, #ffffff); background: -ms-linear-gradient(#dedede, #ffffff); background: -o-linear-gradient(#dedede, #ffffff); background: linear-gradient(#dedede, #ffffff); box-shadow: 0 1px 2px rgba(0, 0, 0, 0.5); padding:5px; border-radius: 5px 5px 5px 5px; border: none; color:#000; } h1 { font-size:20pt; font-weight:bold; font-style:italic; margin-bottom:20px; } /* I don't give a shit about IE. He can't understand selectors such as input[type='submit']. */ /* Buttons */ .bigbutton { background-color: #c0c0c0; background: -moz-linear-gradient(#c0c0c0, #ffffff) repeat scroll 0 0 transparent; background: -webkit-gradient(linear, 0 0, 0 bottom, from(#c0c0c0), to(#ffffff)); background: -webkit-linear-gradient(#c0c0c0, #ffffff); background: -ms-linear-gradient(#c0c0c0, #ffffff); background: -o-linear-gradient(#c0c0c0, #ffffff); background: linear-gradient(#c0c0c0, #ffffff); border-radius: 3px 3px 3px 3px; box-shadow: 0 1px 1px rgba(0, 0, 0, 0.5); cursor: pointer; height: 24px; margin-left: 5px; padding: 0 5px; color: #606060; border-style:outset; border-width:1px; } .smallbutton { background-color: #c0c0c0; background: -moz-linear-gradient(#c0c0c0, #ffffff) repeat scroll 0 0 transparent; background: -webkit-gradient(linear, 0 0, 0 bottom, from(#c0c0c0), to(#ffffff)); background: -webkit-linear-gradient(#c0c0c0, #ffffff); background: -ms-linear-gradient(#c0c0c0, #ffffff); background: -o-linear-gradient(#c0c0c0, #ffffff); background: linear-gradient(#c0c0c0, #ffffff); border-radius: 3px 3px 3px 3px; box-shadow: 0 1px 1px rgba(0, 0, 0, 0.5); cursor: pointer; height: 20px; margin-left: 5px; padding: 0 5px; color: #606060; border-style:outset; border-width:1px; } /* Small tab on the left of each link with edit/delete buttons. */ .button_edit, .button_delete { border-radius:0; box-shadow:none; border-style:none; border-width:0; padding:0; background:none; } .linkeditbuttons { position:absolute; left:-1px; padding:4px 2px 2px 2px; background-color:#f0f0f0; -webkit-border-radius:0px 6px 6px 0px; -moz-border-radius:0px 6px 6px 0px; -o-border-radius:0px 6px 6px 0px; -ms-border-radius:0px 6px 6px 0px; border-radius:0px 6px 6px 0px; -webkit-box-shadow:0px 0px 3px 0px #333333; -moz-box-shadow:0px 0px 3px 0px #333333; -o-box-shadow:0px 0px 3px 0px #333333; -ms-box-shadow:0px 0px 3px 0px #333333; box-shadow:0px 0px 3px 0px #333333; } #pageheader #logo{ background-image: url('../images/logo.png'); background-repeat: no-repeat; float:left; margin:0 10px 0 10px; width:105px; height:55px; cursor:pointer; } #pageheader { background-color: #333333; background: -webkit-gradient(linear, 0 0, 0 bottom, from(#333333), to(#111111)); background: -webkit-linear-gradient(#333333, #111111); background: -moz-linear-gradient(#333333, #111111); background: -ms-linear-gradient(#333333, #111111); background: -o-linear-gradient(#333333, #111111); background: linear-gradient(#333333, #111111); box-shadow: 0 1px 2px rgba(0, 0, 0, 0.5); width:auto; padding:0 10px 5px 10px; margin: auto; } #pageheader a { background-color: #333333; background: -webkit-gradient(linear, 0 0, 0 bottom, from(#333333), to(#000000)); background: -webkit-linear-gradient(#333333, #000000); background: -moz-linear-gradient(#333333, #000000); background: -ms-linear-gradient(#333333, #000000); background: -o-linear-gradient(#333333, #000000); background: linear-gradient(#333333, #000000); box-shadow: 0 1px 2px rgba(0, 0, 0, 0.5); padding:5px; border-radius: 5px 5px 5px 5px; margin:10px 3px 3px 3px; color:#A2DD42; float:left; text-decoration:none; } #toolsdiv a{ clear:both; } #toolsdiv a span{ color:#ffffff; } .linksperpage,.tagfilter,.searchform,.addform { background-color: #dedede; background: -webkit-gradient(linear, 0 0, 0 bottom, from(#dedede), to(#ffffff)); background: -webkit-linear-gradient(#dedede, #ffffff); background: -moz-linear-gradient(#dedede, #ffffff); background: -ms-linear-gradient(#dedede, #ffffff); background: -o-linear-gradient(#dedede, #ffffff); background: linear-gradient(#dedede, #ffffff); display:inline; box-shadow: 0 1px 2px rgba(0, 0, 0, 0.5); padding:5px; border: none; border-radius: 5px 5px 5px 5px; margin:10px 3px 3px 3px; color:#cecece; } .linksperpage{ box-shadow: 0 0 0 rgba(0, 0, 0, 0.5); padding:3px; } .linksperpage input,.tagfilter input, .searchform input, .addform input{ border:none; color:#606060; background:none; box-shadow:none; padding:5px; } .linksperpage input{ padding:0; } .tagfilter input.bigbutton,.searchform input.bigbutton,.addform input.bigbutton{ background-color: #dedede; background: -webkit-gradient(linear, 0 0, 0 bottom, from(#dedede), to(#ffffff)); background: -webkit-linear-gradient(#dedede, #ffffff); background: -moz-linear-gradient(#dedede, #ffffff); background: -ms-linear-gradient(#dedede, #ffffff); background: -o-linear-gradient(#dedede, #ffffff); background: linear-gradient(#dedede, #ffffff); box-shadow: 0 1px 2px rgba(0, 0, 0, 0.5); padding:0 5px 0 5px; margin:5px 0 5px 0; height:20px; border-radius: 5px 5px 5px 5px; cursor:pointer; } #shaarli_title { font-weight:bold; font-style:italic; margin-top:0;} #shaarli_title a { color: #fff !important; } #pageheader a:visited { color:#98C943; text-decoration:none;} #pageheader a:hover { color:#FFFFC9; text-decoration:none;} #pageheader a:active { color:#bbb; text-decoration:none;} #searchcriteria { padding: 4px 0px 5px 5px; font-weight:bold;} .paging { padding:5px;background-color:#777; color:#ccc; text-align:center; clear:both;} .paging a:link { color:#ccc; text-decoration:none;} .paging a:visited { color:#ccc; } .paging a:hover { color:#FFFFC9; } .paging a:active { color:#fff; } #paging_privatelinks { float:left; } #paging_linksperpage { float:right; padding-right:5px; } #paging_current { display:inline; color:#fff; padding:0 20 0 20; } #paging_older { margin-right:15px; } #paging_newer { margin-left:15px; } #headerform { color:#ffffff; padding:5px 5px 5px 5px; clear: both;} #toolsdiv { color:#ffffff; padding:5px 5px 5px 5px; clear:left; } #uploaddiv { color:#ffffff; padding:5px 5px 5px 5px; clear:left; } #editlinkform { height:100%;color:#ffffff; padding:5px 5px 5px 15px; width:80%; clear:left; } #linklist li { padding:4px 10px 15px 20px; border-top: 1px solid #bbb; clear:both; background-color: #F2F2F2; background: -webkit-gradient(linear, 0 0, 0 bottom, from(#F2F2F2), to(#ffffff)); background: -webkit-linear-gradient(#F2F2F2, #ffffff); background: -moz-linear-gradient(#F2F2F2, #ffffff); background: -ms-linear-gradient(#F2F2F2, #ffffff); background: -o-linear-gradient(#F2F2F2, #ffffff); background: linear-gradient(#F2F2F2, #ffffff); } /* #linklist li.publicLinkHightLight:hover,#linklist li:hover{ background: #E9FFCE; } */ #linklist li.private { background: url('../images/private.png') no-repeat 10px center; padding-left:60px; } #linklist li { padding-left:26px; } .private .linktitle a {color:#969696;} .linktitle { font-size:14pt; font-weight:bold; } .linktitle a { text-decoration: none; color:#80AD48; } .linktitle a:hover { color:#F57900; } .linkdate { font-size:8pt; color:#888; } .linkdate a { background-image:url('../images/calendar.png');padding:2px 0 3px 20px;background-repeat:no-repeat;text-decoration: none; color:#E28E3F; } .linkdate a:hover { color: #F57900 } .linkurl { font-size:8pt; color:#4BAA74; } .linkdescription { color:#000; margin-top:0; margin-bottom:12px; font-weight:normal; max-height:400px; overflow:auto; } .linkdescription a { text-decoration: none; color:#3465A4; } .linkdescription a:hover { color:#F57900; } .linktaglist { padding-top:10px; line-height:200%;} .linktag { font-size:9pt; background-color: #F2F2F2; background: -webkit-gradient(linear, 0 0, 0 bottom, from(#F2F2F2), to(#ffffff)); background: -webkit-linear-gradient(#F2F2F2, #ffffff); background: -moz-linear-gradient(#F2F2F2, #ffffff); background: -ms-linear-gradient(#F2F2F2, #ffffff); background: -o-linear-gradient(#F2F2F2, #ffffff); background: linear-gradient(#F2F2F2, #ffffff); box-shadow: 0 0 2px rgba(0, 0, 0, 0.5); padding:3px 3px 3px 20px; height:20px; border-radius: 3px 3px 3px 3px; cursor:pointer; background-image:url('../images/tag_blue.png'); background-repeat:no-repeat; background-position:3px center; background-color:#ffffff; } .linktag:hover { border-color: #555573; color:#000; } .linktag a { color:#777; text-decoration:none; } .linkshort { font-size:8pt; color:#888; } .linkshort a { text-decoration: none; color:#393964; } .linkshort a:hover { text-decoration: underline; } .buttoneditform { display:inline; } #footer { font-size:8pt; text-align:center; border-top:1px solid #ddd; color: #888; clear:both; } #footer a{ color:#486D08;} #footer a:hover{ color:#000000;} #newversion { background-color: #FFFFA0; color:#000; position:absolute; top:0;right:0; padding:2 7 2 7; font-size:9pt;} #cloudtag { padding-left:10%; padding-right:10%; } #cloudtag a { color:black; text-decoration:none; } #installform td { font-size: 10pt; color:black; padding:10px 5px 10px 5px; clear:left; } #changepasswordform { color:#ccc; padding:10px 5px 10px 5px; clear:left; } #changetag { color:#ccc; padding:10px 5px 10px 5px; clear:left; } #configform td { color:#ccc; font-size: 10pt; padding:10px 5px 10px 5px; } #configform { color:#ccc; padding:10px 5px 10px 5px; clear:left; } .thumbnail { float:right; margin-left: 10px; } /* If you want thumbnails on the left: .thumbnail { float:left; margin-right: 10px; } .linkcontainer { position: static; margin-left:130px; } */ /* --- Picture wall CSS --- */ #picwall_container { color:#fff; background-color:#000; clear:both; } .picwall_pictureframe { background-color:#000; z-index:5; position:relative; display:table-cell; vertical-align:middle;width:90px; height:90px; overflow:hidden; text-align:center; float:left; } .picwall_pictureframe img { max-width: 100%;height: auto; } /* Adapt the width of the image */ .picwall_pictureframe a {text-decoration:none;} /* CSS to show title when hovering an image - no javascript required. */ .picwall_pictureframe span.info {display: none;} .picwall_pictureframe:hover span.info { display:block; position:absolute; top:0; left:0; width:90px; font-weight:bold; font-size:8pt; color:#fff; text-align: left; background-color: transparent; background-color: rgba(0, 0, 0, 0.4); /* FF3+, Saf3+, Opera 10.10+, Chrome, IE9 */ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=#66000000,endColorstr=#66000000); /* IE6–IE9 */ text-shadow:2px 2px 1px #000000; } /* Minimal customisation for jQuery widgets */ .ui-autocomplete { background-color:#fff; padding-left:5px;} .ui-state-hover { background-color: #604dff; color:#fff; } #linklist li.publicLinkHightLight{ background: #ffffff; } div#permalinkQrcode { padding:20px; width:220px; height:220px; background-color: #ffffff; border: 1px solid black; position: absolute; top:-100px; left:-100px; text-align:center; font-size: 8pt; z-index:50; -webkit-box-shadow:2px 2px 20px 2px #333333; -moz-box-shadow:2px 2px 20px 2px #333333; -o-box-shadow:2px 2px 20px 2px #333333; -ms-box-shadow:2px 2px 20px 2px #333333; box-shadow:2px 2px 20px 2px #333333; } div.daily { font-family: Georgia, 'DejaVu Serif', Norasi, serif; background-color: #E6D6BE; /* Background paper texture by BashCorpo: http://www.bashcorpo.dk/textures.php http://bashcorpo.deviantart.com/art/Grungy-paper-texture-v-5-22966998 */ background-image: url("../images/Paper_texture_v5_by_bashcorpo_w1000.jpg"); -webkit-background-size: cover; -moz-background-size: cover; -o-background-size: cover; background-size: cover; position:relative; border-bottom: 2px solid black; } #daily_col1 { float:left;position:relative; width:33%; padding-left:1%; } #daily_col2 { float:left;position:relative; width:33%; } #daily_col3 { float:left;position:relative; width:33%;} div.dailyAbout { float:left; border: 1px solid black; font-size: 8pt; position:absolute; left:10px; top: 15px; padding: 5px 5px 5px 5px; text-align:center; } div.dailyAbout a { color: #890500; } div.dailyTitle { font-weight: bold; font-size: 44pt; text-align:center; padding:10px 20px 0px 20px; } div.dailyDate { font-size: 12pt; font-weight:bold; text-align:center; padding:0px 20px 30px 20px; } /* Individual entries in "Daily": */ div.dailyEntry { margin: 5px 10px 2px 5px; font-size: 11pt; border-top: 1px solid #555; } div.dailyEntry a { text-decoration:none; color: #890500; } div.dailyEntryTags { font-size:7.75pt; } div.dailyEntryTitle { font-size:18pt; font-weight:bold;} div.dailyEntryThumbnail { width:100%; text-align:center; background-color:rgb(128,128,128); background:url(../images/50pc_transparent.png); padding:4px 0px 2px 0px; } div.dailyEntryDescription { margin-top: 10px; margin-bottom: 30px; text-align:justify; overflow:auto; } /* Common css screwdriver */ .clear{ clear:both; } /* For lazy images loading in picture wall. using http://www.appelsiini.net/projects/lazyload */ .lazyimage { display:none; } @media print { html {border:none;background:#fff!important;color:#000!important;} body {font-size:12pt;width:auto!important;margin:auto!important;} p {orphans:3; /*pas de ligne seule en bas */widows:3;/*pas de ligne seule en haut*/} a {color:#000!important;text-decoration:none!important;} #pageheader, .paging, #linklist li form, #footer {display:none;} #linklist li { padding:2 0 10 0; border-top: 2px solid #000; clear:both; } #linklist li.private { background-color: none; border-left:0; } .linkdate { line-height:2; } .linkurl { color:#000; } .linkdescription { font-size:10pt;} .linktag { border: 1px solid black; font-style:italic; font-size:8pt;} } @media handheld, only screen and (max-width: 480px), only screen and (max-device-width: 854px) { /* A few fixes for mobile devices (far from perfect). */ .nomobile { display:none; } #logo { display:none; } #pageheader a { padding:5px; border-radius: 5px 5px 5px 5px; margin:3px; } .searchform,.tagfilter { display:block !important; margin:0px !important; padding:0px !important; width:100% !important; } .searchform input,.tagfilter input { margin:0px !important; padding:0px !important; display:inline !important; } .tagfilter input.bigbutton,.searchform input.bigbutton,.addform input.bigbutton{ width:30%; font-size:smaller;} #searchform_value { width:70% !important; } #tagfilter_value { width:70% !important; } div.qrcode { position:relative; float:left; top:-10px; left:0px; } #paging_privatelinks { float;none; } #paging_linksperpage { float:none; margin-bottom:10px; font-size:smaller;} #paging_older,#paging_newer,#paging_linksperpage a { border: 1px solid black; padding:3px 5px 3px 5px; background-color:#666; color:#fff; border-radius: 5px 5px 5px 5px;} .thumbnail { float:none; height:auto; margin: 0px; text-align:center;} #cloudtag { padding:0px; } div.dailyAbout { float:none; position:relative; width:100%; clear:both; padding:0px; top:0px; left:0px; } #daily_col1,#daily_col2,#daily_col3 { float:none; width:100%; padding:0px;} div.dailyTitle { font-size: 18pt; margin-top:5px; padding:0px;} div.dailyDate { font-size: 11pt;padding:0px; display:block; } div.dailyEntryTitle { font-size:16pt; font-weight:bold;} div.dailyEntryDescription { font-size:10pt; } } /* Highlight search results */ .highlight { background-color: #FFFF33; } shaarli-0.0.42~beta~dfsg1/index.php000066400000000000000000003547471236551601300172430ustar00rootroot00000000000000'); // Suffix to encapsulate data in php code. // http://server.com/x/shaarli --> /shaarli/ define('WEB_PATH', substr($_SERVER["REQUEST_URI"], 0, 1+strrpos($_SERVER["REQUEST_URI"], '/', 0))); // Force cookie path (but do not change lifetime) $cookie=session_get_cookie_params(); $cookiedir = ''; if(dirname($_SERVER['SCRIPT_NAME'])!='/') $cookiedir=dirname($_SERVER["SCRIPT_NAME"]).'/'; session_set_cookie_params($cookie['lifetime'],$cookiedir,$_SERVER['HTTP_HOST']); // Set default cookie expiration and path. // Set session parameters on server side. define('INACTIVITY_TIMEOUT',3600); // (in seconds). If the user does not access any page within this time, his/her session is considered expired. ini_set('session.use_cookies', 1); // Use cookies to store session. ini_set('session.use_only_cookies', 1); // Force cookies for session (phpsessionID forbidden in URL) ini_set('session.use_trans_sid', false); // Prevent php to use sessionID in URL if cookies are disabled. session_name('shaarli'); if (session_id() == '') session_start(); // Start session if needed (Some server auto-start sessions). // PHP Settings ini_set('max_input_time','60'); // High execution time in case of problematic imports/exports. ini_set('memory_limit', '128M'); // Try to set max upload file size and read (May not work on some hosts). ini_set('post_max_size', '16M'); ini_set('upload_max_filesize', '16M'); checkphpversion(); error_reporting(E_ALL^E_WARNING); // See all error except warnings. //error_reporting(-1); // See all errors (for debugging only) include "inc/rain.tpl.class.php"; //include Rain TPL raintpl::$tpl_dir = "tpl/"; // template directory if (!is_dir('tmp')) { mkdir('tmp',0705); chmod('tmp',0705); } raintpl::$cache_dir = "tmp/"; // cache directory ob_start(); // Output buffering for the page cache. // In case stupid admin has left magic_quotes enabled in php.ini: if (get_magic_quotes_gpc()) { function stripslashes_deep($value) { $value = is_array($value) ? array_map('stripslashes_deep', $value) : stripslashes($value); return $value; } $_POST = array_map('stripslashes_deep', $_POST); $_GET = array_map('stripslashes_deep', $_GET); $_COOKIE = array_map('stripslashes_deep', $_COOKIE); } // Prevent caching on client side or proxy: (yes, it's ugly) header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT"); header("Cache-Control: no-store, no-cache, must-revalidate"); header("Cache-Control: post-check=0, pre-check=0", false); header("Pragma: no-cache"); // Directories creations (Note that your web host may require differents rights than 705.) if (!is_writable(realpath(dirname(__FILE__)))) die('
ERROR: Shaarli does not have the right to write in its own directory ('.realpath(dirname(__FILE__)).').
'); if (!is_dir($GLOBALS['config']['DATADIR'])) { mkdir($GLOBALS['config']['DATADIR'],0705); chmod($GLOBALS['config']['DATADIR'],0705); } if (!is_dir('tmp')) { mkdir('tmp',0705); chmod('tmp',0705); } // For RainTPL temporary files. if (!is_file($GLOBALS['config']['DATADIR'].'/.htaccess')) { file_put_contents($GLOBALS['config']['DATADIR'].'/.htaccess',"Allow from none\nDeny from all\n"); } // Protect data files. // Second check to see if Shaarli can write in its directory, because on some hosts is_writable() is not reliable. if (!is_file($GLOBALS['config']['DATADIR'].'/.htaccess')) die('
ERROR: Shaarli does not have the right to write in its data directory ('.realpath($GLOBALS['config']['DATADIR']).').
'); if ($GLOBALS['config']['ENABLE_LOCALCACHE']) { if (!is_dir($GLOBALS['config']['CACHEDIR'])) { mkdir($GLOBALS['config']['CACHEDIR'],0705); chmod($GLOBALS['config']['CACHEDIR'],0705); } if (!is_file($GLOBALS['config']['CACHEDIR'].'/.htaccess')) { file_put_contents($GLOBALS['config']['CACHEDIR'].'/.htaccess',"Allow from none\nDeny from all\n"); } // Protect data files. } // Handling of old config file which do not have the new parameters. if (empty($GLOBALS['title'])) $GLOBALS['title']='Shared links on '.htmlspecialchars(indexUrl()); if (empty($GLOBALS['timezone'])) $GLOBALS['timezone']=date_default_timezone_get(); if (empty($GLOBALS['redirector'])) $GLOBALS['redirector']=''; if (empty($GLOBALS['disablesessionprotection'])) $GLOBALS['disablesessionprotection']=false; if (empty($GLOBALS['disablejquery'])) $GLOBALS['disablejquery']=false; if (empty($GLOBALS['privateLinkByDefault'])) $GLOBALS['privateLinkByDefault']=false; // I really need to rewrite Shaarli with a proper configuation manager. // Run config screen if first run: if (!is_file($GLOBALS['config']['CONFIG_FILE'])) install(); require $GLOBALS['config']['CONFIG_FILE']; // Read login/password hash into $GLOBALS. // a token depending of deployment salt, user password, and the current ip define('STAY_SIGNED_IN_TOKEN', sha1($GLOBALS['hash'].$_SERVER["REMOTE_ADDR"].$GLOBALS['salt'])); autoLocale(); // Sniff browser language and set date format accordingly. header('Content-Type: text/html; charset=utf-8'); // We use UTF-8 for proper international characters handling. // Check php version function checkphpversion() { if (version_compare(PHP_VERSION, '5.1.0') < 0) { header('Content-Type: text/plain; charset=utf-8'); echo 'Your server supports php '.PHP_VERSION.'. Shaarli requires at least php 5.1.0, and thus cannot run. Sorry.'; exit; } } // Checks if an update is available for Shaarli. // (at most once a day, and only for registered user.) // Output: '' = no new version. // other= the available version. function checkUpdate() { if (!isLoggedIn()) return ''; // Do not check versions for visitors. // Get latest version number at most once a day. if (!is_file($GLOBALS['config']['UPDATECHECK_FILENAME']) || (filemtime($GLOBALS['config']['UPDATECHECK_FILENAME'])url = $url; $this->filename = $GLOBALS['config']['PAGECACHE'].'/'.sha1($url).'.cache'; $this->shouldBeCached = $shouldBeCached; } // If the page should be cached and a cached version exists, // returns the cached version (otherwise, return null). public function cachedVersion() { if (!$this->shouldBeCached) return null; if (is_file($this->filename)) { return file_get_contents($this->filename); exit; } return null; } // Put a page in the cache. public function cache($page) { if (!$this->shouldBeCached) return; if (!is_dir($GLOBALS['config']['PAGECACHE'])) { mkdir($GLOBALS['config']['PAGECACHE'],0705); chmod($GLOBALS['config']['PAGECACHE'],0705); } file_put_contents($this->filename,$page); } // Purge the whole cache. // (call with pageCache::purgeCache()) public static function purgeCache() { if (is_dir($GLOBALS['config']['PAGECACHE'])) { $handler = opendir($GLOBALS['config']['PAGECACHE']); if ($handler!==false) { while (($filename = readdir($handler))!==false) { if (endsWith($filename,'.cache')) { unlink($GLOBALS['config']['PAGECACHE'].'/'.$filename); } } closedir($handler); } } } } // ----------------------------------------------------------------------------------------------- // Log to text file function logm($message) { $t = strval(date('Y/m/d_H:i:s')).' - '.$_SERVER["REMOTE_ADDR"].' - '.strval($message)."\n"; file_put_contents($GLOBALS['config']['DATADIR'].'/log.txt',$t,FILE_APPEND); } // Same as nl2br(), but escapes < and > function nl2br_escaped($html) { return str_replace('>','>',str_replace('<','<',nl2br($html))); } /* Returns the small hash of a string, using RFC 4648 base64url format eg. smallHash('20111006_131924') --> yZH23w Small hashes: - are unique (well, as unique as crc32, at last) - are always 6 characters long. - only use the following characters: a-z A-Z 0-9 - _ @ - are NOT cryptographically secure (they CAN be forged) In Shaarli, they are used as a tinyurl-like link to individual entries. */ function smallHash($text) { $t = rtrim(base64_encode(hash('crc32',$text,true)),'='); return strtr($t, '+/', '-_'); } // In a string, converts urls to clickable links. // Function inspired from http://www.php.net/manual/en/function.preg-replace.php#85722 function text2clickable($url) { $redir = empty($GLOBALS['redirector']) ? '' : $GLOBALS['redirector']; return preg_replace('!(((?:https?|ftp|file)://|apt:|magnet:)\S+[[:alnum:]]/?)!si','$1',$url); } // This function inserts   where relevant so that multiple spaces are properly displayed in HTML // even in the absence of
  (This is used in description to keep text formatting)
function keepMultipleSpaces($text)
{
    return str_replace('  ','  ',$text);

}
// ------------------------------------------------------------------------------------------
// Sniff browser language to display dates in the right format automatically.
// (Note that is may not work on your server if the corresponding local is not installed.)
function autoLocale()
{
    $loc='en_US'; // Default if browser does not send HTTP_ACCEPT_LANGUAGE
    if (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) // eg. "fr,fr-fr;q=0.8,en;q=0.5,en-us;q=0.3"
    {   // (It's a bit crude, but it works very well. Prefered language is always presented first.)
        if (preg_match('/([a-z]{2}(-[a-z]{2})?)/i',$_SERVER['HTTP_ACCEPT_LANGUAGE'],$matches)) $loc=$matches[1];
    }
    setlocale(LC_TIME,$loc);  // LC_TIME = Set local for date/time format only.
}

// ------------------------------------------------------------------------------------------
// PubSubHubbub protocol support (if enabled)  [UNTESTED]
// (Source: http://aldarone.fr/les-flux-rss-shaarli-et-pubsubhubbub/ )
if (!empty($GLOBALS['config']['PUBSUBHUB_URL'])) include './publisher.php';
function pubsubhub()
{
    if (!empty($GLOBALS['config']['PUBSUBHUB_URL']))
    {
       $p = new Publisher($GLOBALS['config']['PUBSUBHUB_URL']);
       $topic_url = array (
                       indexUrl().'?do=atom',
                       indexUrl().'?do=rss'
                    );
       $p->publish_update($topic_url);
    }
}

// ------------------------------------------------------------------------------------------
// Session management

// Returns the IP address of the client (Used to prevent session cookie hijacking.)
function allIPs()
{
    $ip = $_SERVER["REMOTE_ADDR"];
    // Then we use more HTTP headers to prevent session hijacking from users behind the same proxy.
    if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) { $ip=$ip.'_'.$_SERVER['HTTP_X_FORWARDED_FOR']; }
    if (isset($_SERVER['HTTP_CLIENT_IP'])) { $ip=$ip.'_'.$_SERVER['HTTP_CLIENT_IP']; }
    return $ip;
}

function fillSessionInfo() {
	$_SESSION['uid'] = sha1(uniqid('',true).'_'.mt_rand()); // generate unique random number (different than phpsessionid)
	$_SESSION['ip']=allIPs();                // We store IP address(es) of the client to make sure session is not hijacked.
	$_SESSION['username']=$GLOBALS['login'];
	$_SESSION['expires_on']=time()+INACTIVITY_TIMEOUT;  // Set session expiration.
}

// Check that user/password is correct.
function check_auth($login,$password)
{
    $hash = sha1($password.$login.$GLOBALS['salt']);
    if ($login==$GLOBALS['login'] && $hash==$GLOBALS['hash'])
    {   // Login/password is correct.
		fillSessionInfo();
        logm('Login successful');
        return True;
    }
    logm('Login failed for user '.$login);
    return False;
}

// Returns true if the user is logged in.
function isLoggedIn()
{
    if ($GLOBALS['config']['OPEN_SHAARLI']) return true;

    if (!isset($GLOBALS['login'])) return false;  // Shaarli is not configured yet.

	if (@$_COOKIE['shaarli_staySignedIn']===STAY_SIGNED_IN_TOKEN)
	{
		fillSessionInfo();
		return true;
	}
    // If session does not exist on server side, or IP address has changed, or session has expired, logout.
    if (empty($_SESSION['uid']) || ($GLOBALS['disablesessionprotection']==false && $_SESSION['ip']!=allIPs()) || time()>=$_SESSION['expires_on'])
    {
        logout();
        return false;
    }
    if (!empty($_SESSION['longlastingsession']))  $_SESSION['expires_on']=time()+$_SESSION['longlastingsession']; // In case of "Stay signed in" checked.
    else $_SESSION['expires_on']=time()+INACTIVITY_TIMEOUT; // Standard session expiration date.

    return true;
}

// Force logout.
function logout() { if (isset($_SESSION)) { unset($_SESSION['uid']); unset($_SESSION['ip']); unset($_SESSION['username']); unset($_SESSION['privateonly']); }  
setcookie('shaarli_staySignedIn', FALSE, 0, WEB_PATH);
}


// ------------------------------------------------------------------------------------------
// Brute force protection system
// Several consecutive failed logins will ban the IP address for 30 minutes.
if (!is_file($GLOBALS['config']['IPBANS_FILENAME'])) file_put_contents($GLOBALS['config']['IPBANS_FILENAME'], "array(),'BANS'=>array()),true).";\n?>");
include $GLOBALS['config']['IPBANS_FILENAME'];
// Signal a failed login. Will ban the IP if too many failures:
function ban_loginFailed()
{
    $ip=$_SERVER["REMOTE_ADDR"]; $gb=$GLOBALS['IPBANS'];
    if (!isset($gb['FAILURES'][$ip])) $gb['FAILURES'][$ip]=0;
    $gb['FAILURES'][$ip]++;
    if ($gb['FAILURES'][$ip]>($GLOBALS['config']['BAN_AFTER']-1))
    {
        $gb['BANS'][$ip]=time()+$GLOBALS['config']['BAN_DURATION'];
        logm('IP address banned from login');
    }
    $GLOBALS['IPBANS'] = $gb;
    file_put_contents($GLOBALS['config']['IPBANS_FILENAME'], "");
}

// Signals a successful login. Resets failed login counter.
function ban_loginOk()
{
    $ip=$_SERVER["REMOTE_ADDR"]; $gb=$GLOBALS['IPBANS'];
    unset($gb['FAILURES'][$ip]); unset($gb['BANS'][$ip]);
    $GLOBALS['IPBANS'] = $gb;
    file_put_contents($GLOBALS['config']['IPBANS_FILENAME'], "");
}

// Checks if the user CAN login. If 'true', the user can try to login.
function ban_canLogin()
{
    $ip=$_SERVER["REMOTE_ADDR"]; $gb=$GLOBALS['IPBANS'];
    if (isset($gb['BANS'][$ip]))
    {
        // User is banned. Check if the ban has expired:
        if ($gb['BANS'][$ip]<=time())
        {   // Ban expired, user can try to login again.
            logm('Ban lifted.');
            unset($gb['FAILURES'][$ip]); unset($gb['BANS'][$ip]);
            file_put_contents($GLOBALS['config']['IPBANS_FILENAME'], "");
            return true; // Ban has expired, user can login.
        }
        return false; // User is banned.
    }
    return true; // User is not banned.
}

// ------------------------------------------------------------------------------------------
// Process login form: Check if login/password is correct.
if (isset($_POST['login']))
{
    if (!ban_canLogin()) die('I said: NO. You are banned for the moment. Go away.');
    if (isset($_POST['password']) && tokenOk($_POST['token']) && (check_auth($_POST['login'], $_POST['password'])))
    {   // Login/password is ok.
        ban_loginOk();
        // If user wants to keep the session cookie even after the browser closes:
        if (!empty($_POST['longlastingsession']))
        {
			setcookie('shaarli_staySignedIn', STAY_SIGNED_IN_TOKEN, time()+31536000, WEB_PATH);
            $_SESSION['longlastingsession']=31536000;  // (31536000 seconds = 1 year)
            $_SESSION['expires_on']=time()+$_SESSION['longlastingsession'];  // Set session expiration on server-side.

            $cookiedir = ''; if(dirname($_SERVER['SCRIPT_NAME'])!='/') $cookiedir=dirname($_SERVER["SCRIPT_NAME"]).'/';
            session_set_cookie_params($_SESSION['longlastingsession'],$cookiedir,$_SERVER['HTTP_HOST']); // Set session cookie expiration on client side
            // Note: Never forget the trailing slash on the cookie path !
            session_regenerate_id(true);  // Send cookie with new expiration date to browser.
        }
        else // Standard session expiration (=when browser closes)
        {
            $cookiedir = ''; if(dirname($_SERVER['SCRIPT_NAME'])!='/') $cookiedir=dirname($_SERVER["SCRIPT_NAME"]).'/';
            session_set_cookie_params(0,$cookiedir,$_SERVER['HTTP_HOST']); // 0 means "When browser closes"
            session_regenerate_id(true);
        }
        // Optional redirect after login:
        if (isset($_GET['post'])) { header('Location: ?post='.urlencode($_GET['post']).(!empty($_GET['title'])?'&title='.urlencode($_GET['title']):'').(!empty($_GET['source'])?'&source='.urlencode($_GET['source']):'')); exit; }
        if (isset($_POST['returnurl']))
        {
            if (endsWith($_POST['returnurl'],'?do=login')) { header('Location: ?'); exit; } // Prevent loops over login screen.
            header('Location: '.$_POST['returnurl']); exit;
        }
        header('Location: ?'); exit;
    }
    else
    {
        ban_loginFailed();
        $redir = '';
        if (isset($_GET['post'])) { $redir = '&post='.urlencode($_GET['post']).(!empty($_GET['title'])?'&title='.urlencode($_GET['title']):'').(!empty($_GET['source'])?'&source='.urlencode($_GET['source']):'');  }
        echo ''; // Redirect to login screen.
        exit;
    }
}

// ------------------------------------------------------------------------------------------
// Misc utility functions:

// Returns the server URL (including port and http/https), without path.
// eg. "http://myserver.com:8080"
// You can append $_SERVER['SCRIPT_NAME'] to get the current script URL.
function serverUrl()
{
    $https = (!empty($_SERVER['HTTPS']) && (strtolower($_SERVER['HTTPS'])=='on')) || $_SERVER["SERVER_PORT"]=='443'; // HTTPS detection.
    $serverport = ($_SERVER["SERVER_PORT"]=='80' || ($https && $_SERVER["SERVER_PORT"]=='443') ? '' : ':'.$_SERVER["SERVER_PORT"]);
    return 'http'.($https?'s':'').'://'.$_SERVER['HTTP_HOST'].$serverport;
}

// Returns the absolute URL of current script, without the query.
// (eg. http://sebsauvage.net/links/)
function indexUrl()
{
    $scriptname = $_SERVER["SCRIPT_NAME"];
    // If the script is named 'index.php', we remove it (for better looking URLs,
    // eg. http://mysite.com/shaarli/?abcde instead of http://mysite.com/shaarli/index.php?abcde)
    if (endswith($scriptname,'index.php')) $scriptname = substr($scriptname,0,strlen($scriptname)-9);
    return serverUrl() . $scriptname;
}

// Returns the absolute URL of current script, WITH the query.
// (eg. http://sebsauvage.net/links/?toto=titi&spamspamspam=humbug)
function pageUrl()
{
    return indexUrl().(!empty($_SERVER["QUERY_STRING"]) ? '?'.$_SERVER["QUERY_STRING"] : '');
}

// Convert post_max_size/upload_max_filesize (eg.'16M') parameters to bytes.
function return_bytes($val)
{
    $val = trim($val); $last=strtolower($val[strlen($val)-1]);
    switch($last)
    {
        case 'g': $val *= 1024;
        case 'm': $val *= 1024;
        case 'k': $val *= 1024;
    }
    return $val;
}

// Try to determine max file size for uploads (POST).
// Returns an integer (in bytes)
function getMaxFileSize()
{
    $size1 = return_bytes(ini_get('post_max_size'));
    $size2 = return_bytes(ini_get('upload_max_filesize'));
    // Return the smaller of two:
    $maxsize = min($size1,$size2);
    // FIXME: Then convert back to readable notations ? (eg. 2M instead of 2000000)
    return $maxsize;
}

// Tells if a string start with a substring or not.
function startsWith($haystack,$needle,$case=true)
{
    if($case){return (strcmp(substr($haystack, 0, strlen($needle)),$needle)===0);}
    return (strcasecmp(substr($haystack, 0, strlen($needle)),$needle)===0);
}

// Tells if a string ends with a substring or not.
function endsWith($haystack,$needle,$case=true)
{
    if($case){return (strcmp(substr($haystack, strlen($haystack) - strlen($needle)),$needle)===0);}
    return (strcasecmp(substr($haystack, strlen($haystack) - strlen($needle)),$needle)===0);
}

/*  Converts a linkdate time (YYYYMMDD_HHMMSS) of an article to a timestamp (Unix epoch)
    (used to build the ADD_DATE attribute in Netscape-bookmarks file)
    PS: I could have used strptime(), but it does not exist on Windows. I'm too kind. */
function linkdate2timestamp($linkdate)
{
    $Y=$M=$D=$h=$m=$s=0;
    $r = sscanf($linkdate,'%4d%2d%2d_%2d%2d%2d',$Y,$M,$D,$h,$m,$s);
    return mktime($h,$m,$s,$M,$D,$Y);
}

/*  Converts a linkdate time (YYYYMMDD_HHMMSS) of an article to a RFC822 date.
    (used to build the pubDate attribute in RSS feed.)  */
function linkdate2rfc822($linkdate)
{
    return date('r',linkdate2timestamp($linkdate)); // 'r' is for RFC822 date format.
}

/*  Converts a linkdate time (YYYYMMDD_HHMMSS) of an article to a ISO 8601 date.
    (used to build the updated tags in ATOM feed.)  */
function linkdate2iso8601($linkdate)
{
    return date('c',linkdate2timestamp($linkdate)); // 'c' is for ISO 8601 date format.
}

/*  Converts a linkdate time (YYYYMMDD_HHMMSS) of an article to a localized date format.
    (used to display link date on screen)
    The date format is automatically chosen according to locale/languages sniffed from browser headers (see autoLocale()). */
function linkdate2locale($linkdate)
{
    return utf8_encode(strftime('%c',linkdate2timestamp($linkdate))); // %c is for automatic date format according to locale.
    // Note that if you use a local which is not installed on your webserver,
    // the date will not be displayed in the chosen locale, but probably in US notation.
}

// Parse HTTP response headers and return an associative array.
function http_parse_headers_shaarli( $headers )
{
    $res=array();
    foreach($headers as $header)
    {
        $i = strpos($header,': ');
        if ($i!==false)
        {
            $key=substr($header,0,$i);
            $value=substr($header,$i+2,strlen($header)-$i-2);
            $res[$key]=$value;
        }
    }
    return $res;
}

/* GET an URL.
   Input: $url : url to get (http://...)
          $timeout : Network timeout (will wait this many seconds for an anwser before giving up).
   Output: An array.  [0] = HTTP status message (eg. "HTTP/1.1 200 OK") or error message
                      [1] = associative array containing HTTP response headers (eg. echo getHTTP($url)[1]['Content-Type'])
                      [2] = data
    Example: list($httpstatus,$headers,$data) = getHTTP('http://sebauvage.net/');
             if (strpos($httpstatus,'200 OK')!==false)
                 echo 'Data type: '.htmlspecialchars($headers['Content-Type']);
             else
                 echo 'There was an error: '.htmlspecialchars($httpstatus)
*/
function getHTTP($url,$timeout=30)
{
    try
    {
        $options = array('http'=>array('method'=>'GET','timeout' => $timeout, 'user_agent' => 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:23.0) Gecko/20100101 Firefox/23.0')); // Force network timeout
        $context = stream_context_create($options);
        $data=file_get_contents($url,false,$context,-1, 4000000); // We download at most 4 Mb from source.
        if (!$data) { return array('HTTP Error',array(),''); }
        $httpStatus=$http_response_header[0]; // eg. "HTTP/1.1 200 OK"
        $responseHeaders=http_parse_headers_shaarli($http_response_header);
        return array($httpStatus,$responseHeaders,$data);
    }
    catch (Exception $e)  // getHTTP *can* fail silentely (we don't care if the title cannot be fetched)
    {
        return array($e->getMessage(),'','');
    }
}

// Extract title from an HTML document.
// (Returns an empty string if not found.)
function html_extract_title($html)
{
  return preg_match('!(.*?)!is', $html, $matches) ? trim(str_replace("\n",' ', $matches[1])) : '' ;
}

// ------------------------------------------------------------------------------------------
// Token management for XSRF protection
// Token should be used in any form which acts on data (create,update,delete,import...).
if (!isset($_SESSION['tokens'])) $_SESSION['tokens']=array();  // Token are attached to the session.

// Returns a token.
function getToken()
{
    $rnd = sha1(uniqid('',true).'_'.mt_rand().$GLOBALS['salt']);  // We generate a random string.
    $_SESSION['tokens'][$rnd]=1;  // Store it on the server side.
    return $rnd;
}

// Tells if a token is ok. Using this function will destroy the token.
// true=token is ok.
function tokenOk($token)
{
    if (isset($_SESSION['tokens'][$token]))
    {
        unset($_SESSION['tokens'][$token]); // Token is used: destroy it.
        return true; // Token is ok.
    }
    return false; // Wrong token, or already used.
}

// ------------------------------------------------------------------------------------------
/* This class is in charge of building the final page.
   (This is basically a wrapper around RainTPL which pre-fills some fields.)
   p = new pageBuilder;
   p.assign('myfield','myvalue');
   p.renderPage('mytemplate');

*/
class pageBuilder
{
    private $tpl; // RainTPL template

    function __construct()
    {
        $this->tpl=false;
    }

    private function initialize()
    {
        $this->tpl = new RainTPL;
        $this->tpl->assign('newversion',checkUpdate());
        $this->tpl->assign('feedurl',htmlspecialchars(indexUrl()));
        $searchcrits=''; // Search criteria
        if (!empty($_GET['searchtags'])) $searchcrits.='&searchtags='.urlencode($_GET['searchtags']);
        elseif (!empty($_GET['searchterm'])) $searchcrits.='&searchterm='.urlencode($_GET['searchterm']);
        $this->tpl->assign('searchcrits',$searchcrits);
        $this->tpl->assign('source',indexUrl());
        $this->tpl->assign('version',shaarli_version);
        $this->tpl->assign('scripturl',indexUrl());
        $this->tpl->assign('pagetitle','Shaarli');
        $this->tpl->assign('privateonly',!empty($_SESSION['privateonly'])); // Show only private links ?
        if (!empty($GLOBALS['title'])) $this->tpl->assign('pagetitle',$GLOBALS['title']);
        if (!empty($GLOBALS['pagetitle'])) $this->tpl->assign('pagetitle',$GLOBALS['pagetitle']);
        $this->tpl->assign('shaarlititle',empty($GLOBALS['title']) ? 'Shaarli': $GLOBALS['title'] );
        return;
    }

    // The following assign() method is basically the same as RainTPL (except that it's lazy)
    public function assign($what,$where)
    {
        if ($this->tpl===false) $this->initialize(); // Lazy initialization
        $this->tpl->assign($what,$where);
    }

    // Render a specific page (using a template).
    // eg. pb.renderPage('picwall')
    public function renderPage($page)
    {
        if ($this->tpl===false) $this->initialize(); // Lazy initialization
        $this->tpl->draw($page);
    }
}

// ------------------------------------------------------------------------------------------
/* Data storage for links.
   This object behaves like an associative array.
   Example:
      $mylinks = new linkdb();
      echo $mylinks['20110826_161819']['title'];
      foreach($mylinks as $link)
         echo $link['title'].' at url '.$link['url'].' ; description:'.$link['description'];

   Available keys:
       title : Title of the link
       url : URL of the link. Can be absolute or relative. Relative URLs are permalinks (eg.'?m-ukcw')
       description : description of the entry
       private : Is this link private ? 0=no, other value=yes
       linkdate : date of the creation of this entry, in the form YYYYMMDD_HHMMSS (eg.'20110914_192317')
       tags : tags attached to this entry (separated by spaces)

   We implement 3 interfaces:
     - ArrayAccess so that this object behaves like an associative array.
     - Iterator so that this object can be used in foreach() loops.
     - Countable interface so that we can do a count() on this object.
*/
class linkdb implements Iterator, Countable, ArrayAccess
{
    private $links; // List of links (associative array. Key=linkdate (eg. "20110823_124546"), value= associative array (keys:title,description...)
    private $urls;  // List of all recorded URLs (key=url, value=linkdate) for fast reserve search (url-->linkdate)
    private $keys;  // List of linkdate keys (for the Iterator interface implementation)
    private $position; // Position in the $this->keys array. (for the Iterator interface implementation.)
    private $loggedin; // Is the used logged in ? (used to filter private links)

    // Constructor:
    function __construct($isLoggedIn)
    // Input : $isLoggedIn : is the used logged in ?
    {
        $this->loggedin = $isLoggedIn;
        $this->checkdb(); // Make sure data file exists.
        $this->readdb();  // Then read it.
    }

    // ---- Countable interface implementation
    public function count() { return count($this->links); }

    // ---- ArrayAccess interface implementation
    public function offsetSet($offset, $value)
    {
        if (!$this->loggedin) die('You are not authorized to add a link.');
        if (empty($value['linkdate']) || empty($value['url'])) die('Internal Error: A link should always have a linkdate and url.');
        if (empty($offset)) die('You must specify a key.');
        $this->links[$offset] = $value;
        $this->urls[$value['url']]=$offset;
    }
    public function offsetExists($offset) { return array_key_exists($offset,$this->links); }
    public function offsetUnset($offset)
    {
        if (!$this->loggedin) die('You are not authorized to delete a link.');
        $url = $this->links[$offset]['url']; unset($this->urls[$url]);
        unset($this->links[$offset]);
    }
    public function offsetGet($offset) { return isset($this->links[$offset]) ? $this->links[$offset] : null; }

    // ---- Iterator interface implementation
    function rewind() { $this->keys=array_keys($this->links); rsort($this->keys); $this->position=0; } // Start over for iteration, ordered by date (latest first).
    function key() { return $this->keys[$this->position]; } // current key
    function current() { return $this->links[$this->keys[$this->position]]; } // current value
    function next() { ++$this->position; } // go to next item
    function valid() { return isset($this->keys[$this->position]); }    // Check if current position is valid.

    // ---- Misc methods
    private function checkdb() // Check if db directory and file exists.
    {
        if (!file_exists($GLOBALS['config']['DATASTORE'])) // Create a dummy database for example.
        {
             $this->links = array();
             $link = array('title'=>'Shaarli - sebsauvage.net','url'=>'http://sebsauvage.net/wiki/doku.php?id=php:shaarli','description'=>'Welcome to Shaarli ! This is a bookmark. To edit or delete me, you must first login.','private'=>0,'linkdate'=>'20110914_190000','tags'=>'opensource software');
             $this->links[$link['linkdate']] = $link;
             $link = array('title'=>'My secret stuff... - Pastebin.com','url'=>'http://sebsauvage.net/paste/?8434b27936c09649#bR7XsXhoTiLcqCpQbmOpBi3rq2zzQUC5hBI7ZT1O3x8=','description'=>'SShhhh!!  I\'m a private link only YOU can see. You can delete me too.','private'=>1,'linkdate'=>'20110914_074522','tags'=>'secretstuff');
             $this->links[$link['linkdate']] = $link;
             file_put_contents($GLOBALS['config']['DATASTORE'], PHPPREFIX.base64_encode(gzdeflate(serialize($this->links))).PHPSUFFIX); // Write database to disk
        }
    }

    // Read database from disk to memory
    private function readdb()
    {
        // Read data
        $this->links=(file_exists($GLOBALS['config']['DATASTORE']) ? unserialize(gzinflate(base64_decode(substr(file_get_contents($GLOBALS['config']['DATASTORE']),strlen(PHPPREFIX),-strlen(PHPSUFFIX))))) : array() );
        // Note that gzinflate is faster than gzuncompress. See: http://www.php.net/manual/en/function.gzdeflate.php#96439

        // If user is not logged in, filter private links.
        if (!$this->loggedin)
        {
            $toremove=array();
            foreach($this->links as $link) { if ($link['private']!=0) $toremove[]=$link['linkdate']; }
            foreach($toremove as $linkdate) { unset($this->links[$linkdate]); }
        }

        // Keep the list of the mapping URLs-->linkdate up-to-date.
        $this->urls=array();
        foreach($this->links as $link) { $this->urls[$link['url']]=$link['linkdate']; }
    }

    // Save database from memory to disk.
    public function savedb()
    {
        if (!$this->loggedin) die('You are not authorized to change the database.');
        file_put_contents($GLOBALS['config']['DATASTORE'], PHPPREFIX.base64_encode(gzdeflate(serialize($this->links))).PHPSUFFIX);
        invalidateCaches();
    }

    // Returns the link for a given URL (if it exists). false it does not exist.
    public function getLinkFromUrl($url)
    {
        if (isset($this->urls[$url])) return $this->links[$this->urls[$url]];
        return false;
    }

    // Case insentitive search among links (in url, title and description). Returns filtered list of links.
    // eg. print_r($mydb->filterFulltext('hollandais'));
    public function filterFulltext($searchterms)
    {
        // FIXME: explode(' ',$searchterms) and perform a AND search.
        // FIXME: accept double-quotes to search for a string "as is" ?
        $filtered=array();
        $s = strtolower($searchterms);
        foreach($this->links as $l)
        {
            $found=   (strpos(strtolower($l['title']),$s)!==false)
                   || (strpos(strtolower($l['description']),$s)!==false)
                   || (strpos(strtolower($l['url']),$s)!==false)
                   || (strpos(strtolower($l['tags']),$s)!==false);
            if ($found) $filtered[$l['linkdate']] = $l;
        }
        krsort($filtered);
        return $filtered;
    }

    // Filter by tag.
    // You can specify one or more tags (tags can be separated by space or comma).
    // eg. print_r($mydb->filterTags('linux programming'));
    public function filterTags($tags,$casesensitive=false)
    {
        $t = str_replace(',',' ',($casesensitive?$tags:strtolower($tags)));
        $searchtags=explode(' ',$t);
        $filtered=array();
        foreach($this->links as $l)
        {
            $linktags = explode(' ',($casesensitive?$l['tags']:strtolower($l['tags'])));
            if (count(array_intersect($linktags,$searchtags)) == count($searchtags))
                $filtered[$l['linkdate']] = $l;
        }
        krsort($filtered);
        return $filtered;
    }

    // Filter by day. Day must be in the form 'YYYYMMDD' (eg. '20120125')
    // Sort order is: older articles first.
    // eg. print_r($mydb->filterDay('20120125'));
    public function filterDay($day)
    {
        $filtered=array();
        foreach($this->links as $l)
        {
            if (startsWith($l['linkdate'],$day)) $filtered[$l['linkdate']] = $l;
        }
        ksort($filtered);
        return $filtered;
    }
    // Filter by smallHash.
    // Only 1 article is returned.
    public function filterSmallHash($smallHash)
    {
        $filtered=array();
        foreach($this->links as $l)
        {
            if ($smallHash==smallHash($l['linkdate'])) // Yes, this is ugly and slow
            {
                $filtered[$l['linkdate']] = $l;
                return $filtered;
            }
        }
        return $filtered;
    }

    // Returns the list of all tags
    // Output: associative array key=tags, value=0
    public function allTags()
    {
        $tags=array();
        foreach($this->links as $link)
            foreach(explode(' ',$link['tags']) as $tag)
                if (!empty($tag)) $tags[$tag]=(empty($tags[$tag]) ? 1 : $tags[$tag]+1);
        arsort($tags); // Sort tags by usage (most used tag first)
        return $tags;
    }

    // Returns the list of days containing articles (oldest first)
    // Output: An array containing days (in format YYYYMMDD).
    public function days()
    {
        $linkdays=array();
        foreach(array_keys($this->links) as $day)
        {
            $linkdays[substr($day,0,8)]=0;
        }
        $linkdays=array_keys($linkdays);
        sort($linkdays);
        return $linkdays;
    }
}

// ------------------------------------------------------------------------------------------
// Ouput the last N links in RSS 2.0 format.
function showRSS()
{
    header('Content-Type: application/rss+xml; charset=utf-8');

    // $usepermalink : If true, use permalink instead of final link.
    // User just has to add 'permalink' in URL parameters. eg. http://mysite.com/shaarli/?do=rss&permalinks
    $usepermalinks = isset($_GET['permalinks']);

    // Cache system
    $query = $_SERVER["QUERY_STRING"];
    $cache = new pageCache(pageUrl(),startsWith($query,'do=rss') && !isLoggedIn());
    $cached = $cache->cachedVersion(); if (!empty($cached)) { echo $cached; exit; }

    // If cached was not found (or not usable), then read the database and build the response:
    $LINKSDB=new linkdb(isLoggedIn() || $GLOBALS['config']['OPEN_SHAARLI']);  // Read links from database (and filter private links if used it not logged in).

    // Optionnaly filter the results:
    $linksToDisplay=array();
    if (!empty($_GET['searchterm'])) $linksToDisplay = $LINKSDB->filterFulltext($_GET['searchterm']);
    elseif (!empty($_GET['searchtags']))   $linksToDisplay = $LINKSDB->filterTags(trim($_GET['searchtags']));
    else $linksToDisplay = $LINKSDB;
    $nblinksToDisplay = 50;  // Number of links to display.
    if (!empty($_GET['nb']))  // In URL, you can specificy the number of links. Example: nb=200 or nb=all for all links.
    { 
        $nblinksToDisplay = $_GET['nb']=='all' ? count($linksToDisplay) : max($_GET['nb']+0,1) ;
    }

    $pageaddr=htmlspecialchars(indexUrl());
    echo '';
    echo ''.htmlspecialchars($GLOBALS['title']).''.$pageaddr.'';
    echo 'Shared linksen-en'.$pageaddr.''."\n\n";
    if (!empty($GLOBALS['config']['PUBSUBHUB_URL']))
    {
        echo '';
        echo '';
        echo '';
        echo '';
    }
    $i=0;
    $keys=array(); foreach($linksToDisplay as $key=>$value) { $keys[]=$key; }  // No, I can't use array_keys().
    while ($i<$nblinksToDisplay && $i'.htmlspecialchars($link['title']).''.$guid.''.$guid.'';
        else
            echo ''.htmlspecialchars($link['title']).''.$guid.''.$absurl.'';
        if (!$GLOBALS['config']['HIDE_TIMESTAMPS'] || isLoggedIn()) echo ''.htmlspecialchars($rfc822date)."\n";
        if ($link['tags']!='') // Adding tags to each RSS entry (as mentioned in RSS specification)
        {
            foreach(explode(' ',$link['tags']) as $tag) { echo ''.htmlspecialchars($tag).''."\n"; }
        }

        // Add permalink in description
        $descriptionlink = '(Permalink)';
        // If user wants permalinks first, put the final link in description
        if ($usepermalinks===true) $descriptionlink = '(Link)';
        if (strlen($link['description'])>0) $descriptionlink = '
'.$descriptionlink; echo ''."\n
\n"; $i++; } echo '
'; $cache->cache(ob_get_contents()); ob_end_flush(); exit; } // ------------------------------------------------------------------------------------------ // Ouput the last N links in ATOM format. function showATOM() { header('Content-Type: application/atom+xml; charset=utf-8'); // $usepermalink : If true, use permalink instead of final link. // User just has to add 'permalink' in URL parameters. eg. http://mysite.com/shaarli/?do=atom&permalinks $usepermalinks = isset($_GET['permalinks']); // Cache system $query = $_SERVER["QUERY_STRING"]; $cache = new pageCache(pageUrl(),startsWith($query,'do=atom') && !isLoggedIn()); $cached = $cache->cachedVersion(); if (!empty($cached)) { echo $cached; exit; } // If cached was not found (or not usable), then read the database and build the response: $LINKSDB=new linkdb(isLoggedIn() || $GLOBALS['config']['OPEN_SHAARLI']); // Read links from database (and filter private links if used it not logged in). // Optionnaly filter the results: $linksToDisplay=array(); if (!empty($_GET['searchterm'])) $linksToDisplay = $LINKSDB->filterFulltext($_GET['searchterm']); elseif (!empty($_GET['searchtags'])) $linksToDisplay = $LINKSDB->filterTags(trim($_GET['searchtags'])); else $linksToDisplay = $LINKSDB; $nblinksToDisplay = 50; // Number of links to display. if (!empty($_GET['nb'])) // In URL, you can specificy the number of links. Example: nb=200 or nb=all for all links. { $nblinksToDisplay = $_GET['nb']=='all' ? count($linksToDisplay) : max($_GET['nb']+0,1) ; } $pageaddr=htmlspecialchars(indexUrl()); $latestDate = ''; $entries=''; $i=0; $keys=array(); foreach($linksToDisplay as $key=>$value) { $keys[]=$key; } // No, I can't use array_keys(). while ($i<$nblinksToDisplay && $i'; if ($usepermalinks===true) $entries.=''.$guid.''; else $entries.=''.$guid.''; if (!$GLOBALS['config']['HIDE_TIMESTAMPS'] || isLoggedIn()) $entries.=''.htmlspecialchars($iso8601date).''; // Add permalink in description $descriptionlink = htmlspecialchars('(Permalink)'); // If user wants permalinks first, put the final link in description if ($usepermalinks===true) $descriptionlink = htmlspecialchars('(Link)'); if (strlen($link['description'])>0) $descriptionlink = '<br>'.$descriptionlink; $entries.=''.htmlspecialchars(nl2br(keepMultipleSpaces(text2clickable(htmlspecialchars($link['description']))))).$descriptionlink."\n"; if ($link['tags']!='') // Adding tags to each ATOM entry (as mentioned in ATOM specification) { foreach(explode(' ',$link['tags']) as $tag) { $entries.=''."\n"; } } $entries.="\n"; $i++; } $feed=''; $feed.=''.htmlspecialchars($GLOBALS['title']).''; if (!$GLOBALS['config']['HIDE_TIMESTAMPS'] || isLoggedIn()) $feed.=''.htmlspecialchars($latestDate).''; $feed.=''; if (!empty($GLOBALS['config']['PUBSUBHUB_URL'])) { $feed.=''; $feed.=''; $feed.=''; } $feed.=''.htmlspecialchars($pageaddr).''.htmlspecialchars($pageaddr).''; $feed.=''.htmlspecialchars($pageaddr).''."\n\n"; // Yes, I know I should use a real IRI (RFC3987), but the site URL will do. $feed.=$entries; $feed.=''; echo $feed; $cache->cache(ob_get_contents()); ob_end_flush(); exit; } // ------------------------------------------------------------------------------------------ // Daily RSS feed: 1 RSS entry per day giving all the links on that day. // Gives the last 7 days (which have links). // This RSS feed cannot be filtered. function showDailyRSS() { // Cache system $query = $_SERVER["QUERY_STRING"]; $cache = new pageCache(pageUrl(),startsWith($query,'do=dailyrss') && !isLoggedIn()); $cached = $cache->cachedVersion(); if (!empty($cached)) { echo $cached; exit; } // If cached was not found (or not usable), then read the database and build the response: $LINKSDB=new linkdb(isLoggedIn() || $GLOBALS['config']['OPEN_SHAARLI']); // Read links from database (and filter private links if used it not logged in). /* Some Shaarlies may have very few links, so we need to look back in time (rsort()) until we have enough days ($nb_of_days). */ $linkdates=array(); foreach($LINKSDB as $linkdate=>$value) { $linkdates[]=$linkdate; } rsort($linkdates); $nb_of_days=7; // We take 7 days. $today=Date('Ymd'); $days=array(); foreach($linkdates as $linkdate) { $day=substr($linkdate,0,8); // Extract day (without time) if (strcmp($day,$today)<0) { if (empty($days[$day])) $days[$day]=array(); $days[$day][]=$linkdate; } if (count($days)>$nb_of_days) break; // Have we collected enough days ? } // Build the RSS feed. header('Content-Type: application/rss+xml; charset=utf-8'); $pageaddr=htmlspecialchars(indexUrl()); echo ''; echo 'Daily - '.htmlspecialchars($GLOBALS['title']).''.$pageaddr.''; echo 'Daily shared linksen-en'.$pageaddr.''."\n"; foreach($days as $day=>$linkdates) // For each day. { $daydate = utf8_encode(strftime('%A %d, %B %Y',linkdate2timestamp($day.'_000000'))); // Full text date $rfc822date = linkdate2rfc822($day.'_000000'); $absurl=htmlspecialchars(indexUrl().'?do=daily&day='.$day); // Absolute URL of the corresponding "Daily" page. echo ''.htmlspecialchars($GLOBALS['title'].' - '.$daydate).''.$absurl.''.$absurl.''; echo ''.htmlspecialchars($rfc822date).""; // Build the HTML body of this RSS entry. $html=''; $href=''; $links=array(); // We pre-format some fields for proper output. foreach($linkdates as $linkdate) { $l = $LINKSDB[$linkdate]; $l['formatedDescription']=nl2br(keepMultipleSpaces(text2clickable(htmlspecialchars($l['description'])))); $l['thumbnail'] = thumbnail($l['url']); $l['localdate']=linkdate2locale($l['linkdate']); if (startsWith($l['url'],'?')) $l['url']=indexUrl().$l['url']; // make permalink URL absolute $links[$linkdate]=$l; } // Then build the HTML for this day: $tpl = new RainTPL; $tpl->assign('links',$links); $html = $tpl->draw('dailyrss',$return_string=true); echo "\n"; echo ''."\n\n\n"; } echo ''; $cache->cache(ob_get_contents()); ob_end_flush(); exit; } // "Daily" page. function showDaily() { $LINKSDB=new linkdb(isLoggedIn() || $GLOBALS['config']['OPEN_SHAARLI']); // Read links from database (and filter private links if used it not logged in). $day=Date('Ymd',strtotime('-1 day')); // Yesterday, in format YYYYMMDD. if (isset($_GET['day'])) $day=$_GET['day']; $days = $LINKSDB->days(); $i = array_search($day,$days); if ($i==false) { $i=count($days)-1; $day=$days[$i]; } $previousday=''; $nextday=''; if ($i!==false) { if ($i>1) $previousday=$days[$i-1]; if ($ifilterDay($day); // We pre-format some fields for proper output. foreach($linksToDisplay as $key=>$link) { $taglist = explode(' ',$link['tags']); uasort($taglist, 'strcasecmp'); $linksToDisplay[$key]['taglist']=$taglist; $linksToDisplay[$key]['formatedDescription']=nl2br(keepMultipleSpaces(text2clickable(htmlspecialchars($link['description'])))); $linksToDisplay[$key]['thumbnail'] = thumbnail($link['url']); } /* We need to spread the articles on 3 columns. I did not want to use a javascript lib like http://masonry.desandro.com/ so I manually spread entries with a simple method: I roughly evaluate the height of a div according to title and description length. */ $columns=array(array(),array(),array()); // Entries to display, for each column. $fill=array(0,0,0); // Rough estimate of columns fill. foreach($linksToDisplay as $key=>$link) { // Roughly estimate length of entry (by counting characters) // Title: 30 chars = 1 line. 1 line is 30 pixels height. // Description: 836 characters gives roughly 342 pixel height. // This is not perfect, but it's usually ok. $length=strlen($link['title'])+(342*strlen($link['description']))/836; if ($link['thumbnail']) $length +=100; // 1 thumbnails roughly takes 100 pixels height. // Then put in column which is the less filled: $smallest=min($fill); // find smallest value in array. $index=array_search($smallest,$fill); // find index of this smallest value. array_push($columns[$index],$link); // Put entry in this column. $fill[$index]+=$length; } $PAGE = new pageBuilder; $PAGE->assign('linksToDisplay',$linksToDisplay); $PAGE->assign('linkcount',count($LINKSDB)); $PAGE->assign('col1',$columns[0]); $PAGE->assign('col1',$columns[0]); $PAGE->assign('col2',$columns[1]); $PAGE->assign('col3',$columns[2]); $PAGE->assign('day',utf8_encode(strftime('%A %d, %B %Y',linkdate2timestamp($day.'_000000')))); $PAGE->assign('previousday',$previousday); $PAGE->assign('nextday',$nextday); $PAGE->renderPage('daily'); exit; } // ------------------------------------------------------------------------------------------ // Render HTML page (according to URL parameters and user rights) function renderPage() { $LINKSDB=new linkdb(isLoggedIn() || $GLOBALS['config']['OPEN_SHAARLI']); // Read links from database (and filter private links if used it not logged in). // -------- Display login form. if (isset($_SERVER["QUERY_STRING"]) && startswith($_SERVER["QUERY_STRING"],'do=login')) { if ($GLOBALS['config']['OPEN_SHAARLI']) { header('Location: ?'); exit; } // No need to login for open Shaarli $token=''; if (ban_canLogin()) $token=getToken(); // Do not waste token generation if not useful. $PAGE = new pageBuilder; $PAGE->assign('token',$token); $PAGE->assign('returnurl',(isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER']:'')); $PAGE->renderPage('loginform'); exit; } // -------- User wants to logout. if (isset($_SERVER["QUERY_STRING"]) && startswith($_SERVER["QUERY_STRING"],'do=logout')) { invalidateCaches(); logout(); header('Location: ?'); exit; } // -------- Picture wall if (isset($_SERVER["QUERY_STRING"]) && startswith($_SERVER["QUERY_STRING"],'do=picwall')) { // Optionnaly filter the results: $links=array(); if (!empty($_GET['searchterm'])) $links = $LINKSDB->filterFulltext($_GET['searchterm']); elseif (!empty($_GET['searchtags'])) $links = $LINKSDB->filterTags(trim($_GET['searchtags'])); else $links = $LINKSDB; $body=''; $linksToDisplay=array(); // Get only links which have a thumbnail. foreach($links as $link) { $permalink='?'.htmlspecialchars(smallhash($link['linkdate']),ENT_QUOTES); $thumb=lazyThumbnail($link['url'],$permalink); if ($thumb!='') // Only output links which have a thumbnail. { $link['thumbnail']=$thumb; // Thumbnail HTML code. $link['permalink']=$permalink; $linksToDisplay[]=$link; // Add to array. } } $PAGE = new pageBuilder; $PAGE->assign('linkcount',count($LINKSDB)); $PAGE->assign('linksToDisplay',$linksToDisplay); $PAGE->renderPage('picwall'); exit; } // -------- Tag cloud if (isset($_SERVER["QUERY_STRING"]) && startswith($_SERVER["QUERY_STRING"],'do=tagcloud')) { $tags= $LINKSDB->allTags(); // We sort tags alphabetically, then choose a font size according to count. // First, find max value. $maxcount=0; foreach($tags as $key=>$value) $maxcount=max($maxcount,$value); ksort($tags); $tagList=array(); foreach($tags as $key=>$value) { $tagList[$key] = array('count'=>$value,'size'=>max(40*$value/$maxcount,8)); } $PAGE = new pageBuilder; $PAGE->assign('linkcount',count($LINKSDB)); $PAGE->assign('tags',$tagList); $PAGE->renderPage('tagcloud'); exit; } // -------- User clicks on a tag in a link: The tag is added to the list of searched tags (searchtags=...) if (isset($_GET['addtag'])) { // Get previous URL (http_referer) and add the tag to the searchtags parameters in query. if (empty($_SERVER['HTTP_REFERER'])) { header('Location: ?searchtags='.urlencode($_GET['addtag'])); exit; } // In case browser does not send HTTP_REFERER parse_str(parse_url($_SERVER['HTTP_REFERER'],PHP_URL_QUERY), $params); $params['searchtags'] = (empty($params['searchtags']) ? trim($_GET['addtag']) : trim($params['searchtags']).' '.trim($_GET['addtag'])); unset($params['page']); // We also remove page (keeping the same page has no sense, since the results are different) header('Location: ?'.http_build_query($params)); exit; } // -------- User clicks on a tag in result count: Remove the tag from the list of searched tags (searchtags=...) if (isset($_GET['removetag'])) { // Get previous URL (http_referer) and remove the tag from the searchtags parameters in query. if (empty($_SERVER['HTTP_REFERER'])) { header('Location: ?'); exit; } // In case browser does not send HTTP_REFERER parse_str(parse_url($_SERVER['HTTP_REFERER'],PHP_URL_QUERY), $params); if (isset($params['searchtags'])) { $tags = explode(' ',$params['searchtags']); $tags=array_diff($tags, array($_GET['removetag'])); // Remove value from array $tags. if (count($tags)==0) unset($params['searchtags']); else $params['searchtags'] = implode(' ',$tags); unset($params['page']); // We also remove page (keeping the same page has no sense, since the results are different) } header('Location: ?'.http_build_query($params)); exit; } // -------- User wants to change the number of links per page (linksperpage=...) if (isset($_GET['linksperpage'])) { if (is_numeric($_GET['linksperpage'])) { $_SESSION['LINKS_PER_PAGE']=abs(intval($_GET['linksperpage'])); } // Make sure the referer is from Shaarli itself. $referer = '?'; if (!empty($_SERVER['HTTP_REFERER']) && strcmp(parse_url($_SERVER['HTTP_REFERER'],PHP_URL_HOST),$_SERVER['HTTP_HOST'])==0) $referer = $_SERVER['HTTP_REFERER']; header('Location: '.$referer); exit; } // -------- User wants to see only private links (toggle) if (isset($_GET['privateonly'])) { if (empty($_SESSION['privateonly'])) { $_SESSION['privateonly']=1; // See only private links } else { unset($_SESSION['privateonly']); // See all links } // Make sure the referer is from Shaarli itself. $referer = '?'; if (!empty($_SERVER['HTTP_REFERER']) && strcmp(parse_url($_SERVER['HTTP_REFERER'],PHP_URL_HOST),$_SERVER['HTTP_HOST'])==0) $referer = $_SERVER['HTTP_REFERER']; header('Location: '.$referer); exit; } // -------- Handle other actions allowed for non-logged in users: if (!isLoggedIn()) { // User tries to post new link but is not loggedin: // Show login screen, then redirect to ?post=... if (isset($_GET['post'])) { header('Location: ?do=login&post='.urlencode($_GET['post']).(!empty($_GET['title'])?'&title='.urlencode($_GET['title']):'').(!empty($_GET['source'])?'&source='.urlencode($_GET['source']):'')); // Redirect to login page, then back to post link. exit; } $PAGE = new pageBuilder; buildLinkList($PAGE,$LINKSDB); // Compute list of links to display $PAGE->renderPage('linklist'); exit; // Never remove this one ! All operations below are reserved for logged in user. } // -------- All other functions are reserved for the registered user: // -------- Display the Tools menu if requested (import/export/bookmarklet...) if (isset($_SERVER["QUERY_STRING"]) && startswith($_SERVER["QUERY_STRING"],'do=tools')) { $PAGE = new pageBuilder; $PAGE->assign('linkcount',count($LINKSDB)); $PAGE->assign('pageabsaddr',indexUrl()); $PAGE->renderPage('tools'); exit; } // -------- User wants to change his/her password. if (isset($_SERVER["QUERY_STRING"]) && startswith($_SERVER["QUERY_STRING"],'do=changepasswd')) { if ($GLOBALS['config']['OPEN_SHAARLI']) die('You are not supposed to change a password on an Open Shaarli.'); if (!empty($_POST['setpassword']) && !empty($_POST['oldpassword'])) { if (!tokenOk($_POST['token'])) die('Wrong token.'); // Go away ! // Make sure old password is correct. $oldhash = sha1($_POST['oldpassword'].$GLOBALS['login'].$GLOBALS['salt']); if ($oldhash!=$GLOBALS['hash']) { echo ''; exit; } // Save new password $GLOBALS['salt'] = sha1(uniqid('',true).'_'.mt_rand()); // Salt renders rainbow-tables attacks useless. $GLOBALS['hash'] = sha1($_POST['setpassword'].$GLOBALS['login'].$GLOBALS['salt']); writeConfig(); echo ''; exit; } else // show the change password form. { $PAGE = new pageBuilder; $PAGE->assign('linkcount',count($LINKSDB)); $PAGE->assign('token',getToken()); $PAGE->renderPage('changepassword'); exit; } } // -------- User wants to change configuration if (isset($_SERVER["QUERY_STRING"]) && startswith($_SERVER["QUERY_STRING"],'do=configure')) { if (!empty($_POST['title']) ) { if (!tokenOk($_POST['token'])) die('Wrong token.'); // Go away ! $tz = 'UTC'; if (!empty($_POST['continent']) && !empty($_POST['city'])) if (isTZvalid($_POST['continent'],$_POST['city'])) $tz = $_POST['continent'].'/'.$_POST['city']; $GLOBALS['timezone'] = $tz; $GLOBALS['title']=$_POST['title']; $GLOBALS['redirector']=$_POST['redirector']; $GLOBALS['disablesessionprotection']=!empty($_POST['disablesessionprotection']); $GLOBALS['disablejquery']=!empty($_POST['disablejquery']); $GLOBALS['privateLinkByDefault']=!empty($_POST['privateLinkByDefault']); writeConfig(); echo ''; exit; } else // Show the configuration form. { $PAGE = new pageBuilder; $PAGE->assign('linkcount',count($LINKSDB)); $PAGE->assign('token',getToken()); $PAGE->assign('title',htmlspecialchars( empty($GLOBALS['title']) ? '' : $GLOBALS['title'] , ENT_QUOTES)); $PAGE->assign('redirector',htmlspecialchars( empty($GLOBALS['redirector']) ? '' : $GLOBALS['redirector'] , ENT_QUOTES)); list($timezone_form,$timezone_js) = templateTZform($GLOBALS['timezone']); $PAGE->assign('timezone_form',$timezone_form); // FIXME: put entire tz form generation in template ? $PAGE->assign('timezone_js',$timezone_js); $PAGE->renderPage('configure'); exit; } } // -------- User wants to rename a tag or delete it if (isset($_SERVER["QUERY_STRING"]) && startswith($_SERVER["QUERY_STRING"],'do=changetag')) { if (empty($_POST['fromtag'])) { $PAGE = new pageBuilder; $PAGE->assign('linkcount',count($LINKSDB)); $PAGE->assign('token',getToken()); $PAGE->renderPage('changetag'); exit; } if (!tokenOk($_POST['token'])) die('Wrong token.'); // Delete a tag: if (!empty($_POST['deletetag']) && !empty($_POST['fromtag'])) { $needle=trim($_POST['fromtag']); $linksToAlter = $LINKSDB->filterTags($needle,true); // true for case-sensitive tag search. foreach($linksToAlter as $key=>$value) { $tags = explode(' ',trim($value['tags'])); unset($tags[array_search($needle,$tags)]); // Remove tag. $value['tags']=trim(implode(' ',$tags)); $LINKSDB[$key]=$value; } $LINKSDB->savedb(); // save to disk echo ''; exit; } // Rename a tag: if (!empty($_POST['renametag']) && !empty($_POST['fromtag']) && !empty($_POST['totag'])) { $needle=trim($_POST['fromtag']); $linksToAlter = $LINKSDB->filterTags($needle,true); // true for case-sensitive tag search. foreach($linksToAlter as $key=>$value) { $tags = explode(' ',trim($value['tags'])); $tags[array_search($needle,$tags)] = trim($_POST['totag']); // Remplace tags value. $value['tags']=trim(implode(' ',$tags)); $LINKSDB[$key]=$value; } $LINKSDB->savedb(); // save to disk echo ''; exit; } } // -------- User wants to add a link without using the bookmarklet: show form. if (isset($_SERVER["QUERY_STRING"]) && startswith($_SERVER["QUERY_STRING"],'do=addlink')) { $PAGE = new pageBuilder; $PAGE->assign('linkcount',count($LINKSDB)); $PAGE->renderPage('addlink'); exit; } // -------- User clicked the "Save" button when editing a link: Save link to database. if (isset($_POST['save_edit'])) { if (!tokenOk($_POST['token'])) die('Wrong token.'); // Go away ! $tags = trim(preg_replace('/\s\s+/',' ', $_POST['lf_tags'])); // Remove multiple spaces. $linkdate=$_POST['lf_linkdate']; $url = trim($_POST['lf_url']); if (!startsWith($url,'http:') && !startsWith($url,'https:') && !startsWith($url,'ftp:') && !startsWith($url,'magnet:') && !startsWith($url,'?')) $url = 'http://'.$url; $link = array('title'=>trim($_POST['lf_title']),'url'=>$url,'description'=>trim($_POST['lf_description']),'private'=>(isset($_POST['lf_private']) ? 1 : 0), 'linkdate'=>$linkdate,'tags'=>str_replace(',',' ',$tags)); if ($link['title']=='') $link['title']=$link['url']; // If title is empty, use the URL as title. $LINKSDB[$linkdate] = $link; $LINKSDB->savedb(); // save to disk pubsubhub(); // If we are called from the bookmarklet, we must close the popup: if (isset($_GET['source']) && $_GET['source']=='bookmarklet') { echo ''; exit; } $returnurl = ( isset($_POST['returnurl']) ? $_POST['returnurl'] : '?' ); $returnurl .= '#'.smallHash($linkdate); // Scroll to the link which has been edited. header('Location: '.$returnurl); // After saving the link, redirect to the page the user was on. exit; } // -------- User clicked the "Cancel" button when editing a link. if (isset($_POST['cancel_edit'])) { // If we are called from the bookmarklet, we must close the popup; if (isset($_GET['source']) && $_GET['source']=='bookmarklet') { echo ''; exit; } $returnurl = ( isset($_POST['returnurl']) ? $_POST['returnurl'] : '?' ); $returnurl .= '#'.smallHash($_POST['lf_linkdate']); // Scroll to the link which has been edited. header('Location: '.$returnurl); // After canceling, redirect to the page the user was on. exit; } // -------- User clicked the "Delete" button when editing a link : Delete link from database. if (isset($_POST['delete_link'])) { if (!tokenOk($_POST['token'])) die('Wrong token.'); // We do not need to ask for confirmation: // - confirmation is handled by javascript // - we are protected from XSRF by the token. $linkdate=$_POST['lf_linkdate']; unset($LINKSDB[$linkdate]); $LINKSDB->savedb(); // save to disk // If we are called from the bookmarklet, we must close the popup: if (isset($_GET['source']) && $_GET['source']=='bookmarklet') { echo ''; exit; } $returnurl = ( isset($_POST['returnurl']) ? $_POST['returnurl'] : '?' ); if ($returnurl=='?') { $returnurl = (isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : '?'); } header('Location: '.$returnurl); // After deleting the link, redirect to the page the user was on. exit; } // -------- User clicked the "EDIT" button on a link: Display link edit form. if (isset($_GET['edit_link'])) { $link = $LINKSDB[$_GET['edit_link']]; // Read database if (!$link) { header('Location: ?'); exit; } // Link not found in database. $PAGE = new pageBuilder; $PAGE->assign('linkcount',count($LINKSDB)); $PAGE->assign('link',$link); $PAGE->assign('link_is_new',false); $PAGE->assign('token',getToken()); // XSRF protection. $PAGE->assign('http_referer',(isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : '')); $PAGE->renderPage('editlink'); exit; } // -------- User want to post a new link: Display link edit form. if (isset($_GET['post'])) { $url=$_GET['post']; // We remove the annoying parameters added by FeedBurner and GoogleFeedProxy (?utm_source=...) $i=strpos($url,'&utm_source='); if ($i!==false) $url=substr($url,0,$i); $i=strpos($url,'?utm_source='); if ($i!==false) $url=substr($url,0,$i); $i=strpos($url,'#xtor=RSS-'); if ($i!==false) $url=substr($url,0,$i); $link_is_new = false; $link = $LINKSDB->getLinkFromUrl($url); // Check if URL is not already in database (in this case, we will edit the existing link) if (!$link) { $link_is_new = true; // This is a new link $linkdate = strval(date('Ymd_His')); $title = (empty($_GET['title']) ? '' : $_GET['title'] ); // Get title if it was provided in URL (by the bookmarklet). $description = (empty($_GET['description']) ? '' : $_GET['description']); // Get description if it was provided in URL (by the bookmarklet). [Bronco added that] $tags = (empty($_GET['tags']) ? '' : $_GET['tags'] ); // Get tags if it was provided in URL $private = (!empty($_GET['private']) && $_GET['private'] === "1" ? 1 : 0); // Get private if it was provided in URL if (($url!='') && parse_url($url,PHP_URL_SCHEME)=='') $url = 'http://'.$url; // If this is an HTTP link, we try go get the page to extact the title (otherwise we will to straight to the edit form.) if (empty($title) && parse_url($url,PHP_URL_SCHEME)=='http') { list($status,$headers,$data) = getHTTP($url,4); // Short timeout to keep the application responsive. // FIXME: Decode charset according to specified in either 1) HTTP response headers or 2) in html if (strpos($status,'200 OK')!==false) { // Look for charset in html header. preg_match('##Usi', $data, $meta); // If found, extract encoding. if (!empty($meta[0])) { // Get encoding specified in header. preg_match('#charset="?(.*)"#si', $meta[0], $enc); // If charset not found, use utf-8. $html_charset = (!empty($enc[1])) ? strtolower($enc[1]) : 'utf-8'; } else { $html_charset = 'utf-8'; } // Extract title $title = html_extract_title($data); if (!empty($title)) { // Re-encode title in utf-8 if necessary. $title = ($html_charset == 'iso-8859-1') ? utf8_encode($title) : $title; } } } if ($url=='') $url='?'.smallHash($linkdate); // In case of empty URL, this is just a text (with a link that point to itself) $link = array('linkdate'=>$linkdate,'title'=>$title,'url'=>$url,'description'=>$description,'tags'=>$tags,'private'=>$private); } $PAGE = new pageBuilder; $PAGE->assign('linkcount',count($LINKSDB)); $PAGE->assign('link',$link); $PAGE->assign('link_is_new',$link_is_new); $PAGE->assign('token',getToken()); // XSRF protection. $PAGE->assign('http_referer',(isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : '')); $PAGE->renderPage('editlink'); exit; } // -------- Export as Netscape Bookmarks HTML file. if (isset($_SERVER["QUERY_STRING"]) && startswith($_SERVER["QUERY_STRING"],'do=export')) { if (empty($_GET['what'])) { $PAGE = new pageBuilder; $PAGE->assign('linkcount',count($LINKSDB)); $PAGE->renderPage('export'); exit; } $exportWhat=$_GET['what']; if (!array_intersect(array('all','public','private'),array($exportWhat))) die('What are you trying to export ???'); header('Content-Type: text/html; charset=utf-8'); header('Content-disposition: attachment; filename=bookmarks_'.$exportWhat.'_'.strval(date('Ymd_His')).'.html'); $currentdate=date('Y/m/d H:i:s'); echo << Bookmarks

Bookmarks

HTML; foreach($LINKSDB as $link) { if ($exportWhat=='all' || ($exportWhat=='private' && $link['private']!=0) || ($exportWhat=='public' && $link['private']==0)) { echo '
'.htmlspecialchars($link['title'])."\n"; if ($link['description']!='') echo '
'.htmlspecialchars($link['description'])."\n"; } } exit; } // -------- User is uploading a file for import if (isset($_SERVER["QUERY_STRING"]) && startswith($_SERVER["QUERY_STRING"],'do=upload')) { // If file is too big, some form field may be missing. if (!isset($_POST['token']) || (!isset($_FILES)) || (isset($_FILES['filetoupload']['size']) && $_FILES['filetoupload']['size']==0)) { $returnurl = ( empty($_SERVER['HTTP_REFERER']) ? '?' : $_SERVER['HTTP_REFERER'] ); echo ''; exit; } if (!tokenOk($_POST['token'])) die('Wrong token.'); importFile(); exit; } // -------- Show upload/import dialog: if (isset($_SERVER["QUERY_STRING"]) && startswith($_SERVER["QUERY_STRING"],'do=import')) { $PAGE = new pageBuilder; $PAGE->assign('linkcount',count($LINKSDB)); $PAGE->assign('token',getToken()); $PAGE->assign('maxfilesize',getMaxFileSize()); $PAGE->renderPage('import'); exit; } // -------- Otherwise, simply display search form and links: $PAGE = new pageBuilder; $PAGE->assign('linkcount',count($LINKSDB)); buildLinkList($PAGE,$LINKSDB); // Compute list of links to display $PAGE->renderPage('linklist'); exit; } // ----------------------------------------------------------------------------------------------- // Process the import file form. function importFile() { if (!(isLoggedIn() || $GLOBALS['config']['OPEN_SHAARLI'])) { die('Not allowed.'); } $LINKSDB=new linkdb(isLoggedIn() || $GLOBALS['config']['OPEN_SHAARLI']); // Read links from database (and filter private links if used it not logged in). $filename=$_FILES['filetoupload']['name']; $filesize=$_FILES['filetoupload']['size']; $data=file_get_contents($_FILES['filetoupload']['tmp_name']); $private = (empty($_POST['private']) ? 0 : 1); // Should the links be imported as private ? $overwrite = !empty($_POST['overwrite']) ; // Should the imported links overwrite existing ones ? $import_count=0; // Sniff file type: $type='unknown'; if (startsWith($data,'')) $type='netscape'; // Netscape bookmark file (aka Firefox). // Then import the bookmarks. if ($type=='netscape') { // This is a standard Netscape-style bookmark file. // This format is supported by all browsers (except IE, of course), also delicious, diigo and others. foreach(explode('
',$data) as $html) // explode is very fast { $link = array('linkdate'=>'','title'=>'','url'=>'','description'=>'','tags'=>'','private'=>0); $d = explode('
',$html); if (startswith($d[0],'(.*?)!i',$d[0],$matches); $link['title'] = (isset($matches[1]) ? trim($matches[1]) : ''); // Get title $link['title'] = html_entity_decode($link['title'],ENT_QUOTES,'UTF-8'); preg_match_all('! ([A-Z_]+)=\"(.*?)"!i',$html,$matches,PREG_SET_ORDER); // Get all other attributes $raw_add_date=0; foreach($matches as $m) { $attr=$m[1]; $value=$m[2]; if ($attr=='HREF') $link['url']=html_entity_decode($value,ENT_QUOTES,'UTF-8'); elseif ($attr=='ADD_DATE') { $raw_add_date=intval($value); if ($raw_add_date>30000000000) $raw_add_date/=1000; //If larger than year 2920, then was likely stored in milliseconds instead of seconds } elseif ($attr=='PRIVATE') $link['private']=($value=='0'?0:1); elseif ($attr=='TAGS') $link['tags']=html_entity_decode(str_replace(',',' ',$value),ENT_QUOTES,'UTF-8'); } if ($link['url']!='') { if ($private==1) $link['private']=1; $dblink = $LINKSDB->getLinkFromUrl($link['url']); // See if the link is already in database. if ($dblink==false) { // Link not in database, let's import it... if (empty($raw_add_date)) $raw_add_date=time(); // In case of shitty bookmark file with no ADD_DATE // Make sure date/time is not already used by another link. // (Some bookmark files have several different links with the same ADD_DATE) // We increment date by 1 second until we find a date which is not used in db. // (so that links that have the same date/time are more or less kept grouped by date, but do not conflict.) while (!empty($LINKSDB[date('Ymd_His',$raw_add_date)])) { $raw_add_date++; }// Yes, I know it's ugly. $link['linkdate']=date('Ymd_His',$raw_add_date); $LINKSDB[$link['linkdate']] = $link; $import_count++; } else // link already present in database. { if ($overwrite) { // If overwrite is required, we import link data, except date/time. $link['linkdate']=$dblink['linkdate']; $LINKSDB[$link['linkdate']] = $link; $import_count++; } } } } } $LINKSDB->savedb(); echo ''; } else { echo ''; } } // ----------------------------------------------------------------------------------------------- // Template for the list of links (
'; die; } if (!isset($_SESSION['session_tested'])) { // Step 1 : Try to store data in session and reload page. $_SESSION['session_tested'] = 'Working'; // Try to set a variable in session. header('Location: '.indexUrl().'?test_session'); // Redirect to check stored data. } if (isset($_GET['test_session'])) { // Step 3: Sessions are ok. Remove test parameter from URL. header('Location: '.indexUrl()); } if (!empty($_POST['setlogin']) && !empty($_POST['setpassword'])) { $tz = 'UTC'; if (!empty($_POST['continent']) && !empty($_POST['city'])) if (isTZvalid($_POST['continent'],$_POST['city'])) $tz = $_POST['continent'].'/'.$_POST['city']; $GLOBALS['timezone'] = $tz; // Everything is ok, let's create config file. $GLOBALS['login'] = $_POST['setlogin']; $GLOBALS['salt'] = sha1(uniqid('',true).'_'.mt_rand()); // Salt renders rainbow-tables attacks useless. $GLOBALS['hash'] = sha1($_POST['setpassword'].$GLOBALS['login'].$GLOBALS['salt']); $GLOBALS['title'] = (empty($_POST['title']) ? 'Shared links on '.htmlspecialchars(indexUrl()) : $_POST['title'] ); writeConfig(); echo ''; exit; } // Display config form: list($timezone_form,$timezone_js) = templateTZform(); $timezone_html=''; if ($timezone_form!='') $timezone_html='Timezone:'.$timezone_form.''; $PAGE = new pageBuilder; $PAGE->assign('timezone_html',$timezone_html); $PAGE->assign('timezone_js',$timezone_js); $PAGE->renderPage('install'); exit; } // Generates the timezone selection form and javascript. // Input: (optional) current timezone (can be 'UTC/UTC'). It will be pre-selected. // Output: array(html,js) // Example: list($htmlform,$js) = templateTZform('Europe/Paris'); // Europe/Paris pre-selected. // Returns array('','') if server does not support timezones list. (eg. php 5.1 on free.fr) function templateTZform($ptz=false) { if (function_exists('timezone_identifiers_list')) // because of old php version (5.1) which can be found on free.fr { // Try to split the provided timezone. if ($ptz==false) { $l=timezone_identifiers_list(); $ptz=$l[0]; } $spos=strpos($ptz,'/'); $pcontinent=substr($ptz,0,$spos); $pcity=substr($ptz,$spos+1); // Display config form: $timezone_form = ''; $timezone_js = ''; // The list is in the forme "Europe/Paris", "America/Argentina/Buenos_Aires"... // We split the list in continents/cities. $continents = array(); $cities = array(); foreach(timezone_identifiers_list() as $tz) { if ($tz=='UTC') $tz='UTC/UTC'; $spos = strpos($tz,'/'); if ($spos!==false) { $continent=substr($tz,0,$spos); $city=substr($tz,$spos+1); $continents[$continent]=1; if (!isset($cities[$continent])) $cities[$continent]=''; $cities[$continent].=''; } } $continents_html = ''; $continents = array_keys($continents); foreach($continents as $continent) $continents_html.=''; $cities_html = $cities[$pcontinent]; $timezone_form = "Continent: "; $timezone_form .= "    City:
"; $timezone_js = "" ; return array($timezone_form,$timezone_js); } return array('',''); } // Tells if a timezone is valid or not. // If not valid, returns false. // If system does not support timezone list, returns false. function isTZvalid($continent,$city) { $tz = $continent.'/'.$city; if (function_exists('timezone_identifiers_list')) // because of old php version (5.1) which can be found on free.fr { if (in_array($tz, timezone_identifiers_list())) // it's a valid timezone ? return true; } return false; } if (!function_exists('json_encode')) { function json_encode($data) { switch ($type = gettype($data)) { case 'NULL': return 'null'; case 'boolean': return ($data ? 'true' : 'false'); case 'integer': case 'double': case 'float': return $data; case 'string': return '"' . addslashes($data) . '"'; case 'object': $data = get_object_vars($data); case 'array': $output_index_count = 0; $output_indexed = array(); $output_associative = array(); foreach ($data as $key => $value) { $output_indexed[] = json_encode($value); $output_associative[] = json_encode($key) . ':' . json_encode($value); if ($output_index_count !== NULL && $output_index_count++ !== $key) { $output_index_count = NULL; } } if ($output_index_count !== NULL) { return '[' . implode(',', $output_indexed) . ']'; } else { return '{' . implode(',', $output_associative) . '}'; } default: return ''; // Not supported } } } // Webservices (for use with jQuery/jQueryUI) // eg. index.php?ws=tags&term=minecr function processWS() { if (empty($_GET['ws']) || empty($_GET['term'])) return; $term = $_GET['term']; $LINKSDB=new linkdb(isLoggedIn() || $GLOBALS['config']['OPEN_SHAARLI']); // Read links from database (and filter private links if used it not logged in). header('Content-Type: application/json; charset=utf-8'); // Search in tags (case insentitive, cumulative search) if ($_GET['ws']=='tags') { $tags=explode(' ',str_replace(',',' ',$term)); $last = array_pop($tags); // Get the last term ("a b c d" ==> "a b c", "d") $addtags=''; if ($tags) $addtags=implode(' ',$tags).' '; // We will pre-pend previous tags $suggested=array(); /* To speed up things, we store list of tags in session */ if (empty($_SESSION['tags'])) $_SESSION['tags'] = $LINKSDB->allTags(); foreach($_SESSION['tags'] as $key=>$value) { if (startsWith($key,$last,$case=false) && !in_array($key,$tags)) $suggested[$addtags.$key.' ']=0; } echo json_encode(array_keys($suggested)); exit; } // Search a single tag (case sentitive, single tag search) if ($_GET['ws']=='singletag') { /* To speed up things, we store list of tags in session */ if (empty($_SESSION['tags'])) $_SESSION['tags'] = $LINKSDB->allTags(); foreach($_SESSION['tags'] as $key=>$value) { if (startsWith($key,$term,$case=true)) $suggested[$key]=0; } echo json_encode(array_keys($suggested)); exit; } } // Re-write configuration file according to globals. // Requires some $GLOBALS to be set (login,hash,salt,title). // If the config file cannot be saved, an error message is dislayed and the user is redirected to "Tools" menu. // (otherwise, the function simply returns.) function writeConfig() { if (is_file($GLOBALS['config']['CONFIG_FILE']) && !isLoggedIn()) die('You are not authorized to alter config.'); // Only logged in user can alter config. $config=''; if (!file_put_contents($GLOBALS['config']['CONFIG_FILE'],$config) || strcmp(file_get_contents($GLOBALS['config']['CONFIG_FILE']),$config)!=0) { echo ''; exit; } } /* Because some f*cking services like Flickr require an extra HTTP request to get the thumbnail URL, I have deported the thumbnail URL code generation here, otherwise this would slow down page generation. The following function takes the URL a link (eg. a flickr page) and return the proper thumbnail. This function is called by passing the url: http://mywebsite.com/shaarli/?do=genthumbnail&hmac=[HMAC]&url=[URL] [URL] is the URL of the link (eg. a flickr page) [HMAC] is the signature for the [URL] (so that these URL cannot be forged). The function below will fetch the image from the webservice and store it in the cache. */ function genThumbnail() { // Make sure the parameters in the URL were generated by us. $sign = hash_hmac('sha256', $_GET['url'], $GLOBALS['salt']); if ($sign!=$_GET['hmac']) die('Naughty boy !'); // Let's see if we don't already have the image for this URL in the cache. $thumbname=hash('sha1',$_GET['url']).'.jpg'; if (is_file($GLOBALS['config']['CACHEDIR'].'/'.$thumbname)) { // We have the thumbnail, just serve it: header('Content-Type: image/jpeg'); echo file_get_contents($GLOBALS['config']['CACHEDIR'].'/'.$thumbname); return; } // We may also serve a blank image (if service did not respond) $blankname=hash('sha1',$_GET['url']).'.gif'; if (is_file($GLOBALS['config']['CACHEDIR'].'/'.$blankname)) { header('Content-Type: image/gif'); echo file_get_contents($GLOBALS['config']['CACHEDIR'].'/'.$blankname); return; } // Otherwise, generate the thumbnail. $url = $_GET['url']; $domain = parse_url($url,PHP_URL_HOST); if ($domain=='flickr.com' || endsWith($domain,'.flickr.com')) { // Crude replacement to handle new Flickr domain policy (They prefer www. now) $url = str_replace('http://flickr.com/','http://www.flickr.com/',$url); // Is this a link to an image, or to a flickr page ? $imageurl=''; if (endswith(parse_url($url,PHP_URL_PATH),'.jpg')) { // This is a direct link to an image. eg. http://farm1.staticflickr.com/5/5921913_ac83ed27bd_o.jpg preg_match('!(http://farm\d+\.staticflickr\.com/\d+/\d+_\w+_)\w.jpg!',$url,$matches); if (!empty($matches[1])) $imageurl=$matches[1].'m.jpg'; } else // this is a flickr page (html) { list($httpstatus,$headers,$data) = getHTTP($url,20); // Get the flickr html page. if (strpos($httpstatus,'200 OK')!==false) { // Flickr now nicely provides the URL of the thumbnail in each flickr page. preg_match('! if ($imageurl=='') { preg_match('! tag on that page // http://www.ted.com/talks/mikko_hypponen_fighting_viruses_defending_the_net.html // list($httpstatus,$headers,$data) = getHTTP($url,5); if (strpos($httpstatus,'200 OK')!==false) { // Extract the link to the thumbnail preg_match('!link rel="image_src" href="(http://images.ted.com/images/ted/.+_\d+x\d+\.jpg)"!',$data,$matches); if (!empty($matches[1])) { // Let's download the image. $imageurl=$matches[1]; list($httpstatus,$headers,$data) = getHTTP($imageurl,20); // No control on image size, so wait long enough. if (strpos($httpstatus,'200 OK')!==false) { $filepath=$GLOBALS['config']['CACHEDIR'].'/'.$thumbname; file_put_contents($filepath,$data); // Save image to cache. if (resizeImage($filepath)) { header('Content-Type: image/jpeg'); echo file_get_contents($filepath); return; } } } } } elseif ($domain=='xkcd.com' || endsWith($domain,'.xkcd.com')) { // There is no thumbnail available for xkcd comics, so download the whole image and resize it. // http://xkcd.com/327/ // <BLABLA> list($httpstatus,$headers,$data) = getHTTP($url,5); if (strpos($httpstatus,'200 OK')!==false) { // Extract the link to the thumbnail preg_match('! shaarli-0.0.42~beta~dfsg1/tpl/000077500000000000000000000000001236551601300161765ustar00rootroot00000000000000shaarli-0.0.42~beta~dfsg1/tpl/addlink.html000066400000000000000000000006401236551601300204720ustar00rootroot00000000000000 {include="includes"} {include="page.footer"} shaarli-0.0.42~beta~dfsg1/tpl/changepassword.html000066400000000000000000000010611236551601300220720ustar00rootroot00000000000000 {include="includes"} {include="page.footer"} shaarli-0.0.42~beta~dfsg1/tpl/changetag.html000066400000000000000000000023501236551601300210050ustar00rootroot00000000000000 {include="includes"} {if="empty($GLOBALS['disablejquery'])"}{/if} {include="page.footer"} {if="($GLOBALS['config']['OPEN_SHAARLI'] || isLoggedIn()) && empty($GLOBALS['disablejquery'])"} {/if} shaarli-0.0.42~beta~dfsg1/tpl/configure.html000066400000000000000000000036701236551601300210530ustar00rootroot00000000000000 {include="includes"} {include="page.footer"} shaarli-0.0.42~beta~dfsg1/tpl/daily.html000066400000000000000000000073641236551601300202000ustar00rootroot00000000000000 {include="includes"}
All links of one day
in a single page.
{if="$previousday"} <Previous day{else}<Previous day{/if} - {if="$nextday"}Next day>{else}Next day>{/if}

Daily RSS Feed
The Daily Shaarli
——————————— {$day} ———————————
{if="$linksToDisplay"}
{loop="col1"}
permalink
{if="$value.tags"}
{loop="value.taglist"}{$value|htmlspecialchars} - {/loop}
{/if} {if="$value.thumbnail"}
{$value.thumbnail}
{/if}
{$value.formatedDescription}
{/loop}
{loop="col2"}
permalink
{if="$value.tags"}
{loop="value.taglist"}{$value|htmlspecialchars} - {/loop}
{/if} {if="$value.thumbnail"}
{$value.thumbnail}
{/if}
{$value.formatedDescription}
{/loop}
{loop="col3"}
permalink
{if="$value.tags"}
{loop="value.taglist"}{$value|htmlspecialchars} - {/loop}
{/if} {if="$value.thumbnail"}
{$value.thumbnail}
{/if}
{$value.formatedDescription}
{/loop}
{else}
No articles on this day.
{/if}
-
{include="page.footer"} shaarli-0.0.42~beta~dfsg1/tpl/dailyrss.html000066400000000000000000000006361236551601300207230ustar00rootroot00000000000000{loop="links"}

{$value.title|htmlspecialchars}

{if="!$GLOBALS['config']['HIDE_TIMESTAMPS']"}{$value.localdate|htmlspecialchars} - {/if}{if="$value.tags"}{$value.tags|htmlspecialchars}{/if}
{$value.url|htmlspecialchars}

{if="$value.thumbnail"}{$value.thumbnail}{/if}
{if="$value.description"}{$value.formatedDescription}{/if}


{/loop}shaarli-0.0.42~beta~dfsg1/tpl/editlink.html000066400000000000000000000046611236551601300206760ustar00rootroot00000000000000 {include="includes"} {if="empty($GLOBALS['disablejquery'])"}{/if} {include="page.footer"} {if="($GLOBALS['config']['OPEN_SHAARLI'] || isLoggedIn()) && empty($GLOBALS['disablejquery'])"} {/if} shaarli-0.0.42~beta~dfsg1/tpl/export.html000066400000000000000000000010021236551601300203760ustar00rootroot00000000000000 {include="includes"} {include="page.footer"} shaarli-0.0.42~beta~dfsg1/tpl/import.html000066400000000000000000000017721236551601300204050ustar00rootroot00000000000000 {include="includes"} {include="page.footer"} shaarli-0.0.42~beta~dfsg1/tpl/includes.html000066400000000000000000000013511236551601300206720ustar00rootroot00000000000000{$pagetitle} {if condition="is_file('inc/user.css')"}{/if} shaarli-0.0.42~beta~dfsg1/tpl/install.html000066400000000000000000000016151236551601300205350ustar00rootroot00000000000000 {include="includes"}{$timezone_js}

Shaarli

It looks like it's the first time you run Shaarli. Please configure it:
{$timezone_html}
Login:
Password:
Page title:
{include="page.footer"} shaarli-0.0.42~beta~dfsg1/tpl/linklist.html000066400000000000000000000133501236551601300207170ustar00rootroot00000000000000 {include="includes"} {include="page.footer"} shaarli-0.0.42~beta~dfsg1/tpl/linklist.paging.html000066400000000000000000000020201236551601300221530ustar00rootroot00000000000000
{if="isLoggedIn()"} {/if}
Links per page: 20 50 100
{if="$previous_page_url"} ◄Older {/if}
page {$page_current} / {$page_max}
{if="$next_page_url"} Newer► {/if}
shaarli-0.0.42~beta~dfsg1/tpl/loginform.html000066400000000000000000000017751236551601300210720ustar00rootroot00000000000000 {include="includes"} {include="page.footer"} shaarli-0.0.42~beta~dfsg1/tpl/page.footer.html000066400000000000000000000014341236551601300212770ustar00rootroot00000000000000 {if="$newversion"}
Shaarli {$newversion|htmlspecialchars} is available.
{/if} {if="isLoggedIn()"} {/if} shaarli-0.0.42~beta~dfsg1/tpl/page.header.html000066400000000000000000000023401236551601300212260ustar00rootroot00000000000000
Shaare your links...
{if="!empty($linkcount)"}{$linkcount} links{/if}
{$shaarlititle|htmlspecialchars} {if="!empty($_GET['source']) && $_GET['source']=='bookmarklet'"} {ignore} When called as a popup from bookmarklet, do not display menu. {/ignore} {else} Home {if="isLoggedIn()"} LogoutToolsAdd link {elseif="$GLOBALS['config']['OPEN_SHAARLI']"} ToolsAdd link {else} Login {/if} RSS Feed ATOM Feed Tag cloud Picture wall Daily {/if}
shaarli-0.0.42~beta~dfsg1/tpl/page.html000066400000000000000000000002711236551601300200000ustar00rootroot00000000000000 {include="includes"} You body goes here... {include="page.footer"} shaarli-0.0.42~beta~dfsg1/tpl/picwall.html000066400000000000000000000013561236551601300205240ustar00rootroot00000000000000 {include="includes"} {if="empty($GLOBALS['disablejquery'])"} {/if}
{loop="linksToDisplay"} {/loop}
{include="page.footer"} {if="empty($GLOBALS['disablejquery'])"} {/if} shaarli-0.0.42~beta~dfsg1/tpl/picwall2.html000066400000000000000000000012641236551601300206040ustar00rootroot00000000000000 {include="includes"}
{loop="linksToDisplay"}
{$value.thumbnail}
{$value.title|htmlspecialchars}
{$value.description|htmlspecialchars}

{/loop}
{include="page.footer"} shaarli-0.0.42~beta~dfsg1/tpl/readme.txt000066400000000000000000000020731236551601300201760ustar00rootroot00000000000000===== Shaarli template organisation ===== Any Shaarli page should conform to this RainTPL template: ----------------------------------------------------- {include="includes"} You body goes here... {include="page.footer"} ----------------------------------------------------- If you want to also add something in the page header (in the dark area), do it here: Example: "Add new link" form: ----------------------------------------------------- {include="includes"} {include="page.footer"} ----------------------------------------------------- shaarli-0.0.42~beta~dfsg1/tpl/tagcloud.html000066400000000000000000000007571236551601300206770ustar00rootroot00000000000000 {include="includes"}
{loop="tags"} {$value.count}{$key|htmlspecialchars} {/loop}
{include="page.footer"} shaarli-0.0.42~beta~dfsg1/tpl/tools.html000066400000000000000000000032301236551601300202220ustar00rootroot00000000000000 {include="includes"} {include="page.footer"}