JFIF     "" $(4,$&1'-=-157:::#+?D?8C49:7 7%%77777777777777777777777777777777777777777777777777"H !1AQ"2aqB#R3b$Cr4Ss%Tt&c$!1AQ"a#2B ? }XuAo)8^ IƟ`vUp9jY0Ǧ w)E허2jU`SEKw5]kSno!]:?jc\غV7/9N+{t#8zd/޲3F/=ź3GNquV"/4:{z%ۣI'D@ %88^f}VV)S_2ed^Mx"͟?UC62Q%чmO͓ cq0rŖJ\Õ_Sݶ'|G.q޾D U]nP%EF>˲E"d&'f2s6H]4w IS˶4VbaQ+9]XtNx:M0JNxϙ⟟"{nr;|{%vo\z-wc,*|k}-m55o4W9ؓw߱Yzk .=/oϡȴ^9ҧʹamtQԬZ]4?egjrQ}+)MleE]MPEn!`IK2RUEwVIoͷcp;lśe7΄uN ;rПV8|e\׹9Y-V_G.)XԢOv<;_"ڜ]ߙEr݊'K{KuBJ}KI}24|"v)/ʻo5)6-Tjd7.C]Q&lU,Yk1P4~UKZs|$kX6+屷CUq+N(jlGrpG&UB3#k3\9qfg7O8Kim(AJOO~C#e`i0wĦij$cWh<dtQߺ"NOtG+ZǪ]b5%]v5$)u|qZ柡s-rۖu$MKڎCmN_V'/1u,21pvlc>қeNnֺ|bkl=lǷNOʣlz*]»vȎ[)j[fs[]:s#m6Qt6*Q+`};ßj[F_jcv`r#w}|k<ڞ/r53N8>Kh q_-_??@enſEܥ\D\YAEo+ ޟd}IcY7+t{=ɩ>}i\\JfxzVdSzᔢ]Q^CJի\iceitMM5hڦg')^ et#ۯ"ÿfF->4iؤ2ݷ6#p6^-R̫gETj^I.kӽUp~D9[:/>h> \gJ|ۿؘ>ml9jMK =+*2i=0RiͶۗV{"u]IH`9J_˹KƼK$X-|=ve/ bjxw.9i%NqVJcFYKcTtO,F;%67vYb8֝qq0tUt=DvawsS~~Edzr^F-v{c++ݔ\|9Iy #nOavOY=3690Tcrilwa\˓m$?箵S6U c(.~R7suMhqcMOnKoc*ȣȩEd'J ܜk*_q}%M/7c.|;trddbsdcJev85̤iW Ę 8C# .딖e$sk80^\J众2)Nm~|Idj_ O+6ǻ#(MIz4Qo:օY,:q]̌"lK}{F]ζ)h>ʶ ^ue78_G#rqv$wkk[Q c+վ+ĸZΝFB]VzoiJRke&Kgom_7Wef_7,osJɽE%lzBt>mRs)v8'P0ֲtrOg4p_2`GlhYڦDF/ӚKmtm'P2kqU765fJY:y؊.ox%8V_ִ̌ܞjpqwЮQ;iUcNoOoٸcY w*4soӵkqf$?-jy~0{>?DaL8XL/ɞo+'8 {ʸxգj#Dy)wk̘e۩+%}~;ڼ5xek|y-%ڱ-ʜe:EEScÚ5z|r'&I&яF*F7|[nRF =(4ۖ@. n7@xx:N^8Bg%u/ny6&dR{?8U_Q6Z߯-oh.NR]} qi6~H(j7*uF&l&o8ts]/P89:jW*$w׹Ӌ FxpsCJi.7N q4WU_}7*M#qWiصnk'4ݍl*t^ c<'d:~͗enFQRz9v~ddoTZ̚k7X(wUswO̙fոҁՕ[$IAI>WW~ĪEѢNoeutYߑ-Eixιpxq{FnyfRrjqU᫤]>wPU8)Y-7Wbq㛋w:7ܣ].j%K:y4] %9$I%pT(󨪙VqiYٓ4y~5S/XTDZM2lȪ; S~Kx:(Mn0';-{*qV&|W3S+\֔a{R{s=lYmN9Fn&o'}Vi( ?*qV5ѼCNsM饏zߴ$^O69@ ,$y|jE;gW/u|M?3+ZՕN86յw%|QO㏏S\E#ddsgl+Scl3~~CԕQľ?5_ z߿t11OĶ0>oB9E/SOSk+b&Yn>$툧eg) "!܉(1 uBoJ)/t/,:=7M+1ܺ#CmS^Nz 6[u&]+|Dfj:uZ5-Z^TjMtm>cȳ NdT_,M#Ex;pt۴ͮ#!N iKl!zPծ~$1SiO} HI&g Bf)b%Ko̧kumEnص;V?j>nltOMVۆl>.WueYaw2+qK,?uHiqqSM}~gu3xbcWSy/Xc{%sZ]uaUM;7:cb5G97'7þյW,;$ܛyVjl޻y7S;o6gf.Tг[7/i1Z^rE cUF'P1-?%u&q{fw~27ޡ ^w$?SwP[=R3Y73 4x(Kk&rLȫMKn:RjcI?3Al`vض[POĖSYujj6v+-[xҵ=~zNN>\ɲQ/uufo*e6l;31붏.>w6=7#7dFDc%ƶTbd;2/=?Asr! ~ZSS~I"9y]Hn,ĊJ7S}cK"amCg3yP=RQɤW}t;-{F+v+RɔڎB?º{SV묖kۏmK~%.Q;OfEf_Y/F-V-MdD)m.ZՍ8Y*h[g/6ydmCc[rdfʾ䖗gd$^֍^ʅѻL|<[݉\߯RiJUo';œN?B smS ܹkس,mRE^ѣlJ&.ċ԰YO:޼f\Z'HCѯU[ʩ1ff4S-٥YxTIGLiыr }L)edׂ*l|ٚuoxӿnWkTbbVm zT_'"x5Vިxo1ج^Fq6Sd3ws'/ڞ6m?}1OsRGݝ+,~ڬ%^p1ef5c25vq~﹉ă[r-eq] 8+/ESj}?mUE.xYK3"oƔ^Y9I]I ޑ" &*4.Jâ}ټQbXKJ񽼀ncg`+riܭ_'Bֽp%bX'7cB}WPm|zHָLJhj~E>i~Z$297|_hyΕ&s}ZϷ *j]:v.HK<SP8`Pƣ)r ,}8Wk[ArHgn=о7:J]TTP>OOj J_KyB\Ԥrm嬷ȫr{ݙ5R(FRЪ6q}KLmR'eޖz6[YތesYYL5Tr7s\^rؙV͸컬j5d?yk'b S }kra^ߚRH)[sg.fLM\u= vJQ]rVkZuoN}#G?yjO%|i2fKoӰღC P_Ϳ6Zr{e/m$i}9 G2')YG9KY>|1ӫ +v+i;h\Q@˿Lӭn˖ 7ck>Vr.D0)hC<˄4"0[eԬݭe+l2s3ss oX]1r]+VK vI;mZ')R6e5=/i@]H^Z۬՝EW.jƆf{8mXMV~_̝z^VR}T63}}k3+k3:j1Phlpi{欍BȽ}6w73GtUZv>4eUj$ xz$$D/߇ߟI"uk̜aƪ*ke/F:dһ_PE1ݡkp(5ʏ-ɮ{Yllԧg!ܝ g]i-umεŸxOê^=PR ##XeMy%2L~󜺶Hm ݙ2t_ƶz7'\Z4T<"AM-&xaC]a5.huQ۫$cMμ|h;.J.o߸sE-zU{d];|YLSMvSEneNKr1B[]NeonNߪ$4̘FPrkxޱ=0lr7Q%=$KQ;0r*XKdGۃ*]w-npᬶ\tt4>Dc[Ouo3/)-WҴ xs71eԤm*ٖ웗H''.Cnmy]݊Kra[9)Y#2U6d7tf.[R.GdE>#O_.+-K`{KonR_ÕM/)?:F,Xo1ƽRmz8C]lD %(x+d2Ah+\CCLJ!D65x\ȼv)\Nrp*[YُfL*PyVΚuWA K4hyYdwihNIy#ub?4NDϐ'4 :nFe(o%ve@@xl-k%QƭRP&kεMŪ-Ys2u ]T!}8*TQnZ}v =~mԧyDM&8K>2|Bnugܷ.wvCs̼5F^ubES7ݢM&4Ź-~mKx1((sr!M5uy\q)oy|a)ˣ,A?w"T휳2\F}PR-<2%`~4Z5\W"(USkGpT(~Qj>ɰ쏳ǓSKKx's]nEf'.iݙL>Moƹk7ݭ[.г6lk<;?)#E]xFU7'>vF%R;t:Җs}NSBWX=Y8ث}~G)S^^ƽwR[)/Fm-ڞTK~˓Z]U;RQ=M/"NԝP[-Y9t_8V+}P?Ue{M/O&WWKvc#r'KM'p[±vtpRC/W|7K2Rfm;ljm%Z]^T[6}6iTC }L[uxg7(Z}. SRI)jҞzȶ쳢oYRw$ŷ"J\ǭw{u'R taF{;3hHB\RP(*ZQ]y;;k٥nWbGKv-V?NDҞkd9@z LJ}Kc9C*?V-*[*۸-0.|󲝳ߗZK#%_OFGF$kC$[NNJ7Yn[k~Xzc+Sʲuhsw^^4+nElbƮKD,}YLV=i=|p|_=b5mȵ(~,em#Xƥ.sVoEaWXc.lY uG\m';'*\ӆ}|˯UfQBvo}/"zw + qvMrQ[[AdU2ٽCGgjؖS~Ev%9">$_2Sߚ%ѽ7jX(t#21r{̬F]b()?r[Rı)W[O/6]XL9 vuLh-Ȃ9"'7f!Փ䮿Bf}[lag֧]?Pc#D9EmfK7o*})+n!]qIo^FrNVNo!Eƃd#OP?%ۋ(mPu93ۣ{}2&$%cZ߯LҚY);U afԶd,*'6_?B:R~}^̬~mJ+vC}Ѩe"MY+mi :s쥸;iJeYvBddeK|#5/mzR]F2 JHUU )/S{Ic$=: W)>} @0#URsR=w"L{+ɞ)d|*qq2>[nƨDۋ-G[6½J|{Ѿ4MwyG-Σ Ze{ug>2|'zΤ2%xՑ*<Q̥T')uLkjn(zF-JOR}wn~FV5zq2m'^VS=7Y^RdfeO)>EpX붚w*r*w˿^kڴ{J;K۔sRŶU]p\zn@dx6[+yeH[_m_/I&mv|M5&&-G"v۴^{vg8Y(K_~h0e AxfrzڬkhS/Vy1ϯdW3'͹}{'V-:MW(V/ͷ*E7s\EmEW}bUr'k,P{9?B֫ #[uNrB,wo^{fdF(5tRf.2J-/:~ t0M"d_/c^32*q]yLl^2[ݥZc*vtm213r'tSuM-Խ#o/HF+2VEpmǦޟS?Rs+t:u G8n,Ԛf,hY8SX*rKf>+cpruɬ=DMrXgϸ:~ɲ ~]'5'kElw\=ڞAG&')G9R\_̝1K;nPg&T(ի[^Jҟ"qoӸ.W}3mF>'$<\U6-~?x?B~{^xkpv-vlߣe빹j\(ښsuu6lH(qoaYt?x8}Ie '@b%TݲygV.+O9/W4MsCMuFjYzG.{ds.k(>G~K?ni-=R r}r ?s̥%l5Ϛ9IN6~۩RĢWNʾE[|nb.HY—קWkr1ҺշMNDp)^¸R:w;u1 12]T/Uiʹd%2OC2K*r5S]g凫5 UQ.ȫ– /i91njFkQxuJ1rn%XDžy?s˗վuMGƋ/m^J*RsF))uF,'l{=|nFm9:N\%u#tnXE->e2Y0PũjUȨEŭ|'eʹ[o{Ցms%CGg/}t|snzrvm\g}cÊ94Pvg'L}ّg궮ԱߢO^f.W-sT]M˔ېе<^Н'KuNn_Vl8*Kж^ xsuW51-ᅱFzƉT-kY/9wzDޯ/XlW)gypǚjDɨ~{ݤHCim.[>rqE_Uرx/>|L64%aj;fxӱF(K֓J9՞ -K> I_5Enn´&=Oc%o̟IJZF$۲5I9Wݚ n.WTuѲӏ[4U/9.2zX5\j3ĎEsMq4%9.d[7јc9eNa+sjE';%s#ɤ`ףS=WI쫢.Mv:j/[3:rTF_zt:.z%udW%]xܮVz$Vŗ49[^y.խN~M&mx+wGR~_4KC[ʻ:v>03߶v9x-Mȧ$c:lrCWjeg%ֹ_Nh՝Qɏj^ϛr^.>WhlE5yֵ6\W^确]*гc&^NI[oCDn.ߑ!,m&M_/'Mn$s\r^8|uSZZ1|LV<(zq׮xmٚZƏ%.Ԁs^2𱸒O#&,s[mײ9kޖCoSq&俙qxP.N] 2UǎsM2iN.f r[mcQZmFُE{#[TbҔ*sfaSrn^8N<\_'MarJ6 EQғ|F[S'[~q~kmn[_x?B f5Q١X=g(~[Cx}GO ĺo'e)~dq(Ot`sN=~heu ::m'Cjj>~5V柙cyQD%uqEc{[l^U O]b~eŦۑ'W3&' 2V.^D%G S6\wYNO$. O+^ŵG~haEs^=1*bICzFF4O#,Wu3허ekB\I'tWMߩOG3iFz{rgeM9g r] i3gk&u1r/1kVgR-ɿuF .^;3;?3큦bN̂r4ovMkڞ}[:,IVG<};*-2",>K%bK2Ƨ[w!)ˤ;d?4%Ul2ږec4#ōIw^R_/TFX+*FM[F|a'ߚ2SIMeVGn ~&Y Ym(?ԛ],=|сG4yjk"Q^~ԗ^c,qqrg^-:Uc[E8>>k|nS..LBIc>3i|ZEZXAqm nuOm<; X~mrK=~ ƱrSN<U!F΋WS/|t?K)zd} ,C"ovx?bբs3mX3桭X֖˦kFddhg}$ggSo5jL*NdJis$ EQ\v=0HxzyW~FT_Ƶccg,&=_V(%kq+_÷O'[_[Uڽv F $Ξ9n5EN/4Yy/%*} .jΔ`V_6\VͲohzfOgޯzpj}y}v:34WH;+x7ӻu<ݦ"mJ/=>eoD֣c4kXW-[}٬6;t[Na_• _5i5˗sٴ]+e;Joj㼶ۙyLumo5&F)F\ {(sm_M>gzcr)KU̠Ħ=VDd'h;-aŤ9KٰqQܫަazMp4bk9 UX.ͮ]KeS5Uq[¹X0ɦ6]roFjʧ2׏6/C6eQE5KӰmsFnIz&`z팡-ٯ.ixyك?c2//z6M4W[]_"?Õ[? Vfvӳq]I5(d|MʝzcC*mN>B2gD+><e:Gh %UkW%zJ8k_ˠ=KFRfw{sŖ^q\/{v[Ω}gLjT[t_ޕg6G~rkkMcSRKբ54?SAûO1o%[>5/R~CioNdNʛćh>f6H8c/<1xd[ŦCEk.9"ej?w&O6^ژR[vrQ.z㎩f6:V8}hi2z~ s-w]+|I9s_C~>-S&9ZFVLf7-d'pՠplJ#mm؎s(?Ʋ?/A%_sXuGNnR}_dq>1ʍ|У3]NXYZʷ/&ܛ彖LS? 6]"_t5qP5Kq]^m91jW暹U6-5WU澦M0˵f2ӪǮ.P~? _nEJTcTei)ٳrۣ%x %gs}7l9'tb~dXst# r?}Weaq>=+to)7،E*vn\e_,\NFxcivz]tM˼?Oԝ2Zrλs-ĺEtonIIfm/9^[^EBUjOnr6vI& l]%0")2䒶-+R*zyX<> -X9GUo^xYQ8ιvixٔa\t)hv}ьոVU~tK,=_wLLa?TYIo]$`N6cbi?#7;MRt<.~Q-mob\\g5췍 ڌ_?8nfJN/Y͢n3?_sϩ{HiְPo'yS??_jߡWi5q? MWȲ)8a]lLˏ--b[TXlΫRy;o5뜾$HW.mm?շG[Ƀ seo5Q}Le%*،«~uU{R$t\^%!weX:G('6WupTS&~8=jo?2_PϖE[nf6Tٯ;GLW)NM[o*\j%.gb|䭹noOX:1R)UTj74˓]D_bʝkzNI.9|^G`KeQ{mOjX/sR7evdgi7qm}ތW&4=~|YY)?7Oj}xXkF×4c.l?i|b[5Ή5j-[Y\z<茲Z$Ff&o;gErǩݦ̪/q[&[/9uuzi;PS^_/?]=ΕqK~ӛ5'NM[m_Ϲc'[oӯE#g߂vvGNRo϶o5Ǩ[ɉtov2~i<7iSȜN(G5+/ٛMTܣukj鷣/$1˒!Mxr\ߤs1ZuMQȌ^]c$CXrj#N/˦Ķ9]Nzê5zi;W,v!ŧD6zğ7uR5^MW}>igl2U2nXo{}_w]&vte\Z3 MEEe/ 2s㗼S_bIղTI}|[Ye/c]*̪9u/DmyNxSDgi `Z?.RFj۪'~.[KVb޺o濡to?E#[.^y=q4F8ڎ/GX\.YW!Z.ѕtt:?gYYyU%Uw~ri>ȦKhg,5/=>V?TrN4aWO,oӕ7-SRi*"dܽpuaVQÞd-#J2Nr:#``ѧWR-F?I-T -cOT2pr?þזgE\Ij~L9%EMoџUؙt8_eYΧWjU}e9y9z/#TT-2dLt3H=ڼcKb'"uIٓ'[[߱F~\2]r%C]^VCLjm[cJNryf}ջ.[DEoRՒb'>fVy_c6[K4Na5>{ɳaw/Uj.Զ_K~?IeJ7OQx3IgFc*جɊǽ-o3Ӭp / ]7V*ENܜ[r/tOJΉw*ʨ*JFN^.WZeLgUwKi/M9y8dkOᛊHxGĶM*&#h/U|6D(uFyE5hYxiSEVm^D|,ۿCj;<*ouOkYpΔ2{x-L] !k2ا#IM'a7:M}M1Y儭Mnk[/;4Uwkkɫ%aɔoXVV$m;2Z4i9:>\Yů= ?[{t6,~!c`Un+dW.gKyIB]l+3kض(\MZ\}>k\C~閹l[ů]VNtƸr몮X+U>v'nv{y7s[г̭9Ctvt% GqT8=wa(6\Rd柮YWv^Fd^\+緉,+=-^S"k:NVu o[_TIѝ椯bF/G㿏dΙ?T}K-T)W>s?3M)V*,;P\,}B u{rDexڥVFfw}47׋w}]Դ 1dmk1V%/'T:Fǒ_TEe[l/l/ٯc{Ƀ[~`zj⾥r}Vܪ{M8Qv]$mU]8J2MngcxY?鑞.9HjxSy.fS(|]MgcK2$(jRQ3XO|<f:Jq4& fw|$N )A8ת99 mFNM*Dϒ NoIa9i9y?:D⻧߇\7ɧ]mu"-˥5/w̨_ 7DK['[2"(%xzT\*GT"+<,yX.lEJrfo?.4N;l>jmZߣ5FdB3\r,t,./S]Q{tm5lӕT~A [fv7Iہc: ΪN7I]2(|o$NLW"#~Dͭ=v-Mv{-lqn{I3xn'6.=DƟܖަ~deQV;k2Ei\[bӴ1_]OhZl朠&t3xkei+c\'ZԪ'hK梿X@cTԫ#emIz6e^i?8 NBc̆f+MׇdC]YSd%lώ8-c7eι/}_con/no\핍~[WNReXMo+اn ?#Ͷ-AUFN1V4!y,{1a$S﹑;Ǚr"__[o) xk}7EI/riwؙ7mR}`|yrEVdo/B# uٳiNQKQkᑑ^d@/=ˑɒ768fsuor9=7ףܹճpMr-$1uySOZN?đrqզ9F q=.!T?ػ bf{¯q=$^:!ES߿ Fu\OS,8e^UוS^hF4BQƺȪw-kF39@X06 Fv=Q^|ƞ5}2tnmG_|Λ(|%](-5>KȁN$=6lq).12 V6m$ׇlOcҫܸ K{;ľ>+Q?Rx-Keu uMy$i B}G*h$Q -W[-&a"[i\}~Ek$<~c{MffS eS.#\^lMiytު]9S{u4 {DFޅSź}R ]R$y;r/P̙3niXMt;&!rxw\ZFmQ"w\L{^۔K&/gr:m=2%5bwE"^e[\$ɟPi!U_rdS2d?=[!(I.rC QZEim%}|YmzZ_ά<ۡLQM|` ybPȏ}?]Eu[`kҫgFb~F}Q8NP>5lӳ^-K%Q}$sx7SvnfTƸ|Kzd'_ⰽח$4L Y?qy32t j2e ȜrJ{mبhۍUU'p#8y'ѝ=i+Tĩo7WYyČkL5؝M=%"Nt}eXW)N.~sv5pɮ sSQ[+-/}kVk'FEɩ9SE&T=&\緵 --tf.9Ѳ4_##_ɱTFV؞~YTddS&s=䟚Fb1._5}~gM'p#,U hs--XG wtԹTi7M:GYK5'^W?C>_Gq/S&d| k_gO ӊiJeHU G_ Êg#),}-:5>V1emq}t}q?meKU:BqJeiPɗ#\$sI} Z生ƫoo=V=pVcUg"%wEm叡vIdhrȔ~F]p58_.,O|'Ɇ^L!c6OWӷ{x9?Fp?ceOuT+Uɵݹ&gx9i퓃sxGIm}_3Īr#:ԣ?4בc[jö#B7KʌWNo)=+c }YvP{lv^r+5Vxx_:~=̌Q}CTy+Wh鸚f$101뢊F[#--Y\i@l)W8/E>8nlj/ktOľ,q*[sE[]:?ZeQvŔɺ|j(Wx,LW=:S?κq%81c)jJvODLiW,{96vr-2}-EH,}%3k#l5gl~x__W Sڎ 8YJQvA=QIWju6-X9$kWЩCI4UWd'&O/Cf=Pi/#+>n$KYst܅y4ʷD^~%~myj,s_4Q}΍Cή;SW:h=Ff{.B/inȇo=-T͸OY2}hlK}.m7-z?,f-/^b\QWs/_͔/3In[6M;l ygؼ!WUË_)D9YL4_>f}ϵ3hV5Oѣ(l8?L4蹥[-Э=7V{&ʢPʼ*3cMz>u4@[oM gKS[jy"Lھzɵfx)GE`ֿ.=kJ>/iˢ[j-qץQC B@o V(ʯG?Bܻ\I>=K-].(vOE.5׮=/Pf^&$caY9{3މ%YOxZ~6Z;;ԗ.NJzş/YϖĜ%ѿO^tY$ν4|e}2ɶU9A؜h˺LrIm%J.|I]kG|DzU k4'(T\9߱^!z -:mW^ <= <^2*;Seq(6ªsHf5ʸO{Ilr~G uJY^k5X_y;5'59O@ƣ̶>pnCOvNwX4oUUf]Џe%MV9Xm9]x'Q=82z)c/~1\~LSow>ﺍƻUql~Sqo羘sk}VjG71kYؽ]b4qnMӡ; w@̇IL㿗[43)]=v*)EH'a񖳋ҎTkxuXGK& ZIR(M8?:ixJp-dmckpu*%N^-7E3='ceE&';_J'Mw𶥏Y9+d9+>!e_Sn|VX -TZu]Ģ/6\ckr /ޗ/z[y.N:*k$ }Yǭ}GUm^-%dm;K_#ctBsg2:8rz-VE|T w.}w9NEPGnoCe8/&3qT}MJ̙Mۗ~哳,-WI_Bsh+~͛vN{ZdYKݲkr%+lo*re-ه?:vYqFfCsqMXRķ{yqgrx.oǓ\xdڗ_ZC9WomX|KmV_%UJܷr$drȳL~MoKyYLic Jq<1$UuٯTד374s<ĕ96춉r9 pGc9=p^:)ZJb&VӝXٽ 0/X& ۳*_ԙƏ.5J 6<$$6B0d_d?hqd>XCe- wO@pg:.>$.Ϣ~L޲|,{-ɪ2.u/Ds-[ُiVIWK5M#Fܭ3?x.)ۣ,wJ)Ȳڣ-#fbdq&Tͧ8Q,YqQ)/R­?\k˔[p_+ogzP[6r^o}_kT}JiJ;<ivEH8wI@MOPʊ\#+$%PDF-1.7 GIF89;
ANDA PELER
Server IP : 182.253.108.180  /  Your IP : 3.138.32.110
Web Server : Apache
System : Linux sma1wiradesa.sch.id 4.15.0-213-generic #224-Ubuntu SMP Mon Jun 19 13:30:12 UTC 2023 x86_64
User : wijaya ( 1017)
PHP Version : 7.3.33-10+ubuntu18.04.1+deb.sury.org+1
Disable Function : pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_get_handler,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,pcntl_async_signals,
MySQL : OFF  |  cURL : ON  |  WGET : ON  |  Perl : ON  |  Python : ON  |  Sudo : ON  |  Pkexec : ON
Directory :  /usr/bin/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Command :


