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.149.241.93
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/share/usermin/htaccess/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Command :


[ HOME ]     

Current File : /usr/share/usermin/htaccess/apache-lib.pl
# apache-lib.pl
# Common functions for apache configuration

BEGIN { push(@INC, ".."); };
use WebminCore;
$directive_type_count = 20;

our ($saved_conf_files);

if ($module_name ne 'htaccess') {
	&init_config();
	%access = &get_module_acl();
	@access_types = $access{'types'} eq '*' ? (0 .. $directive_type_count)
					: split(/\s+/, $access{'types'});
	}
else {
	@access_types = (0 .. $directive_type_count);
	}
map { $access_types{$_}++ } @access_types;
$site_file = ($config{'webmin_apache'} || $module_config_directory)."/site";
$httpd_info_cache = $module_config_directory."/httpd-info";
$last_config_change_flag = $module_var_directory."/config-flag";
$last_restart_time_flag = $module_var_directory."/restart-flag";

# Check if a list of supported modules needs to be built. This is done
# if the Apache binary changes, when Webmin is upgraded, or once every five
# minutes if automatic rebuilding is enabled.
if ($module_name ne 'htaccess') {
	local %oldsite;
	local $httpd = &find_httpd();
	local @st = stat($httpd);
	&read_file($site_file, \%oldsite);
	local @sst = stat($site_file);
	if ($oldsite{'path'} ne $httpd ||
	    $oldsite{'size'} != $st[7] ||
	    $oldsite{'webmin'} != &get_webmin_version() ||
	    $config{'auto_mods'} && $sst[9] < time()-5*60) {
		# Need to build list of supported modules
		local ($ver, $mods, $fullver) = &httpd_info($httpd);
		if ($ver) {
			my @allmods = &available_modules();
			local @mods = map { "$_/$ver" }
				          &configurable_modules(\@allmods);
			foreach my $m (@mods) {
				if ($m =~ /(\S+)\/(\S+)/) {
					$httpd_modules{$1} = $2;
					}
				}
			# Call again now that known modules have been set, as
			# sometimes there are dependencies due to LoadModule
			# statements in an IfModule block
			undef(@get_config_cache);
			@allmods = &available_modules();
			@mods = map { "$_/$ver" }
				    &configurable_modules(\@allmods);
			local %site = ( 'size' => $st[7],
					'path' => $httpd,
					'modules' => join(' ', @mods),
					'allmodules' => join(' ', @allmods),
					'version' => $ver,
					'fullversion' => $fullver,
					'webmin' => &get_webmin_version() );
			&lock_file($site_file);
			&write_file($site_file, \%site);
			chmod(0644, $site_file);
			&unlock_file($site_file);
			}
		}
	}

# Read the site-specific setup file, then require in all the module-specific
# .pl files
if (&read_file($site_file, \%site)) {
	local($m, $f, $d);
	$httpd_size = $site{'size'};
	foreach $m (split(/\s+/, $site{'modules'})) {
		if ($m =~ /(\S+)\/(\S+)/) {
			$httpd_modules{$1} = $2;
			}
		}
	foreach $m (split(/\s+/, $site{'allmodules'})) {
		$all_httpd_modules{$m} = $site{'version'};
		}
	foreach $m (keys %httpd_modules) {
		if (!-r "$module_root_directory/$m.pl") {
			delete($httpd_modules{$m});
			}
		}
	foreach $f (split(/\s+/, $site{'htaccess'})) {
		if (-r $f) { push(@htaccess_files, $f); }
		}
	foreach $m (keys %httpd_modules) {
		do "$m.pl";
		}
	foreach $d (split(/\s+/, $site{'defines'})) {
		$httpd_defines{$d}++;
		}
	}

$apache_docbase = $config{'apache_docbase'} ? $config{'apache_docbase'} :
		  $httpd_modules{'core'} >= 2.0 ?
			"http://httpd.apache.org/docs-2.0/mod/" :
			"http://httpd.apache.org/docs/mod/";

# parse_config_file(handle, lines, file, [recursive])
# Parses lines of text from some config file into a data structure. The
# return value is an array of references, one for each directive in the file.
# Each reference points to an associative array containing
#  line -	The line number this directive is at
#  eline -	The line number this directive ends at
#  file -	The file this directive is from
#  type -	0 for a normal directive, 1 for a container directive
#  name -	The name of this directive
#  value -	Value (possibly with spaces)
#  members -	For type 1, a reference to the array of members
#  indent -     Number of spaces before the name
sub parse_config_file
{
local($fh, @rv, $line, %dummy);
$fh = $_[0];
$dummy{'line'} = $dummy{'eline'} = $_[1]-1;
$dummy{'file'} = $_[2];
$dummy{'type'} = 0;
$dummy{'name'} = "dummy";
@rv = (\%dummy);
local %defs;
foreach my $d (&get_httpd_defines()) {
	if ($d =~ /^(\S+)=(.*)$/) {
		$defs{$1} = $2;
		}
	else {
		$defs{$d} = '';
		}
	}
while($line = <$fh>) {
	$line =~ s/\r|\n//g;
	$line =~ s/^\s*#.*$//g;
	if ($line =~ /^\s*<\/(\S+)\s*(.*)>/) {
		# end of a container directive. This can only happen in a
		# recursive call to this function
		$_[1]++;
		last if (lc($_[3]) eq lc($1));
		}
	elsif ($line =~ /^\s*<IfModule\s+(\!?)(\S+)\.c>/i ||
	       $line =~ /^\s*<IfModule\s+(\!?)(\S+)>/i) {
		# start of an IfModule block. Read it, and if the module
		# exists put the directives in this section.
		local ($not, $mod) = ($1, $2);
		local $oldline = $_[1];
		$_[1]++;
		local @dirs = &parse_config_file($fh, $_[1], $_[2], 'IfModule');
		local $altmod = $mod;
		$altmod =~ s/^(\S+)_module$/mod_$1/g;
		local $mpmmod = $mod;
		$mpmmod =~ s/^mpm_//; $mpmmod =~ s/_module$//;
		if ($mod eq "prefork") {
			# Special case for all the prefork aliases
			($mod, $altmod, $mpmmod) = ("mod_".$mod."_module",
						    "mod_mpm_".$mod, $mod);
			}
		if (!$not && $httpd_modules{$mod} ||
		    $not && !$httpd_modules{$mod} ||
		    !$not && $httpd_modules{$altmod} ||
		    $not && !$httpd_modules{$altmod} ||
		    !$not && $httpd_modules{$mpmmod} ||
		    $not && !$httpd_modules{$mpmmod}
		    ) {
			# use the directives..
			push(@rv, { 'line', $oldline,
				    'eline', $oldline,
				    'file', $_[2],
				    'name', "<IfModule $not$mod>" });
			push(@rv, @dirs);
			push(@rv, { 'line', $_[1]-1,
				    'eline', $_[1]-1,
				    'file', $_[2],
				    'name', "</IfModule>" });
			}
		}
	elsif ($line =~ /^\s*<IfDefine\s+(\!?)(\S+)>/i) {
		# start of an IfDefine block. Read it, and if the define
		# exists put the directives in this section
		local ($not, $def) = ($1, $2);
		local $oldline = $_[1];
		$_[1]++;
		local @dirs = &parse_config_file($fh, $_[1], $_[2], 'IfDefine');
		if (!$not && defined($defs{$def}) ||
		    $not && !defined($defs{$def})) {
			# use the directives..
			push(@rv, { 'line', $oldline,
				    'eline', $oldline,
				    'file', $_[2],
				    'name', "<IfDefine $not$def>" });
			push(@rv, @dirs);
			push(@rv, { 'line', $_[1]-1,
				    'eline', $_[1]-1,
				    'file', $_[2],
				    'name', "</IfDefine>" });
			}
		}
	elsif ($line =~ /^\s*<IfVersion\s+(\!?)(\S*)\s*(\S+)>/i) {
		# Start of an IfVersion block. Read it, and if the version
		# matches put the directives in this section
		local ($not, $op, $ver) = ($1, $2, $3);
		local $oldline = $_[1];
		$_[1]++;
		local @dirs = &parse_config_file($fh, $_[1], $_[2], 'IfVersion');
		$op ||= "=";
		local $match = 0;
		local $myver = $httpd_modules{'core'};
		$myver =~ s/^(\d+)\.(\d)(\d+)$/$1.$2.$3/;
		if ($op eq "=" || $op eq "==") {
			if ($ver =~ /^\/(.*)\/$/) {
				$match = 1 if ($myver =~ /$1/);
				}
			else {
				$match = 1 if ($myver eq $ver);
				}
			}
		elsif ($op eq ">") {
			$match = 1 if ($myver > $ver);
			}
		elsif ($op eq ">=") {
			$match = 1 if ($myver >= $ver);
			}
		elsif ($op eq "<") {
			$match = 1 if ($myver < $ver);
			}
		elsif ($op eq "<=") {
			$match = 1 if ($myver <= $ver);
			}
		elsif ($op eq "~") {
			$match = 1 if ($myver =~ /$ver/);
			}
		$match = !$match if ($not);
		if ($match) {
			# use the directives..
			push(@rv, { 'line', $oldline,
				    'eline', $oldline,
				    'file', $_[2],
				    'name', "<IfVersion $not$op $ver>" });
			push(@rv, @dirs);
			push(@rv, { 'line', $_[1]-1,
				    'eline', $_[1]-1,
				    'file', $_[2],
				    'name', "</IfVersion>" });
			}
		}
	elsif ($line =~ /^(\s*)<(\S+)\s*(.*)>/) {
		# start of a container directive. The first member is a dummy
		# directive at the same line as the container
		local(%dir, @members);
		%dir = ('line', $_[1],
			'file', $_[2],
			'type', 1,
			'name', $2,
			'value', $3);
		local $indent = $1;
		$dir{'value'} =~ s/\s+$//g;
		$dir{'words'} = &wsplit($dir{'value'});
		$_[1]++;
		@members = &parse_config_file($fh, $_[1], $_[2], $dir{'name'});
		$dir{'members'} = \@members;
		$dir{'eline'} = $_[1]-1;
		$indent =~ s/\t/        /g;
		$dir{'indent'} = length($indent);
		push(@rv, \%dir);
		}
	elsif ($line =~ /^(\s*)(\S+)\s*(.*)$/) {
		# normal directive
		local(%dir);
		%dir = ('line', $_[1],
			'eline', $_[1],
			'file', $_[2],
			'type', 0,
			'name', $2,
			'value', $3);
		local $indent = $1;
		$indent =~ s/\t/        /g;
		$dir{'indent'} = length($indent);
		if ($dir{'value'} =~ s/\\$//g) {
			# multi-line directive!
			while($line = <$fh>) {
				chop($line);
				$cont = ($line =~ s/\\$//g);
				$dir{'value'} .= $line;
				$dir{'eline'} = ++$_[1];
				if (!$cont) { last; }
				}
			}
		$dir{'value'} =~ s/\s+$//g;
		if ($dir{'value'} =~ /^(.*)\$\{([^\}]+)\}(.*)$/) {
			# Contains a variable .. replace with define
			local $v = $defs{$2};
			if ($v) {
				$dir{'value'} = $1.$v.$3;
				}
			}
		$dir{'words'} = &wsplit($dir{'value'});
		push(@rv, \%dir);
		$_[1]++;
		}
	else {
		# blank or comment line
		$_[1]++;
		}
	}
return @rv;
}

