pax_global_header00006660000000000000000000000064130164076440014517gustar00rootroot0000000000000052 comment=0f0e3e2701aacf7eba2c0a15f7c42b92f4a8ad7f prometheus_varnish_exporter-1.2/000077500000000000000000000000001301640764400172365ustar00rootroot00000000000000prometheus_varnish_exporter-1.2/.github/000077500000000000000000000000001301640764400205765ustar00rootroot00000000000000prometheus_varnish_exporter-1.2/.github/grafana.png000066400000000000000000004617031301640764400227160ustar00rootroot00000000000000PNG  IHDR=2xKusRGBgAMA a pHYsodtEXtSoftwarepaint.net 4.0.9l3~NIDATx^݉[ٽ??pM2s# .Bo , n ((6c$$d$ܿwTU4xrrTO o ,( ʂ- o ,( ʂ- o ,(fxOh#E[t%p:-+`e,mټEp>4LeBTM57N((&2m ܛ`'m_Z @6{SMlM /- Lhj&6& y[BP&M5T{센-K a(ڦ`oͽ vB@A@0 mSM7;!o @hʄ&؛jbsoP|iP 4LeBTM57WSͷ^Kܝnt[*)"ol+>\b'ɜcuQW{V97vj?oۮֈΞхSUt2q.ig~:LKn :=4~/#&)'Czoga`:]d *3OxtW$˻φ:ɋ]c3ĻzNkZ7Ɇœ袞Iag?;o>N NP,*:Eg\g[}^XmgO٣anRn lAh(+Q= {hZ?/t'%cH-==Dh?;ԛ+̥bY³&55M=E=WjJq0/{WpFa#fEf6hǻe 8?F rt{ts|n[.D-|i+H,65˯|~tV06~,ف`>eX-hzES}\<=Wpq㦤yO7>~Nq |Km&[y 9Qa|scp]OZ];ͽ'<ˁ `2rbVQQ+/nm{M.f*02PGbn#.D}-k%n~/-4jcys3~P۾:;FE?YHn^g彁ژEz;lA<;, PmW 9c MBok)!#.]^:iER\8oAؒnGUP&e/~5br%'߈ZɘlЮw )KZ;n<Mg2ɵtK%,Oiʛ[@eX-hz$p_ev/ۋGssY ?DrwHظtD>LLOGۦ|wo s߆}=2uB?iUx 6j2 !D֥:M_ "2.iӷw}uV1Y#ƤƦ:LoϺmnt7unq'>^PG$D4&}7!nn +$/V˱}Elj6OH"p2=mdzijczūмɨx7ѝ\o X.@q]vR)}h{'t4Ls7b׸$\iy5r}"fo Dwo)W 3|]+<1-_$ݠ}S藖ES$.=? x`G&z(Kō1oGƛ#ׯ?68u}H-jAôYRʐYcG[ι˹snq~sY 3Rӟ:l\ؠDز?Ldgm|86|>*뷅In4׆ÕU*w{s5`"Μ79!t4hBl+_CL7W3Ĝ3,4d/lgYJ.>tE_Ky[)_|WG+mntѶ{da T( $f<>- PmW{~>4s|ԤsJplLz̴(0&Wr&:d݂y ҲxDd}7\y>3{-\hi ک:G`[24L̜zyr nd+ݸ?Dtщ[:[lҳ6>Dm&aǮ߄/8\99\I+)׻w{s5d@k8 z&!'a)a38hv<`qWjyT>"-SMVMkiMMV-ܼ=˽(~;d.}Qdg_-.@q]3,xو1r7_w7`{%#g$}:G|fj[:8l[0O_Z(oCjg(wzځ'愑 c~R+j}XdI`[~EXhz$=!ɵe$l̛BS+fu.sefBo.z_2ΦC{dYa b+ VLhd#ok] o"E_LK,f9w*?]Y[-)b_E󃚑b/Fxtv[0O_Z|.X:݅f|i+ iˉNMf>,oV e#"Gv/V@s.ⲸHL,n;/Z應,sm ۴pL+~R%<\I}g7Wɳ}֥r_^KsjG_">n 亽IsgnqsMu\}[֗ڸgc-]V+T74j̧\*]'llבl~U/% [笋.Ꙝ&ɔ`QZ&FۂG@[{o:m|w3Zl8ۮֈΞzUjgSGvy5S_;/-==D|bH#uz ڢfG"f|׌wlmWχ:w[6hǻeMhLn2c [|b<|i+H,6%zih<+  2ӳ"Gv;/ֶ=Om?gD?+5ߦ!;3?|Jqwr٢}ȂO%MawKnd+~ۡ":{Y6]:0Ҹ736ek疘544f^w!*ԧ1t8y[^-wx^_}é9N/:W8mVꅆ!dHO۪kMwMSIY>n=mMozLPެ&Oq}6ZoOךo}'t-p4_+XeQg.NHp{idK ľ ]K[m*C?spo</Ѧ> !o+@V!\3o)y m{&߼8om}&Ƶ2;iE)m|p .6mu6C]~8{.pq*ݛmZ$ܛ.o-~oߵA$

ɇhjw(7`s|k<^K>(栺! ؛~bk)yͺmܠd^dfNܮ+-zPM٥V&'p`.U@۔^tKIafe{+:T7lMWAxoo'{+A|C$HCdn ut>(= 'ZR־aDD,'cvU8]pkFtdi./0fynq{~;V6FEV{'J4ر-.]#.]IN.]^!Rr0C@{y7yٱ!@4^q͏k3#;̍rM{S?DjLܛMm@[j[}/*qjV>¿KPhAdUM=ym%c]NPN$=jy޸w%QY`:(s@.I9@6]q /z/f.@дf;B7KT$hji{{J+/ G_Z&3jWW!a*tkXkrY9<;:|R;X ufn-mEPvL}}$*z\]j[fl޹5Kvk iK_̞۬x&fzZa*>8\aWKnyg=>cx\mI| NK~(GDJҽqk_[-{ӥ ;Ƥ-)5'e\ q`ƴ泱)\pyy[Ip/rŷ:Nd0uVIxtQrC3 ١\:[}T{ iRa3!z͔ۄEe0[&Re)_ y[ЮY|RfOﱫ۾GQD#v5K ɯm~L4) _Zրp(%\y>3~O!C:z  BT*Yz+=ޑym}ӝJ{mӎLj\7H3J{L%X,v1XE{ӥ}t)io'z~,ީߩ; %HӲfP߲ dhfdhfRn9yMyCK9g%: H}6qH}o7KJ_PMNyY"T2I"X:&ۯIr,5BF{{M[^'n+,̞RI@_6+Uc?Xvj\޳۸t5U+-_Zsةlkzwޕζ MENTQ>e%ob̟[B /#KM{2}m}g3K|q+)EePxg>0sbZ Ady%w1c+.v|[P[y[rAng\tPp]t=q_Ws@Nj0_fzM{'+tZ ti-ҙ\>QwnHҝPRNM2)rMҔ|Ӽ:m߸To^۾/iEIXӶj#I1&*w?/̂%wsߧhh-o"ulkm"oJJ}`WlfDoG%Z}պDK3M|t8|p[,aD4+1x -]'an}. y֤߮ !a\y[#? )0,'zژ}r6_Z鐵72Թ4u:i^Sc?<?.VKX?ZHeI;^*-[x让:>04<7c=tpɶio[,=smiqc= KIW u+UtOwz~9g@|N+ߛፃf.L=ª7]2v[k!onm%ʾʥDW]䈹$P^^-6ptvwCEedn75{GeHxOLh[07sQ̙~U1ɐo7ْ$b6LtF„mHW}$yWvmSUWK#A %9[!Yd@w}N,\L#!ܮEْE,~͞?I> bz~w3pb1Mј, n.mƛGM^*"-Cu&jBwx'pɶyC: kδrhW\=M0f$],WGր^z.}{`so*EiYs*%Z[߳^{p 0ۺu֍eQWIy3Д˗nqSH|u $C>kgcX[-=q̒ n;rbOUr_뺒v40v_dQuϟ"j=ogV"Km@6U_ZFUrp1 ?^,f]r¤]򇋄xpOC\h]t݉7D,;y[i緪|; gэG{sC;sd\y־<0:*Wf:}զνi˫P%@7oט͏¯ 6Kޗ߾f2¾WP u_2 %N+jA2ZyMuuwH@ =ҰdI?ˍOn([I8d;v4Wbv9qpi:ob ݩ,y[?Zcyt2;c%1ӻHK+f N@Wq-Ay0A+ʹlis,ڸe`"t](PzϵEqI\mڑJ=sk^,.h̥󔱓Pόwq̪somV(V)MWoNQ+ͽ~iYc}P F$xFҼm .VvHRl'ps%F㐲Kd+|(ytMleQ D_dHFQX@:T==Ьy73[؅!o\;^խgVFK}x:ۊrR5= ׅI),K~iQzO0cMp%bG'{-h3[ό_ޠ( 4Le)ۇ`b>%,4} WjJ{Ld5`Ud۴#*ɞyA"^<"~M}3v3}C{W1465ٛi+s=/6kٝy[#1ه_$$ J~;J_w_$*utˢ-q.r [M]8%]':&^m,z4t~m-˟Y-+H5v)}jǽVVK~iQIy{H;flpew|=b ?y#НHATpF=7%}owVG5vvoCuԤa?.UmӎAiQ{g7I; uZ$a}8_3x,9=4 9bߦ@{SzI y%޾ۨfPZtvtm$i7|W|k2mL6FےKkx?y[ F$))y̽g$23NNvy[=^uOq_o7/D]g'ff򶣝%M6:y[?2J4v+J/^Nc_ZHvdye!:p{hrbG^v|[Ӌݢc3ܽzhxpF\mړeX3N{[dkrC{si Z[Ez ){RO 3=髡vuiv)J,y[r8ogVWDy۾J:Of*p/-d|jOeD%bP0twv(}{Zs SA|e=)c,v_f^CH:ysu?%KM$UZ*GthZxߑzcawozJ͗9ٵ|o.Xx?7]tyv;#tmf{ܶ |7Y?wb~ BTхjB3Ky[2sn򟥻k G}3;1~<+I[pɶiwޖVtn|lޘ{>OMAym@4-^xտ7S9?$çKX؛'ahd[3j9lM5n,K++vʠhOW(sk&a+]\{~NwB:"BC7]t0eV6=#"itQDօQA^LC&R,NZ~at(7W3W۲oT9_ k<{t{6F+%&2m ܛ*߳[ICօx9ZƊ:_ޖX^odI[Oހɖ'm9L>ĭőܢ.TaLvlӸ% d}fm?\pK2|ia@VAlm̊4[U}LnؽTNaՅ/- Lhj&6j8} t)\RӸxC1׼-'{3ӓWC7Y=h5ͼܸC'Rc.SwiZV:[|s ͻzudaڳفq{~ 4 }3c9&~o cAMU;̊`Ҡ̚H _Z @6{SMlMkm4隯0K a(ڦ`oͽ vB@A@0 mSM7;!o @hʄ&؛jbsoP|iP 4LeBTM57N((&2m ܛ`'m_Z @6{SMlM /- Lhj&6& y[BP&M5T{센-K a(ڦ`oͽ vB@A@0 mSM7;!o @hʄ&؛jbsoP|iP 4LeBTM57N((&2m ܛ`'m_Z @6{SMlM /- Lhj&6& y[BP&M5T{센-K a(ڦ`oͽ vB@A@0 mSM7;!o @hʄ&؛jbsoP|iP 4LeBTM57N((&2m ܛ`'m_Z @6{SMlM /- Lhj&6& y[BP&M5T{센-K a(ڦ`oͽ vB@A@0 mSM7;!o @hʄ&؛jbso,mའ8mЕh#.6 J"n1y[eA@YPmy[eA@YPmy[eA@YPmy[eA@Ym7X ,m*@@YPmy[eA@YPmy[eA|b<ē.T?A*m@!m2OWxNϐ7py[p m@!p9}ݻg~)[ix's+ͯCp4~tâE_28wCd߂A$oisUyRLv֒$UZZ\2ۚ_ m@!̏|m^\G[mݽ g޽~5K?KV{5^\v|{ͼŭENL{OY"'jl o ai-s$gQl[Ud!XZܚGksmhҼ@b)ͺ5`y|5Fu8ؔqŭCs@ hҼ-a~56Yc޾ !Z&aȂW8 B7Xiv;[1\B_ew *+0-d y[Pm@ATy[eA@YPmy[eA@YPUnذĩ7=yF fH=}>r/jkЧ^_{hy-[> o184Bx9WرK6Gx"m_:9okEm̼ ޿sUۆGDNLϥGS3Yٲ9\]O|rd»gjS_v{757sn{ѯ}g~ů'x%|_v*^[z~CV¯a]mw~K9JmR;&{-"o7Jt+7q{z>w3yѠ-ls;Ty[// 6:#mSMMr!g M-9\R\THm}= ?:#7'sb_$Mgv{{{Vmmwmڻ)𲖷xѝȴozۍ[7vŗ6 ξnn9 f.rnV`ffLLOwtak톥|M]^m|ΥBr~1mk3\Ot;ݚ?/r TqR^Q }(0-$Cyy[>24JmwepqLéy[ۆ't Vadadadadadaddadadadadad±0Ҕ (RQ<"(ogk/=b/K6^^Ag[<\7,ۓm+$O1]J\J}uŅߦMl܏we6.ƷM>BۊpOP|102020202020H202020202020<[yۍ=_BMcޖKbhp[JE95v>]$Qc5o%ok>.ݾ}s>>dΕ7vᓑ D n8ÏܚOB~W~Oe1}O5B!ߖ{mmp%vz/nc8}۱DŽ /=ri!oIv|'mƷ5`>.%bOͼGC#cnx9JOF&F&F&F&F&F&FVI&F&F&F&F&F&Fg+o~W>Ik'|S!!ʧ>%4 Ľ\7׻g~{k;oK=6mݗ,jҸ!ok>@@@@@@YA$@@@@@@R7vi?ߓtۑew搷5L L L L L L L L L L L L kᓑ D `-C<|2202020202020H202020202020eۚOF&F&F&F&F&F&FVI&F&F&F&F&F&F y[ "!ok>@@@@@@YA$@@@@@@2m'#######+$######ZyddadadadBa $%=Ա%I5uzs\xvEBWFjQ p420H202020202020eۚOF&F&F&F&-7uLWd6 7f.h)Kud٢fgeZKhdaddadadadadadaXː5L L L L5[GKgV0;-"wݴ98@YA$@@@@@@ڃyddadadadBaܾ۳q$4#0,3h\ZTaݴ98@YA$@@@@@Pz݈ 6l!A.ٴ>&9#:WA_ `A<`@@@Pkno|P*o[p:5Zp420H202020202020mذc-۶{yyy>\k2! o2s<=mCflݺu g-[=1O\ȄZøSaU6TrBUݴ98@YA$@@@@@Pv6{xl{޽ZN ^NK|@pt:{ٻg^2A=wڹs7I_mEzY=H,[c'_{(cb߶yn _:ks۟5nu_NQg6;$y(*sǭ}rgԹm3ÿ,*[텼y800202020[(K:\rO$':@7mF&FVI&F&F&F&F&F&F 7mٲ? 8$ؘQ"bccDGEA4Y}@TDXC  )2+8(0`4~{З[8/1>Wb67}oߪrƴOT#~lg28z'szC^}Q{%i<{tϼ;CSQb+$c]9Wux:5-=}5'&F&F&F&ƽjeWKĔhisp420H202020202020nuێ]{D'$edgfgfE999i)ɩ)R:55-=-LԔ計`ď__d?3󏯧 Oťӹԭ}O^zWW%o:z wpzvХ4\~rUT~;mߙ/jK >׻ϒ7 z7;S/~ňIwM O_m ?Է/W~udgYK*F&FVI&F&F&F&F&F&Fy#))/?pLTUTTUUVWU颂쬌А0z|nK9؟?L冫|m_OS8b[)?Xo)ttF "z'aљSyr];n옸~H6wa@c6rP!~:ԲkZx okN0L L L L5=U9%H|)kU "Ȅøc󎝻AY%58vhƆښCM-Mnlhj?T_]E;T[]SSS]UYQ^^QYUM&+JK sғb"B㘊ξW?'FGXW_}|_ȯ?SWi8 E^ =^g%)ns=|N )Eg]*zx}(Ib:mXt`{MOȄZè-K:\Rb ϦM D gqK}F\1e*x 6m[ZycmGikmnkjnjmihⲹGZj7\涪P!2]Vy0>:"4[].P%.&\e+S,?[sqxƌZ9?vI]_&-\_S^t9<[^̠Tj+:0 5>Nۚ ###j c`r,p9]r!nL L L L L L L83^,rA=oM[w1M:_^uHˑ֖cǏmk>\PWYYVR^VQwpCm}}߶Fo[[WSITTVRY]eskJ sӓb"Âw7$ +9"f"*m3}P 5;p\w1xeҝoi}DĻJGF$++Ls-mͮivB<`@@@Pk%J.eүCQe=thdaddadadadadad™at$okoSR^wp}Í͍u%E%EYٙiYYEEeeeeEdiiIQQa^n^^^AA~aaaIiYeUUUEiq~VZbtxH^O_Ϙ:P-ok6ogS՟|6W_⍯R6xsgw 1&/lzþi1KVE?|~#"xx>R"Ʈ/7v*| xkZ{5'&F&F&F&iY%@lisp420H202020202020hԭtm#b ʪ*+*J RS&%'DLMHn;v0%LNNJOLL"ӳs sR"4{3]޿q}@>0(0$txDXDdd'2"&K:\bJM D EmMl_:n۶y[nBlܺm7۷*d5g={k4zN%[sM=刺 zq 1dTY]a)ݴ98@YA$@@@@@Pv6{lڲs>>^^^۷oۺu˦M9Gٛlݺmv/o>>;vlܺe3 ֞+}47v5<.P `@@@Pk+Oүk8@YA$@@@@@Px6l6s| *v +pٴi|͛7mmm-yn֎d:<"rzn~jˏ~8h2*:FX 1&2d,p n6G9aܗ#%hLq(H=cN[ZS]LB7,hԬ L L L L L L(sxߜ1n###j czKlF{IYKdt&!EdR~5G7hԬ L L L L L L83–m" GqÒGdύ;w ;`@@@PkN&g+)Go޶n݄B˜T{ A;w^ JM;5+$##### #Mm#73P;EM>hj& 0Pxe˖'zo;`@@@PkRZbeȕO-t&cmz^JIFw4jVI&F&F&F&F&F&F:ͪ>zjG'&F&F&F&s1DJJp_Ou c饌(;we9hԬ L L L L L L834ud7geT7m"ۚ ###j cqwhY"r%~u cp;wwv 4jVI&F&F&F&F&F&F:RM6ojGȄZX֓|YSR2xӭPH[޹åljLS]hԬ L L L L L L834u,87oٲeVO9[-[xdRܲ߰6ZjGȄZXq5;6R\I߳o'ݺ %lMhF;\OWӭ;5+$##### #M-Ǧ͛7omovv޽K@8t>< 3vC7g'ڱc/v) okN0L L L L5U7rYmoҭPB=2HN;@hԬ L L L L L L834u 6okn_. 00h_о}  09ABsy:b z2CkݻǗK>C,J+v瓯l,3oWsοx<=ůØWvGٙ'~&_qј\m_|>q;۟ΤD{:E5'&F&F&F&ƚY"r%7Gw`/ݺ %q޻~a6hbJc ݺSQH202020202020ԑ6m޲m}5:CpXDtll|||BBBbRbb|l\lL|\\bB|B|,$bcc㢣"##"y d</`i˩;yyEťeEEŅ%y\NOHOHLO s2223R""BqO>+OZ\}'_p/g w>ܓ-S~)ZV[̗=\«~ mw̎>1핹5{,{7;z qL3}۟&<1vT^M^Lg>\_ل=km"ۚ ###j c☒PY"r%RFPn݄¸?Pv)CWR2:HhԬ L L L L L L834ud[nٽG_^]][[SW_tСCꪚC5,-.+-( )///+-Red(?/7;;#%!.:2zq.՗ #/_%3K>ꋗG#<<"z~OUϦӼmƍ_|[CϭX^_2 vK|1Wdf\WXs5[ko?9/ލOm*$E)Z3mp)ԙq.IJGHXzQsQ*0n|=km"ۚ ###j cҨDJJ̐Tݺ %1x4^IIm);˯> ~hܞ_}G旎%/D07:3IWRRbJ.ӭ;5+$##### cyˮ{Qz])&. %"WR/G[70wJJR]T,u@fdadadadadad™al;+Қ)>hkn?MpXDbjzqUms{[{G[cO<tpCsS}ccCssӑ֦Cmá^uuMuM!.X_W[YZ8Rˤ\OǪ]̷~;kLˊۊۮBޖKq>:AiU:y%[GuKc.`yZDȄZ>U-ODM.OnB a,T%{+) ՑU7r֝D gс-6(4,`jAyUCsSSsccssKkKcCmEyiiyyiYI^~nVn^^iyiUeYeeEMMu]]UUeiIYYY7maAaaaqqQIIIyEeMm]mueyQ^fJ|Ldh~z\T˖v3,70SvoT1-"+=7 u G]m)YL``LW ^^gg^.W/.dzN>{tmY c:,3P\I?WFnB a[[.{+)5ytNF "Ȅ3^C%k< NH.**/.HKKOOMKOLMLJJ/(HHJMNNII! KJJ2Sc"‚_K~gܨ_~2VշL}Sw218/>"kc w!8Η>GO0]gO~괼-J`LviȂw}'Vu%^TªG&mFޖ5`@@@Pe7lp똩`=XA_qa֝D guvݾڀI9y9ٙYii)1aaB>lj %<,l$>!`JJFffVzJr|t^zjGȄ*icTۼmvgRr}}1"ea١JRw<&rR_x{{(,jVk)%5)MDdeݢ5lšK{u 4jVI&F&F&F&F&F&F:[<|vhC"cbc""‚tZ g=?Z`0:2G˯9/PwNozjGȄ*øiGrI̬M1L8FbJC:P&sH.oH:8?@~ȑG:5+$##### #MmӦ[mk^>0h_pp`Pޠh|w"رg.b7oΝdYg^Vkzf;ov) okN0L L L L2[vln+ch:@_ca,8K'"{+,mS:5+$##### #M-æ[zn۱g]\k6Oϭ[6o޲Vܲ ݹ{={-ڱ}Yk3}5MQy[paadadadBam3H\ީL8+YIud/1SM߫SQH202020202020ԑܹ\Bsw ݼi]NdC|s;vl߱]\m"ۚ ### =ۚmӚbΧ0X-+ JtՆn>4jVI&F&F&F&F&F&F:;M͛7mh,>L -)@S o C@@Pe}w4 l.A_cal}\"{!E։ ]}hԬ L L L L L L834ud7*v) okN0L L L L2 Kr]T,&ㆍ:fJ˶m޾ՇF "Ȅ3HSGv,Ԏ6Em U7ЧN,’PYٛM_a4jVI&F&F&F&F&F&Fyۮ3^}'dаGS3>Ș! PX'#j c|eD~WJhF Rv9+nL L2AZ]Y#[0@k"sO%^Eiz^W5+$######ZԼ ;Oׯ߾}s>>7\AoddBaLi>(KX8\NL6G## cA} Y\a 񤊾 ˜u41-^*J+e=Yq>4jVI&F&F&F&F&F&F̩y]v =*-ׯKIK'Eťf>Pk:2ڙ%PRcϧM Uqz@eyc5L8ƒ G^EibFPՇF "95o9=7?5G?}4hj: LEš>Pk Τ60+/"p42020goK 7אr 7s#e/Rz)#$@CfdadadadadadaX˜˟y}}wFMLO kON 57 OffdUڟT[7 U1V>e];ƖTK((̪OxQH20202020202XiJ\Sbis-mobj cŵٷnF&F&Tdrel6RIUx%VΧ(xQH202020202020e3o;5󴨤tbz.` mGaϏ%,VRJ.ffp0 G#*ݤD fkCE&K)t2eaSdraR  )!{ ³1;B "95o[RZ>(I_CjaڳiDyۼS^}lddadadadadadaX˜ݲe]_y 7p cOͼGC#c%'#j cXYdA,a]{;/0^\w (Q+LE!uP\R{vߟf0ƉTȸBɥ}:is cd^pα;-q|zV{"(-[Ty=YSd Ϥ2X{xݴ9i4ِWw29HUV,Q 'w/0~tW{8mZSlQw ÙD `-C<|220zm?t_&J/fׂ'ϧM)W=_=?h{Rߏ^Z$3_LgΟ0޶8sIqV %VX#oҰ>'4'p33">Ojnyininu og3W{ d9K\ExgjeII9Sz!JV綧ZZD2a\!*}nDp@2020202020eۚOF&Td}%f?K,;œ1SM.,Rk)-<*?.AGg<Q.U7X9G?{e6.S+ֆ p oQ'3ZImV~-1a Vk322ZB3͖d+%ř~䴕r8ZedTtӰ$#####ZyddBa+?J);Zu򡨜I`%]/u1,4\HG_` pYokg f߶0,},9ڟ88SۯJVҡ(2GWlކtdadadadadaXː5L2IuئlR<W 1z#ZujcLDRy#GKn0ddr:J.e( "lWv>좴NG݁t 7 trQ=;8oWc.nwM~rL 5ynyf;~Lm섚X{@6=,B7 p@2020202020eۚOF&T̎ٗؕ#-ܹ`hkzFq‰˧V~#^؟nxjmmi%rFPn݄a9~$N*+,)1=W2ɡ~hԍ%ƺ^+eWȕ-ꚾ3joǖ*cYIv_Y8 @@@@G|dBq!i2Qp,CHCRfi"C<`PeOL;b.<~@ٸԟ ifs:RaC/F?Ns3?Ok܊.O1ڨN$̊^ [7@K/f$[Xӱ?=@\EX,"T/ˬo'o@EMf=TCwUCj2}m顸>D|Px~zΑYdײ  aP7V^\28\,[~~Qrz3H0KBe,lWavc@hJ!wT۟_}#L<\Fjrf'uUoN*y[>wq]pqۚ  cٗʺ_wkKi n慓EǏp6 =1ܸ|(cੵQIMoa-<Sb1VVnBUUVƮ̊父бm_e6jZ!n6Kn:ӸH(EB_rz3W!X{@(M7 p@20202020گc*43Pv9$iՉ3ٙ[vly800]LxwJcSOXܸ%c, >D1ڨ!!xa<4P[.;VR 7ѭXn﮾+{ ؼ<Ӟ9&oJ+)7;m|~ߟؾ(Df7=,gj;ya޶RFXf :,Ȅca옩&WjTjEšEf3,L v*8+; kÄٽ}y+G\nޖoO*GsòJRqPX1խ+Hm86Q{"eQ7/. Q+)Y:-v^n㬍ե^iY/ Ǽgr/0aW&(@WR wdgj;{H2wG[E8 @p,3U!}itZ:8S(8M/,v$68.0کf{_#o !okN0L/[wln^:8e/ڔȂPc[W.Lk W0.:Px.eQ_c?n7:Ren!iws?rL͂{9W7La7)Z,fA7?Ʋ;jMhϲΊ6& {-,⻬&7,c]i^WRncv?_[qYYx65x?:,Ȅa%Kt. G#{5%cA`-C<`P_lkkShogݤ&@'r8B: Rk:Ťf + }~vӏt1s75h돸q#0R yF(~ѭpnэоB r=@js+?VטŁJ._h/[uGL<&i/_9ͭ [mc䁶Q' JJ}I:zN=U7rd~:WNp@202@no|PLdݱ_YӗG7p420m[L-ZԼ-[/,?/8:swB? Ähצ~=cNm1e-&z6 Rkجgkㄹ"$tOkcaiv]߲x{.OgE9͏h#-cHIqP1- y YOkL mjOw5YɅ zNXY؊r ԇ7 J㢶InybaSTvR\yrV{e}mkI\EġMe)٦9M 5yYG=ӭ&L >/X[l{Ff臣&-~=s2`PHK pWXs~]1R< 7N3˞DdkRE`;^ ڟ`%&8SLROJS=6>|r*T{4:o8Djgum^ iͱg-ѱS imKHlmeqYXwWܝ.,`Fk|duXKG&F&ctsiƾx'ݺkhsF$.e'o959y32soqc  lL9%(w 3}S7re'GÍh@J[s+W΍e;mY tJTk']xO-rg,wwr]TUk;v94PW.{!Kز0i".$Tt'OZZDƓ?nґ ˜Tw D#n%?Ͼt G#j f#q) e2IWp:LT̕y'5{5ŋ.eM5"qA`-{y윙g յEis"A^)X%12&}[D{KQf˽eq'xVqedL8RW&*sc>Q*cte\˧V+={"1˨MWQeN\>;_@vrz$4w%%-~ =M8p 똩bx@ήɣ[WȿgVkqs02aθgܢ?还6|>e]t7 Jxt>\:202@˻sJd>VR,[wM8Pk2b<,9trkn;C1+{.93], ) hJ\eUO+3-=cj)}b:+088 KEm/Ǭy.e7n{>cD  L._dsڨk;)Ķ[&n*-),hC3dUTy=U-%ʅSk +uZ䡬!G݄0<#Uҭ+UAc='[ڴǛHٴT_8LjRNhVͩnkA[z9nґ Xz1`C#n%lpzݺkȄZ%iMPV[YDjRdH\EP m'22KJˇG o}w ާ 7PBv^ ay[ f:hݝ݁>4J_ߕ"{Ʋ˝iڳma^oKߟjcs *|@;xy[63ڿhzդ禿Y9 pix{Qwl&8D+hmWJLFE#c×,= NpȄaP)|[I)8S{G#j cTAHyCB[/eNv_yL =~7/?@4J$X-O'o1~֯y"}MdX'[4[/;)m5o-@fYo[u#GTҏeu$޹,r'phݴRz }tUy?NkR ոlfƽ4M\wp-q~u\|h|KnioپRb2㳭@[;"H#ÝnfyۿVL L8Ceo+)9I]F&ƴX#Ҳ-eNۺPBqN{GW5?7ֳ/nk;hi'kƯhg.>wfdlN6,o.g&hhL\jjcr/w³uLWM+oOq^с m^o:R 39_ 3I0N 7/4WU\mao;=8TMN+,e=!zTx6wS3zYe林VL L8ƶ`JJڑܓt G#j c饌zCX/eۚ4JcbMߟwj:tgMfkÿ?&-Jy[RL{KOwA^^4zR2uCH;o P e9 5NdfwuESC,c_k˪R>3T+Wwn#=|K3m~ ܢӭ{EGsO%M[W okO|J9mMސ]Z)ͭc:,K~8HN>[^3Sy=7.@Xn7mxRe}x喃Qe=K"L5 bJdm2my %d_tbL[[2 u[&h>~1wZR@=PX$Կ|tWBWEИ*Ub+O\4=,ݶSW<0_M X3mCN> okgȝܖ'U%3\6YAqnq9hsFJD}. RRGdo޸{P'Lk+5mT\l<Ʋ1ݕtL L,7vnm~X12?kȄ*vt:4-Zy8O30ل7K'Ym覬WʱOWDFVjמl|MHWQ U4J:QO^cqr~p΋n]tv&YEmtOxtG״[ viϟpqߞN&."ut~ax|f&+:HNʓJ2qt{xlniQǓIn|[{t: Qd 'úG)tH!C5}mU9#eϯ> ZW^1zsqssMHu\306[6o]Yyqh|sWwq۟. oj@wb߁Fu4pF.g}Yڇ n O!Gg2XIIi)쁌qr|P_֓)8Zyi}\Ӄ"*{Ѿ?=@\ iՉHmvqP`eP3&*6oD߮kRe *.;WXF5ڴ$3{Ά ǑEKZUy`@<\520iys' ߼b՟kXx. smI;,oO՟9)𻱅\wS$<<8o ۪LM^x2oT{j6mMd˼;DZ1KS5fOGVN* ՑU7r覝WL,7y݌P*ڻ"E#{m,J8TGѷT٨j#sO<<2JbœOv!okxasAw~3)2NioQtޖ?͠aU$]_lYlŁs (Rxf7/XvfqhwA# ߟO orV68iCO~teYnq9%\:rC.[ɲJlYxý"ig8 c|eDR{;ONݙ${ƢLa:U6³mѿw\ZRmn/u__X$s6mKzm2mU#=t^X]88{v]dF`xF"$) 'VGfB.;%S޶(!oKXv%]פFKm#uPl"R,=~N9?uݏC>k~e;W.<[$<~ߝ-w%y[ y[p{ct<3}B b~;w%x~58q Cd7G_@2+Ty+Y^'nc@(}vy @f?(RO37EKCs״^b/=6OO/X}5ݻ;|PB {dL5ݴ Nvn.OJzK\BE8({2;be(!o>ۻYF |xrRwLW W7~QH h0[qDX?\73G/=VZE`-C<\52XU͓gA 9v6=٪9Ѫ9G&:=>/:OjnB#7_=V^Tm*Ƣ'úۏM={"Yv+.\|6O/H!3?­ơKc- #3 /&yǥqQ\𞶫]d,jnbW7&7[6۲c,:8ܣTf} )ґew:}S2Bv5uU\.A&I]M#"aNɥ9E⺲7R:(P Gwо# FtdB)6xPf@q =r\O\+$`6++*2阩⢄-) wxwҨ+N' NjفgvaǮoX(ۂ-Zyjd±0K֑Cꤺд &a룮QrE )I \NgRF[|g{@~E`KKP76.=|XS@%*琚X|n$A΢Fu4!-^ە^@y[pȄakn"~^tWC2(/Go}ȋ ;&"on;۽7f.&GgIoIߟjIih?m{ϹynrS/K6r;*Rsgد'yG,Ƙkm/CwA3wX??Lԅ-Wz9CV:w*"=lRi-v/aڣ3Ƌ/oݺ7EQJӴoO3r_H-,z/gs&36>g3gFb0g2o{y!Əp`ڑXgJJ8uR8p|rC;q叾myl!X:F |ԙ;-/"|?iX+{sNVHn 'å9Nׂ<᪑ xV ـmQBn%'*gswg:=ˊaƓ,'lY\ I k3}ձnF0^h{S~OhzO'}f7IwVssqa,~ok։ WLyœ>(s' ߼kkO 3e+)Q&\۩??"BŁFAie}%CڶfUVX*f%jiV\jJ7)1 os,aרwfCC zMC=6<᪑ xxOY5rq#0VL3 z@;1[,KxԿs8v4uNǒ<#g5 rx/K졬Y&{2i 1⇲Z%__KCya#@$\w ]G?K꛹ U̕siQE!tN+p;Oȼ`2c{U)CH8[z9䡱懏H?uPHΧ%e3I}Qy\E%Ł0Vpy.壻ګXsO$'S(Qz5+b>P mU#qj#Jr=]=uLWn8:[3U&3IMJt%{xl[MX>UI Hx\5y=[g vzotAVi})@g@C򷽪űOtEnCsۢ6|90~qTUݝG&-< uH) 6 +=,3.),{qq ӥ'pxx3#?Nsk W {ZRuni2Yr$8&n)pnmSVPM8~9a{U6٫8o[ّݙD9YG+e꼮Ʉ 2% D;=0Ǯ^f:zSlTz$9>,r*=aMhZ_<0r{ ,=|u굨gjmTy[pȄaly[IQHǹ}YaA:4;0"?L]tQcg }B͂ʣ5OcT?"Yn 7}t+dBX;@gdl0=o M^_:_Ҩ]5?=ա I3k2 {e~?iցHqPPԟ+.}s;5B=vS5]8}T/hҳH={C8u=|4;36!㫲O0ےP;almeqRdۗ]wYm֓٫$TE#)Ш2#?و}&^XCr\H?!Npɷ3G'QzVGʆ;لF&'BVRrFT`0^鮰\9{u[BWo{_ǼԤL7/>?"Wϴ_%4ꬣ_?wL-j(=o'\'ઑ y3/ MY_?ra=E: ?z̋Bϸ^adoG'ND{ۧ,5im4N+p{WF?Ok:rLh{/~PW9묎L|L-Zf3)yNh ŁGwu×Gr2D;2~'~-Zyn O!6'~9͝SBnF.ObBŁ35mu{>qw\520zl@.&N;w &~:?zF_`Zn4XZ}uL2sؚj2|~:2yۻt?Ќh>'Gwmɫ˚wE\-,_mZ"'۾4jW/*VΦd=C~2-jfvfnq-dl@$? >{tGcWX[>6$zjC"UG!Ooj>n͟{<Dj`sUsei}hdWe~@Iݳ~SZcw d1l/ǹ_>wK>e{@s󶧏N\ܛ~PXDN ՘x =! G֎v|$"Rcն7(R")6ne{MM%*{/"fV8qIb'ǎ%y~7XXŀ{_>> f_;vEk2f'pjmiNMK&\H@Vw?k=4MzTyfn&eZL fRNoT?aen?ʾ^:! {S}t|:v*jel$ |1^'t>2Jzʩ.oq췎 /V]3gΐ|r.{#A6ZmhX=7i]%n}:=ޒOߑe@K˦JVYV[<铒 2UY^hӼvU٤P |S]I ]W G3FҫWoX*`r>sWgVeB\zUjꙜ[1\"H! 8pۚ"2֞  ۊ2&eE)lOweh/29Ɖ]c+hb+705\}^m Rb(||kY52V?V+\aT+Ri\'!7jE/2תIZUnk;pK|Nx˲};#{Tu<.o o/.wI7ztȭy[6u} N|xL@hk=Ƒdxby [s6My߮zNApR9yۏ杯^Vr#y[QVƊx(ߐtA[{b@[>jʡFQ 2bQ,ְܠc=c.6,3n!n.߰U~1ڹyfU~#Jm/ ]n]vwņWdErѾɞ,>ШMUUwSSF6Nfű:fuU)oY&:[v`&5F .Ɯy{.ܮ(Xq,,qgS歘WMf1~:Lr:Hd Ul$3a`]~Π쀁{lfYUxt:6ox'4+<BxOm">75r qu!1ժm'tƻ;ZeTGS;BXysœBpz%#9OA ܖy[N '#oliOAj? 򶢠7)3yCnBߔKE}x:%p4bQb%z{G7B8O^G 7cxj#`g\HF@[%RN<;Jmn6vQsOgdc%/+?`o/vՃ&(?[ǖV͈6_הvG__9 v7Lg C|nY[`۽owo{^R`V~?u==T=}kkqޔf)+=+dvf3&5{'UjRʉ_yĔo7)滘g#nU콹S_ӯ WMeWg0 TF*ƙ:PǬRm[ږ\v meby[!7!鈌ZqLxjRt4m(FQ 2bQ,} ȴQYwH7sŧE'7Es:߽8[Ǒ/E޸%5metq w=;Mlu^)R5Gޤq콭`ZKʉ=Ϊw'Cw䏇m?s"]-}:s:hjH .p6P{q1*:q[ܟ xWq;*~&G m=Ғ}|,<%&#bFS!eB*͘GqMYqߵ;#YDI{z5=Uq@zjRM!-PC>e YŞ/7n7m-0#ѫk@E?`ZQ[ o [ o [ o [ o m 5>gu 7xλ=VVlM||V7rI9+'wm);0dkkVO~-m7zq]\yщi[M?>#XFccέ/813Kxpe}C\틎B#~'4J.t{\XYKJIe'eljiS/{9WO/9SWo֑@##ȨєQ͞_[EF =7Cˈ/2%[vr޾'>A"!+WjjH}҇i.o{]\%HCʵfn33 9$}ͭ?hd$6[hd,)!G㣾ށanA#vIM -/:\Hq?a%ًus ##JR[П7QJ}r?4q>B_ddd!_[-EFFr|B##c~۝v_!n"AG'6_Hn6Nrf~ށģcb$[G2Z[[OfrϜ_^cNȂd$^A)r/s X2^F͋?hd<7h fyQǤԩR-42&61E_d)W-- "B#T&;`+(ed }ZXX{>ˋ} ܲ r{Mgf-mU$Ae$"Kȵ\ZR&ؚz$jQdܳ#+(e]tؚz&(A=;g>mmHZs+Ȉ/2jv˸wזj|a10(xYߠ]E/2b1o»Bd=~|imC#[&N38$tucyQ//119eV\B󛬉5%gy}%vosRظŕuEF=+'ddmͻpUa2f"\U=FO^TL-pU@N̑l5}FcS3Ca2'&jwc+- Wዌ&d$];JES ;.vvqA"a#qcdQi:[Ϯ&&[So%2jKǟ5&cxD${sFFrDʣQ]][X[pʣF=Fm7?Ś@s@mU0k6[nNLsa2FDFዌ&jwc+H#LFv "y۷ 5aϷʚf_8=-+DFM]zzfSd+P,da\,cvncr(r+ʣVa2{ͻpp z0%+k};Dp^ = / NFn~#L[w/ٵz }/2x_[m5#0գ<2 mdf吻O//33L-ڱuԨEӳ˾~\ }HVJUwOЈ ê0Ua2GF H0sryٚz I{~"hEؚ0%e2Bl\ٚz,%5119eucx##Ȕ _d4Q˨fbnn/2Qݛ'd  N=۞!WZ6x򽉙9rCHrO=Y Ai '/^v"=&WC_%2W=}]r˨td~A-ʣlD,# nwXѩmr-d]mMovɜtm-*fHpQ茡ej; Y< QIحր3Lc3Lf-Ϝz-/fc.qLk-dTaUCy[pyۜ3^O_Tdفo};o{F5,w7Bg倜QR?M.H`k̟aRYdEW fH @QmϜT'$U홤G/b U90$sUj-Ty۲e5f.7&y[hMMvLNͷ>palm1Cb ƹ gU~TsN%nϼLT5%7f}ܒ6zظFw};TU MZXZY=V9B چ:B`9ylhhH^Աcwq.~?4r/oIN^ʺBd\e#M-mwt YŮUeu]Đۍڟ@ nBT5$5Xn0kW>7V<7Vrۍ3~]{Cɮ:Z}W_]ЬqLU q^8W* =-6~VɔU󺪠eo>[<#9BIY:glmҹnB>wCQw۩ZCZXX4~{xl⢙f`+jGHҥxcccN !4bҚl&Ѥt۱E&r# lύ?a7螻]ߍH)vPhUWtV7~ls指ayO,?=gH\7:ΙHεݖ{:<ޖ值mtl:v6<2jbz.0(88$td|*(8dϼz~۵'Iɩ\ ،a93`gjzѵW~ɦ 7:ݶU 6WL0clMUr(y[Y6: Kx;o!ۋ[ڰ)Zu;'7ox[Vff]\UT7}gޖok``6IMMJ@{ PO0'HG hzt4PKa=g'ӧ9uF6VO5=~^5:լ\'ؿn0W \LH]jrAۋjsvNh6;7iqzF:3[VQ9<>9<6spޖ`mm=13^p˽PܟZ9u'ԋ/K{ K ̬θk\cO0'HG hzt4zg ]066hfaaaIb9AU$As3,MM/^4SC&&& .r%+ o+>pKYtqEu= +g =@:`  PO0G  Ѡ=ghdlbjnaico/ RtT*r\&e`rf`rT"swsppH$@K,%H? i\D+־Z5y~/pX{>P-ib[׵כ󽱶\öe^gΘGX*q0UDצټ DH쿟|~ime׆*ѩZߋ=?]AǛӯ^yy 1]=FS/N\x/+js. =@:`  PO0G  Ѡ_4sptq MHHJNJIMIOOKKIJJONNJKMNIJHJLLJI!c"ã"#""HR   puvrtUTŚj-?)Tj/DKv/thlΤn& QOy+oTgiy[˖1uj5ehPH_ZoAW /؀׍]={ip'~8hA"v#%^ȲaG^AB'l  OaE 0=oz8hzt4@=@: PO0'HG.gtApK+(**-/++),),*,%Ԍ̌􌌌̌Ԕ4RNOMNL p^L[eRGQt߼b]67o8$T*lUmdg7jZRjJ1zGU(kNmÌǜT mr֕QdqS-\σDq$:7vvh˞;mWf׮1mrr6>}ށ![[6f=~򼻧 dutrZ^ =Ṱv5*&vvqe+%k#ٿ3pJ -e`YTyݽ'HG  hzt4@=@:tYfV2'gҊ򪚚ˍ5eUUuUEEE%Օe%eU%$^ZR\RTPXXX_@Yi)1a~f"Uo|4ΝU W ;#l:^yCRUIncf8 y4e~+Hߞ'!7G^1oY\Znnny]E dfuz~Zsz-Aa[[;v1 Ožo{*rlfʒ[!m**gH9$Pr㣓SfԋuZnlrzmccco.o4>RrxXaV9ifk[  hz4@=@:`  Gŕ~v k;{`XDJN~yMuMmum}嫗KU&egdۖm y lniQA~VZRLX:aWVsH,Wݕr ܄qmmS=-Sї\F&ehZ{^#13Z_tm /5p;շ{ay w8ryۉ9kkkRY^`@  64j1شlyeLף^6iK3oˎQW;FpyW: s\{cO0'HG hzt4zx̜򊪊⼬̴ܼ̌܂46+3==-9)99955%---3+;/???7+#%>:Y^L:L;yo\'!15--=%1>*4Y)^lϼ3a'Nz59>n¬?=@:`  PO0G  Ѡ_4dk'st rwsU*vv66VV66vD*dR DTzzyx;+e,M !mcf}$IS Al o8օ5w&&,oS1/pԫNre`YQo%ݽ'HG  hzt4@=@:tY= -.J R&I$6V/LLL &&/,,,,fU*YeuN"*rbmeafjr<'ab`{'/^vﲴ"G''awE3-K033a꼭z\\h8}5,x3¬Q ^  hz4@=@:`  sF獍M/[ZZZYYXX]411>!6*$|䢙%+Kf&H3?3z .o4>W pԓx>J_[jkT`A  hz4@=@:`  Gц&fll%2҉DYc D L.6B Jlb_[m5(F6uod$7f'ym7|_m ^/L6^x5DŽ Lm6[:I}36 2{Qats`t;5@V|pyᔩ'J_[rsDp^  hz4@=@:`  GcS3K6R?00888$$$4,4480(0 8((4$8$8T+BH ??o/ooyxYtwssuuqR*2G'Ő5}N/q # EF_:x'Ŀb͞3AIu*9ZF3h~sæ3W#MLk^o>(bbf^[OyBJ$Xyx/܉ L=C}M>\{cO0'HG hzt4z\GḼ.9䮞^Q ɩiYYYi)IiiYi))i)%'DŒHll\\LtTxXXHp'bLxZ*JG? | jDN6o\g6VT/~FSW-vrΧ~6SK;m.lE;شzrOUN|6*n3IzN.7qA!ü۾7<_%o~ 3{Ŗ9t^[q:o{,;5@V|pyᔩ,͹K ī%\{cO0'HG hzt4z\G.ZɝcRr KK+*+KJ JJK*B~AA~aIIIYIAQa^aQAQq^n^VFvVv^nN.'''';+IfeBzJrRBBldH?do`4S7>m$|Ȼշo\/e6>g #U\6՗3LK/%S!v7$]I5+okRԽ誑+x>4kf2ل]`a7g 3PTj۩vdbjer+Azfכ:^,l&lZ3o{;5@V|pyᔩ&-op9,ܟkz/p hzt4@=`  PO0#SKh%;'7̜+׮^\WW]Y[WX_S]QJ(,((."BqQAA~AaQ1)dGr/$U\Vç?VU(“?b7~Qv<. FvzU'[V~ UꗙawkLXw,܌{+W0|Y=?[}+o=|3A&is+ܭws 0oͼy[卆S{2N,/*CǞ`  PO0'HGԣ h82rglbx0$T5\|To.+bmQaQIIYEyEyqqQ^vFbtdH@PbLRU3UgU!lߪŲ+yUf7_>}񛏧-SGՖ/~ڇ$m?g|;>5EQ -q\N ER߮ ܊12QF\rחZ]]eҔO0{Rc̡e^[m7NzNY͓W[58hzt4@=@: PO0'HGÑWjaV\RA_TU_WPWkWk*T&TUUVTUUUVVTpmJ U0܊⢼ ?Ue2Xf;cpwη}ɌUe53o9Lpg%cL /oU=}-3e*oes֯gW_k,-윶 02LRs{Qvv#{/܉!mZ4OGDF5\|;v[ZYwtn={3s.g8:9-m峋 +kך[bbgZ}6<2|F)S;9hmc낓sM=@:`  PO0G  pd ZK=<"Rs˪*+**k+ʊrsrr3Sⓒrr 2symR22333sr rғ"|<<ݹcr\Ykw2s(2;ljAvLn~Vf0Rtb'%u_u+۪fe&=m94w̜3-q&y<C_/ w6{A;hnnts<ɾ:mbvʹp80;<41 gj8 >PZYd\_yz'm{Nl bA.bq 3s^^ )4\ZRV1<6imccieow`Xݲfuz~Zs+i]KЬ`hhz}jn֎]{F)S75f4/*b["Ǟ`  PO0'HGԣ F: &??]~uw%L =p pd9\.3<+3HXBzf^QaAa~^A~^~NFZR\lttLLTtdphH`hXXtllBB\bbbJJJjjRbBlLll S+*<<22,'fdff$Ex{:9m Tg̬~0]^X5M·/uXu͗ ٧y7nN {mwZl}cx^^aFn g)IaIwCK15om&y'\Tj|l !aY0o~zyCg >${Nl "o:5P*em7o=T/Ӳvcoxdtx[\u]'z&tR`s9ė k-oIDATUlX2J uE : hz9v2ڣ*x?ݣj?dP'HGÑ%{А*.\8-qV_ [ْf%[r^q}ۆGD.8:9WZ6x򽉙9O/NĖ6ԕ5Ӳ33щ=]yU\ZΛX卆S^\}pl]0nU{<=@:}7>G%lY]A8%m'HGԣ إ+Nݚ 3#`  GцsqÄ{16p'Opyᔩ|-<&w*؂rRǞ`  {Z;…YJsgvO8hzt4@=`Wg/zĉP2bIy\G<@:L=.8p'ۊ.o42R[#yw-(ǫd0kz/p  @GI!޼#\r4phz4@=t XqqN +\"ajis/xO% /̸C e`Qorj[$) #\zY@t42oFEV31c=  +K 疕V\' x4@=@: PO0+2@ A2bVbLNtU`kᤐM<'>^RBChTef %\zY@t422oDnUgD^ Az%iٞ#\fX_=i hz9^oF4Vgx׺XI-F1ī ) c˚AMx%,ԏkW9KS^vg\xhy[4l'HGF3=xG0+LVXp4phz4@=Ncו~3&-t(,uQ} 3@[TF{Lub,;qq !/\xQ1u"*j+EFfd.׮ރsm4 L{ E<|O[\.^ Az#\$;[s4phz4@=N )H HQU{cvEV84V9ij)Gn~*j*oW[̵Dy[AM)S/;!w;(|j瑷=  ԫMu,+Qkǵ{G #@:PYVGS 4V9ifkȼy6򶱵M\zY@t42 {ryh>1|'HGjr|f߉s r4phz4@=-J}'w+ɰq;*̓^EmZmR"v4@=( o+>i8e|95pM=@:W;Z֝8h%I PO0G}#D.:bCi KnG%LZmTe`(], P ۊ:hNzeY<4UmHGV=0˼̵+R/;b~i{:M q<wIfia>`U IHvy1~#@:rh]4uĊzS\.q;*юYm#IϵDy[AM)SO%qZrsgwcO0m;{ljX3] tƕžٜI)e#P;9&X:FLȮ"JSIf p<x%'xy:bH`Q?8u,R=l]sUڍGɤаԈkG3ohޖtnG;Emx_x], P ۊ:hNzUY<4< ±'HG32hX-o5-6E+]1@p@B8ݽG.O~v Ki}LŒyC?Jphz %7.q@ b{i .I{pᔩW» fwcO0m36P3+NbX\}Hl]״X:Ue{A^\{ߌ}L¬l$]܇%8hz4@=.?J(sq;*!&gxt+pᔩװ/f޶r2Ҙk}8hV=r WMeJi;KE)Wfc\{euF>&aV2faG < PO0 o]:bYwb"܎Ax_0ޫMm`gP:׮ރsm4 Lkb%XȺhmµ {t4hiDXFdy@i1P9=Hཊ0Mq x4P/^BhcfE).V\' x4@=`Hp%4NG3ĜZm3<*'^sm4 I=s m+2QǞ`  ڪgabspyvgUwKb>^AzCw'90 P'ҥ6y+;ɅQ1H[{iKs9ozY@t4& ۖdXJ̹=@:U̢l8]S#$Gx':gގ彊`k\- Ǟ`  ڪg,ڃ{TNdqMADA6֪/<W9Y01~#@ažKG,9<$ߛQ1 /㽊ڴz:7p=8gizQ8^;H$+WF;6{;o:=x]KЬ`hhz}jnӤK&=|5I8> Ǟ`  ڪfSГ;ok|.״7 9fo+I= P'ҕfy.غ`nGŠd0Nj%F\ Y@1ok``pVGSKf5:6nmWǦf2fbvg[_e'%FIJNehB#&55+9MVe;E/=,5{] A[B{y6zxqSS1\{ V>5 ^hB`pftAhDnꂦ $Lkͻĵ{V=O/φ$ $VErM4hz ]tNbUjMT=T{\E\@+N48gi 1o?69 QKk I-m7F'Sx< =s+WZm 2sWփBBj:\NzNV=|{vcO0mse݉4vR5&r$}w!w%^Ez>kz kr DrsDpI= P'U.b>Pz:7ukwmŽ8DM-m gY^۸ Tmcb6cHyϼ-zbfNx4gf]̻ؓAvcO0ms g3o{Ұ }')D5 s,[wK_4zfgr&] +:G z< PO0NѼmdy@F{4b}߬yۊ s\ Y@1oF`OXJLN122jn1_8Ho8օ5wےFԏ8;^Apԓzo)Qdu9L'Ǟ`  ڪ}G['qu\RRg߉#k}ؚz< PO0Jgx~)Og!>}g/6o[ԛb"xN:8gizQ@V|ApsRMCÆ5Jz`x1HG;bX {WNi U+aWl !1A\' mc'ڳ"*nP= P'mp|hOb݂r|0~+m޶QCtp4./nMvfNn<Nt^`8hV= QH4u'#֑kC^4t-<|W 8^EK>ihM#ђJ}aǣtV&U-fysJi夘yD׺~sm4 I=(eSOsWXaAO 'HGxKb̏S[2뎘Lo Z߅/fTTEU_GLIC[d>y]%KsM4hzV:sY: K/6os/^)K'4@=( o+>i8v_̫ͨɩ \Ul^b,z _G }0&_A`;'HGx'7i `Kk Ivhs+\p/ažWٜ Oڪ(!޾` -җ@GYIŝ]\Mq'Wn_QZ ^BӴf߉s r78gizQ@V|ApY+,+F3݂ <|\C Et hS3(ZvG>;N] A[Š}6C+䦈"u:sRZ ]z}YPx=A޼W1NY+e5sē9k/ͨ"`xfD6)/族f%z.aSy$sM4hzV:GSkI:+5EM_m6vKk]9KcW9Ts7#I-_}(_||k%8OgHGEd-b񍡑\tDoeYς*+t g=Š}Ջ!L{`:U;y[heVG, 4z< PO0Jg3c熕|n_zi8vT3oĤ^]ێuߟr )u8hVBc7l#^a;HӥA]f{LLM} +ͽxsɮW1_g_ ڪ,b6 ýbLx4@=`gSn+gr{K LM_.`W¾+pKn 1k @~l7\PlzhV`BcQ5%iu/_9U:kfslUM16H6't8"yXHwp5x_EG~19nGmIvI)~i\' x4@=`Ng q/3"˾sПfӓY@t4z=͊IoeǞ`  ڪ'_Gy:E+cg Q 6 _k+ú<;Qeᣭz[n߭<}(iKJWe_.1ZXc"HeuL%fR~Cvm)׺!Oi O[Tҟ7 IWy{!a|kW'mJpμyt 3nwip&] /yzY@t4z)no+>?Ts_d*?`֪Y`AGS;AR^>[P4җl!}[t ߭H$c*4m?x0@4h^vg\xm55J':k9An_mՋ z5tߡUyUd񊤯Ml߹L2RmMי7˲k)M u$ޔ1u!ٝ j~3&N2/t-$>1G3Gqp F[|S2{aXP%t48m.E{WDy[AMG}*#}//#}gP6,=I$t5IxWJpZq?e^vɳ.x S/$^] zm m˽Ztv>ý9Tա㧲ĹG+}=|U/ZSN#iۮ(bA6paӖ,ԶHX'b1>(x^{s+v\/hzV::eE)LVx5׾ikZopAzމ. %e܌&jyAw'88$g߉#ٜk^&- rַ4r%Ab+?pNٱwbRiEz몱||׆kw/pҠz )Уm^V:X']~LƭWn_mKmtVwSWfe1f6\GhO>ju s=^ty)-ڝGlݚ]:*Cyk^lmp•Pu, P ۊ:h 15*< %R%DDV%^  !Abk<)rql{8e;m:yXavm m+I}G:V9inwvO[~ZjkdP=[[2ڣ\o'o YHH3U !ψ5y[x'] `gt'ʼݥ#>8~5m; %k]9K{'7Gx~ Jow[EVDtژ˹s/|$jr$?d0U&aRqNf=Ρ:=~ͺ:f- 4h9 rxߑN[̹76J3S%\U/n &_f ˻\2T>#ִMaߌMs{p F["+u:o{/^!,twiEV߈Zoppy[ccέ/|obfu緓>~^G' usaeZskTL2YVx5kdmxN\_A @r+ݘNݕ-uxAEhoX_•0RWwcjv.evF#冟O9$2¬>ŃӖm+Nz؊R{ґ.A?=^ Vo1Ua8eOVȼQX6O= \/hzVغฺ`޹S}')D.7*xkyr҅r78gizQ8ļmIYؤգށav+ccㇽ_VdwGy[WkͭZfCCSs ܆t4P/!ܛAxmG:y"qo1Tl-OUZjO[26nz$ p"X-KA pҠzS[$th+]հZ]vt@VdmW0{>(xr<Pqp F[钛cjzvLŚ^x_Vg׺~sCjP2/[|iY[[I<2:Fszu]4FR8^tף+E=> uvr -:yvzEy4@=(Qz᱉ff rlr:=3KraaӲcS3]z٤-aϼ-;޶hD]AM~oZ?ep@E.|^rvo޳ۢ/f݇C;^;Af;RnYQ*CXj^"- ڪW;;Na2Ϳ܍+嵯;Z[j^dgD9#Ҩc8?= 23),_'%~7廃wdҥ) ^:M D3(⧗?19<#wφd+KnGwӖmkX,/}؊Sc ø76JW>Rk_w,6r,G[b7}K[w{>µ{-%G># e"[fsB] `QZqn ƗsKGHVRm}MӶKm-Zop @=.z6.!qVAQ )ŏMN;H$,t{x-\mja{500Y\Y e#piS\qMłT޺oK_e%9I|SQ5w=}؂pswx?[r :.pҠz`fgߛqt'$H]l%ȺfٝqWCy%8w )N ΫI|PgLm0)7R/ͽj*m#蔿uvf&MV=kqNX{/kW'mJok(rQ-hX'v)WeTOguu~1ʉ,6yмvz^Ci Y@7o8=#]ljiSempdQn5ӲqKkѱ̬yokmm=13=.A @ʉL4qߎKy_Oik)%TQ" +Ku#vQ=cvCe`Fw˒$Flx2wmW+Wxg~5%xߎ - ڪwyIYOƾNReK|[ S3XTHz3wR'޹SQ{/|ꈭ$|$Xx:X>T+HUYw?/rǫ +1yxޮRwK]=Þ Pn3g=bMa$sM=^t gXaYo[h_{Hx@_wǚ^@(sR78gizQ8ļmPHlK\kn]XYsombr&Y8AMjs}ř+A=۾Neߍ&/%a28, P9gcel0aJRW*FgBXzdͽ,Ō=fvӖ38w~9EVq>/eYJ޹SFL81a$Ojc9˃O{xC[J#.={fc-xhyv>)\:qtXy[fp:״ރ PO0JW<y[Q,3m;=t)nsC۶wtj]^pt↥eĖF'FbvVqi:2A @~ +MۼCО AުN/ wv RH~ >|M 3a>,_]ഥA+.-y,k&}FIYI#3mIv`DT+Z@<+r{&Xkk/W0WT56x Vޔ?*,59.;!hu{gwh=| W+ Lwt {rx G7 PO0J<0Sw9bӶIq]XoLM y݉jy;6ܟY ܋'>/N:2[K\Y@1oA[kXC==w(>/kQd`GBԾop,  FIoo)['ഥA+.f)kaYsw4Ӭx1 n\UgK$NZD)a2Zx?\:[Xys/c:]*H}:j:Z5ƕ˫WxAָUlpu;$~0Z8`r*KiN DA<ߥ\T/)o+A?W<$oY9sD`:~0X>t*]1 nqۓȞAR+Qim\GVdW^6R Š|iV=sssN~="[z ͨFGr|g@Ovl\'ikԣ-7Lyu]n=ےnhyۍ9i4V(} IEkN76e1~ A,>?i^lK7l@xRjD aFbXt@Bs\ͱ_/]=QX_x#AzQvjjX_Q\d}fdw0& '5zV|'&j۸ZI)iף*x/!̒COh@t4hr}gK֨ R'=- :ULdV ;eS6=)Yd3#=o8]>b2vCUw=qOܸf //H)JKo.c y;x y]P3c-?hV]|0hczzI~Y?/ ?S{ >d:m(:wkFۺE*Ǽő˛jenz1:fYGNjH60jji̵1Hs7w #Az?m)}ǎ edߪ?7HYIo7# kIzl:r@qq 6,ܔžs'mۮ-[AO+qszH%[/P׬2"1URZ#*#;^g0~Ϟkw/:m-%3gVb]7_.K6 9x"eWPVVrIsZd}G zXVGͻՁghӦsuE^Ƚruyjm//cJp&'sf~iUSG9)o6۩x{eU]umы+$*;lݬzKsW{x'T㚋wT}òh8& o[3kdl}05mEd{ mS9ne @D뺡ۺ|,n1x f.|X*(e& Wg1k"8 $Yf{W¾S:m/-FBo-7)DvBjM22qF9o'd߭1?zN׳-KhRFj_eӲH}&I6eYc=s~S.\.^T4Ѽm@' N{穵X<-LX+hbZޢzF r&-'u ?Yu'^dWa5ƃFem^pWrI-aEI<mջt❹o6N/M)N'jr/H-J'|&ZU:FP7 [R.IDVm39$cb~f&G#$ߧ'k9DA[CeZvq7ː=(߬ܢ0R(҈ u4k#S}2hVUq.tɞLrW]*˲rbGIz\A{*1|o|6xgq[zb'rTELJ: ouf.GA?.zXuːlϟQQ5knTGVmU٦V&Cuq_X{D&s=މDy[AMy8}]~y[Ɛ=%; } w(I=-̢ksV-:PeEJn{&*j[\ R:R\u0}0П{#*M+m'=||)ˣwZyW4/ n84fooFGU#bf\Ӈ$Y3wsNuiv.'ō& S*ƳE:5\#9IMh{wzQ@V|AӠz)?mnT yۃdqQQ{_yaE~yBVir}V9_kNxK:q\v0[pyoJaI!A8YqM>ڪWU"ݜhgS=udF v#oKc+Iq A9)miv.!/4@=( o+>iV=;e5m/ ޽/kpGa,JyY\{i+͂hky6 ׬y44\GM V4V%k-|4%i$7%AbL񵳹ė>J",ul$ L$>+d VwȾ^yoV\¿6O^5&jG'zCV}&lN8E}P;C|L6񅏒 {AL L6X:Vԛ'(ϯ˵XtP~݄ןmGm9.48G7Z[_8+Zv}ec䠤b%1/@0Lz>Z!Τ Cy9N,),b{0&ƕYb2g/P5M|L.䮆NH S;AP]v"X@V|pyA[r뼿^y“klʳ+ISzl;dj\U;aٹ_RNjrB_G=טiնޣ~CUȈ'ī uU﫲7¿ [1SiSvIywXU^T,,Ve:}^\ Yʺj%ymT3V9.ܸ;Ylx 2*RVcXoLMPpRH/&\Xq!1q !I"a,bѢ$O ׺q{"!Nmo+o ĚX֝8ᣭzN/'y`vdQw2o$6miLzE)" E{V$ΣbY+I> uይ51X'yi.)H;D~+9˼wmvYW,錋(On'Dsn'dk&5']e Apm{䢭zu>$ !o{yA#pB1ԡdBqSdY\Q,=ܩ'ʙ;O ;=y;wOcUY}:VS5V1ONo'_ I^},%Ya&N/'jQ闋rۧ{"QgT+a򉪬 . rZUdS:{7e߮ae?f2z۲* e..&3v;/U];sWָo{GvGzq' 7&t?nrutRowVq{%;sW\8ۼ kgEXF{o+ᣭzKCmڝ8$x8fu{FޖWؓlf}6tTMe6FXvgSkх/UYe#uyEUTNd!d0|q&X7V䔏BFv)fTOg58j^5-(9L,c zi<3m{Շ'k/}=*#*w/dqj#ds.?+_ݪ'{<9V?;S`1~y{b/%Ձ; 8+E/xE})~{u ِuhesA\'mc Wk~` J\gK!ZN~TiFu;Uu=֕8k5aA6U-!Ǯbb f󄚅'%"ҋk]Ȋ4덫= BTļ|lߟ 䦈|oG[ޝq-oKMh'e{E> !oKcԫ̽_9Y>A|f;vR`˽ OcoD5x˸xD#ǏٳgQ λE+W WQ't4MҘ{s7s<,@K}]yA=bw,p ڪ M?km:Ϸ6;<-uuwF^)\UwbEA_j\ ߛP~fZ՚co?@ku&5uniuzD+sR?헍md}7V,zSdOzEw'*D͋n1^W\ѼK^0}aɵ͓x>,146kVO\%nX=M+bkv#oKcԋ Ho!7kaףxu0_ܼmJsdpؿZ+,F y[( o+>~y#M(Oc}Q_J~W")TNKrőBx:X6Ny`rf)|0hOl1w{:l^;I G"v#oKcPn]xM/ H87՟[{c1;4mP1|C~ uAër`;^گ9hj@j`'^CwiVbjt"վ㪴Q-W%]ͪ5U}š[|pU͆sƎ]ʿH*ʟ IiگO+aZ 8sniwMqhu4V{/kV7bzs=w>XP~Ұ(?11?_:{KAD;mn\f^ YTfAZZ$.f{FޖNzѕNCؿFU$] )pR y[( o+>~y31P#3+үGf;Vw<溑 9 vqɩ@$e,ȼõ NےJo_.kxޢlq 9Kc=nV#2RDKT-<.`DzDn!;O0MeH rx@̼n/g%\~2j:㿘ulҁ[ ~5q&No } t벇=WS.JnGwqy>IM.ƂJR333iK~O^qz=ժR?qlxN{dqm'ǏI+%&% j[ܐpFޖNz!>Gcbs/^ߐ!o m/or_IbmR[utAޖ3۱KbeW)n /-\ˡѕ~`y[;edzfp!s_l5[ԱGiDy[9qZ`5}h_֝ڑ 9 v wھit0Kqݤ|+ʵ/{S1t'2>y~KJKDjkd%j_ڟq3,IN Րp)SN3Qo>VuYѴ ~Jg_-1659KL} .-:>&c% ԕ0wW?n|/]Z+!iu˺k.Y걓UW^+Ο_5:}Fl8t(v.VJ>Yp}::eC7y0Z|}:Dޖިb99#{#L ~Ob|>|V/fՂԲ R[cI .0u,J'rߠ / ?LȺW1E|PĪsrUA=H(cYd Λc "~8)lVAr+{9,rN~=&8#}5"1Hnwg;G{{Dy[9mh5`d>Gh2;ob+r` 7Hn_qYq~eIg,RUОW`v Yo\'k6~$>T>-hjg&FI{^eɎsI3ء v4u\lwV5ڑHkA+9KcOO.+E.WM5 5MtZs>{W}S]7]Q`Ow^(xuaz5EރvR}UNբ)NHM<.UUT|mc@2?ƗE,n=EÊ}4I{NutA 56,4./Uբʫ"SfW5,3e&vp 9eA&G/xk +o->Sm2ϻvz;j$gʗr;_ߟt%~y~Bd\b恒̍?mXQ^xn>W?Kf܌Owg?lRAf&w`;m҉: g"^cm;H׸YzMt]Pٗ WvGP 6nVs%y"'{y)0@'2Cóh{7t1krޭع\vJߝ-G=}~ĆJ S!~ʓT(/qͺ,,u{xm3U\=lvqeɍ^rTdVR;26Xo_޹*)Rq ߬0qfq?V}"zQA oTlT j/(x2|Ny٫ar42E9G* 7HM25 ]y[U# Zc.v6CIf/93_Ocf^$jc)ALuIHƫ[}(HUb,K\`\g I󇇦Zj UV+!Y^aUv5"#4v(nSʫ;겺陟~.eM3`N6#v˅<]hk•Ds%iFUy~9) &g.q*F[#<\ v?W|>0͠*՘,V\`ć{L63#.4T@n>#ܱ#>kg]:\:|xRt;go \ ȢǪl׹k٦>FWLiL|r`Ad (o˙Eq& ͸կ~CoGnu4<$om-~;*9t$ ș__ī l}mɅ@:}wY*r7_$pAD\@7 ՞<{K`{M[A]jHk\IWqYHaO[< HfX-,y[-y[-y[-y[100-5\|;v[ZYu4['嬜ܵͧr[A굴x5k{HsvqF'Nl5F=`錍;:$̜+WOqѷ z'HGz9בoae-)%WVMH\=}KIK_yy4zj6/h#칹 X=|hA:ƈOO ]DB WԐ+'U ]^,.-777'7aJz/W\3,l@>}>g@ APHJFr9g1 "A2"s=ݳOsf}ηk6EZM7ͼ꭪[kMW033o$7d'Z A U/,ntƆtg/o3U+䗍,TAhޠz '"pݴа,Og 2<&2U5uM򹶎G*H=8:ӄ>PE:?>_o.j>6Դ itٴw`(4z|`-V"o(E'wr R[v')%uht\*r',r&bg`ڍwɇ_?Kr2KXRPE=Ҹ{PN:7E=W/A%U[DQE:/_i=NZGCzW<o;UԳ#I=*|4QXRϟ/T? p~'0/LAtJȼ6yspt\L&Kkp >2~]S7nE eԋv=*:LIi}C؄պu,z҅GF ¤z [gm-E >R32E-tQ}O[wdoTE Ux^gU]XLVaG'oN\M.jg4>_d&,@ >MT5t0Ko %oRU ;8-Q;/]&k7YFS{"oaI}C $UV| WT"sYzO0WIWQY-z }OMd_ƭNHQuYzze1FFFM::l}O0| ԛLX@.kxv>|9a~+TQ/Jߖ'r&hy쏽 !z2Cޕ %w9z^¤n2G^Gg%*v<0';vEt ;B' >ɛQG2,㙚utxt^§#Ge, s կx|!$#JiBVE~'xVV/ߖ:%5=r033H~[[;as# z}|.w=p.g(E$rrvj9s\Ekk}W| d!|wZzY% OmO",WIqcWoumBn’iK&jCԋNnڧt|A'c )4ann|ɾU0uO;]& wtv -zz֊O圜B5}O Yݿ^bǛ||zIޞnCB{22z zMr^A p&[:| ԓADn2HO|- >|[-nt [-m@o |[-nt ~V(mh [-m@o |[-nt [-m@o |[-kh j. -m@o |[-nt [-XN{5w]Ibj,C:3"$:|[l0;/8r1q҆g-]BqQ8d >=oN8uO͚}ӷئ頏tZo[UXx5PwKZ}\0˄֑陛}tɊP .j,^?~2*:FQEdd]*,.5RVQ58:CgX!Y$700س@~[[;a.؞}7AVOݛA[MaqIO$vrvfNXaff~rKZjvyxz|[]3)l1;p|X69/6o.ᰪd[pMVvt%&|̴Oc6(=4hyks{hri []^m-Y=#UF7RS]a2T9 gU4Eo럒ޱG*ǾdR.F=%>^V:sHÄo ؀h@1 ␷^Blv($q1Qe(Un_Ue天FF&+P 8hb YZ;n !3Ʉ/u6n[n.$irݼiFƖ/ݷ(ab_AǭuFUh:2ޖdI~ 6.f'z&Nv *dދⲿ{֙LOCdOIiYIzLd5Otn'uJf&gIpm(D[_?wIo?&$$+!e !^on|[*2a9?173E87Yb@4V(DcE3025wٲ7hGdttl\l|B|RRbb|llθĄؘx2+66&:&6::&*<"48,4$<, #I(Bwx8:n[¡هO9&i)}nA~7Ahג><fʞ$_Kf>hVPvxRX/y[92/ߜ+McOόt5y*Z@abxi+& GUŢbxk0wrK1k!F}3dqXb@4V}V;$*&%==3+3;70?''+='7$i999y9YiYYii II)ɩI)I $OJ{-tc|JCb^KG_-vL *'}0)qH ‚F,4o+[;Ksc kLwGk64u@0!>J^(v0!:$ r/Ą52|K2G:SU*k'nݸ}9K++ͽw`xνngM’R +P ey/|CE- /lqqnfjb73mieMV(DcqXg֘YYoܴ?pgbJNAAqqQiyyumMMUyYqaiYieEiqAnnnN~qIqYIAQa~QqaIiA~Avi/HO&iFZjJb|L@wYya!دϮIR{ݝ3YFybk!۾͕UXpOڅR\/|[Ӛ{y'fnN; u#s'L2GVs^f8 Iߔ2ö+V}ݳrtDDҡlO:SmΞ$733oܳթGOEn@4VmՔ mֶ-KO:k70'jm9ZMV(DcqXb3+k߈!')ZX:mq QXZZVQVQ]] 7'7'DWI}]sW_Otcf5gW$^y^aE+3߷sJ}o?/Yv SmtR@aSb}XEs}Qd?wyw+ٓRK:,RZ\rH\ !Fo7K\]u}[yx`t0́`.'uR5C.$#|`䚰 -BD>^خ߰v3nm$ { 8h@1 +_bmcR K 2SSRvFGH榦$%%%$'&&efeee& Yan>}saŊI<=&1%8|'qn%;wIG>xО+}tVobztۆP\~/^\߶ tk>3RV3=k.U/lul%y)_$u\3/ ێTԪR;ħ:g!yVΛ!(;H hRY#B"[E>dd1V.ٽ%ABBM) $$HM_y]V %9aZ/޵YHkƏ n4۞U 5I٦~Vh lRZݵ44;ri"I++$UVB" stuM$j 9DЛh+* ɇMBruv r/\Y 'q!49eD &$֤$HvBM9m$OHI5*$$Rx=VHHBBQlD:KqFn um]HHwPBM&YT厺lCg5㬅x\`/$_m5;\gDY!]ĭٚdCB"HnFraodCtoga0E GMFry"j$ו.4L^*:#$"kSٗ[H3BB|^|oZm~d' rY#y7+$$e+$Uz&H6*FQ3YNEtO\شOr<]tخ IHhi ~_l`j@\%!'Ȋ>++EXVomZl0rMOX88:IP ۞khdd$,&CsalH30<]XXu_Xƪ0:"|[Dcq?ZS-mzۚh-妩oΊe9ZMV(DcqXфbffmY9tZȁ1O/ajݺm ֝=We2LUXb@Eʼ o;s@m)߰v¬EzŝK >?>87Yb@4V(DcE99;w )闻zIU˙si3F' KI#Y~bViEBM%PEXfZtz-`8h rʿ4;U*ێ_i=oXYCiޝ|q}Wy> 8h@1 +P,8$w`E:j-Ȩ~WԭkBeu\%s._jȷo;|z^AˆX]Kvd&9zRH*m42Z+lBauD -y_ێ^:}oXYSU6|A.u87Yb@4V(DcQ/LYj-Zdh2A׭"a)jAfaaannn&܊n m(D[Ks{Dvh9+}^'_\>w]VdqXb@4V/F1꾰bFGM6oټeW-[6lrqDZ6 !i@22iFǍDZ$ ׯ3<ӧ,Fy>>(s2^sNe¼OOH|ad[-N |㍤Çv\>2)s3̌t-kOK^飗G2[ƑgGbZdm:G??jtyV 4]:;oNw6?.mSGkJ#rl@4Vm!nrmU|۞+r k7;{qHOr.ZwYs(DcqXb@4VŨ‚͞~ٹ9yť%%EŒ$+;;+'??0?;7'3'7;7/3#359-5-3#='===-5Eb$)>.6::24sm)e#󶒦Oox:tKLc$ر Hfi5܎?[i2[IXywb;K;m-l[Vsg)zֹsdZxύs[k\[eƨĹ̔Ҝ&wp0ew8C:xoM01:"|[DcqkOD& }+tnvlo"= GheMV(DcqXb 7mu_\\ZVZQUUP__[YYVRQYQSU^V\@(*+/,/.-)*-+)(.*%EEy[59JǷn _Õö2ׂ{n~d1rvd9`H8Jۭپƾg&oIXX^Sz-`8h $o{VZNafDf|qܱheMV(DcqXb|O^ed쒊ʪ꺺]{w7TUVVWTWWWUʪ JKJ%Ը/,.*.LK K7o+mtJiٯ)&tַS`0kĚRVy K={0oHoq%z`'14f^yx\BGmn~ԝ{=WƦ}2TyaIm[)(D[WE& }GnvEzťǻҺ @1 +P (f{q$jui$HƷuqu =ᑑQ111 1ё‚CCCΝ;SRRBy8ʜVE+ Ruau*xGoe,ےeυOH_;LM{.Xs([ؘ\U;"&sV:쩅{vg0/\IOn#m`eMRF;F~F3voh6~~?#b|MuD 헮XXZY>{|Qt m[)(D["m]Ǻi9$ғ/ڏmu87Yb@4V(DcQ/,ZZnt#"*&>.&6:jgTxx@?//wm۶n ˓'3"48m@94ʓ50"2I(۞UZNaf3Wnn\u87Yb@4V(DcQ/,[۰u>>]7n ;ۭ_oGe͛78;9ҥ7oqm&G,-: ȱD/umvݮ~_?:[KVDcq,7h$o{ZNaf{%ғ/nB.+pn8h@1 +Pu_X0213^i-6orrvڰ҂`fnnNceeΚ`#z: Y҂̲[~ƍ..%v6,-LM: ȱmxd?|zTty˙sgȕz)IHHP - OU-GD- ť#\nXf|sWheMV(DcqXP:u_XXcdlbjnnaeemkkkgk-k,,MML֮5Z+Ij4BHu666vvJVfdtc^Gиo3|zvn>%<"rhtNh 2(D[Ɗ[WEo8ͻwoX٫[C(Ѳd 8h@1 +_b}ab͚CTĨ]f ]@I֬!IjRZ^GЬo58z-)9N90#2I()doXw'Օ䋣oGheMV(DcqXb Wޫ&0:"}oNbhtm۶]Snܾ{& -ęNL@MUEn%"=pCŷ3r @1 +P (FV/ tc^GРoVʁ.)SE M5B"-$qؾE& }|{oXٟ^k,˿4I.+pn8h@1 +PƊ>+jI,+6tA_L;x*^桐x2ݟczuZ8h {hwk$o,_}D$;~|%$$~RH7B_,6: Y7hQEvz`WYHOWSMZwYs(DcqXb@4VYK`Y NSeQIV dQPͻ*t3 B\lrPdP޷+wOi9+*Ig |.KKrDmQg7iQEv{$O'_,. 8h@1 +zV5 `Y Ldx`Z8h 1~lWP޷)^r:ɿ4;U8!ZT?Fh87Yb@4V(Dci,O6.4;U(Kcf@tpWP޷Ǘ .uee^h+|Q_tz 8h@1 +PL\,o кhn]~zqSQ Ʒy B<9s`WP޷%?~G+.v*#ז}|?m;sZwYs(DcqXb@4V\+WZzUy ܲf:MJ VKLA[W -mZ-bG;#"DU,cnf@x15pFԫI0WKlXo?<+Qö$GnFO 0ꂬ- 8h@1 +zU YXXX$,--IQniE&TL`lllDXK02,+6.ZNJ܃. |%Q&t3 B;ڼJԫI0᫵kt+ gm([|,nFԵo- 8h@1 +F&6otttrrrvvvqvrrqF9I%3 ɔvۯ[oggoo`o$䯝u,-,̭V>A+E(χg}g/_sszf5Җ}|mZ,vQ>3{q⻇Do?551uw3-E{93ZZL/=QoKU,MV(DcqXgV52wpqCf _2m67mn[ݶnݶ]2I2y&ggn[ط5:|ht W78гE'Äo кh7t9 L?t3 BުbQ&ۻV洢ΰǧhJibϴ2u3k+wմ&+P 8hbFv.[툌OOJJLOfDFGDGaaa$ %YXh?_-Ѝ)*'?N+J^߹NAˑ 1bCq߳ªwNIIf|-ih{_(mSmDOV uF:Nw:$r@׏/ r8h 73.MɷmhE/=u~;#$$B?>_|)$3j4FIWV-8/S7!qWFk߯CdqXb@4VM(ش$N'-[\];{Nݹ?< ,&#:&$H*1C#z\6m"14:.+H*KP5VNn^!Q1)YٹE99Y99$LOOOLJNKMKLHNJJMINMNJNNNINJLOH$yRB\LȈ~n[ƔmO򼭤,_"٧Oirb6ĝw%˓&zv%!nlBgK%qt3 B%.Mɷ=;ZQ}lvԖ8wQHH={~c:!_SR"U?0627nf:9ZdqXb@4V+jժmu ffmt\V>UX\*%/#q/o:{ M"}WfMw&WTVVdg윜̬̌lf$DŽp[ط݃\Ƿ4͕bv~QɟvyӝB.{%hŊHrmf"ѓUa·lh]?m55Ѷ^uq|ܷVWOmXoK/pn8h@1 +PƊv=*:̼̹Eœ7?)?ʁó?+ bimG'c#|[mLJz^QaaQAAQQqiqA^fjJbRJrRr;ӒR323ӒԔĸظĔԴ̬}=mv=Gfǚ u&d4yDbg^Eau\8h@1 +PƊKIMlierܹ7:vW -mff'6=3kt|Ȉ,P]W?1urmc&Da`djn˦m^޾>n[]6_ogkgkckcemmemccgar,6np_/Ez{r[\]=<||}6;o]ginbB7XVhз%߼3u^gUr n{IKGgJ9ЮhU3WDk|sw,8VYΰDU hK?+^1GzDn, %}c}"Rh-W3 +P ϊ\m`hC $"]4126653\geh-)Z 2`Ѡo+OzfXTtLШ=ށaa{hOk`7" f@4zѤ? J(Nյm,5nhGT_V*ԅobA.KBI6pw\.jDcqXb@4VY+WIXCC5k%~UV\IQ0YERg͚FkO]ZZR.XV,oKq HKR+ݡx|7%V )  GdZX]$O Inˈ>.jY,$#BcL퓉ޤh;j Ph[ڍ{#ɱtͲbfFTE>44ZH-K!rcI(&VNk7pXb@4VVL\%!'Ȋ>++EXV,o50֝Emi7ve&S7+HO|8-Jhh uY]ƒPҷM}>8op 8h@1 +V8tce}ۨk׳sI.[?oKKIBB̀hWѩvU/֖ӊ݌]HrCμ9UB[-$򍲄@lɞ(};=*B<"jY$O 6TѢlݢmi7hSKoL@Ct_+ϦuGkE먨EadJk7pXb@4VŨ<y iYגSIOPc|eE[r5RNjt3tA ߄WH|tWԟ8+i 8P1uN-<`f9 tpZ]/pFԱID+ΪcduZK- 8h|1I. n m G~6y[G},N?zrEX7>SL^-ΡE5 Z鱐dxEgՏ|C ؙC&XwqV2->N8-ږvcmou1ݿy0u;BCU1'Emdi- +P (FVKF8tc^GРo{pY lxu`xνngɀ ZR(L޼z8ZgS;fh]RDnQuZ3KZKMԕWU}&VņG}cgpBsݿy0u3ޫ*EʁˑEm`FeQmZK- 8h|1Qء96(ھ꒩^5<6qZTq U^}X rǦZjhSɷm#hQqrAѶg;O7nvbo3pgE^{ ++$mRJʻZ.\L,g q_Hv5f\G$8wo8h@1 +_b}ad͚5kD2c1YO I堍FFk: AN^j.|[0-viPg,A7@D|+rK{gZKM,'oBn].?(ږv=̓o3pA*E^MBIsgf;ZKхΪ15'lϔql6E@}ȅ&wcjP2.=tyz5NI?6eͼ w4:3U;Lz-`C8N}pDשÃ-A7@뢭\aGT<7J(8c7-&3~Rԟ`mG/>TKcݭwݸtgݿy0uK'=*Jhh ulҾmF׫| oTDn/E@G[2yspnѩPcc򮙉%?rvd=ՙxᙞ ip$[wʤ 8rG1Ȏ"8&E~z~gouK'wE5Z`ںᷪygm"!o;rQ#C}|2-}FsNe¼OOMBHIz_QA[*ƑgGhpisV1;<Ӛ& '2t?ܮ~V\ɾM>+yw[8ؾ[}iQ̓nƁE[kj^=*m!gpZNM t>,B0m'CW5ֈ8ō`fctW44Z(Z&$m˻m] ʬ@Gѫ“i%MV(DcQ/,Z9nWPP\ZRR__,Ir ss2srs232SR233RS$njIb#C|<<Ƥ5N)kIHCC鏟w89t<@orwG:TبM;fzgΛgwuHGXsWG%iN wf]`@:5̮&{aJͰg)~Vعe|xSI>X*Lb2N6ƂCoam/=-NyqHNZWquLl*zf۲#S:Ng!|/Gw3*Dnm~;=BoLzK B]Tt?K.jN ůz7iI}(DcqXb 7mu_\\ZVZQUUP__[YYVRQYQSU^V\@(*+/,/.-)*-+)(.*%EEyZpdqXb@E031(3EH4To%$e9-dGoD)H^ed쒊ʪ꺺]{w7TUVVWTWWWUʪ JKJ%Ը/,.*.LK  m%tք%qU>3;Sn!6js:)@{*s*UfK@xuE(IVg{VvU`9?=yPbR;9|tIK+©jT{4I?5&/9X4mY^Go `a_߫ 4WHH*YQ\'A7@뢭۸=U|#=YrP? v:4qU^m*mK[t]>{X|1vFPCcsEmΩQ'ZNpm7\͢O.ݏypdqXb@E8wox_?m!3B&kɔ=L $1.D] 6\=E$gVUVUWVn(-PR]XTXZRP\\XZZR^QR\O-ϑ/qs r3Swzэ-n7c ٙr ).Qkʹf=5* *v6oy))Q{?4eQ+ 0wuV\ƱKIC;l'%Ym%cʾ-Aä96XEۺwJS"/$_;JOqul7L!fqb!-&Lg!|-ǯmi7+ ɛ~`fzZW%oh~[,Q&o+*d{ -hjfje/%urK@1 +P]gt>\B(#IHU|cqfQ{mtzm!a Y%%ťeeŅ驩i)q;cRS2233rr2SS2$&&$&&&''gdfg'Eymsw[܄ujaGg iVLTب5[άd֞( aЃ&Cqbp CbʼaL%v5=ZgcL^ޑU x|6g}_-&F:ʡ +yES- }OFx?LOL=*y:"|[h[?>>!!6&:2"22BTXpphh(ڹsg\|BrJJjR|\Tv?OwM~˄xQ:zc͑Zeٙr \Q;H/l1vohsDZ?m!5vGHHtÖ&DW6w?NwQàquR^(9 r.X~ەVӊ*#@2ՅY&Rcf375\f,-cQj+&[-V>5XG+ڽ۸=}[W}(DcqFoEoHhyUVU ;8]MGO~? p`Zhxr|Vxޖ>0<]X4R: nxrֽGdƣ'N ͼQoݱkt3.ZF&s5 ӊ*Cz7z,|_|I몉E/x0]Br.w3;uz}ۆFͣU ԃ,o[~偹FZT_7ܤuoVҺMV(D[7МoK  553kʡ3fZ{om ֝=We 6XE{ugl} Jo{}wy˹(69mӫmk tꤦvQɷ-8{͏W{5sHh*z]㮵+apdqXb@ƊB[#jme4NݹsÃ4 HDZO@`Y$zcWZ%me_WP$o |[h_LO9|YmE.ѿqu OeTl (ZەxNԟ`msZF|BiQ}EW3´CWD _䞾#0o8``uMQNCEkKDQ~4ZtYnD[F*?Sֈ}[o `헷MXpW]3#Wb.jt3.Zɥi"ۂ5o[K⹩@շm]BcE᭾vVt!]>s\f^n[>>)jdB]m8#B0G숥E^v% z]"U`?vpdq*Zdp?}pw2_/E{DׅխOheM!Fk+*ڿ}gtREݽ{|`0#A7@Ut?K.QpjEemc+ sZZ+}^]ዧNh{9廙^UV=+b]Tړ,o{=rY>VF{5lm.|v;.0o8`-/-hWIV(3E|oW]Ӌ۴݌{;|s-( |[heȁSݳt݌V'>_d[F鱍iE*̺;xYԓej4kgE[х;^sQf暨ǯ.3S]}\ԟ`mu$(\X,yCׅ/ڶgҺMV,RJ*3W݌?> -`Uū"/.K[ݳbzRmqE nƁE~#-X#ĠچQUCԓe -NxJ]3G[^En?Sh"=∨? &^I+ڽe-#z]"%0apdq*ڹ#{N.|O5 r`w`dυuet/5 mzDl h৊ʻsp7-gn>.gϷZ~c ."VoGw+V{)~@r.w]e*x:GPU}_&LO|nZKa/zfz[ZNl O8zU7o5 @1D[]vRqGg6G9xK nƁvEubPdXpDxތ޽ŲhKƃ޳B"W5J˶_;{P޷m>~HzӛK2_?{9١EUW"v,ŷY+:Kԟ`mOx}x!$L s!Y/ @W!s/-ՏI%&Go] RȮM&zET \lB\,$$D$EGz^*B5//)jU|ivT>5V>!:IdZhIP:K#K|dQk]~n.~o7aFυD*p';9V=Ct_{jof]k Bhܷ]jU=ZXn{vv$4j J9`07_l#Ug:5yrot/5 58N-_.ߝ}rwN\m#ΈxJHH(jjj@Ho]#7ϴ_g;z:όtf%οٳW޴Ƿʡ|7;VQYՃ1;6t+W5\{O/d(Hře!k-vtﭾ6:gE/1 ?~us(:4SebkO^t #|pnKEhw{ZV#AHH}B1=$p(Vuobc=Ӣ &Ѿ9xFtΪXQH{_Ëi!!}"{?_t6[;r[ǿ?XW&2¹{3-g.mٶw:Q}0D5k ʡ|7k_?r񔨬z_BT(݆`fmjm}<էtk]ͽ1:IZ\ԣ^nP#)(ZN$m,?"zEt!/nkjļ;Q凓uZKb މ^zM.+Dzmrą{iuGu9P_)$ ߺj{u +$|[f}-ϵ]<|Lm=B<[Ndz/?)gLʡ|7;wd`IQYޔX QXkb&8V,o{gXw98/=&l݄p 7: ɡvAte& 25^]}ͽt/cIDAT}E΂ߌ=Ǘ;=Y ,x3EFU4ZwY$~|U!:gU{ \u<*5ޘn޾hj|}wTgdYrժU64l?ٷU/'$.IB!!o%$ IMWeE.6^h#6mn++{ZKb;bSK;EzӺ E#W*Ʃ%$SQk&lzJG!ZNLW_搨Bn/>|,omDxѳ~D[ j*qWY|A7@eV'm=R>yG^NMYQym;Gn>/]ܙ4XӋ;.t_PtrJ #ѵ|"ީ󁺞î 狧Wc^WlvEΩQM5.3 RԲP _# 0%m::;`ieEZhr$ڽ۷n<#U\t截_Hq]"J5}4勓S_m5M] -ɷ=[kKdo<or(ͦzڏU= wVdm v= nz,X}_}ަ%#1rn*rrDbdl;}hI(| w6EIǴVbCM_?OҿBǗB/wO>}ad`Xm JINы!zK{'ZN*[=_+ٙVؘyb]V(/=MbRDnBWD+(Y'>OjSQ([_H뷏l|^Lsao Y Vg&Ѿ1qcJ-{wGWܻ=9gFN-Y$˶l+HebŜss3@s9)'iqGݢA ZgqmՅ]P}ԴNOM ŒuڅxlR*k0REY|HVms ScH9wlvMr i YQQb#jSW& 98]TOE2#k~=0Y~ 8^w#jUQ3?U=[%wy9,{"Bӣo}Tg{ؙ|~~0g>ǣ7/ya6P]KU]=92C0lsOd*o쵿?L'@vc00 } 6LmUCLy;äxm͛5c<]3?ؖEu1姠1ڂ]G]Id} H)z~u޶ZVy{b]GHuZ]MWL:zI;m]'J439JUSUIVeaVpQlW;R3y`íIk;\/jv*n@+Sy-цٕAsuYqaT0-b o XUN7ޫ3Q3\[yI5q4a:-Cq<ZUP=.*T+Ը@*o466V"f׶Z G} .&XfZ)9jT3bC>ÇN{hHfdUwFr rr˱WRZbZflȚիHC9~o&+NS_KRQ#HuZyKu ; >WXz]̄>c^_1T9Fb `j*Uy&e'ڱ=KM ;yn־]_O] -`V9̠Jkg880|ݍYM$ %f,0gqHma> lӐ`j>#2HfdUoY_h܂M>4^D̎姠Q^??:IU:u1<`1v7ErP'X;;-z,Hֻj),Sw\aTGcB >t LiVRMŲ*o[UcеTi^>xh;#?B61dKHONR_b㟟D^+VO,(]k:K7l؈ \ΜU4U$d9z =~Be Kc=mv_eP;yaôԲ\Xooɫ5 G'#|ۤD a|a_y_٩]bd֢*jP Y1ysZQQr*i ٭ކ sRrQRXC!p}FNӪGP*XK=1֢ln k9qFZ.~G3q\KTc~ "-E},׵L_?/Sx{ZEjv: / ON۰~ݟmP#;4QN [UTS&EMIk湘B_(vR/gh-2%0E-Pۮ\219?)}߁Fo_իWDy+V["=Zлچ"/8o_|լPk'xvf˾ FH6|K[€Nl ǰdkYi?ݟ fnz<־ufP["0{|J]٩AC=%Ԡ@6od$3.GN驦 G]:iTi hv(K>Î3**Y J3Nk)fZub蟟HLS؈=wUC[h">o4u7Shdd@2X/Sw8ª_[`>۶H-HON$F"g$`cA 8TȖtf6?O ;1^3:~ɑm  S"o+/Wg༭_@`u6!*pժՕ2ED~SG%Qqw줮y[S3;\<2ڟ2b сږ}'I]˂UNTI:(U@|  MjGDaa_ww٩X-b4jP Ymmn*6jU'`y=m@U]59e7>î ir*YNH2Dd,#UP{;j-=Ӣ,? WޮvNX͆VNtookWsԣClik +)R*YMNjbJJPF\ZEǯtob$OA+TLU1νˤK~:-VO#aդ:cֽQPZ7~`<ޑ2 Bf Mv.cU S~gUNڼ;H[X56Wx!6cltKdo^GKbEN6.?pЄI5=~ocz,El{-mmCsJڙSaYgYr]IHZ,wڋ/'3e G ii޲JsuGg"!0{T#|tn*%TVXm~\NkVZ{#컹`oZRf֔>AψKIKhU6G7@kwבW^6xbt+!MH?s *wT*Vpb>oOLkTZɒZRclSHu]/{w!RNKn6.ⳬ#Z_{3bdd,Q>5sdDaa_Eh&w;=U򖷍 tS#ڼF!95+̍BvaٌV,nG^宪:Yه`8w!ALE2#%%F*a`/wް- dwXZ/D*S걡jFAH2c6*u(S"\A/k["MN̤Vn[#y5mFc>:xcgG.vֆaX]:)c*_O QTT4>jMȫ8]@u ;Viک06oۢ*K "X56پϷ)D1fdl.Җ!okF׺E]NToxF~zy@xKML XN{sڟNeQ'3Ui-‡'!s}cI5vhy9oypu5"۪&Gֽa>9ZF#M!m50뽱?OZ6*dsET$3*o[%PE7f*VV|Ե<~/Q噫`ib7ύ)fi&{ZMFcvtZك,䖥v*]xwsUb=@iƭ^b (˨yI|/-ŢѾS!Th-o[]%{J'T1#,|5ՓH yۓ]TZgvozmBu#5oqmh Zr嚵k#c[ۃBÖ̹F]~ɠ4T9kYiEfr `CxþNky0).b=Ԉ6o[-ܼ8܈ ީP\V,'|ܩj"'M]A!NZrUUNEIuMO?cVVVE5bf[Q 3DJJ˩gh19Yl}oRسV]MQRcB/%KࢫU/y@rH:"D..\,-# \Si#k)c ΊUcG S8%Bt!/Ļm}<ֱl`: Y5k ? Vtt#)T3ΣPy[f}[CRhfy[;S; +x]7˝uNe'3UZ5B=FKgI[mŒ/ۥ)˕"mRM*côpӈRsi/rq?.(-.3S#ڼBVygbM[w!p "Zռ]V̻yi 3vF0\L,?I3## 5rNR*W΍Gx=KȕR3'%K.R`:"΃{4-Qc:t_ U/>Mu)<Ljy(Er_~=;LW/ӇSÝQl<}4~=/gŜe |YI>L25"UI6U_Ći]!- VM\1Dj|qWn*D1$A Ub#vA>bH{ W0wgTNX mw{dv_Ќ˝v'柡Ee%\}o7V[b0㑸`N$h-f+\\ 3ϺN܎N{m0/yW~7Q"SQZEeO6o+7 m'"}r 6L2-tiuBQIzaګ+љ'[Z*Jl& WR'ҩ`fdUv~JRNeNMMd&B5 bY56;urIUja4 =wȹ|>CUjҫ{zֿTjcG ;%>cNS1}U~qUc3X޻5_u#Tʸ Kai8gTͽMCR|\'VDR-DTX mɻ4QkM[,wڥKΎRg2ܕ_R^O,ԥrhBf ,?ǑOcדYl<&[>}4դ+ Ԩgś_FX56cn>=!}{o''L!~>IG_ddeU sY,oqo&SƯbr3ϋFX m#?64B;omNvoz:BsYM]GjKfN\4"QNbTt ٛ~7?hmnRdiZpQEB(ՁNfLU%hPMŲjl(YRB_!U׾y%(;c\jt~oSRcB{]ࢣ :R|FDy0?/}4~\람cW/x\Fs 6-dļ UEUBU|˂csBy~3DDb HNFbB")LIzdžS43s(Tf_ekA`1' ONT`y#5˝tkb9K9yY9fei]@ +7IHQlGp6SYO>"f<2ѪK{UUS'ZOGoW=)lpgT^Uլ7jQ̵ cy3(!AkжWI6*Ev񢺃].i" &Cݩ_$Fj;Ǩ"MhtX0,Xލe'{|ͼOO{y=}4CulILmyۄ䶮^RRj'{b8!ALͯʯvmNzcVƁf`WmϕHG|(O<*jjJ{ܼ䡃ÌGN ,Vc ye@TiVR&T,q۟%g}MnjדRc6lPovGL-qhs ݋YԴtpep-dz,зoć|lD䞉̣ggw5Pl_W T0-b5o}N}mXѭPivC^=1@>& 嚦}q9ibxbykXZ[T~lHuM@+. Zl+u=RUNePKI=#^Ì/voE+,ԡaG}xധJ%muQ곳Suw5Y+mEc~K>JKK T/W%RuFX̲mϜ;oo:rfժEbRM^=1@׌Gͯbb!hRi2d띆f%6J4 XlZB*Twafdխ5Lv:)"{v3r|\ %T;:m nTBV٨uO vMPcyQO񕷝kh,z_S, wkE!-B{01]𥺘y[Иc]T]Y WAu9Ǔ=e%%Ծ9yx<2&g}:kXۛ#Rchȩ:B_[&ه%EߑYHQaDՔ5Ee^c]:iTc w Fwjj2FX̲mM9~⤾~ ۖ .l۾#:(T$1X:a .qYeIio*_d,UJZC 35ЧH>"f<=ҬASJV#!U/ŽN;[TGu1;; 곳SnVst JQ]C<[ez2szfv7K5XP3~ ߰0|<h*Ey)?& ц3T3M,[ÝT A?H=*JaY;6>:MʪM"ΛCÝMT3mRc$0#'>DVZ+-{2Q M=.R%J-,XFH|fLMZuMCVTav)ґJmNlmjoB* 3iH؋o񈾲@QI3VFlFT+X0O㊙+2@ڴu7n_5G;r.ۃ,VUGXmprYho<ϋjp{c'=Cqfn`iq$g*Ea{W][yF*ꄠ樄d'39Ԏ_ wTHtQ#jb Uxz 6L ּ]?7RB}aRHTX|#˻>ģю@1b)wH+>r ϻM$>lcs]~em|BkgE;J;Mu myە+W%4tt+7`'P`kyjreh'˝6PO‘J.iZ1ƹ^||0y8ꘉb5\Mɯf(_06|J€lI{S蚮 nnTRNsrIwffS0f"oN_;"{FӃ`Y5`SRRbώ/qIxD0xWsm [kF;rrDTk<\ l֎=Wè]8yFU|#7?3ݳ0- |]X‹_ܞFU(TmK,?Ҹ"9Auwyh>8}1_vz4S^*vGRDbf Ym;vuaM}{JJ f(62Ӄmu]zl|3?Φ=ƣ^l }>;\,Ez2C"OڪH$/y[IEYw:!^W%>n+o{g/,څVb_HL~Pîm[ :vV1**sRQAk moڳD OZ)v޻)H5W1~m؈Mb#H}&Ln Y#2c[zF/XX mƉs1NVF1;ZiᨲX7I|t,1kXa^`Wx•T3Z/B9v. ;`B$S FQʕzLM1#yooG~y8YY+PPmJd:#3+-=%)"o2%X B]>0m% >9=dˏ4T/SKIE} ho]FdPE٢C=*{;]/ǷG6L`lʠwe:fD(*, ݸ"9NͯNW6X'cUUU<-=@qa˝ *Z8W5GGQd ƌXm4?tڝ<.ꚨ6 D ZU7edfSsԏwFVzX`y?/yہ:]TV*zvj-D0lʦvl0^ Wpۊkk{uTmK,?҈œ$w-:L!B}ܻ2[#d!.Cl&oۢ*K "Q哦-$(EJCaE/XX mWANo~Lr}ukRBQIOCHOX %G}'==sd:`⨾ZE鈏;-?=[t2$.% ͤB.y8:t -*RU}'6m@PRrc6T-uO.bznܵ'3Ee+Ws6LZˍ*#鸪}-5aCfh́uk 'ֿqY7"X>6'Ur!N9x<ח?RD܍j/ ڢ"~y~eyE^~m _>8~; _TV!R-HW?{kr 9SHv#"递d!#|бx~Ծ&o[])(ቓ!gݭe߼m^#_JՕz_ o ڍ`y>`j~eu'\I &3A\XR,S3Z)cAUPk†i!æbbwl{o'DYĸ8UٱX8 ӭ3&=X2bC=z7x: k6n_Nu,w;奔nC5S']06̺ҊRj&,s[_ r~vTܛy:'E0SGe-LLl0\lcM'\ӫH,WYi:#1!Q*𸫦m&o[;Ҭ&Q"Q$j\ 7o;ӢY} *(VuRy[@nDf?;Eͯ]^cp'2Hy?ߟ+o{'Z|#H>&l g]҈K7*q!?MRꀉ a'>"2$S{aOOXb|<{7j6 1W'#}^r%&cp,8W[o}5$Ov4S]l*擩>qI '{¨VFhmFRp6Yf9ڏ!!qNaүŗWF\xv.&tLHS`& l|\-G}8/Vjc^Z?fDf[)K/fљ LvWq|c!hwQm\nNf&PLU%3a@Vz?E>-gvBIK.yɻX u_ B. +B efdִ%H4#ElcVT(t=غe3 >y1|Ŧ|l>}4 D|>qXf:U@څ0;{&*/+gNa=9gBC=8Ǿ!}W<_ȝ_LDzr,dzzFw Hy'> lp{@EG@d(cT&e*H՜UP+kv]L kx{}X/(8Jo-HyۉVݙ=dwGwưQd/6~-*԰(G=I6y[@>|t謇HKͯu*4bR9XwlѴ`~?oy@i>"myFgBSiG <4NAOg\N̙I~7V}lBvb9K5\¿u%*JC}hXRme֬ͻm%'Tc~?Рn16VV٤v0I*tPp6Y>%v+bwGż+:&P{vi[`?numnQYeM=uUYSWRN ɑzYnݿ١IIirDHIIc o$'SFQ~G +NNLm:W8R4t#Qy[@>:}5CIͯu/=Tmc,tڶ=?%wF^N9ԽOv ^Ykrys˨&R5`UNɪS}WC=3T1J ***|ƒE rn-$:j6 zAmŅrym;UۊjípyC[X=J6DFu FֆY~j&(K+_#̙Fa_ (HzwqR oey񕕤ɣ-)EUhʔJ/$GJ wj%HccH%¹:l0o;񶖦R F,˧C1I)԰"Q^h;i}}9<@>s1 ͩFMd/6Ta_K-6L u罂q:3yj9tܲTp%av#tXE;6tLg̫Hg 녵U/=2} uQ?Vq#\=U? %]Z*l')șD,{tܢ[s՞'o*[*H8 WPW S;3|`kY<\ox;B奥OQmf#kì;ܿkY5H@AOu k.ng`#6c-|oal J>;#!mC_[&~PEM r,dBM*긫DOΤHy۠k⌄$&꒜DYY B@ۧEWu旔SnIJ| h*{R$u_hDb_ o Zoݝ)lcôҍ9hNVhT#Mv7aըDW#6kaZ`+/?kPb4X贓85C M xIROff^W3.H9ZlxtX|\16WSd]ꀉB5cǺ<SPM[wq#R79*e-5rdwsL ,Y2=[ LQBf^EZM 1Tw:;Ȕ웷Ev48u5bSY86 uPW8/_љV#kLWvʪ)̓p!̙[:֚k) Hz^30(S(Fnem@LN3֍DeCTOStb2;$kOA2;zrܝ.T,^6X ǻ#/,6inddr :)g#1RTIfaôLFB=ITvʌm.G\H.6c3:!e?tɛj6;DS U?#aGS{fj O ē~[S`mUST^`y4?˨aĔm'Rl|zمg _YƏv?rS'h5Vn6bcY B@3*yI\ua*BVu-y?k: ]Ծ,o˗bC4KX5vP#n+biur&my[+xc ه݌l`t`zf65Y#_O6̽rtN |fxQkޖVl|3;ôD6uc[蓊N]M3hkeߟNRiɨa^Rm5)S˙B̫:^U:VE-2C+ruZٹR]hgCv…甬==:C}y?sJ SBo[HNϤjF坉#̙oNR=Z#yTm!!m_*><.=0MK"Qr,e o(L:H fZ(2j P%w;Z**\#LVU<@ T9*+zn(^_4ԖX贐STSL4@JMK S 3E4oaokKAFf֯_W(ʞoSg4JyA]ЉzćU*(˕F}eGcrW^22gz[%o],rCM)iTY(>9 ]F/Q5y{3cϜ 'P_Ju,9ю Js!Qo=RPP@ψEpŨ1T#j` zld G:hABpo3sN)C_hԧ_ӓ_S=Z=M q `[Hy[!~dKNbhWw{UfoC=0[TJ{ڮ%4b"]7mJTP,.yd jZp45Xhi1é]EEbM(L$,V,;if-Nz<++zYZN$]4ԖXؔ[c}TSWbqj|~ onLh.+-=c/gzH?Ocl 1oIC@\jXKfh-jԫkk,i)scoI{@Ma#B3F[{) tNIݞ"74٘E5n,\Y) R{̘sET±YZRl>}7Rf_Nd/0k*t*z 6{llUSӽ@@>55-==Xouk?dŊ/?JVH_WW 8au? 6H@ b)dJ[9z$ԕ/njLJuk^^C<ˇ)v n'pfK/K, m0=BbZ|#hj<@q y[ay[ay[ay[ay[ay[ay[ay[ay+V'ѝ_$^v-Ɣ264yx"ͽm\\ZaF3`ۺz KQ'nSi =r[f!L?y O\λ>#J#y7Xb tJͅ۶oG__AW}m ?Бz MoX44"h-i=QhE-z%ccp;6p#5B*'84xWiԤtx8٣Q1W T1>zlpBComf6l؈DgޖӜ,`ǖ;)ۿT:0=_B8)aj.Qܦm0GGJZ x࠱ !%khi':8̹S.gVZLT_rZeW}]#`籵ᗨ; v):\r9tu~If_'B"Ip4.!8<܋l&K!KN;j\Μ]reBRD$/;v1= `<o@Wp)x8J.sS"з?Lfm=FtpRh?΁%N3j uC[S-n`;v;azcc!瀝rrIp4\Bqy, 8]QƦeaU9:6#/8 <\7Ư: ܿ͜,2y99B%n,ss(ulX{iO%o{ xm۾}ժ) fÆx>t?۵{od g߼yڵEbqyo:d` can be configured to return a 200 OK response, by default not enabled. [#6](https://github.com/jonnenauha/prometheus_varnish_exporter/pull/6) * Releases from now on are built with go 1.7.3 1.0 === * First official release prometheus_varnish_exporter-1.2/LICENSE000066400000000000000000000020661301640764400202470ustar00rootroot00000000000000The MIT License (MIT) Copyright (c) 2016 Jonne Nauha Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. prometheus_varnish_exporter-1.2/README.md000066400000000000000000000067201301640764400205220ustar00rootroot00000000000000[![Build Status](https://travis-ci.org/jonnenauha/prometheus_varnish_exporter.svg?branch=master)](https://travis-ci.org/jonnenauha/prometheus_varnish_exporter) # Varnish exporter for Prometheus ![Grafana example](.github/grafana.png) Scrapes the `varnishstat -j` JSON output on each Prometheus collect and exposes all reported metrics. Metrics with multiple backends or varnish defined identifiers (e.g. `VBE.*.happy SMA.*.c_bytes LCK.*.creat`) and other metrics with similar structure (e.g. `MAIN.fetch_*`) are combined under a single metric name with distinguishable labels. Vanish naming conventions are preserved as much as possible to be familiar to Varnish users when building queries, while at the same time trying to following Prometheus conventions like lower casing and using `_` separators. Handles runtime Varnish changes like adding new backends via vlc reload. Removed backends are reported by `varnishstat` until Varnish is restarted. Advanced users can use `-n -N`, they are passed to `varnishstat`. Tested to work against Varnish 4.1.0, 4.0.3 and 3.0.5. Missing category groupings in 3.x like `MAIN.` are detected and added automatically for label names to be consistent across versions, assuming of course that the Varnish project does not remove/change the stats. I won't make any backwards compatibility promises at this point. Your built queries can break on new versions if metric names or labels are refined. If you find bugs or have feature requests feel free to create issues or send PRs. # Installing and running You can find the latest binary releases for linux, darwin, windows, freebsd, openbsd and netbsd from the [github releases page](https://github.com/jonnenauha/prometheus_varnish_exporter/releases). See `prometheus_varnish_exporter -h` for available options. To test that `varnishstat` is found on the host machine and to preview all exported metrics run prometheus_varnish_exporter -test # Grafana examples Here are some of the queries that I used to create Grafana dashboards with Prometheus data exported by this exporter. I am fairly new to Prometheus so these examples might be not be optimal, but will get you started. If you are monitoring multiple Varnish instances, you need make the queries more detailed with Prometheus label selectors. I'd be interested in Grafana dahsboard .json exports or Prometheus queries you make with this exporter. Perhaps we could make a wiki page of examples and premade generic dashboards. // Frontend requests irate(varnish_main_client_req[5m]) // Frontend requests irate(varnish_main_backend_req[5m]) // Network bytes frontend irate(varnish_main_s_resp_hdrbytes[5m]) + irate(varnish_main_s_resp_bodybytes[5m]) // Network bytes per backend sum by (backend) keep_common (irate(varnish_backend_beresp_hdrbytes[5m]) + irate(varnish_backend_beresp_bodybytes[5m])) // Free memory (malloc allocator) varnish_sma_g_space{type="s0"} # Build Use `go build` or `./build.sh` for cross compilation. # Docker notes Building a docker image would not be useful for this application. It operates by executing the `varnishstat` tool. This executable is of course not available inside the exporters container. We could install and run Varnish inside the same container, but this would make little sense and be harder to manage. I do not know of a way to get the varnish stats over the network (--net="host" could be used to talk to it). If you have more info on this, please open an issue. prometheus_varnish_exporter-1.2/build.sh000077500000000000000000000033371301640764400207020ustar00rootroot00000000000000#!/bin/bash set -e rm -rf bin mkdir -p bin/release VERSION=$1 VERSION_HASH="$(git rev-parse --short HEAD)" VERSION_DATE="$(date -u '+%d.%m.%Y %H:%M:%S')" echo -e "\nVERSION=$VERSION" echo "VERSION_HASH=$VERSION_HASH" echo "VERSION_DATE=$VERSION_DATE" if [ -z "$VERSION" ]; then echo "Error: First argument must be release version" exit 1 fi for goos in linux darwin windows freebsd openbsd netbsd ; do for goarch in amd64 386; do # path outdir="bin/$goos/$goarch" path="$outdir/prometheus_varnish_exporter" if [ $goos = windows ] ; then path=$path.exe fi mkdir -p $outdir cp LICENSE CHANGELOG.md README.md $outdir/ # build echo -e "\nBuilding $goos/$goarch" GOOS=$goos GOARCH=$goarch go build -o $path -ldflags "-X 'main.Version=$VERSION' -X 'main.VersionHash=$VERSION_HASH' -X 'main.VersionDate=$VERSION_DATE'" echo " > `du -hc $path | awk 'NR==1{print $1;}'` `file $path`" # compress (for unique filenames to github release files) if [ $goos = windows ] ; then zip -rjX ./bin/release/$goos-$goarch.zip ./$outdir/ > /dev/null 2>&1 else tar -C ./$outdir/ -cvzf ./bin/release/$goos-$goarch.tar.gz . > /dev/null 2>&1 fi done done go env > .goenv source .goenv rm .goenv echo -e "\nRelease done: $(./bin/$GOOS/$GOARCH/prometheus_varnish_exporter --version)" for goos in linux darwin windows freebsd openbsd netbsd ; do for goarch in amd64 386; do path=bin/release/$goos-$goarch.tar.gz if [ $goos = windows ] ; then path=bin/release/$goos-$goarch.zip fi echo " > `du -hc $path | awk 'NR==1{print $1;}'` $path" done done prometheus_varnish_exporter-1.2/main.go000066400000000000000000000122601301640764400205120ustar00rootroot00000000000000package main import ( "encoding/json" "flag" "fmt" "log" "net/http" "os" "time" "github.com/prometheus/client_golang/prometheus" ) var ( ApplicationName = "prometheus_varnish_exporter" Version string VersionHash string VersionDate string PrometheusExporter = NewPrometheusExporter() VarnishVersion = NewVarnishVersion() StartParams = &startParams{ ListenAddress: ":9131", // Reserved and publicly announced at https://github.com/prometheus/prometheus/wiki/Default-port-allocations Path: "/metrics", Params: &varnishstatParams{}, } logger *log.Logger ) type startParams struct { ListenAddress string Path string HealthPath string Params *varnishstatParams Verbose bool Test bool Raw bool } type varnishstatParams struct { Instance string VSM string } func (p *varnishstatParams) isEmpty() bool { return p.Instance == "" && p.VSM == "" } func (p *varnishstatParams) make() (params []string) { // -n if p.Instance != "" { params = append(params, "-n", p.Instance) } // -N is not supported by 3.x if p.VSM != "" && VarnishVersion != nil && VarnishVersion.Major >= 4 { params = append(params, "-N", p.VSM) } return params } func init() { // prometheus conventions flag.StringVar(&StartParams.ListenAddress, "web.listen-address", StartParams.ListenAddress, "Address on which to expose metrics and web interface.") flag.StringVar(&StartParams.Path, "web.telemetry-path", StartParams.Path, "Path under which to expose metrics.") flag.StringVar(&StartParams.HealthPath, "web.health-path", StartParams.HealthPath, "Path under which to expose healthcheck. Disabled unless configured.") // varnish flag.StringVar(&StartParams.Params.Instance, "n", StartParams.Params.Instance, "varnishstat -n value.") flag.StringVar(&StartParams.Params.VSM, "N", StartParams.Params.VSM, "varnishstat -N value.") // modes version := false flag.BoolVar(&version, "version", version, "Print version and exit") flag.BoolVar(&StartParams.Verbose, "verbose", StartParams.Verbose, "Verbose logging.") flag.BoolVar(&StartParams.Test, "test", StartParams.Test, "Test varnishstat availability, prints available metrics and exits.") flag.BoolVar(&StartParams.Raw, "raw", StartParams.Test, "Raw stdout logging without timestamps.") flag.Parse() if version { fmt.Printf("%s %s\n", ApplicationName, getVersion(true)) os.Exit(0) } logger = log.New(os.Stdout, "", log.Ldate|log.Ltime) if len(StartParams.Path) == 0 || StartParams.Path[0] != '/' { logFatal("-web.telemetry-path cannot be empty and must start with a slash '/', given %q", StartParams.Path) } if len(StartParams.HealthPath) != 0 && StartParams.HealthPath[0] != '/' { logFatal("-web.health-path must start with a slash '/' if configured, given %q", StartParams.HealthPath) } if StartParams.Path == StartParams.HealthPath { logFatal("-web.telemetry-path and -web.health-path cannot have same value") } } func main() { if b, err := json.MarshalIndent(StartParams, "", " "); err == nil { logInfo("%s %s %s", ApplicationName, getVersion(false), b) } else { logFatal(err.Error()) } // Initialize if err := VarnishVersion.Initialize(); err != nil { logFatal("Varnish version initialize failed: %s", err.Error()) } logInfo("Found varnishstat %s", VarnishVersion) if err := PrometheusExporter.Initialize(); err != nil { logFatal("Prometheus exporter initialize failed: %s", err.Error()) } // Test to verify everything is ok before starting the server { metrics := make(chan prometheus.Metric) go func() { for m := range metrics { if StartParams.Test { logInfo("%s", m.Desc()) } } }() tStart := time.Now() if buf, err := scrapeVarnish(metrics); err != nil { logRaw("\n%s\n", buf.Bytes()) logFatal("Test scrape failed: %s", err.Error()) } close(metrics) logInfo("Test scrape done in %s", time.Now().Sub(tStart)) logRaw("") } if StartParams.Test { return } // Start serving logInfo("Server starting on %s with metrics path %s", StartParams.ListenAddress, StartParams.Path) prometheus.MustRegister(PrometheusExporter) // 400 Bad Request for anything except the configured metrics path, or health if configured. // If you want to make the path obscure to hide it from snooping while still exposing // it to the public web, you don't want to show some "go here instead" message at root etc. if StartParams.Path != "/" { http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusBadRequest) }) } if StartParams.HealthPath != "" { http.HandleFunc(StartParams.HealthPath, func(w http.ResponseWriter, r *http.Request) { // As noted in the "up" metric, needs some way to determine if everything is actually Ok. // For now, this just lets us check that we're accepting connections w.WriteHeader(http.StatusOK) fmt.Fprintln(w, "Ok") }) } // metrics http.Handle(StartParams.Path, prometheus.Handler()) logFatalError(http.ListenAndServe(StartParams.ListenAddress, nil)) } func getVersion(date bool) (version string) { if Version == "" { return "dev" } version = fmt.Sprintf("v%s (%s)", Version, VersionHash) if date { version += " " + VersionDate } return version } prometheus_varnish_exporter-1.2/prometheus.go000066400000000000000000000174061301640764400217700ustar00rootroot00000000000000package main import ( "regexp" "strings" "sync" "time" "github.com/prometheus/client_golang/prometheus" ) const ( exporterNamespace = "varnish" ) // prometheusExporter type prometheusExporter struct { sync.RWMutex up prometheus.Gauge version prometheus.Gauge } func NewPrometheusExporter() *prometheusExporter { return &prometheusExporter{ // @todo varnishstat never fails, even if varnish is not running. // Figure our a reliable way to detect if varnish is running and use that for up. up: prometheus.NewGauge(prometheus.GaugeOpts{ Namespace: exporterNamespace, Name: "up", Help: "Was the last scrape of varnish successful.", }), } } func (pe *prometheusExporter) Initialize() error { pe.version = prometheus.NewGauge(prometheus.GaugeOpts{ Namespace: exporterNamespace, Name: "version", Help: "Varnish version information", ConstLabels: VarnishVersion.Labels(), }) pe.version.Set(1) return nil } // Implements prometheus.Collector func (pe *prometheusExporter) Describe(ch chan<- *prometheus.Desc) { start := time.Now() ch <- pe.up.Desc() ch <- pe.version.Desc() if StartParams.Verbose { logInfo("prometheus.Collector.Describe %s", time.Now().Sub(start)) } } // Implements prometheus.Collector func (pe *prometheusExporter) Collect(ch chan<- prometheus.Metric) { start := time.Now() pe.Lock() defer pe.Unlock() if _, err := scrapeVarnish(ch); err == nil { pe.up.Set(1) } else { logError(err.Error()) pe.up.Set(0) } ch <- pe.up ch <- pe.version if StartParams.Verbose { logInfo("prometheus.Collector.Collect %s", time.Now().Sub(start)) } } // utils type group struct { name string prefixes []string } var ( groups = []group{ group{name: "backend", prefixes: []string{ "vbe.", }}, group{name: "mempool", prefixes: []string{ "mempool.", }}, group{name: "lck", prefixes: []string{ "lck.", }}, group{name: "sma", prefixes: []string{ "sma.", }}, group{name: "mgt", prefixes: []string{ "mgt.", }}, group{name: "main", prefixes: []string{ "main.", }}, } ) type grouping struct { newPrefix string prefix string total string desc string labelKey string } var ( fqGroupPrefixes = []*grouping{ &grouping{ prefix: "main_fetch", total: "main_s_fetch", desc: "Number of fetches", }, &grouping{ newPrefix: "main_sessions", prefix: "main_sess", total: "main_s_sess", desc: "Number of sessions", }, &grouping{ newPrefix: "main_worker_threads", prefix: "main_n_wrk", total: "main_n_wrk", desc: "Number of worker threads", }, &grouping{ newPrefix: "main_bans", prefix: "main_n_ban", total: "main_n_ban", desc: "Number of bans", labelKey: "action", }, } fqNames = map[string]string{ "varnish_lck_colls": "varnish_lock_collisions", "varnish_lck_creat": "varnish_lock_created", "varnish_lck_destroy": "varnish_lock_destroyed", "varnish_lck_locks": "varnish_lock_operations", } fqIdentifiers = map[string]string{ "varnish_lock_collisions": "target", "varnish_lock_created": "target", "varnish_lock_destroyed": "target", "varnish_lock_operations": "target", "varnish_sma_c_bytes": "type", "varnish_sma_c_fail": "type", "varnish_sma_c_freed": "type", "varnish_sma_c_req": "type", "varnish_sma_g_alloc": "type", "varnish_sma_g_bytes": "type", "varnish_sma_g_space": "type", } ) var ( // (prefix:). regexBackendUUID = regexp.MustCompile(`([[0-9A-Za-z]{8}-[0-9A-Za-z]{4}-[0-9A-Za-z]{4}-[89ABab][0-9A-Za-z]{3}-[0-9A-Za-z]{12})(.*)`) // (,(),) regexBackendParen = regexp.MustCompile(`(.*)\((.*)\)`) ) func findLabelValue(name string, keys, values []string) string { for i, key := range keys { if key == name { if i < len(values) { return values[i] } return "" } } return "" } func cleanBackendName(name string) string { name = strings.Trim(name, ".") for _, prefix := range []string{"boot.", "root:"} { if startsWith(name, prefix, caseInsensitive) { name = name[len(prefix):] } } return name } // https://prometheus.io/docs/practices/naming/ func computePrometheusInfo(vName, vGroup, vIdentifier, vDescription string) (name, description string, labelKeys, labelValues []string) { // name and description { fq := strings.ToLower(vName) // Remove unique identifiers from name to group similar metrics by labeling if len(vIdentifier) > 0 { fq = strings.Replace(fq, "."+strings.ToLower(vIdentifier), "", -1) } // Make sure our group is prefixed only once fq = prometheusTrimGroupPrefix(fq) // Build fq name name = exporterNamespace + "_" + vGroup + "_" + strings.Replace(fq, ".", "_", -1) if swapName := fqNames[name]; len(swapName) > 0 { name = swapName } description = vDescription } // labels: can alter final name and description { if len(vIdentifier) > 0 { if isVBE := startsWith(vName, "VBE.", caseSensitive); isVBE { if hits := regexBackendUUID.FindAllStringSubmatch(vIdentifier, -1); len(hits) > 0 && len(hits[0]) >= 3 { labelKeys, labelValues = append(labelKeys, "backend"), append(labelValues, cleanBackendName(hits[0][2])) labelKeys, labelValues = append(labelKeys, "server"), append(labelValues, hits[0][1]) } else if hits := regexBackendParen.FindAllStringSubmatch(vIdentifier, -1); len(hits) > 0 && len(hits[0]) >= 3 { labelKeys, labelValues = append(labelKeys, "backend"), append(labelValues, cleanBackendName(hits[0][1])) labelKeys, labelValues = append(labelKeys, "server"), append(labelValues, strings.Replace(hits[0][2], ",,", ":", 1)) } // We must be consistent with the number of labels and their names inside this scrape and between scrapes, or we will get this error: // https://github.com/prometheus/client_golang/blob/3fb8ace93bc4ccddea55af62320c2fd109252880/prometheus/registry.go#L704-L707 if len(labelKeys) == 0 { labelKeys, labelValues = append(labelKeys, "backend"), append(labelValues, cleanBackendName(vIdentifier)) labelKeys, labelValues = append(labelKeys, "server"), append(labelValues, "unknown") } } if len(labelKeys) == 0 { labelKey := fqIdentifiers[name] if len(labelKey) == 0 { labelKey = "id" } labelKeys, labelValues = append(labelKeys, labelKey), append(labelValues, vIdentifier) } } // create groupings by moving part of the fq name as a label and optional total for _, grouping := range fqGroupPrefixes { fqTotal := exporterNamespace + "_" + grouping.total fqPrefix := exporterNamespace + "_" + grouping.prefix fqNewName := fqPrefix if len(grouping.newPrefix) > 0 { fqNewName = exporterNamespace + "_" + grouping.newPrefix } if name == fqTotal { // @note total should not be a label as it breaks aggregation name, description = fqNewName+"_total", grouping.desc break } else if len(name) > len(fqPrefix)+1 && strings.HasPrefix(name, fqPrefix+"_") { labelKey := "type" if len(grouping.labelKey) > 0 { labelKey = grouping.labelKey } labelKeys, labelValues = append(labelKeys, labelKey), append(labelValues, name[len(fqPrefix)+1:]) name, description = fqNewName, grouping.desc break } } } return name, description, labelKeys, labelValues } func prometheusTrimGroupPrefix(name string) string { nameLower := strings.ToLower(name) for _, group := range groups { for _, prefix := range group.prefixes { if startsWith(nameLower, prefix, caseSensitive) { return name[len(prefix):] } } } return name } // Always returns at least one main label func prometheusGroup(vName string) string { vNameLower := strings.ToLower(vName) for _, group := range groups { if startsWithAny(vNameLower, group.prefixes, caseSensitive) { return group.name } } return "main" } prometheus_varnish_exporter-1.2/utils.go000066400000000000000000000037461301640764400207370ustar00rootroot00000000000000package main import ( "fmt" "os" "strings" ) // logging func logRaw(format string, args ...interface{}) { fmt.Printf(format+"\n", args...) } func logTitle(format string, args ...interface{}) { logInfo(format, args...) title := strings.Repeat("-", len(fmt.Sprintf(format, args...))) if len(title) > 0 { logInfo(title) } } func logInfo(format string, args ...interface{}) { if StartParams.Raw { logRaw(format, args...) } else { logger.Printf(format, args...) } } func logWarn(format string, args ...interface{}) { format = "[WARN] " + format if StartParams.Raw { logRaw(format, args...) } else { logger.Printf(format, args...) } } func logError(format string, args ...interface{}) { format = "[ERROR] " + format if StartParams.Raw { logRaw(format, args...) } else { logger.Printf(format, args...) } } func logFatal(format string, args ...interface{}) { format = "[FATAL] " + format if StartParams.Raw { logRaw(format, args...) } else { logger.Printf(format, args...) } os.Exit(1) } func logFatalError(err error) { if err != nil { logFatal(err.Error()) } } // strings type caseSensitivity int const ( caseSensitive caseSensitivity = 0 caseInsensitive caseSensitivity = 1 ) func startsWith(str, prefix string, cs caseSensitivity) bool { if cs == caseSensitive { return strings.HasPrefix(str, prefix) } return strings.HasPrefix(strings.ToLower(str), strings.ToLower(prefix)) } func startsWithAny(str string, prefixes []string, cs caseSensitivity) bool { for _, prefix := range prefixes { if startsWith(str, prefix, cs) { return true } } return false } func endsWith(str, postfix string, cs caseSensitivity) bool { if cs == caseSensitive { return strings.HasSuffix(str, postfix) } return strings.HasSuffix(strings.ToLower(str), strings.ToLower(postfix)) } func endsWithAny(str string, postfixes []string, cs caseSensitivity) bool { for _, postfix := range postfixes { if endsWith(str, postfix, cs) { return true } } return false } prometheus_varnish_exporter-1.2/varnish.go000066400000000000000000000124221301640764400212400ustar00rootroot00000000000000package main import ( "bufio" "bytes" "encoding/json" "fmt" "os/exec" "reflect" "regexp" "strconv" "strings" "sync" "github.com/prometheus/client_golang/prometheus" ) const ( varnishstatExe = "varnishstat" ) var ( descCache = make(map[string]*prometheus.Desc) mDescCache sync.RWMutex ) func scrapeVarnish(ch chan<- prometheus.Metric) (*bytes.Buffer, error) { params := []string{"-j"} if VarnishVersion.Major >= 4 && VarnishVersion.Minor >= 1 { // timeout to not hang for a long time if instance is not found. // Varnish 3.x exits immediately on faulty params params = append(params, "-t", "2") } if !StartParams.Params.isEmpty() { params = append(params, StartParams.Params.make()...) } buf, errExec := executeVarnishstat(params...) if errExec != nil { return buf, errExec } // The output JSON annoyingly is not stuctured so that we could make a nice map[string]struct for it. metricsJSON := make(map[string]interface{}) dec := json.NewDecoder(buf) if err := dec.Decode(&metricsJSON); err != nil { return buf, err } // This is a bit broad but better than locking on each desc query below. mDescCache.Lock() defer mDescCache.Unlock() for vName, raw := range metricsJSON { if vName == "timestamp" { continue } if dt := reflect.TypeOf(raw); dt.Kind() != reflect.Map { if StartParams.Verbose { logWarn("Found unexpected data from json: %s: %#v", vName, raw) } continue } data, ok := raw.(map[string]interface{}) if !ok { if StartParams.Verbose { logWarn("Failed to cast to map[string]interface{}: %s: %#v", vName, raw) } continue } var ( vGroup = prometheusGroup(vName) vDescription string vIdentifier string vValue float64 vErr error ) if value, ok := data["description"]; ok && vErr == nil { if vDescription, ok = value.(string); !ok { vErr = fmt.Errorf("%s description it not a string", vName) } } if value, ok := data["ident"]; ok && vErr == nil { if vIdentifier, ok = value.(string); !ok { vErr = fmt.Errorf("%s ident it not a string", vName) } } if value, ok := data["value"]; ok && vErr == nil { if vValue, ok = value.(float64); !ok { vErr = fmt.Errorf("%s value it not a float64", vName) } } if vErr != nil { if StartParams.Verbose { logWarn(vErr.Error()) } continue } pName, pDescription, pLabelKeys, pLabelValues := computePrometheusInfo(vName, vGroup, vIdentifier, vDescription) descKey := pName + "_" + strings.Join(pLabelKeys, "_") pDesc, ok := descCache[descKey] if !ok { pDesc = prometheus.NewDesc( pName, pDescription, pLabelKeys, nil, ) descCache[descKey] = pDesc } ch <- prometheus.MustNewConstMetric(pDesc, prometheus.GaugeValue, vValue, pLabelValues...) } return buf, nil } // Returns the result of 'varnishtat' with optional command line params. func executeVarnishstat(params ...string) (*bytes.Buffer, error) { buf := bytes.Buffer{} cmd := exec.Command(varnishstatExe, params...) cmd.Stdout = &buf cmd.Stderr = &buf if err := cmd.Start(); err != nil { return &buf, err } if err := cmd.Wait(); err != nil { return &buf, err } return &buf, nil } // varnishVersion type varnishVersion struct { Major int Minor int Patch int Revision string } func NewVarnishVersion() *varnishVersion { return &varnishVersion{ Major: -1, Minor: -1, Patch: -1, } } func (v *varnishVersion) Initialize() error { return v.queryVersion() } func (v *varnishVersion) queryVersion() error { buf, err := executeVarnishstat("-V") if err != nil { return err } scanner := bufio.NewScanner(buf) for scanner.Scan() { return v.parseVersion(scanner.Text()) } return nil } func (v *varnishVersion) parseVersion(version string) error { r := regexp.MustCompile(`(\d)\.?(\d)?\.?(\d)?(?:.*revision\s(.*)\))?`) parts := r.FindStringSubmatch(version) if len(parts) > 1 { if err := v.set(parts[1:]); err != nil { return err } } if !v.isValid() { return fmt.Errorf("Failed to resolve version from %q", version) } return nil } func (v *varnishVersion) Labels() map[string]string { labels := make(map[string]string) if v.Major != -1 { labels["major"] = strconv.Itoa(v.Major) } if v.Minor != -1 { labels["minor"] = strconv.Itoa(v.Minor) } if v.Patch != -1 { labels["patch"] = strconv.Itoa(v.Patch) } if v.Revision != "" { labels["revision"] = v.Revision } labels["version"] = v.VersionString() return labels } func (v *varnishVersion) set(parts []string) error { for i, part := range parts { if len(part) == 0 { continue } if i == 3 { v.Revision = part break } num, err := strconv.Atoi(part) if err != nil { return err } switch i { case 0: v.Major = num case 1: v.Minor = num case 2: v.Patch = num } } return nil } func (v *varnishVersion) isValid() bool { return v.Major != -1 } // Version string with numbers only, no revision. func (v *varnishVersion) VersionString() string { parts := []string{} for _, num := range []int{v.Major, v.Minor, v.Patch} { if num != -1 { parts = append(parts, strconv.Itoa(num)) } } return strings.Join(parts, ".") } // Full version string, including revision. func (v *varnishVersion) String() string { version := v.VersionString() if v.Revision != "" { version += " " + v.Revision } return version } prometheus_varnish_exporter-1.2/varnish_test.go000066400000000000000000000064211301640764400223010ustar00rootroot00000000000000package main import ( "fmt" "runtime" "testing" "github.com/prometheus/client_golang/prometheus" ) func Test_VarnishVersion(t *testing.T) { tests := map[string]*varnishVersion{ "varnishstat (varnish-4.1.0 revision 3041728)": &varnishVersion{ Major: 4, Minor: 1, Patch: 0, Revision: "3041728", }, "varnishstat (varnish-4 revision)": &varnishVersion{ Major: 4, Minor: -1, Patch: -1, }, "varnishstat (varnish-3.0.5 revision 1a89b1f)": &varnishVersion{ Major: 3, Minor: 0, Patch: 5, Revision: "1a89b1f", }, "varnish 2.0": &varnishVersion{ Major: 2, Minor: 0, Patch: -1, }, "varnish 1": &varnishVersion{ Major: 1, Minor: -1, Patch: -1, }, } for versionStr, test := range tests { v := NewVarnishVersion() if err := v.parseVersion(versionStr); err != nil { t.Error(err.Error()) continue } if test.Major != v.Major || test.Minor != v.Minor || test.Patch != v.Patch || test.Revision != v.Revision { t.Errorf("version mismatch on %q", versionStr) continue } t.Logf("%q > %s\n", versionStr, v.String()) } } func dummyBackendValue(backend string) (string, map[string]interface{}) { return fmt.Sprintf("VBE.%s.happy", backend), map[string]interface{}{ "description": "Happy health probes", "type": "VBE", "ident": backend, "flag": "b", "format": "b", "value": 0, } } func Test_VarnishBackendNames(t *testing.T) { for _, backend := range []string{ "eu1_x.y-z:w(192.52.0.192,,8085)", // 4.0.3 "root:eu2_x.y-z:w", // 4.1 "def0e7f7-a676-4eed-9d8b-78ef7ce21e93.us1_x.y-z:w", "root:29813cbb-7329-4eb8-8969-26be2ef58c88.us2_x.y-z:w", // ?? "boot.default", "ce19737f-72b5-4f4b-9d39-3d8c2d28240b.default", } { vName, data := dummyBackendValue(backend) var ( vGroup = prometheusGroup(vName) vDescription string vIdentifier string vErr error ) if value, ok := data["description"]; ok && vErr == nil { if vDescription, ok = value.(string); !ok { vErr = fmt.Errorf("%s description it not a string", vName) } } if value, ok := data["ident"]; ok && vErr == nil { if vIdentifier, ok = value.(string); !ok { vErr = fmt.Errorf("%s ident it not a string", vName) } } if vErr != nil { t.Error(vErr) return } name, _, labelKeys, labelValues := computePrometheusInfo(vName, vGroup, vIdentifier, vDescription) t.Logf("%s > %s\n", backend, name) t.Logf(" ident : %s\n", vIdentifier) t.Logf(" backend : %s\n", findLabelValue("backend", labelKeys, labelValues)) t.Logf(" server : %s\n", findLabelValue("server", labelKeys, labelValues)) } } func Test_VarnishMetrics(t *testing.T) { // @todo This is kind of pointless. The idea was to test against // JSON output of different versions of Varnish. Enable back at some point // and figure out a way to scrape from buffer without code duplication. if runtime.GOOS != "linux" { t.Skipf("Host needs to be linux to run metrics test: %s", runtime.GOOS) return } StartParams.Verbose = true StartParams.Raw = true metrics := make(chan prometheus.Metric) go func() { for m := range metrics { t.Logf("%s", m.Desc()) } }() if _, err := scrapeVarnish(metrics); err != nil { t.Skipf("Host machine needs varnishstat to be able to run tests: %s", err.Error()) } close(metrics) }