[ HOME ]     

Current File : /usr/bin/dpkg-shlibdeps
#!/usr/bin/perl
#
# dpkg-shlibdeps
#
# Copyright © 1996 Ian Jackson
# Copyright © 2000 Wichert Akkerman
# Copyright © 2006 Frank Lichtenheld
# Copyright © 2006-2010,2012-2015 Guillem Jover <guillem@debian.org>
# Copyright © 2007, 2016 Raphaël Hertzog <hertzog@debian.org>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <https://www.gnu.org/licenses/>.

use strict;
use warnings;
use feature qw(state);

use List::Util qw(any none);
use Cwd qw(realpath);
use File::Basename qw(dirname);

use Dpkg ();
use Dpkg::Gettext;
use Dpkg::ErrorHandling;
use Dpkg::Path qw(relative_to_pkg_root guess_pkg_root_dir
		  check_files_are_the_same get_control_path);
use Dpkg::Version;
use Dpkg::Shlibs qw(find_library get_library_paths);
use Dpkg::Shlibs::Objdump;
use Dpkg::Shlibs::SymbolFile;
use Dpkg::Substvars;
use Dpkg::Arch qw(get_host_arch);
use Dpkg::Deps;
use Dpkg::Control::Info;
use Dpkg::Control::Fields;