# wsplit(string)
# Splits a string like  foo "foo \"bar\"" bazzz  into an array of words
sub wsplit
{
local($s, @rv); $s = $_[0];
$s =~ s/\\\"/\0/g;
while($s =~ /^"([^"]*)"\s*(.*)$/ || $s =~ /^(\S+)\s*(.*)$/) {
	$w = $1; $s = $2;
	$w =~ s/\0/"/g; push(@rv, $w);
	}
return \@rv;
}

# wjoin(word, word, ...)
sub wjoin
{
local(@rv, $w);
foreach $w (@_) {
	if ($w =~ /^\S+$/) { push(@rv, $w); }
	else { push(@rv, "\"$w\""); }
	}
return join(' ', @rv);
}

# find_directive(name, &directives, [1stword])
# Returns the values of directives matching some name
sub find_directive
{
local (@vals, $ref);
foreach $ref (@{$_[1]}) {
	if (lc($ref->{'name'}) eq lc($_[0])) {
		push(@vals, $_[2] ? $ref->{'words'}->[0] : $ref->{'value'});
		}
	}
return wantarray ? @vals : !@vals ? undef : $vals[$#vals];
}

# find_directive_struct(name, &directives)
# Returns references to directives matching some name
sub find_directive_struct
{
local (@vals, $ref);
foreach $ref (@{$_[1]}) {
	if (lc($ref->{'name'}) eq lc($_[0])) {
		push(@vals, $ref);
		}
	}
return wantarray ? @vals : !@vals ? undef : $vals[$#vals];
}

# find_vdirective(name, &virtualdirectives, &directives, [1stword])
# Looks for some directive in a <VirtualHost> section, and then in the 
# main section
sub find_vdirective
{
if ($_[1]) {
	$rv = &find_directive($_[0], $_[1], $_[3]);
	if ($rv) { return $rv; }
	}
return &find_directive($_[0], $_[2], $_[3]);
}

# get_config()
# Returns the entire config structure
sub get_config
{
local($acc, $res, $lnum, $conf, @virt, $v, $mref, $inc);
if (@get_config_cache) {
	return \@get_config_cache;
	}

# read primary config file
($conf) = &find_httpd_conf();
return undef if (!$conf);
my %seenfiles;
@get_config_cache = &get_config_file($conf, \%seenfiles);

# Read main resource and access config files
$lnum = 0;
$res = &find_directive("ResourceConfig", \@get_config_cache);
if (!$res) { $res = $config{'srm_conf'}; }
if (!$res) { $res = "$config{'httpd_dir'}/conf/srm.conf"; }
if (!-r &translate_filename($res)) {
	$res = "$config{'httpd_dir'}/etc/srm.conf";
	}
push(@get_config_cache, &get_config_file($res, \%seenfiles));

$lnum = 0;
$acc = &find_directive("AccessConfig", \@get_config_cache);
if (!$acc) { $acc = $config{'access_conf'}; }
if (!$acc) { $acc = "$config{'httpd_dir'}/conf/access.conf"; }
if (!-r &translate_filename($acc)) {
	$acc = "$config{'httpd_dir'}/etc/access.conf";
	}
push(@get_config_cache, &get_config_file($acc, \%seenfiles));

# Read extra config files in VirtualHost sections
@virt = &find_directive_struct("VirtualHost", \@get_config_cache);
foreach $v (@virt) {
	my %seenfiles;
	$mref = $v->{'members'};
	foreach $idn ("ResourceConfig", "AccessConfig", "Include", "IncludeOptional") {
		foreach $inc (&find_directive_struct($idn, $mref)) {
			local @incs = &expand_apache_include(
					$inc->{'words'}->[0]);
			foreach my $ginc (@incs) {
				push(@$mref, &get_config_file($ginc,
							      \%seenfiles));
				}
			}
		}
	}

return \@get_config_cache;
}

# get_config_file(filename, [&seen-files])
# Returns a list of config hash refs from some file
sub get_config_file
{
my ($file, $seen) = @_;

# Convert sites-enabled to real path in sites-available
$file = &simplify_path(&resolve_links($file));
return ( ) if ($seen && $seen->{$file}++);
local @rv;
if (opendir(DIR, $file)) {
	# Is a directory .. parse all files!
	local @files = readdir(DIR);
	closedir(DIR);
	foreach my $f (sort { $a cmp $b } @files) {
		next if ($f =~ /^\./);
		push(@rv, &get_config_file("$file/$f", $seen));
		}
	}
else {
	# Just a normal config file
	local $lnum = 0;
	&open_readfile(CONF, $file);
	@rv = &parse_config_file(CONF, $lnum, $file);
	close(CONF);
	}

# Expand Include directives
foreach $inc (&find_directive_struct("Include", \@rv),
	      &find_directive_struct("IncludeOptional", \@rv)) {
	local @incs = &expand_apache_include($inc->{'words'}->[0]);
	foreach my $ginc (@incs) {
		push(@rv, &get_config_file($ginc, $seen));
		}
	}

return @rv;
}

# expand_apache_include(dir)
# Given an include directive value, returns a list of matching files
sub expand_apache_include
{
local ($incdir) = @_;
if ($incdir !~ /^\//) { $incdir = "$config{'httpd_dir'}/$incdir"; }
if ($incdir =~ /^(.*)\[\^([^\]]+)\](.*)$/) {
	# A glob like /etc/[^.#]*.conf , which cannot be handled
	# by Perl's glob function!
	local $before = $1;
	local $after = $3;
	local %reject = map { $_, 1 } split(//, $2);
	$reject{'*'} = $reject{'?'} = $reject{'['} = $reject{']'} =
	  $reject{'/'} = $reject{'$'} = $reject{'('} = $reject{')'} =
	  $reject{'!'} = 1;
	local $accept = join("", grep { !$reject{$_} } map { chr($_) } (32 .. 126));
	$incdir = $before."[".$accept."]".$after;
	}
return sort { $a cmp $b } glob($incdir);
}

# get_virtual_config(index|name)
# Returns the Apache config block with some index in the main config, or name
sub get_virtual_config
{
local ($name) = @_;
local $conf = &get_config();
local ($c, $v);
if (!$name) {
	# Whole config
	$c = $conf;
	$v = undef;
	}
elsif ($name =~ /^\d+$/) {
	# By index
	$c = $conf->[$name]->{'members'};
	$v = $conf->[$name];
	}
else {
	# Find by name, in servername:port format
	my ($sn, $sp) = split(/:/, $name);
	VHOST: foreach my $virt (&find_directive_struct("VirtualHost", $conf)) {
		local $vp = $virt->{'words'}->[0] =~ /:(\d+)$/ ? $1 : 80;
		next if ($vp != $sp);
		local $vn = &find_directive("ServerName", $virt->{'members'});
		if (lc($vn) eq lc($sn) || lc($vn) eq lc("www.".$sn)) {
			$c = $virt->{'members'};
			$v = $virt;
			last VHOST;
			}
		foreach my $n (&find_directive_struct("ServerAlias",
						      $virt->{'members'})) {
			local @lcw = map { lc($_) } @{$n->{'words'}};
			if (&indexof($sn, @lcw) >= 0 ||
			    &indexof("www.".$sn, @lcw) >= 0) {
				$c = $virt->{'members'};
				$v = $virt;
				last VHOST;
				}
			}
		}
	}
return wantarray ? ($c, $v) : $c;
}

# get_htaccess_config(file)
sub get_htaccess_config
{
local($lnum, @conf);
&open_readfile(HTACCESS, $_[0]);
@conf = &parse_config_file(HTACCESS, $lnum, $_[0]);
close(HTACCESS);
return \@conf;
}

# save_directive(name, &values, &parent-directives, &config, [always-at-end])
# Updates the config file(s) and the directives structure with new values
# for the given directives.
# If a directive's value is merely being changed, then its value only needs
# to be updated in the directives array and in the file.
sub save_directive
{
local($i, @old, $lref, $change, $len, $v);
@old = &find_directive_struct($_[0], $_[2]);
local @files;
for($i=0; $i<@old || $i<@{$_[1]}; $i++) {
	$v = ${$_[1]}[$i];
	if ($i >= @old) {
		# a new directive is being added. If other directives of this
		# type exist, add it after them. Otherwise, put it at the end of
		# the first file in the section
		if ($change && !$_[4]) {
			# Have changed some old directive.. add this new one
			# after it, and update change
			local(%v, $j);
			%v = (	"line", $change->{'line'}+1,
				"eline", $change->{'line'}+1,
				"file", $change->{'file'},
				"indent", $change->{'indent'},
				"type", 0,
				"name", $_[0],
				"value", $v,
				"words", &wsplit($v) );
			$j = &indexof($change, @{$_[2]})+1;
			&renumber($_[3], $v{'line'}, $v{'file'}, 1);
			splice(@{$_[2]}, $j, 0, \%v);
			$lref = &read_file_lines($v{'file'});
			push(@files, $v{'file'});
			splice(@$lref, $v{'line'}, 0,
				(" " x $v{'indent'})."$_[0] $v");
			$change = \%v;
			}
		else {
			# Adding a new directive to the end of the list
			# in this section
			local($f, %v, $j);
			$f = $_[2]->[0]->{'file'};
			for($j=0; $_[2]->[$j]->{'file'} eq $f; $j++) { }
			$lref = &read_file_lines($f);
			if ($_[2] eq $_[3]) {
				# Top-level, so add to the end of the file
				$l = scalar(@$lref) + 1;
				}
			else {
				# Add after last directive in the same section
				$l = $_[2]->[$j-1]->{'eline'}+1;
				}
			%v = (	"line", $l,
				"eline", $l,
				"file", $f,
				"indent", $_[2]->[$j-1]->{'indent'},
				"type", 0,
				"name", $_[0],
				"value", $v,
				"words", &wsplit($v) );
			&renumber($_[3], $l, $f, 1);
			splice(@{$_[2]}, $j, 0, \%v);
			push(@files, $f);
			splice(@$lref, $l, 0, 
				(" " x $v{'indent'})."$_[0] $v");
			}
		}
	elsif ($i >= @{$_[1]}) {
		# a directive was deleted
		$lref = &read_file_lines($old[$i]->{'file'});
		push(@files, $old[$i]->{'file'});
		$idx = &indexof($old[$i], @{$_[2]});
		splice(@{$_[2]}, $idx, 1);
		$len = $old[$i]->{'eline'} - $old[$i]->{'line'} + 1;
		splice(@$lref, $old[$i]->{'line'}, $len);
		&renumber($_[3], $old[$i]->{'line'}, $old[$i]->{'file'}, -$len);
		}
	else {
		# just changing the value
		$lref = &read_file_lines($old[$i]->{'file'});
		push(@files, $old[$i]->{'file'});
		$len = $old[$i]->{'eline'} - $old[$i]->{'line'} + 1;
		&renumber($_[3], $old[$i]->{'eline'}+1,
			  $old[$i]->{'file'},1-$len);
		$old[$i]->{'value'} = $v;
		$old[$i]->{'words'} = &wsplit($v);
		$old[$i]->{'eline'} = $old[$i]->{'line'};
		splice(@$lref, $old[$i]->{'line'}, $len,
			(" " x $old[$i]->{'indent'}).$_[0]." ".$v);
		$change = $old[$i];
		}
	}
&update_last_config_change();
@files = &unique(@files);
push(@{$saved_conf_files}, @files);
return @files;
}

# save_directive_struct(&old-directive, &directive, &parent-directives,
#			&config, [firstline-only])
# Updates, creates or removes only multi-line directive like a <virtualhost>
sub save_directive_struct
{
local ($olddir, $newdir, $pconf, $conf, $first) = @_;
return if (!$olddir && !$newdir);	# Nothing to do
local $file = $olddir ? $olddir->{'file'} :
	      $newdir->{'file'} ? $newdir->{'file'} : $pconf->[0]->{'file'};
local $lref = &read_file_lines($file);
local $oldlen = $olddir ? $olddir->{'eline'}-$olddir->{'line'}+1 : undef;
local @newlines;
if ($newdir) {
	my $isrc = $olddir ? $olddir :
		   @$pconf ? $pconf->[0] : undef;
	if ($isrc) {
		&recursive_set_indent($newdir, $isrc->{'indent'});
		}
	@newlines = &directive_lines($newdir);
	}
if ($olddir && $newdir) {
	# Update in place
	if ($first) {
		# Just changing first and last line, like virtualhost IP
		$lref->[$olddir->{'line'}] = $newlines[0];
		$lref->[$olddir->{'eline'}] = $newlines[$#newlines];
		$olddir->{'name'} = $newdir->{'name'};
		$olddir->{'value'} = $newdir->{'value'};
		}
	else {
		# Re-writing whole block
		&renumber($conf, $olddir->{'eline'}+1, $file,
			  scalar(@newlines)-$oldlen);
		local $idx = &indexof($olddir, @$pconf);
		$pconf->[$idx] = $newdir if ($idx >= 0);
		$newdir->{'file'} = $olddir->{'file'};
		$newdir->{'line'} = $olddir->{'line'};
		$newdir->{'eline'} = $olddir->{'line'}+scalar(@newlines)-1;
		splice(@$lref, $olddir->{'line'}, $oldlen, @newlines);

		# Update sub-directive lines and files too
		if ($newdir->{'type'}) {
			&recursive_set_lines_files($newdir->{'members'},
						   $newdir->{'line'}+1,
						   $newdir->{'file'});
			}
		}
	}
elsif ($olddir && !$newdir) {
	# Remove
	splice(@$lref, $olddir->{'line'}, $oldlen);
	local $idx = &indexof($olddir, @$pconf);
	splice(@$pconf, $idx, 1) if ($idx >= 0);
	&renumber($conf, $olddir->{'line'}, $olddir->{'file'}, -$oldlen);
	}
elsif (!$olddir && $newdir) {
	# Add to file, at end of specific file or parent section
	local ($addline, $addpos);
	if ($newdir->{'file'}) {
		$addline = scalar(@$lref);
		$addpos = scalar(@$pconf);
		}
	else {
		for($addpos=0; $addpos < scalar(@$pconf) &&
			       $pconf->[$addpos]->{'file'} eq $file;
		    $addpos++) {
			# Find last parent directive in same file
			}
		$addpos--;
		$addline = $pconf->[$addpos]->{'eline'}+1;
		}
	$newdir->{'file'} = $file;
	$newdir->{'line'} = $addline;
	$newdir->{'eline'} = $addline + scalar(@newlines) - 1;
	&renumber($conf, $addline, $file, scalar(@newlines));
	splice(@$pconf, $addpos, 0, $newdir);
	splice(@$lref, $addline, 0, @newlines);

	# Update sub-directive lines and files too
	if ($newdir->{'type'}) {
		&recursive_set_lines_files($newdir->{'members'},
					   $newdir->{'line'}+1,
					   $newdir->{'file'});
		}
	}
&update_last_config_change();
}

# recursive_set_indent(&directive, indent)
# Set the indent to match another at the same level
sub recursive_set_indent
{
my ($dir, $indent) = @_;
$dir->{'indent'} = $indent if (!defined($dir->{'indent'}));
if ($dir->{'type'}) {
	foreach my $m (@{$dir->{'members'}}) {
		&recursive_set_indent($m, $indent+4);
		}
	}
}

# recursive_set_lines_files(&directives, first-line, file)
# Update the line numbers and filenames in a list of directives
sub recursive_set_lines_files
{
my ($dirs, $line, $file) = @_;
foreach my $dir (@$dirs) {
	$dir->{'line'} = $line;
	$dir->{'file'} = $file;
	if ($dir->{'type'}) {
		# Do sub-members too
		&recursive_set_lines_files($dir->{'members'}, $line+1, $file);
		$line += scalar(@{$dir->{'members'}})+1;
		$dir->{'eline'} = $line;
		}
	else {
		$dir->{'eline'} = $line;
		}
	$line++;
	}
return $line;
}

# delete_file_if_empty(file)
# If a virtual host file is now empty, delete it (and any link to it)
sub delete_file_if_empty
{
local ($file) = @_;
local $lref = &read_file_lines($file, 1);
foreach my $l (@$lref) {
	return 0 if ($l =~ /\S/);
	}
&unflush_file_lines($file);
unlink($file);
&delete_webfile_link($file);
}

# renumber(&config, line, file, offset)
# Recursively changes the line number of all directives from some file 
# beyond the given line.
sub renumber
{
local($d);
if (!$_[3]) { return; }
foreach $d (@{$_[0]}) {
	if ($d->{'file'} eq $_[2] && $d->{'line'} >= $_[1]) {
		$d->{'line'} += $_[3];
		}
	if ($d->{'file'} eq $_[2] && $d->{'eline'} >= $_[1]) {
		$d->{'eline'} += $_[3];
		}
	if ($d->{'type'}) {
		&renumber($d->{'members'}, $_[1], $_[2], $_[3]);
		}
	}
}

# server_root(path)
# Convert a relative path to being under the server root
sub server_root
{
if (!$_[0]) { return undef; }
elsif ($_[0] =~ /^\//) { return $_[0]; }
else { return "$config{'httpd_dir'}/$_[0]"; }
}

sub dump_config
{
local($c, $mref);
print "<table border>\n";
print "<tr> <td>Name</td> <td>Value</td> <td>File</td> <td>Line</td> </tr>\n";
foreach $c (@_) {
	printf "<tr> <td>%s</td> <td>%s</td><td>%s</td><td>%s</td> </tr>\n",
		$c->{'name'}, $c->{'value'}, $c->{'file'}, $c->{'line'};
	if ($c->{'type'}) {
		print "<tr> <td colspan=4>\n";
		$mref = $c->{'members'};
		&dump_config(@$mref);
		print "</td> </tr>\n";
		}
	}
print "</table>\n";
}

sub def
{
return $_[0] ? $_[0] : $_[1];
}

# make_directives(ref, version, module)
sub make_directives
{
local(@rv, $aref);
$aref = $_[0];
local $ver = $_[1];
if ($ver =~ /^(1)\.(3)(\d+)$/) {
	$ver = sprintf "%d.%d%2.2d", $1, $2, $3;
	}
foreach $d (@$aref) {
	local(%dir);
	$dir{'name'} = $d->[0];
	$dir{'multiple'} = $d->[1];
	$dir{'type'} = int($d->[2]);
	$dir{'subtype'} = $d->[2] - $dir{'type'};
	$dir{'module'} = $_[2];
	$dir{'version'} = $ver;
	$dir{'priority'} = $d->[5];
	foreach $c (split(/\s+/, $d->[3])) { $dir{$c}++; }
	if (!$d->[4]) { push(@rv, \%dir); }
	elsif ($d->[4] =~ /^-([\d\.]+)$/ && $ver < $1) { push(@rv, \%dir); }
	elsif ($d->[4] =~ /^([\d\.]+)$/ && $ver >= $1) { push(@rv, \%dir); }
	elsif ($d->[4] =~ /^([\d\.]+)-([\d\.]+)$/ && $ver >= $1 && $ver < $2)
		{ push(@rv, \%dir); }
	}
return @rv;
}


# editable_directives(type, context)
# Returns an array of references to associative arrays, one for each 
# directive of the given type that can be used in the given context
sub editable_directives
{
local($m, $func, @rv, %done);
foreach $m (keys %httpd_modules) {
	$func = $m."_directives";
	if (defined(&$func)) {
		push(@rv, &$func($httpd_modules{$m}));
		}
	}
@rv = grep { $_->{'type'} == $_[0] && $_->{$_[1]} &&
	     !$done{$_->{'name'}}++ } @rv;
@rv = grep { &can_edit_directive($_->{'name'}) } @rv;
@rv = sort { local $td = $a->{'subtype'} <=> $b->{'subtype'};
	     local $pd = $b->{'priority'} <=> $a->{'priority'};
	     local $md = $a->{'module'} cmp $b->{'module'};
	     $td ? $td : $pd ? $pd : $md ? $md : $a->{'name'} cmp $b->{'name'} }
		@rv;
return @rv;
}

# can_edit_directive(name)
# Returns 1 if the Apache directive named can be edited by the current user
sub can_edit_directive
{
local ($name) = @_;
if ($access{'dirsmode'} == 0) {
	return 1;
	}
else {
	local %dirs = map { lc($_), 1 } split(/\s+/, $access{'dirs'});
	if ($access{'dirsmode'} == 1) {
		return $dirs{lc($name)};
		}
	else {
		return !$dirs{lc($name)};
		}
	}
}

# generate_inputs(&editors, &directives, [&skip])
# Displays a 2-column list of options, for use inside a table
sub generate_inputs
{
local($e, $sw, @args, @rv, $func, $lastsub);
foreach $e (@{$_[0]}) {
	if (defined($lastsub) && $lastsub != $e->{'subtype'}) {
		print &ui_table_hr();
		}
	$lastsub = $e->{'subtype'};

	# Build arg list for the editing function. Each arg can be a single
	# directive struct, or a reference to an array of structures.
	$func = "edit";
	undef(@args);
	foreach $ed (split(/\s+/, $e->{'name'})) {
		local(@vals);
		$func .= "_$ed";
		@vals = &find_directive_struct($ed, $_[1]);
		if ($e->{'multiple'}) { push(@args, \@vals); }
		elsif (!@vals) { push(@args, undef); }
		else { push(@args, $vals[$#vals]); }
		}
	push(@args, $e);

	# call the function
	@rv = &$func(@args);
	local $names;
	if ($config{'show_names'} || $userconfig{'show_names'}) {
		$names = " (";
		foreach $ed (split(/\s+/, $e->{'name'})) {
			# nodo50 v0.1 - Change 000004 - Open new window for Help in Apache module and mod_apachessl Help from http://www.apache-ssl.org and
			# nodo50 v0.1 - Change 000004 - Abre nueva ventana para Ayuda del módulo Apache y para mod_apachessl busca la Ayuda en http://www.apache-ssl.org and
			$names .= "<tt>".&ui_link( ($e->{'module'} eq 'mod_apachessl' ? 'http://www.apache-ssl.org/docs.html#'.$ed : $apache_docbase."/".$e->{'module'}.".html#".lc($ed)), $ed )."</tt>&nbsp;";
			#$names .= "<tt><a href='".$apache_docbase."/".$e->{'module'}.".html#".lc($ed)."'>".$ed."</a></tt> ";
			# nodo50 v0.1 - Change 000004 - End
			}
		$names .= ")";
		}
	if ($rv[0] >= 2) {
		# spans 2 columns..
		if ($rv[0] == 3) {
			# Takes up whole row
			print &ui_table_row(undef, $rv[2], 4);
			}
		else {
			# Has title on left
			print &ui_table_row($rv[1], $rv[2], 3);
			}
		}
	else {
		# only spans one column
		print &ui_table_row($rv[1], $rv[2]);
		}
	}
}

# parse_inputs(&editors, &directives, &config)
# Reads user choices from a form and update the directives and config files.
sub parse_inputs
{
# First call editor functions to get new values. Each function returns
# an array of references to arrays containing the new values for the directive.
&before_changing();
&lock_apache_files();
foreach $e (@{$_[0]}) {
	@dirs = split(/\s+/, $e->{'name'});
	$func = "save_".join('_', @dirs);
	@rv = &$func($e);
	for($i=0; $i<@dirs; $i++) {
		push(@chname, $dirs[$i]);
		push(@chval, $rv[$i]);
		}
	}

# Assuming everything went OK, update the configuration
for($i=0; $i<@chname; $i++) {
	&save_directive($chname[$i], $chval[$i], $_[1], $_[2]);
	}
&flush_file_lines();
&unlock_apache_files();
&after_changing();
&format_modifed_config_files();
}

# opt_input(value, name, default, size)
sub opt_input
{
return &ui_opt_textbox($_[1], $_[0], $_[3], $_[2]);
}

# parse_opt(name, regexp, error, [noquotes])
sub parse_opt
{
local($i, $re);
local $v = $in{$_[0]};
$v =~ /\r|\n|\0/ && &error($text{'enewline'});
if ($in{"$_[0]_def"}) { return ( [ ] ); }
for($i=1; $i<@_; $i+=2) {
	$re = $_[$i];
	if ($v !~ /$re/) { &error($_[$i+1]); }
	}
return ( [ $v =~ /\s/ && !$_[3] ? "\"$v\"" : $v ] );
}

# choice_input(value, name, default, [choice]+)
# Each choice is a display,value pair
sub choice_input
{
my($i, $rv);
for($i=3; $i<@_; $i++) {
	$_[$i] =~ /^([^,]*),(.*)$/;
	$rv .= &ui_oneradio($_[1], $2, $1, lc($2) eq lc($_[0]) ||
				!defined($_[0]) && lc($2) eq lc($_[2]))."\n";
	}
return $rv;
}

# choice_input_vert(value, name, default, [choice]+)
# Each choice is a display,value pair
sub choice_input_vert
{
my($i, $rv);
for($i=3; $i<@_; $i++) {
	$_[$i] =~ /^([^,]*),(.*)$/;
	$rv .= &ui_oneradio($_[1], $2, $1, lc($2) eq lc($_[0]) ||
				!defined($_[0]) && lc($2) eq lc($_[2]))."<br>\n";
	}
return $rv;
}

# parse_choice(name, default)
sub parse_choice
{
if (lc($in{$_[0]}) eq lc($_[1])) {
	return ( [ ] );
	}
else {
	$in{$_[0]} =~ /\r|\n|\0/ && &error($text{'enewline'});
	return ( [ $in{$_[0]} ] );
	}
}

# select_input(value, name, default, [choice]+)
sub select_input
{
my($i, @sel);
my $selv;
for($i=3; $i<@_; $i++) {
	$_[$i] =~ /^([^,]*),(.*)$/;
	if (lc($2) eq lc($_[0]) || !defined($_[0]) && lc($2) eq lc($_[2])) {
		$selv = $2;
		}
	push(@sel, [ $2, $1 || "&nbsp;" ]);
	}
return &ui_select($_[1], $selv, \@sel, 1);
}

# parse_choice(name, default)
sub parse_select
{
return &parse_choice(@_);
}

# handler_input(value, name)
sub handler_input
{
my($m, $func, @hl, @sel, $h);
my $conf = &get_config();
push(@hl, "");
foreach $m (keys %httpd_modules) {
	$func = $m."_handlers";
	if (defined(&$func)) {
		push(@hl, &$func($conf, $httpd_modules{$m}));
		}
	}
if (&indexof($_[0], @hl) < 0) { push(@hl, $_[0]); }
foreach $h (&unique(@hl)) {
    push(@sel, [$h, $h, ($h eq $_[0] ? "selected" : "")] );
	}
push(@sel, ["None", "&lt;".$text{'core_none'}."&gt;", ($_[0] eq "None" ? "selected" : "")] );
return &ui_select($_[1], undef, \@sel, 1);
}

# parse_handler(name)
sub parse_handler
{
if ($in{$_[0]} eq "") {
	return ( [ ] );
	}
else {
	$in{$_[0]} =~ /\r|\n|\0/ && &error($text{'enewline'});
	return ( [ $in{$_[0]} ] );
	}
}

# filters_input(&values, name)
sub filters_input
{
local($m, $func, @fl, $rv, $f);
local $conf = &get_config();
foreach $m (keys %httpd_modules) {
	$func = $m."_filters";
	if (defined(&$func)) {
		push(@fl, &$func($conf, $httpd_modules{$m}));
		}
	}
foreach $f (@{$_[0]}) {
	push(@fl, $f) if (&indexof($f, @fl) < 0);
	}
foreach $f (&unique(@fl)) {
	$rv .= &ui_checkbox($_[1], $f, $f, (&indexof($f, @{$_[0]}) < 0 ? 0 : 1 ) ); 
	}
$rv ||= &ui_textbox($_[1], "", 20);
return $rv;
}

# parse_filters(name)
sub parse_filters
{
$in{$_[0]} =~ /\r|\n|\0/ && &error($text{'enewline'});
local @f = split(/\0/, $in{$_[0]});
return @f ? ( [ join(";", @f) ] ) : ( [ ] );
}



# virtual_name(struct, [forlog])
sub virtual_name
{
if ($_[0]) {
	local $n = &find_directive("ServerName", $_[0]->{'members'});
	if ($n) {
		return &html_escape($_[0]->{'value'} =~ /:(\d+)$/ ? "$n:$1"
								  : $n);
		}
	else {
		return &html_escape(
			$_[0]->{'value'} =~ /^\[(\S+)\]$/ ? $1 :
			$_[0]->{'value'} =~ /^\[(\S+)\]:(\d+)$/ ? "$1:$2" :
				$_[0]->{'value'});
		}
	}
else { return $_[1] ? "*" : $text{'default_serv'}; }
}

# dir_name(struct)
# Given a <directory> or similar structure, return a human-readable description
sub dir_name
{
$_[0]->{'name'} =~ /^(Directory|Files|Location|Proxy)(Match)?$/;
my ($dfm, $mat) = ($1, $2);
if ($dfm eq "Proxy" && !$mat && $_[0]->{'words'}->[0] eq "*") {
	# Proxy for all
	return $text{'dir_proxyall'};
	}
elsif ($mat) {
	# Match-type directive
	return "$dfm regexp <tt>".&html_escape($_[0]->{'words'}->[0])."</tt>";
	}
elsif ($_[0]->{'words'}->[0] eq "~") {
	# Regular expression
	return "$dfm regexp <tt>".&html_escape($_[0]->{'words'}->[1])."</tt>";
	}
else {
	# Exact match
	return "$dfm <tt>".&html_escape($_[0]->{'words'}->[0])."</tt>";
	}
}

# list_user_file(file, &user,  &pass)
sub list_user_file
{
local($_);
&open_readfile(USERS, $_[0]);
while(<USERS>) {
	/^(\S+):(\S+)/;
	push(@{$_[1]}, $1); $_[2]->{$1} = $2;
	}
close(USERS);
}


# config_icons(context, program)
# Displays up to 18 icons, one for each type of configuration directive, for
# some context (global, virtual, directory or htaccess)
sub config_icons
{
local ($ctx, $prog) = @_;
local($m, $func, $e, %etype, $i, $c);
foreach $m (sort { $a cmp $b } (keys %httpd_modules)) {
        $func = $m."_directives";
	if (defined(&$func)) {
		foreach $e (&$func($httpd_modules{$m})) {
			if ($e->{$ctx}) { $etype{$e->{'type'}}++; }
			}
		}
        }
local (@titles, @links, @icons);
for($i=0; $text{"type_$i"}; $i++) {
	if ($etype{$i} && $access_types{$i}) {
		push(@links, $prog."type=$i");
		push(@titles, $text{"type_$i"});
		push(@icons, "images/type_icon_$i.gif");
		}
	}
for($i=2; $i<@_; $i++) {
	if ($_[$i]) {
		push(@links, $_[$i]->{'link'});
		push(@titles, $_[$i]->{'name'});
		push(@icons, $_[$i]->{'icon'});
		}
	}
&icons_table(\@links, \@titles, \@icons, 5);
print "<p>\n";
}

# restart_button()
# Returns HTML for a link to put in the top-right corner of every page
sub restart_button
{
local $args = "redir=".&urlize(&this_url());
local @rv;
if (&is_apache_running()) {
	if ($access{'apply'}) {
		my $n = &needs_config_restart();
		if ($n) {
			push(@rv, &ui_link("restart.cgi?$args&newconfig=1",
					"<b>$text{'apache_apply'}</b>") );
			}
		else {
			push(@rv, &ui_link("restart.cgi?$args", $text{'apache_apply'}) );
			}
		}
	if ($access{'stop'}) {
		push(@rv, &ui_link("stop.cgi?$args", $text{'apache_stop'}) );
		}
	}
elsif ($access{'stop'}) {
	push(@rv, &ui_link("start.cgi?$args", $text{'apache_start'}) );
	}
return join("<br>\n", @rv);
}

# this_url()
# Returns the URL in the apache directory of the current script
sub this_url
{
local($url);
$url = $ENV{'SCRIPT_NAME'};
if ($ENV{'QUERY_STRING'} ne "") { $url .= "?$ENV{'QUERY_STRING'}"; }
return $url;
}

# find_all_directives(config, name)
# Recursively finds all directives of some type
sub find_all_directives
{
local(@rv, $d);
foreach $d (@{$_[0]}) {
	if ($d->{'name'} eq $_[1]) { push(@rv, $d); }
	if ($d->{'type'} == 1) {
		push(@rv, &find_all_directives($d->{'members'}, $_[1]));
		}
	}
return @rv;
}

# httpd_info(executable)
# Returns the httpd version and modules array
sub httpd_info
{
local ($cmd) = @_;
$cmd = &has_command($cmd);
local @st = stat($cmd);
local %cache;
&read_file_cached($httpd_info_cache, \%cache);
if ($cache{'cmd'} eq $cmd && $cache{'time'} == $st[9]) {
	# Cache looks up to date
	return ($cache{'version'}, [ split(/\s+/, $cache{'mods'}) ],
		$cache{'fullversion'});
	}
local(@mods, $verstr, $ver, $minor, $fullver);
$verstr = &backquote_command(quotemeta($cmd)." -v 2>&1");
if ($config{'httpd_version'} =~ /(\d+)\.([\d\.]+)/) {
	$fullver = $config{'httpd_version'};
	$ver = $1;
	$minor = $2;
	$minor =~ s/\.//g;
	$ver .= ".$minor";
	}
elsif ($verstr =~ /Apache(\S*)\/(\d+)\.([\d\.]+)/) {
	# standard apache
	$fullver = "$2.$3";
	$ver = $2;
	$minor = $3;
	$minor =~ s/\.//g;
	$ver .= ".$minor";
	}
elsif ($verstr =~ /HP\s*Apache-based\s*Web\s*Server(\S*)\/(\d+)\.([\d\.]+)/) {
	# HP's apache
	$fullver = "$2.$3";
	$ver = $2;
	$minor = $3;
	$minor =~ s/\.//g;
	$ver .= ".$minor";
	}
elsif ($verstr =~ /Red\s*Hat\s+Secure\/2\.0/i) {
	# redhat secure server 2.0
	$fullver = $ver = 1.31;
	}
elsif ($verstr =~ /Red\s*Hat\s+Secure\/3\.0/i) {
	# redhat secure server 3.0
	$fullver = $ver = 1.39;
	}
elsif (&has_command("rpm") &&
       &backquote_command("rpm -q apache 2>&1") =~ /^apache-(\d+)\.([\d\.]+)/) {
	# got version from the RPM
	$fullver = $ver = $1;
	$minor = $2;
	$minor =~ s/\.//g;
	$ver .= ".$minor";
	}
else {
	# couldn't get version
	return (0, undef);
	}
if ($ver < 1.2) {
	# apache 1.1 has no -l option! Use the standard list
	@mods = ("core", "mod_mime", "mod_access", "mod_auth", "mod_include",
		 "mod_negotiation", "mod_dir", "mod_cgi", "mod_userdir",
		 "mod_alias", "mod_env", "mod_log_common");
	}
else {
	# ask apache for the module list
	@mods = ("core");
	&open_execute_command(APACHE, "\"$_[0]\" -l 2>/dev/null", 1);
	while(<APACHE>) {
		if (/(\S+)\.c/) { push(@mods, $1); }
		}
	close(APACHE);
	if ($?) {
		# httpd crashed! Use last known good set of modules
		local %oldsite;
		&read_file($site_file, \%oldsite);
		if ($oldsite{'modules'}) {
			@mods = split(/\s+/, $oldsite{'modules'});
			}
		}
	@mods = &unique(@mods);
	}
$cache{'cmd'} = $cmd;
$cache{'time'} = $st[9];
$cache{'version'} = $ver;
$cache{'fullversion'} = $fullver;
$cache{'mods'} = join(" ", @mods);
&write_file($httpd_info_cache, \%cache);
return ($ver, \@mods, $fullver);
}

# print_line(directive, text, indent, link)
sub print_line
{
local $line = $_[0]->{'line'} + 1;
local $lstr = "$_[0]->{'file'} ($line)";
local $txt = join("", @{$_[1]});
local $left = 85 - length($lstr) - $_[2];
if (length($txt) > $left) {
	$txt = substr($txt, 0, $left)." ..";
	}
local $txtlen = length($txt);
$txt = &html_escape($txt);
print " " x $_[2];
if ($_[3]) {
	print &ui_link($_[3], $txt);
	}
else { print $txt; }
print " " x (90 - $txtlen - $_[2] - length($lstr));
print $lstr,"\n";
}

# can_edit_virt(struct)
sub can_edit_virt
{
return 1 if ($access{'virts'} eq '*');
local %vcan = map { $_, 1 } split(/\s+/, $access{'virts'});
local ($can) = grep { $vcan{$_} } &virt_acl_name($_[0]);
return $can ? 1 : 0;
}

# virt_acl_name(struct)
# Give a virtual host, returns a list of names that could be used in the ACL
# to refer to it
sub virt_acl_name
{
return ( "__default__" ) if (!$_[0]);
local $n = &find_directive("ServerName", $_[0]->{'members'});
local @rv;
local $p;
if ($_[0]->{'value'} =~ /(:\d+)/) { $p = $1; }
if ($n) {
	push(@rv, $n.$p);
	}
else {
	push(@rv, $_[0]->{'value'});
	}
foreach $n (&find_directive_struct("ServerAlias", $_[0]->{'members'})) {
	local $a;
	foreach $a (@{$n->{'words'}}) {
		push(@rv, $a.$p);
		}
	}
return @rv;
}

# allowed_auth_file(file)
sub allowed_auth_file
{
local $_;
return 1 if ($access{'dir'} eq '/');
return 0 if ($_[0] =~ /\.\./);
local $f = &server_root($_[0], &get_config());
return 0 if (-l $f && !&allowed_auth_file(readlink($f)));
local $l = length($access{'dir'});
return length($f) >= $l && substr($f, 0, $l) eq $access{'dir'};
}

# directory_exists(file)
# Returns 1 if the directory in some path exists
sub directory_exists
{
local $path = &server_root($_[0], &get_config());
if ($path =~ /^(\S*\/)([^\/]+)$/) {
	return -d $1;
	}
else {
	return 0;
	}
}

# allowed_doc_dir(dir)
# Returns 1 if some directory is under the allowed root for alias targets
sub allowed_doc_dir
{
return $access{'aliasdir'} eq '/' ||
       $_[0] !~ /^\// ||	# Relative path, like for <Files>
       &is_under_directory($access{'aliasdir'}, $_[0]);
}

sub lock_apache_files
{
local $conf = &get_config();
local $f;
@main::locked_apache_files = &unique(map { $_->{'file'} } @$conf);
foreach $f (@main::locked_apache_files) {
	&lock_file($f);
	}
}

sub unlock_apache_files
{
local $conf = &get_config();
local $f;
foreach $f (@main::locked_apache_files) {
	&unlock_file($f);
	}
@main::locked_apache_files = ( );
}

# directive_lines(directive, ...)
sub directive_lines
{
local @rv;
foreach $d (@_) {
	next if ($d->{'name'} eq 'dummy');
	my $indent = (" " x $d->{'indent'});
	if ($d->{'type'}) {
		push(@rv, $indent."<$d->{'name'} $d->{'value'}>");
		push(@rv, &directive_lines(@{$d->{'members'}}));
		push(@rv, $indent."</$d->{'name'}>");
		}
	else {
		push(@rv, $indent."$d->{'name'} $d->{'value'}");
		}
	}
return @rv;
}

# test_config()
# If possible, test the current configuration and return an error message,
# or undef.
sub test_config
{
if ($httpd_modules{'core'} >= 1.301) {
	# Test the configuration with the available command
	local $cmd;
	if ($config{'test_apachectl'} &&
	    -x &translate_filename($config{'apachectl_path'})) {
		# Test with apachectl
		$cmd = "\"$config{'apachectl_path'}\" configtest";
		}
	else {
		# Test with httpd
		local $httpd = &find_httpd();
		$cmd = "\"$httpd\" -d \"$config{'httpd_dir'}\" -t";
		if ($config{'httpd_conf'}) {
			$cmd .= " -f \"$config{'httpd_conf'}\"";
			}
		foreach $d (&get_httpd_defines()) {
			$cmd .= " -D$d";
			}
		}
	local $out = &backquote_command("$cmd 2>&1");
	if ($out && $out !~ /(syntax|Checking).*\s+ok/i) {
		return $out;
		}
	}
return undef;
}

# before_changing()
# If testing all changes, backup the config files so they can be reverted
# if necessary.
sub before_changing
{
if ($config{'test_always'} || $access{'test_always'}) {
	local $conf = &get_config();
	local @files = &unique(map { $_->{'file'} } @$conf);
	local $/ = undef;
	local $f;
	foreach $f (@files) {
		if (&open_readfile(BEFORE, $f)) {
			$before_changing{$f} = <BEFORE>;
			close(BEFORE);
			}
		}
	}
}

# after_changing()
# If testing all changes, test now and revert the configs and show an error
# message if a problem was found.
sub after_changing
{
if ($config{'test_always'} || $access{'test_always'}) {
	local $err = &test_config();
	if ($err) {
		# Something failed .. revert all files
		&rollback_apache_config();
		&error(&text('eafter', "<pre>$err</pre>"));
		}
	}
}

# rollback_apache_config()
# Copy back all config files from their originals
sub rollback_apache_config
{
local $f;
foreach $f (keys %before_changing) {
	&open_tempfile(AFTER, ">$f");
	&print_tempfile(AFTER, $before_changing{$f});
	&close_tempfile(AFTER);
	}
}

# find_httpd_conf()
# Returns the path to the http.conf file, and the last place looked
# (without any translation).
sub find_httpd_conf
{
local $conf = $config{'httpd_conf'};
return ( -f &translate_filename($conf) ? $conf : undef, $conf ) if ($conf);
$conf = "$config{'httpd_dir'}/conf/httpd.conf";
$conf = "$config{'httpd_dir'}/conf/httpd2.conf"
	if (!-f &translate_filename($conf));
$conf = "$config{'httpd_dir'}/etc/httpd.conf"
	if (!-f &translate_filename($conf));
$conf = "$config{'httpd_dir'}/etc/httpd2.conf"
	if (!-f &translate_filename($conf));
$conf = undef if (!-f &translate_filename($conf));
return ( $conf, "$config{'httpd_dir'}/conf/httpd.conf" );
}

# find_httpd()
# Returns the path to the httpd executable, by appending '2' if necessary
sub find_httpd
{
return $config{'httpd_path'}
	if (-x &translate_filename($config{'httpd_path'}) &&
	    !-d &translate_filename($config{'httpd_path'}));
return $config{'httpd_path'}.'2'
	if (-x &translate_filename($config{'httpd_path'}.'2') &&
	    !-d &translate_filename($config{'httpd_path'}.'2'));
return undef;
}

# get_pid_file()
# Returns the path to the PID file (without any translation)
sub get_pid_file
{
return $config{'pid_file'} if ($config{'pid_file'});
local $conf = &get_config();
local $pidfilestr = &find_directive_struct("PidFile", $conf);
local $pidfile = $pidfilestr ? $pidfilestr->{'words'}->[0]
		       	     : "logs/httpd.pid";
return &server_root($pidfile, $conf);
}

# restart_apache()
# Re-starts Apache, and returns undef on success or an error message on failure
sub restart_apache
{
local $pidfile = &get_pid_file();
if ($config{'apply_cmd'} eq 'restart') {
	# Call stop and start functions
	local $err = &stop_apache();
	return $err if ($err);
	local $stopped = &wait_for_apache_stop();
	local $err = &start_apache();
	return $err if ($err);
	}
elsif ($config{'apply_cmd'}) {
	# Use the configured start command
	&clean_environment();
	local $out = &backquote_logged("$config{'apply_cmd'} 2>&1");
	&reset_environment();
	&wait_for_graceful() if ($config{'apply_cmd'} =~ /graceful/);
	if ($?) {
		return "<pre>".&html_escape($out)."</pre>";
		}
	}
elsif (-x &translate_filename($config{'apachectl_path'})) {
	# Use apachectl to restart
	if ($httpd_modules{'core'} >= 2) {
		# Do a graceful restart
		&clean_environment();
		local $out = &backquote_logged(
			"$config{'apachectl_path'} graceful 2>&1");
		&reset_environment();
		&wait_for_graceful();
		if ($?) {
			return "<pre>".&html_escape($out)."</pre>";
			}
		}
	else {
		&clean_environment();
		local $out = &backquote_logged(
			"$config{'apachectl_path'} restart 2>&1");
		&reset_environment();
		if ($out !~ /httpd restarted/) {
			return "<pre>".&html_escape($out)."</pre>";
			}
		}
	}
else {
	# send SIGHUP directly
	&open_readfile(PID, $pidfile) || return &text('restart_epid', $pidfile);
	<PID> =~ /(\d+)/ || return &text('restart_epid2', $pidfile);
	close(PID);
	&kill_logged('HUP', $1) || return &text('restart_esig', $1);
	&wait_for_graceful();
	}
&restart_last_restart_time();
return undef;
}

# wait_for_graceful([timeout])
# Wait for some time for Apache to complete a graceful restart
sub wait_for_graceful
{
local $timeout = $_[0] || 10;
local $errorlog = &get_error_log();
return -1 if (!$errorlog || !-r $errorlog);
local @st = stat($errorlog);
my $start = time();
while(time() - $start < $timeout) {
	sleep(1);
	open(ERRORLOG, "<".$errorlog);
	seek(ERRORLOG, $st[7], 0);
	local $/ = undef;
	local $rest = <ERRORLOG>;
	close(ERRORLOG);
	if ($rest =~ /resuming\s+normal\s+operations/i) {
		return 1;
		}
	}
return 0;
}

# stop_apache()
# Attempts to stop the running Apache process, and returns undef on success or
# an error message on failure
sub stop_apache
{
local $out;
if ($config{'stop_cmd'}) {
	# use the configured stop command
	$out = &backquote_logged("($config{'stop_cmd'}) 2>&1");
	if ($?) {
		return "<pre>".&html_escape($out)."</pre>";
		}
	}
elsif (-x $config{'apachectl_path'}) {
	# use the apachectl program
	$out = &backquote_logged("($config{'apachectl_path'} stop) 2>&1");
	if ($httpd_modules{'core'} >= 2 ? $? : $out !~ /httpd stopped/) {
		return "<pre>".&html_escape($out)."</pre>";
		}
	}
else {
	# kill the process
	$pidfile = &get_pid_file();
	open(PID, "<".$pidfile) || return &text('stop_epid', $pidfile);
	<PID> =~ /(\d+)/ || return &text('stop_epid2', $pidfile);
	close(PID);
	&kill_logged('TERM', $1) || return &text('stop_esig', $1);
	}
return undef;
}

# start_apache()
# Attempts to start Apache, and returns undef on success or an error message
# upon failure.
sub start_apache
{
local ($out, $cmd);
&clean_environment();
if ($config{'start_cmd'}) {
	# use the configured start command
	if ($config{'stop_cmd'}) {
		# execute the stop command to clear lock files
		&system_logged("($config{'stop_cmd'}) >/dev/null 2>&1");
		}
	$out = &backquote_logged("($config{'start_cmd'}) 2>&1");
	&reset_environment();
	if ($?) {
		return "<pre>".&html_escape($out)."</pre>";
		}
	}
elsif (-x $config{'apachectl_path'}) {
	# use the apachectl program
	$cmd = "$config{'apachectl_path'} start";
	$out = &backquote_logged("($cmd) 2>&1");
	&reset_environment();
	}
else {
	# start manually
	local $httpd = &find_httpd();
	$cmd = "$httpd -d $config{'httpd_dir'}";
	if ($config{'httpd_conf'}) {
		$cmd .= " -f $config{'httpd_conf'}";
		}
	foreach $d (&get_httpd_defines()) {
		$cmd .= " -D$d";
		}
	local $temp = &transname();
	local $rv = &system_logged("( $cmd ) >$temp 2>&1 </dev/null");
	$out = &read_file_contents($temp);
	unlink($temp);
	&reset_environment();
	}

# Check if Apache may have failed to start
local $slept;
if ($out =~ /\S/ && $out !~ /httpd\s+started/i) {
	sleep(3);
	if (!&is_apache_running()) {
		return "<pre>".&html_escape($cmd)." :\n".
			       &html_escape($out)."</pre>";
		}
	$slept = 1;
	}

# check if startup was successful. Later apache version return no
# error code, but instead fail to start and write the reason to
# the error log file!
sleep(3) if (!$slept);
local $conf = &get_config();
if (!&is_apache_running()) {
	# Not running..  find out why
	local $errorlogstr = &find_directive_struct("ErrorLog", $conf);
	local $errorlog = $errorlogstr ? $errorlogstr->{'words'}->[0]
				       : "logs/error_log";
	if ($out =~ /\S/) {
		return "$text{'start_eafter'} : <pre>$out</pre>";
		}
	elsif ($errorlog eq 'syslog' || $errorlog =~ /^\|/) {
		return $text{'start_eunknown'};
		}
	else {
		$errorlog = &server_root($errorlog, $conf);
		$out = `tail -5 $errorlog`;
		return "$text{'start_eafter'} : <pre>$out</pre>";
		}
	}
&restart_last_restart_time();
return undef;
}

# get_error_log()
# Returns the path to the global error log, if possible
sub get_error_log
{
local $conf = &get_config();
local $errorlogstr = &find_directive_struct("ErrorLog", $conf);
local $errorlog = $errorlogstr ? $errorlogstr->{'words'}->[0]
			       : "logs/error_log";
$errorlog = &server_root($errorlog, $conf);
return $errorlog;
}

sub is_apache_running
{
if ($gconfig{'os_type'} eq 'windows') {
	# No such thing as a PID file on Windows
	local ($pid) = &find_byname("Apache.exe");
	return $pid;
	}
else {
	# Check PID file
	local $pidfile = &get_pid_file();
	return &check_pid_file($pidfile);
	}
}

# wait_for_apache_stop([secs])
# Wait 30 (by default) seconds for Apache to stop. Returns 1 if OK, 0 if not
sub wait_for_apache_stop
{
local $secs = $_[0] || 30;
for(my $i=0; $i<$secs; $i++) {
	return 1 if (!&is_apache_running());
	sleep(1);
	}
return 0;
}

# configurable_modules([&all-mods])
# Returns a list of Apaches that are compiled in or dynamically loaded, and
# supported by Webmin.
sub configurable_modules
{
my ($allmods) = @_;
$allmods ||= [ &available_modules() ];
return grep { -r "$module_root_directory/$_.pl" } @$allmods;
}

# available_modules()
# Returns a list of Apaches that are compiled in or dynamically loaded
sub available_modules
{
my ($ver, $mods) = &httpd_info(&find_httpd());
my @rv;

# Add compiled-in modules
push(@rv, @$mods);

# Add dynamically loaded modules
my $conf = &get_config();
foreach my $l (&find_directive_struct("LoadModule", $conf)) {
	if ($l->{'words'}->[1] =~ /(mod_\S+)\.(so|dll)/) {
		push(@rv, $1);
		}
	elsif ($l->{'words'}->[1] =~ /libssl\.so/) {
		push(@rv, "mod_apachessl");
		}
	elsif ($l->{'words'}->[1] =~ /lib([^\/\s]+)\.(so|dll)/) {
		push(@rv, "mod_$1");
		}
	}

# Add dynamically loaded modules
if ($config{'apachectl_path'}) {
	&open_execute_command(APACHE,
		"$config{'apachectl_path'} -M 2>/dev/null", 1);
	while(<APACHE>) {
		if (/(\S+)_module/) {
			push(@rv, "mod_${1}");
			}
		}
	close(APACHE);
	}

return &unique(@rv);
}

# get_httpd_defines(automatic-only)
# Returns a list of defines that need to be passed to Apache
sub get_httpd_defines
{
local ($auto) = @_;
if (@get_httpd_defines_cache) {
	return @get_httpd_defines_cache;
	}
local @rv;
if (!$auto) {
	push(@rv, keys %httpd_defines);
	}
if ($config{'defines_file'}) {
	# Add defines from an environment file, which can be in
	# the format :
	# OPTIONS='-Dfoo -Dbar'
	# or regular name=value format
	local %def;
	&read_env_file($config{'defines_file'}, \%def);
	if ($config{'defines_name'} && $def{$config{'defines_name'}}) {
		# Looking for var like OPTIONS='-Dfoo -Dbar'
		local $var = $def{$config{'defines_name'}};
		foreach my $v (split(/\s+/, $var)) {
			if ($v =~ /^-[Dd](\S+)$/) {
				push(@rv, $1);
				}
			else {
				push(@rv, $v);
				}
			}
		}
	else {
		# Looking for regular name=value directives.
		# Remove $SUFFIX variable seen on debian that is computed
		# dynamically, but is usually empty.
		foreach my $k (keys %def) {
			$def{$k} =~ s/\$SUFFIX//g;
			push(@rv, $k."=".$def{$k});
			}
		}
	}
foreach my $md (split(/\t+/, $config{'defines_mods'})) {
	# Add HAVE_ defines from modules
	opendir(DIR, $md);
	while(my $m = readdir(DIR)) {
		if ($m =~ /^(mod_|lib)(.*).so$/i) {
			push(@rv, "HAVE_".uc($2));
			}
		}
	closedir(DIR);
	}
foreach my $d (split(/\s+/, $config{'defines'})) {
	push(@rv, $d);
	}
@get_httpd_defines_cache = @rv;
return @rv;
}

# create_webfile_link(file)
# Creates a link in the debian-style link directory for a new website's file
sub create_webfile_link
{
local ($file) = @_;
if ($config{'link_dir'}) {
	local $short = $file;
	$short =~ s/^.*\///;
	local $linksrc = "$config{'link_dir'}/$short";
	&lock_file($linksrc);
	symlink($file, $linksrc);
	&unlock_file($linksrc);
	}
}

# delete_webfile_link(file)
# If the given path is in a directory like /etc/apache2/sites-available, delete
# the link to it from /etc/apache2/sites-enabled
sub delete_webfile_link
{
local ($file) = @_;
if ($config{'link_dir'}) {
	local $short = $file;
	$short =~ s/^.*\///;
	opendir(LINKDIR, $config{'link_dir'});
	foreach my $f (readdir(LINKDIR)) {
		if ($f ne "." && $f ne ".." &&
		    (&simplify_path(
		       &resolve_links($config{'link_dir'}."/".$f)) eq $file ||
		     $short eq $f)) {
			&unlink_logged($config{'link_dir'}."/".$f);
			}
		}
	closedir(LINKDIR);
	}
}

# can_configure_apache_modules()
# Returns 1 if the distro has a way of selecting enabled Apache modules
sub can_configure_apache_modules
{
if ($gconfig{'os_type'} eq 'debian-linux') {
	# Debian and Ubuntu use an /etc/apacheN/mods-enabled dir
	return -d "$config{'httpd_dir'}/mods-enabled" &&
	       -d "$config{'httpd_dir'}/mods-available";
	}
else {
	return 0;
	}
}

# list_configured_apache_modules()
# Returns a list of all Apache modules. Each is a hash containing a mod and
# enabled, disabled and available flags.
sub list_configured_apache_modules
{
if ($gconfig{'os_type'} eq 'debian-linux') {
	# Find enabled modules
	local @rv;
	local $edir = "$config{'httpd_dir'}/mods-enabled";
	opendir(EDIR, $edir);
	foreach my $f (readdir(EDIR)) {
		if ($f =~ /^(\S+)\.load$/) {
			push(@rv, { 'mod' => $1, 'enabled' => 1 });
			}
		}
	closedir(EDIR);

	# Add available modules
	local $adir = "$config{'httpd_dir'}/mods-available";
	opendir(ADIR, $adir);
	foreach my $f (readdir(ADIR)) {
		if ($f =~ /^(\S+)\.load$/) {
			local ($got) = grep { $_->{'mod'} eq $1 } @rv;
			if (!$got) {
				push(@rv, { 'mod' => $1, 'disabled' => 1 });
				}
			}
		}
	closedir(ADIR);

	# XXX modules from apt-get

	return sort { $a->{'mod'} cmp $b->{'mod'} } @rv;
	}
else {
	# Not supported
	return ( );
	}
}

# add_configured_apache_module(module)
# Updates the Apache configuration to use some module. Returns undef on success,
# or an error message on failure.
sub add_configured_apache_module
{
local ($mod) = @_;
if ($gconfig{'os_type'} eq 'debian-linux') {
	# XXX download from apt-get ?

	# Enable with a2enmod if installed
	if (&has_command("a2enmod")) {
		local $out = &backquote_logged(
				"a2enmod ".quotemeta($mod)." 2>&1");
		return $? ? $out : undef;
		}
	else {
		# Fall back to creating links
		local $adir = "$config{'httpd_dir'}/mods-available";
		local $edir = "$config{'httpd_dir'}/mods-enabled";
		opendir(ADIR, $adir);
		foreach my $f (readdir(ADIR)) {
			if ($f =~ /^\Q$mod->{'mod'}\E\./) {
				&symlink_logged("$adir/$f", "$edir/$f") ||
					return $!;
				}
			}
		closedir(ADIR);
		return undef;
		}
	}
else {
	return "Operating system does not support Apache modules";
	}
}

# remove_configured_apache_module(module)
# Updates the Apache configuration to stop using some module. Returns undef
# on success, or an error message on failure.
sub remove_configured_apache_module
{
local ($mod) = @_;
if ($gconfig{'os_type'} eq 'debian-linux') {
	# Disable with a2dismod if installed
	if (&has_command("a2dismod")) {
		local $out = &backquote_logged(
				"a2dismod ".quotemeta($mod)." 2>&1");
		return $? ? $out : undef;
		}
	else {
		# Fall back to removing links
		local $edir = "$config{'httpd_dir'}/mods-enabled";
		opendir(EDIR, $edir);
		foreach my $f (readdir(EDIR)) {
			if ($f =~ /^\Q$mod->{'mod'}\E\./) {
				&unlink_logged("$edir/$f");
				}
			}
		closedir(EDIR);
		return undef;
		}
	}
else {
	return "Operating system does not support Apache modules";
	}
}

# is_virtualmin_domain(&virt)
# Returns the domain hash if some virtualhost is managed by Virtualmin
sub is_virtualmin_domain
{
local ($virt) = @_;
return 0 if ($config{'allow_virtualmin'});
local $n = &find_directive("ServerName", $virt->{'members'});
return undef if (!$n);
return undef if (!&foreign_check("virtual-server"));
&foreign_require("virtual-server");
local $d = &virtual_server::get_domain_by("dom", $n);
return $d if ($d);
$n =~ s/^www\.//i;
local $d = &virtual_server::get_domain_by("dom", $n);
return $d;
}

# update_last_config_change()
# Updates the flag file indicating when the config was changed
sub update_last_config_change
{
&open_tempfile(FLAG, ">$last_config_change_flag", 0, 1);
&close_tempfile(FLAG);
}

# restart_last_restart_time()
# Updates the flag file indicating when the config was changed
sub restart_last_restart_time
{
&open_tempfile(FLAG, ">$last_restart_time_flag", 0, 1);
&close_tempfile(FLAG);
}

# needs_config_restart()
# Returns 1 if a restart is needed for sure after a config change
sub needs_config_restart
{
my @cst = stat($last_config_change_flag);
my @rst = stat($last_restart_time_flag);
if (@cst && @rst && $cst[9] > $rst[9]) {
	return 1;
	}
return 0;
}

# format_config(conf-lines-ref, [indent])
# Formats Apache config lines with default
# four spaces of indent for each block
sub format_config
{
my ($conf_lref, $indent) = @_;

# Prevent formatting if not allowed in config
return if (!&format_config_allowed());

# Default single indent equals 4 spaces
$indent ||= 4;
$indent = " " x $indent;

# At first check if Apache blocks are ballanced
my $conf_block_opening;
my $conf_block_closing;
foreach my $l (@{$conf_lref}) {

    # If line doesn't start with # disregard of trailing spaces
    if ($l !~ /^\s*#/) {

        # This is a new block, count it
        if ($l =~ /(<[a-zA-Z]+).*>/) {
            $conf_block_opening++;
            }

        # This is a new closing block, count it
        if ($l =~ /(<\/[a-zA-Z]+).*>/) {
            $conf_block_closing++;
            }
        }
    }

# If the number of closing and opening blocks
# is the same then generate proper indents
if ($conf_block_opening == $conf_block_closing) {

    my $conf_lvl = 0;
    foreach my $l (@{$conf_lref}) {
        my $indent_current = $indent x $conf_lvl;

        # If line doesn't start with # disregard of trailing spaces
        if ($l !~ /^\s*#/) {

            # Indent up next line if a new block
            if ($l =~ /(<[a-zA-Z]+).*>/) {
                $conf_lvl++;
                }

            # Indent down next line if a closing block
            if ($l =~ /(<\/[a-zA-Z]+).*>/) {
                $conf_lvl--;

                # Change current indent right now as it is a closing block
                $indent_current = $indent x $conf_lvl;
                }
            }

        # Replace beginning spaces with needed indent
        $l =~ s/^\s*/$indent_current/
            if($l);
        }
    }
}

# format_config(filename, [indent])
# Formats Apache config given file
sub format_config_file
{
my ($file, $indent) = @_;

# Prevent formatting if not allowed in config
return if (!&format_config_allowed());

# If file was deleted prevent recreating an empty file
return if (!-r $file);

# Lock file
&lock_file($file);

# Open file
my $conf_lref = &read_file_lines($file);

# Format
&format_config($conf_lref, $indent);

# Write file
&flush_file_lines($file);

# Unlock file
&unlock_file($file);
}

# format_modifed_configs([test-config])
# Formats all modifed Apache configs during the call
sub format_modifed_config_files
{
my ($force_config_test) = @_;
if($saved_conf_files) {
	if (&format_config_allowed()) {
		# Test config first if not already
		# tested and don't format on error
		if ($force_config_test) {
			if ($config{'test_manual'} ||
			    $config{'test_always'}) {
				my $conf_err = &test_config();
				if ($conf_err) {
					return;
					}
				}
			}
		# Format indents for each file individually
		foreach my $saved_conf_file (&unique(@{$saved_conf_files})) {
				&format_config_file($saved_conf_file, $config{'format_config_indent'});
			}
		}
	}
}

# format_config_allowed()
# Checks if formatting config is allowed
sub format_config_allowed
{
return $config{'format_config'};
}

1;


Anon7 - 2022
SCDN GOK