use constant {
    WARN_SYM_NOT_FOUND => 1,
    WARN_DEP_AVOIDABLE => 2,
    WARN_NOT_NEEDED => 4,
};

# By increasing importance
my @depfields = qw(Suggests Recommends Depends Pre-Depends);
my $i = 0; my %depstrength = map { $_ => $i++ } @depfields;

textdomain('dpkg-dev');

my $admindir = $Dpkg::ADMINDIR;
my $shlibsoverride = "$Dpkg::CONFDIR/shlibs.override";
my $shlibsdefault = "$Dpkg::CONFDIR/shlibs.default";
my $shlibslocal = 'debian/shlibs.local';
my $packagetype = 'deb';
my $dependencyfield = 'Depends';
my $varlistfile = 'debian/substvars';
my $varlistfilenew;
my $varnameprefix = 'shlibs';
my $ignore_missing_info = 0;
my $warnings = WARN_SYM_NOT_FOUND | WARN_DEP_AVOIDABLE;
my $debug = 0;
my @exclude = ();
my @pkg_dir_to_search = ();
my @pkg_dir_to_ignore = ();
my $host_arch = get_host_arch();

my (@pkg_shlibs, @pkg_symbols, @pkg_root_dirs);

my ($stdout, %exec);
foreach (@ARGV) {
    if (m/^-T(.*)$/) {
	$varlistfile = $1;
    } elsif (m/^-p(\w[-:0-9A-Za-z]*)$/) {
	$varnameprefix = $1;
    } elsif (m/^-L(.*)$/) {
	$shlibslocal = $1;
    } elsif (m/^-l(.*)$/) {
	Dpkg::Shlibs::add_library_dir($1);
    } elsif (m/^-S(.*)$/) {
	push @pkg_dir_to_search, $1;
    } elsif (m/^-I(.*)$/) {
	push @pkg_dir_to_ignore, $1;
    } elsif (m/^-O$/) {
	$stdout = 1;
    } elsif (m/^-O(.+)$/) {
	$varlistfile = $1;
    } elsif (m/^-(?:\?|-help)$/) {
	usage(); exit(0);
    } elsif (m/^--version$/) {
	version(); exit(0);
    } elsif (m/^--admindir=(.*)$/) {
	$admindir = $1;
	if (not -d $admindir) {
	    error(g_("administrative directory '%s' does not exist"), $admindir);
	}
	$ENV{DPKG_ADMINDIR} = $admindir;
    } elsif (m/^-d(.*)$/) {
	$dependencyfield = field_capitalize($1);
	if (not defined $depstrength{$dependencyfield}) {
	    warning(g_("unrecognized dependency field '%s'"), $dependencyfield);
	}
    } elsif (m/^-e(.*)$/) {
	if (exists $exec{$1}) {
	    # Affect the binary to the most important field
	    if ($depstrength{$dependencyfield} > $depstrength{$exec{$1}}) {
		$exec{$1} = $dependencyfield;
	    }
	} else {
	    $exec{$1} = $dependencyfield;
	}
    } elsif (m/^--ignore-missing-info$/) {
	$ignore_missing_info = 1;
    } elsif (m/^--warnings=(\d+)$/) {
	$warnings = $1;
    } elsif (m/^-t(.*)$/) {
	$packagetype = $1;
    } elsif (m/^-v$/) {
	$debug++;
    } elsif (m/^-x(.*)$/) {
	push @exclude, $1;
    } elsif (m/^-/) {
	usageerr(g_("unknown option '%s'"), $_);
    } else {
	if (exists $exec{$_}) {
	    # Affect the binary to the most important field
	    if ($depstrength{$dependencyfield} > $depstrength{$exec{$_}}) {
		$exec{$_} = $dependencyfield;
	    }
	} else {
	    $exec{$_} = $dependencyfield;
	}
    }
}
usageerr(g_('need at least one executable')) unless scalar keys %exec;

report_options(debug_level => $debug);

sub ignore_pkgdir {
    my $path = shift;
    return any { $path =~ /^\Q$_\E/ } @pkg_dir_to_ignore;
}

if (-d 'debian') {
    push @pkg_symbols, grep { !ignore_pkgdir($_) } glob 'debian/*/DEBIAN/symbols';
    push @pkg_shlibs, grep { !ignore_pkgdir($_) } glob 'debian/*/DEBIAN/shlibs';
    my %uniq = map { guess_pkg_root_dir($_) => 1 } (@pkg_symbols, @pkg_shlibs);
    push @pkg_root_dirs, keys %uniq;
}

my $control = Dpkg::Control::Info->new();
my $fields = $control->get_source();
my $bd_value = deps_concat($fields->{'Build-Depends'}, $fields->{'Build-Depends-Arch'});
my $build_deps = deps_parse($bd_value, build_dep => 1, reduce_restrictions => 1);
error(g_('error occurred while parsing %s'), 'Build-Depends/Build-Depends-Arch')
    unless defined $build_deps;

my %dependencies;

# Statistics on soname seen in the whole run (with multiple analysis of
# binaries)
my %global_soname_notfound;
my %global_soname_used;
my %global_soname_needed;

# Symfile and objdump caches
my %symfile_cache;
my %objdump_cache;
my %symfile_has_soname_cache;

# Used to count errors due to missing libraries
my $error_count = 0;

my $cur_field;
foreach my $file (keys %exec) {
    $cur_field = $exec{$file};
    debug(1, ">> Scanning $file (for $cur_field field)");

    my $obj = Dpkg::Shlibs::Objdump::Object->new($file);
    my @sonames = $obj->get_needed_libraries;

    # Load symbols files for all needed libraries (identified by SONAME)
    my %libfiles;
    my %altlibfiles;
    my %soname_libs;
    my %soname_notfound;
    my %alt_soname;
    foreach my $soname (@sonames) {
	my @libs = my_find_library($soname, $obj->{RPATH}, $obj->{exec_abi}, $file);
	unless (scalar @libs) {
	    $soname_notfound{$soname} = 1;
	    $global_soname_notfound{$soname} = 1;
	    my $msg = g_('cannot find library %s needed by %s (ELF ' .
	                 "format: '%s' abi: '%s'; RPATH: '%s')");
	    my $exec_abi = unpack 'H*', $obj->{exec_abi};
	    if (scalar(split_soname($soname))) {
		errormsg($msg, $soname, $file, $obj->{format}, $exec_abi, join(':', @{$obj->{RPATH}}));
		$error_count++;
	    } else {
		warning($msg, $soname, $file, $obj->{format}, $exec_abi, join(':', @{$obj->{RPATH}}));
	    }
	    next;
	}

	# Track shared libraries for a given SONAME.
	push @{$soname_libs{$soname}}, @libs;

	# Track shared libraries for package mapping.
	foreach my $lib (@libs) {
	    $libfiles{$lib} = $soname;
	    my $reallib = realpath($lib);
	    if ($reallib ne $lib) {
		$altlibfiles{$reallib} = $soname;
	    }
	    debug(1, "Library $soname found in $lib");
        }
    }
    my $file2pkg = find_packages(keys %libfiles, keys %altlibfiles);
    my $symfile = Dpkg::Shlibs::SymbolFile->new();
    my $dumplibs_wo_symfile = Dpkg::Shlibs::Objdump->new();
    my @soname_wo_symfile;
    SONAME: foreach my $soname (@sonames) {
      # Select the first good entry from the ordered list that we got from
      # find_library(), and skip to the next SONAME.

      foreach my $lib (@{$soname_libs{$soname}}) {
	if (none { $_ ne '' } @{$file2pkg->{$lib}}) {
	    # The path of the library as calculated is not the
	    # official path of a packaged file, try to fallback on
	    # on the realpath() first, maybe this one is part of a package
	    my $reallib = realpath($lib);
	    if (exists $file2pkg->{$reallib}) {
		$file2pkg->{$lib} = $file2pkg->{$reallib};
	    }
	}
	if (none { $_ ne '' } @{$file2pkg->{$lib}}) {
	    # If the library is really not available in an installed package,
	    # it's because it's in the process of being built
	    # Empty package name will lead to consideration of symbols
	    # file from the package being built only
	    $file2pkg->{$lib} = [''];
	    debug(1, "No associated package found for $lib");
	}

	# Load symbols/shlibs files from packages providing libraries
        my $missing_wanted_shlibs_info = 0;
	foreach my $pkg (@{$file2pkg->{$lib}}) {
	    my $symfile_path;
            my $haslocaldep = 0;
            if (-e $shlibslocal and
                defined(extract_from_shlibs($soname, $shlibslocal)))
            {
                $haslocaldep = 1;
            }
            if ($packagetype eq 'deb' and not $haslocaldep) {
		# Use fine-grained dependencies only on real deb
                # and only if the dependency is not provided by shlibs.local
		$symfile_path = find_symbols_file($pkg, $soname, $lib);
            }
            if (defined($symfile_path)) {
                # Load symbol information
                debug(1, "Using symbols file $symfile_path for $soname");
                $symfile_cache{$symfile_path} //=
                   Dpkg::Shlibs::SymbolFile->new(file => $symfile_path);
                $symfile->merge_object_from_symfile($symfile_cache{$symfile_path}, $soname);
            }
	    if (defined($symfile_path) && $symfile->has_object($soname)) {
		# Initialize dependencies with the smallest minimal version
                # of all symbols (unversioned dependency is not ok as the
                # library might not have always been available in the
                # package and we really need it)
		my $dep = $symfile->get_dependency($soname);
		my $minver = $symfile->get_smallest_version($soname) || '';
		update_dependency_version($dep, $minver);
		debug(2, " Minimal version of ($dep) initialized with ($minver)");

                # Found a symbols file for the SONAME.
                next SONAME;
	    } else {
		# No symbol file found, fall back to standard shlibs
                debug(1, "Using shlibs+objdump for $soname (file $lib)");
                $objdump_cache{$lib} //= Dpkg::Shlibs::Objdump::Object->new($lib);
                my $libobj = $objdump_cache{$lib};
                my $id = $dumplibs_wo_symfile->add_object($libobj);
		if (($id ne $soname) and ($id ne $lib)) {
		    warning(g_('%s has an unexpected SONAME (%s)'), $lib, $id);
		    $alt_soname{$id} = $soname;
		}
		push @soname_wo_symfile, $soname;

		# Only try to generate a dependency for libraries with a SONAME
                if (not $libobj->is_public_library()) {
                    debug(1, "Skipping shlibs+objdump info for private library $lib");
                    next;
		}

                # If we found a shlibs file for the SONAME, skip to the next.
                next SONAME if add_shlibs_dep($soname, $pkg, $lib);

                $missing_wanted_shlibs_info = 1;

                debug(1, "No shlibs+objdump info available, trying next package for $lib");
	    }
	}

        next if not $missing_wanted_shlibs_info;

        # We will only reach this point, if we have found no symbols nor
        # shlibs files for the given SONAME.

        # This failure is fairly new, try to be kind by
        # ignoring as many cases that can be safely ignored
        my $ignore = 0;
        # 1/ when the lib and the binary are in the same
        # package
        my $root_file = guess_pkg_root_dir($file);
        my $root_lib = guess_pkg_root_dir($lib);
        $ignore++ if defined $root_file and defined $root_lib
            and check_files_are_the_same($root_file, $root_lib);
        # 2/ when the lib is not versioned and can't be
        # handled by shlibs
        $ignore++ unless scalar split_soname($soname);
        # 3/ when we have been asked to do so
        $ignore++ if $ignore_missing_info;
        error(g_('no dependency information found for %s ' .
                 "(used by %s)\n" .
                 'Hint: check if the library actually comes ' .
                 'from a package.'), $lib, $file)
            unless $ignore;
      }
    }

    # Scan all undefined symbols of the binary and resolve to a
    # dependency
    my %soname_used;
    foreach my $soname (@sonames) {
        # Initialize statistics
        $soname_used{$soname} = 0;
        $global_soname_used{$soname} //= 0;
        if (exists $global_soname_needed{$soname}) {
            push @{$global_soname_needed{$soname}}, $file;
        } else {
            $global_soname_needed{$soname} = [ $file ];
        }
    }
    my $nb_warnings = 0;
    my $nb_skipped_warnings = 0;
    # Disable warnings about missing symbols when we have not been able to
    # find all libs
    my $disable_warnings = scalar(keys(%soname_notfound));
    my $in_public_dir = 1;
    if (my $relname = relative_to_pkg_root($file)) {
        my $parent_dir = '/' . dirname($relname);
        $in_public_dir = any { $parent_dir eq $_ } get_library_paths();
    } else {
        warning(g_('binaries to analyze should already be ' .
                   "installed in their package's directory"));
    }
    debug(2, 'Analyzing all undefined symbols');
    foreach my $sym ($obj->get_undefined_dynamic_symbols()) {
	my $name = $sym->{name};
	if ($sym->{version}) {
	    $name .= '@' . "$sym->{version}";
	} else {
	    $name .= '@' . 'Base';
	}
        debug(2, " Looking up symbol $name");
	my %symdep = $symfile->lookup_symbol($name, \@sonames);
	if (keys %symdep) {
	    my $depends = $symfile->get_dependency($symdep{soname},
		$symdep{symbol}{dep_id});
            debug(2, " Found in symbols file of $symdep{soname} (minver: " .
                     "$symdep{symbol}{minver}, dep: $depends)");
	    $soname_used{$symdep{soname}}++;
	    $global_soname_used{$symdep{soname}}++;
            if (exists $alt_soname{$symdep{soname}}) {
                # Also count usage on alternate soname
                $soname_used{$alt_soname{$symdep{soname}}}++;
                $global_soname_used{$alt_soname{$symdep{soname}}}++;
            }
	    update_dependency_version($depends, $symdep{symbol}{minver});
	} else {
	    my $syminfo = $dumplibs_wo_symfile->locate_symbol($name);
	    if (not defined($syminfo)) {
                debug(2, ' Not found');
                next unless ($warnings & WARN_SYM_NOT_FOUND);
		next if $disable_warnings;
		# Complain about missing symbols only for executables
		# and public libraries
		if ($obj->is_executable() or $obj->is_public_library()) {
		    my $print_name = $name;
		    # Drop the default suffix for readability
		    $print_name =~ s/\@Base$//;
		    unless ($sym->{weak}) {
			if ($debug or ($in_public_dir and $nb_warnings < 10)
                            or (not $in_public_dir and $nb_warnings < 1))
                        {
                            if ($in_public_dir) {
			        warning(g_('symbol %s used by %s found in none of the ' .
				           'libraries'), $print_name, $file);
                            } else {
			        warning(g_('%s contains an unresolvable reference to ' .
                                           "symbol %s: it's probably a plugin"),
                                        $file, $print_name);
                            }
			    $nb_warnings++;
			} else {
			    $nb_skipped_warnings++;
			}
		    }
		}
	    } else {
                debug(2, " Found in $syminfo->{soname} ($syminfo->{objid})");
		if (exists $alt_soname{$syminfo->{soname}}) {
		    # Also count usage on alternate soname
		    $soname_used{$alt_soname{$syminfo->{soname}}}++;
		    $global_soname_used{$alt_soname{$syminfo->{soname}}}++;
		}
		$soname_used{$syminfo->{soname}}++;
		$global_soname_used{$syminfo->{soname}}++;
	    }
	}
    }
    warning(P_('%d similar warning has been skipped (use -v to see it)',
               '%d other similar warnings have been skipped (use -v to see ' .
               'them all)', $nb_skipped_warnings), $nb_skipped_warnings)
        if $nb_skipped_warnings;
    foreach my $soname (@sonames) {
	# Adjust minimal version of dependencies with information
	# extracted from build-dependencies
	my $dev_pkg = $symfile->get_field($soname, 'Build-Depends-Package');
	if (defined $dev_pkg) {
            debug(1, "Updating dependencies of $soname with build-dependencies");
	    my $minver = get_min_version_from_deps($build_deps, $dev_pkg);
	    if (defined $minver) {
		foreach my $dep ($symfile->get_dependencies($soname)) {
		    update_dependency_version($dep, $minver, 1);
                    debug(1, " Minimal version of $dep updated with $minver");
		}
	    } else {
                debug(1, " No minimal version found in $dev_pkg build-dependency");
            }
	}

	# Warn about un-NEEDED libraries
	unless ($soname_notfound{$soname} or $soname_used{$soname}) {
	    # Ignore warning for libm.so.6 if also linked against libstdc++
	    next if ($soname =~ /^libm\.so\.\d+$/ and
	             any { m/^libstdc\+\+\.so\.\d+/ } @sonames);
            next unless ($warnings & WARN_NOT_NEEDED);
	    warning(g_('%s should not be linked against %s (it uses none of ' .
	               "the library's symbols)"), $file, $soname);
	}
    }
}

# Warn of unneeded libraries at the "package" level (i.e. over all
# binaries that we have inspected)
foreach my $soname (keys %global_soname_needed) {
    unless ($global_soname_notfound{$soname} or $global_soname_used{$soname}) {
        next if ($soname =~ /^libm\.so\.\d+$/ and
                 any { m/^libstdc\+\+\.so\.\d+/ } keys %global_soname_needed);
        next unless ($warnings & WARN_DEP_AVOIDABLE);
        warning(P_('package could avoid a useless dependency if %s was not ' .
                   "linked against %s (it uses none of the library's symbols)",
                   'package could avoid a useless dependency if %s were not ' .
                   "linked against %s (they use none of the library's symbols)",
                   scalar @{$global_soname_needed{$soname}}),
                join(' ', @{$global_soname_needed{$soname}}), $soname);
    }
}

# Quit now if any missing libraries
if ($error_count >= 1) {
    my $note = g_('Note: libraries are not searched in other binary packages ' .
	"that do not have any shlibs or symbols file.\nTo help dpkg-shlibdeps " .
	'find private libraries, you might need to use -l.');
    error(P_('cannot continue due to the error above',
             'cannot continue due to the errors listed above',
             $error_count) . "\n" . $note);
}

# Open substvars file

my $substvars = Dpkg::Substvars->new();
if ($stdout) {
    $varlistfilenew = '-';
} else {
    $substvars->load($varlistfile) if -e $varlistfile;
    $substvars->filter(remove => sub { $_[0] =~ m/^\Q$varnameprefix\E:/ });

    $varlistfilenew = "$varlistfile.new";
}

# Write out the shlibs substvars
my %depseen;

sub filter_deps {
    my ($dep, $field) = @_;
    # Skip dependencies on excluded packages
    foreach my $exc (@exclude) {
	return 0 if $dep =~ /^\s*\Q$exc\E\b/;
    }
    # Don't include dependencies if they are already
    # mentioned in a higher priority field
    if (not exists($depseen{$dep})) {
	$depseen{$dep} = $dependencies{$field}{$dep};
	return 1;
    } else {
	# Since dependencies can be versioned, we have to
	# verify if the dependency is stronger than the
	# previously seen one
	my $stronger;
	if ($depseen{$dep} eq $dependencies{$field}{$dep}) {
	    # If both versions are the same (possibly unversioned)
	    $stronger = 0;
	} elsif ($dependencies{$field}{$dep} eq '') {
	    $stronger = 0; # If the dep is unversioned
	} elsif ($depseen{$dep} eq '') {
	    $stronger = 1; # If the dep seen is unversioned
	} elsif (version_compare_relation($depseen{$dep}, REL_GT,
                                          $dependencies{$field}{$dep})) {
	    # The version of the dep seen is stronger...
	    $stronger = 0;
	} else {
	    $stronger = 1;
	}
	$depseen{$dep} = $dependencies{$field}{$dep} if $stronger;
	return $stronger;
    }
}

foreach my $field (reverse @depfields) {
    my $dep = '';
    if (exists $dependencies{$field} and scalar keys %{$dependencies{$field}}) {
	$dep = join ', ',
	    map {
		# Translate dependency templates into real dependencies
		my $templ = $_;
		if ($dependencies{$field}{$templ}) {
		    $templ =~ s/#MINVER#/(>= $dependencies{$field}{$templ})/g;
		} else {
		    $templ =~ s/#MINVER#//g;
		}
		$templ =~ s/\s+/ /g;
		$templ;
	    } grep {
		filter_deps($_, $field)
	    } keys %{$dependencies{$field}};
    }
    if ($dep) {
        my $obj = deps_parse($dep);
        error(g_('invalid dependency got generated: %s'), $dep) unless defined $obj;
        $obj->sort();
        $substvars->set_as_used("$varnameprefix:$field", "$obj");
    }
}

$substvars->save($varlistfilenew);

# Replace old file by new one
if (!$stdout) {
    rename $varlistfilenew, $varlistfile
        or syserr(g_("install new varlist file '%s'"), $varlistfile);
}

##
## Functions
##

sub version {
    printf g_("Debian %s version %s.\n"), $Dpkg::PROGNAME, $Dpkg::PROGVERSION;

    printf g_('
This is free software; see the GNU General Public License version 2 or
later for copying conditions. There is NO warranty.
');
}

sub usage {
    printf g_(
'Usage: %s [<option>...] <executable>|-e<executable> [<option>...]')
    . "\n\n" . g_(
"Positional options (order is significant):
  <executable>             include dependencies for <executable>,
  -e<executable>           (use -e if <executable> starts with '-')
  -d<dependency-field>     next executable(s) set shlibs:<dependency-field>.")
    . "\n\n" . g_(
"Options:
  -l<library-dir>          add directory to private shared library search list.
  -p<varname-prefix>       set <varname-prefix>:* instead of shlibs:*.
  -O[<file>]               write variable settings to stdout (or <file>).
  -L<local-shlibs-file>    shlibs override file, not debian/shlibs.local.
  -T<substvars-file>       update variables here, not debian/substvars.
  -t<type>                 set package type (default is deb).
  -x<package>              exclude package from the generated dependencies.
  -S<package-build-dir>    search needed libraries in the given
                             package build directory first.
  -I<package-build-dir>    ignore needed libraries, shlibs and symbols files
                             in the given build directory.
  -v                       enable verbose mode (can be used multiple times).
  --ignore-missing-info    don't fail if dependency information can't be found.
  --warnings=<value>       define set of active warnings (see manual page).
  --admindir=<directory>   change the administrative directory.
  -?, --help               show this help message.
      --version            show the version.")
    . "\n\n" . g_(
'Dependency fields recognized are:
  %s
'), $Dpkg::PROGNAME, join('/', @depfields);
}

sub get_min_version_from_deps {
    my ($dep, $pkg) = @_;
    if ($dep->isa('Dpkg::Deps::Simple')) {
	if (($dep->{package} eq $pkg) &&
	    defined($dep->{relation}) &&
	    (($dep->{relation} eq REL_GE) ||
	     ($dep->{relation} eq REL_GT)))
	{
	    return $dep->{version};
	}
	return;
    } else {
	my $res;
	foreach my $subdep ($dep->get_deps()) {
	    my $minver = get_min_version_from_deps($subdep, $pkg);
	    next if not defined $minver;
	    if (defined $res) {
		if (version_compare_relation($minver, REL_GT, $res)) {
		    $res = $minver;
		}
	    } else {
		$res = $minver;
	    }
	}
	return $res;
    }
}

sub update_dependency_version {
    my ($dep, $minver, $existing_only) = @_;
    return if not defined($minver);
    $minver = Dpkg::Version->new($minver);
    foreach my $subdep (split /\s*,\s*/, $dep) {
	if (exists $dependencies{$cur_field}{$subdep} and
	    defined($dependencies{$cur_field}{$subdep}))
	{
	    if ($dependencies{$cur_field}{$subdep} eq '' or $minver ne '' and
		version_compare_relation($minver, REL_GT,
				         $dependencies{$cur_field}{$subdep}))
	    {
		$dependencies{$cur_field}{$subdep} = $minver;
	    }
	} elsif (!$existing_only) {
	    $dependencies{$cur_field}{$subdep} = $minver;
	}
    }
}

sub add_shlibs_dep {
    my ($soname, $pkg, $libfile) = @_;
    my @shlibs = ($shlibslocal, $shlibsoverride);
    if ($pkg eq '') {
	# If the file is not packaged, try to find out the shlibs file in
	# the package being built where the lib has been found
	my $pkg_root = guess_pkg_root_dir($libfile);
	if (defined $pkg_root) {
	    push @shlibs, "$pkg_root/DEBIAN/shlibs";
	}
	# Fallback to other shlibs files but it shouldn't be necessary
	push @shlibs, @pkg_shlibs;
    } else {
	my $control_file = get_control_path($pkg, 'shlibs');
	push @shlibs, $control_file if defined $control_file;
    }
    push @shlibs, $shlibsdefault;
    debug(1, " Looking up shlibs dependency of $soname provided by '$pkg'");
    foreach my $file (@shlibs) {
	next if not -e $file;
	my $dep = extract_from_shlibs($soname, $file);
	if (defined($dep)) {
	    debug(1, " Found $dep in $file");
	    foreach (split(/,\s*/, $dep)) {
		# Note: the value is empty for shlibs based dependency
		# symbol based dependency will put a valid version as value
		$dependencies{$cur_field}{$_} = Dpkg::Version->new('');
	    }
	    return 1;
	}
    }
    debug(1, ' Found nothing');
    return 0;
}

sub split_soname {
    my $soname = shift;
    if ($soname =~ /^(.*)\.so\.(.*)$/) {
	return wantarray ? ($1, $2) : 1;
    } elsif ($soname =~ /^(.*)-(\d.*)\.so$/) {
	return wantarray ? ($1, $2) : 1;
    } else {
	return wantarray ? () : 0;
    }
}

sub extract_from_shlibs {
    my ($soname, $shlibfile) = @_;

    my $shlibs_re = qr{
        ^\s*
        (?:(\S+):\s+)?              # Optional type
        (\S+)\s+                    # Library
        (\S+)                       # Version
        (?:
          \s+
          (\S.*\S)                  # Dependencies
        )?
        \s*$
    }x;

    # Split soname in name/version
    my ($libname, $libversion) = split_soname($soname);
    unless (defined $libname) {
	warning(g_("can't extract name and version from library name '%s'"),
	        $soname);
	return;
    }
    # Open shlibs file
    open(my $shlibs_fh, '<', $shlibfile)
        or syserr(g_("unable to open shared libs info file '%s'"), $shlibfile);
    my $dep;
    while (<$shlibs_fh>) {
	s/\s*\n$//;
	next if m/^\#/;
	if (!m/$shlibs_re/) {
	    warning(g_("shared libs info file '%s' line %d: bad line '%s'"),
	            $shlibfile, $., $_);
	    next;
	}
	my $depread = $4 // '';
	if (($libname eq $2) && ($libversion eq $3)) {
	    # Define dep and end here if the package type explicitly
	    # matches. Otherwise if the packagetype is not specified, use
	    # the dep only as a default that can be overridden by a later
	    # line
	    if (defined($1)) {
		if ($1 eq $packagetype) {
		    $dep = $depread;
		    last;
		}
	    } else {
		$dep //= $depread;
	    }
	}
    }
    close($shlibs_fh);
    return $dep;
}

sub find_symbols_file {
    my ($pkg, $soname, $libfile) = @_;
    my @files;
    if ($pkg eq '') {
	# If the file is not packaged, try to find out the symbols file in
	# the package being built where the lib has been found
	my $pkg_root = guess_pkg_root_dir($libfile);
	if (defined $pkg_root) {
	    push @files, "$pkg_root/DEBIAN/symbols";
	}
	# Fallback to other symbols files but it shouldn't be necessary
	push @files, @pkg_symbols;
    } else {
	push @files, "$Dpkg::CONFDIR/symbols/$pkg.symbols.$host_arch",
	    "$Dpkg::CONFDIR/symbols/$pkg.symbols";

	state %control_file_cache;
	if (not exists $control_file_cache{$pkg}) {
	    $control_file_cache{$pkg} = get_control_path($pkg, 'symbols');
	}
	my $control_file = $control_file_cache{$pkg};
	push @files, $control_file if defined $control_file;
    }

    foreach my $file (@files) {
	if (-e $file and symfile_has_soname($file, $soname)) {
	    return $file;
	}
    }
    return;
}

sub symfile_has_soname {
    my ($file, $soname) = @_;

    if (exists $symfile_has_soname_cache{$file}{$soname}) {
        return $symfile_has_soname_cache{$file}{$soname};
    }

    open(my $symfile_fh, '<', $file)
        or syserr(g_('cannot open file %s'), $file);
    my $result = 0;
    while (<$symfile_fh>) {
	if (/^\Q$soname\E /) {
	    $result = 1;
	    last;
	}
    }
    close($symfile_fh);
    $symfile_has_soname_cache{$file}{$soname} = $result;
    return $result;
}

# find_library ($soname, \@rpath, $format)
sub my_find_library {
    my ($lib, $rpath, $format, $execfile) = @_;

    # Create real RPATH in case $ORIGIN is used
    # Note: ld.so also supports $PLATFORM and $LIB but they are
    # used in real case (yet)
    my $libdir = relative_to_pkg_root($execfile);
    my $origin;
    if (defined $libdir) {
	$origin = "/$libdir";
	$origin =~ s{/+[^/]*$}{};
    }
    my @RPATH = ();
    foreach my $path (@{$rpath}) {
	if ($path =~ /\$ORIGIN|\$\{ORIGIN\}/) {
	    if (defined $origin) {
		$path =~ s/\$ORIGIN/$origin/g;
		$path =~ s/\$\{ORIGIN\}/$origin/g;
	    } else {
		warning(g_('$ORIGIN is used in RPATH of %s and the corresponding ' .
		'directory could not be identified due to lack of DEBIAN ' .
		"sub-directory in the root of package's build tree"), $execfile);
	    }
	}
	push @RPATH, $path;
    }

    # Look into the packages we're currently building in the following
    # order:
    # - package build tree of the binary which is analyzed
    # - package build tree given on the command line (option -S)
    # - other package build trees that contain either a shlibs or a
    #   symbols file
    # But ignore:
    # - package build tree given on the command line (option -I)

    my @builddirs;
    my $pkg_root = guess_pkg_root_dir($execfile);
    push @builddirs, $pkg_root if defined $pkg_root;
    push @builddirs, @pkg_dir_to_search;
    push @builddirs, @pkg_root_dirs;
    my %dir_checked;
    foreach my $builddir (@builddirs) {
	next if defined($dir_checked{$builddir});
	next if ignore_pkgdir($builddir);
	my @libs = find_library($lib, \@RPATH, $format, $builddir);
	return @libs if scalar @libs;
	$dir_checked{$builddir} = 1;
    }

    # Fallback in the root directory if we have not found what we were
    # looking for in the packages
    return find_library($lib, \@RPATH, $format, '');
}

my %cached_pkgmatch = ();

sub find_packages {
    my @files;
    my $pkgmatch = {};

    foreach my $path (@_) {
	if (exists $cached_pkgmatch{$path}) {
	    $pkgmatch->{$path} = $cached_pkgmatch{$path};
	} else {
	    push @files, $path;
	    $cached_pkgmatch{$path} = ['']; # placeholder to cache misses too.
	    $pkgmatch->{$path} = [''];      # might be replaced later on
	}
    }
    return $pkgmatch unless scalar(@files);

    my $pid = open(my $dpkg_fh, '-|');
    syserr(g_('cannot fork for %s'), 'dpkg-query --search') unless defined $pid;
    if (!$pid) {
	# Child process running dpkg --search and discarding errors
	close STDERR;
	open STDERR, '>', '/dev/null'
	    or syserr(g_('cannot open file %s'), '/dev/null');
	$ENV{LC_ALL} = 'C';
	exec 'dpkg-query', '--search', '--', @files
	    or syserr(g_('unable to execute %s'), 'dpkg');
    }
    while (<$dpkg_fh>) {
	chomp;
	if (m/^local diversion |^diversion by/) {
	    warning(g_('diversions involved - output may be incorrect'));
	    print { *STDERR } " $_\n"
		or syserr(g_('write diversion info to stderr'));
	} elsif (m/^([-a-z0-9+.:, ]+): (\/.*)$/) {
	    my ($pkgs, $path) = ($1, $2);
	    my $realpath = realpath($path);
	    $cached_pkgmatch{$path} = $pkgmatch->{$path} = [ split /, /, $pkgs ];
	    $cached_pkgmatch{$realpath} = $pkgmatch->{$realpath} = [ split /, /, $pkgs ];
	} else {
	    warning(g_("unknown output from dpkg --search: '%s'"), $_);
	}
    }
    close($dpkg_fh);
    return $pkgmatch;
}

Anon7 - 2022
SCDN GOK