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 : 13.58.61.176
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/core.pl
# core.pl
# Defines the core module directives

# core_directives(version)
# Returns ar array of references to associative arrays, each containing
# information about some directive. The keys of each array are:
#  name -	The name of this directive
#  multiple -	Can this directive appear multiple times
#  type -	What kind of directive this in. Possible values are
#		0 - Processes and limits
#		1 - Networking and addresses
#		2 - Apache Modules
#		3 - Log files
#		4 - Access control
#		5 - document options
#		6 - MIME types
#		7 - Error handling
#		8 - Users and Groups
#		9 - Miscellaneous
#		10- Aliases and redirects
#		11- CGI programs
#		12- Directory indexing
#		13- Proxying
#		14- SSL
#		15- Perl
#		16- PHP
#		17- Vhost aliases
#		18- Filters
#		19- Character Sets
#		20- Image maps
#  global -	Can be used in the global server context
#  virtual -	Can be used in a VirtualHost section or in the global section
#  directory -	Can be used in a Directory section context
#  htaccess -	Can be used in a .htaccess file
sub core_directives
{
local($rv);
$rv = [	[ 'AccessFileName', 0, 5, 'virtual', undef, 5 ],
	[ 'AddDefaultCharset', 0, 19, 'virtual directory htaccess', 2.0 ],
	&can_configure_apache_modules() ? ( ) :
		( [ 'ClearModuleList AddModule', 1, 2, 'global', -2.0 ] ),
	[ 'AllowOverride', 0, 5, 'directory' ],
	[ 'AuthName', 0, 4, 'directory htaccess', undef, 10 ],
	[ 'AuthType', 0, 4, 'directory htaccess', undef, 8 ],
	[ 'BindAddress Listen Port', 1, 1, 'global', -2.0, 10 ],
	[ 'ContentDigest', 0, 5, 'virtual directory htaccess' ],
	[ 'CoreDumpDirectory', 0, 9, 'global', '1.3-2.0' ],
	[ 'DefaultType', 0, 6, 'virtual directory htaccess' ],
	[ 'DocumentRoot', 0, 5, 'virtual', undef, 10 ],
	[ 'ErrorDocument', 1, 7, 'virtual directory htaccess' ],
	[ 'ErrorLog', 0, 3, 'virtual' ],
	[ 'FileETag', 0, 5, 'virtual directory htaccess', 2.0 ],
	[ 'ForceType', 0, 6, 'directory htaccess', 2.0 ],
	[ 'Group', 0, 8, 'virtual', -2.0 ],
	[ 'HostNameLookups', 0, 1, 'virtual directory' ],
	[ 'IdentityCheck', 0, 1, 'virtual directory' ],
	[ 'KeepAlive MaxKeepAliveRequests', 0, 1, 'global' ],
	[ 'KeepAliveTimeout', 0, 1, 'global' ],
	[ 'ListenBacklog', 0, 1, 'global', '1.2-2.0' ],
	[ 'LockFile', 0, 9, 'global', -2.0 ],
	[ 'LimitRequestBody', 0, 0, 'virtual directory htaccess', 1.302 ],
	[ 'LimitRequestFields', 0, 0, 'global', 1.302 ],
	[ 'LimitRequestFieldsize', 0, 0, 'global', 1.302 ],
	[ 'LimitRequestLine', 0, 0, 'global', 1.302 ],
	[ 'LimitXMLRequestBody', 0, 0, 'virtual directory htaccess', 2.0 ],
	[ 'LogLevel', 0, 3, 'virtual', 1.3 ],
	[ 'MaxClients', 0, 0, 'global', -2.0 ],
	[ 'MaxRequestsPerChild', 0, 0, 'global', -2.0 ],
	[ 'StartServers', 0, 0, 'global', -2.0 ],
	[ 'MinSpareServers', 0, 0, 'global', -2.0 ],
	[ 'MaxSpareServers', 0, 0, 'global', -2.0 ],
	[ 'NameVirtualHost', 1, 1, 'global', '1.3-2.4', 5 ],
	[ 'Options', 0, 5, 'virtual directory htaccess', undef, 3 ],
	[ 'PidFile', 0, 9, 'global', -2.0 ],
	[ 'Protocols', 0, 1, 'virtual', 2.4 ],
	[ 'require', 0, 4, 'directory htaccess', undef, 6 ],
	[ 'RLimitCPU', 0, 0, 'virtual', 1.2 ],
	[ 'RLimitMEM', 0, 0, 'virtual', 1.2 ],
	[ 'RLimitNPROC', 0, 0, 'virtual', 1.2 ],
	[ 'Satisfy', 0, 4, 'directory htaccess', 1.2, 4 ],
	[ 'ScoreBoardFile', 0, 9, 'global', '1.2-2.0' ],
	[ 'SendBufferSize', 0, 1, 'global', -2.0 ],
	[ 'ServerAdmin', 0, 1, 'virtual' ],
	$access{'names'} ? (
		[ 'ServerAlias', 1, 1, 'virtual virtualonly', 1.2 ],
		[ 'ServerName', 0, 1, 'virtual' ] ) : ( ),
	[ 'ServerPath', 0, 5, 'virtual' ],
	[ 'ServerType', 0, 9, 'global', -2.0 ],
	[ 'ServerTokens', 0, 9, 'global', 1.3 ],
	[ 'ServerSignature', 0, 5, 'virtual directory htaccess', 1.3 ],
	[ 'SetOutputFilter', 0, 18, 'virtual directory htaccess', 2.0 ],
	[ 'SetInputFilter', 0, 18, 'virtual directory htaccess', 2.0 ],
	[ 'TimeOut', 0, 1, 'global' ],
	[ 'UseCanonicalName', 0, 1, 'virtual directory', 1.3 ],
	[ 'User', 0, 8, 'virtual', -2.0, 10 ] ];
return &make_directives($rv, $_[0], "core");
}

# core_handlers(config, version)
# Returns an array of all available handlers
sub core_handlers
{
return ();
}

#########################################################################
# Process and limit directives
sub edit_MaxClients
{
return (1,
	$text{'core_maxconc'},
	&opt_input($_[0]->{'value'}, "MaxClients", $text{'core_default'}, 4));
}
sub save_MaxClients
{
return &parse_opt("MaxClients", '^\d+$',
		  $text{'core_emaxconc'});
}

sub edit_MaxKeepAliveRequests
{
return (1,
	$text{'core_maxkeep'},
	&opt_input($_[0]->{'value'}, "MaxKeepAliveRequests", $text{'core_default'}, 4));
}
sub save_MaxKeepAliveRequests
{
return &parse_opt("MaxKeepAliveRequests", '^\d+$',
		  $text{'core_emaxkeep'});
}

sub edit_MaxRequestsPerChild
{
return (1,
	$text{'core_maxreq'},
	&opt_input($_[0]->{'value'}, "MaxRequestsPerChild", $text{'core_default'}, 5));
}
sub save_MaxRequestsPerChild
{
return &parse_opt("MaxRequestsPerChild", '^\d+$',
		  $text{'core_emaxreq'});
}

sub edit_MinSpareServers
{
return (1,
	$text{'core_minspare'},
	&opt_input($_[0]->{'value'},"MinSpareServers",$text{'core_default'}, 4));
}
sub save_MinSpareServers
{
return &parse_opt("MinSpareServers", '^\d+$',
		  $text{'core_eminspare'});
}

sub edit_MaxSpareServers
{
return (1,
	$text{'core_maxspare'},
	&opt_input($_[0]->{'value'},"MaxSpareServers",$text{'core_default'}, 4));
}
sub save_MaxSpareServers
{
return &parse_opt("MaxSpareServers", '^\d+$',
		  $text{'core_emaxspare'});
}

sub edit_StartServers
{
return (1,
	$text{'core_initial'},
	&opt_input($_[0]->{'value'}, "StartServers", $text{'core_default'}, 4));
}
sub save_StartServers
{
return &parse_opt("StartServers", '^\d+$',
		  $text{'core_einitial'});
}

sub edit_RLimitCPU
{
return &rlimit_input("RLimitCPU", $text{'core_cpulimit'}, $_[0]);
}
sub save_RLimitCPU
{
return &parse_rlimit("RLimitCPU", $text{'core_cpulimit2'});
}

sub edit_RLimitMEM
{
return &rlimit_input("RLimitMEM", $text{'core_memlimit'}, $_[0]);
}
sub save_RLimitMEM
{
return &parse_rlimit("RLimitMEM", $text{'core_memlimit2'});
}

sub edit_RLimitNPROC
{
return &rlimit_input("RLimitNPROC", $text{'core_proclimit'}, $_[0]);
}
sub save_RLimitNPROC
{
return &parse_rlimit("RLimitNPROC", $text{'core_proclimit2'});
}

# rlimit_input(name, desc, value)
sub rlimit_input
{
local(@v, $rv);
@v = split(/\s+/, $_[2]->{'value'});
$rv = sprintf "<input type=radio name=$_[0]_mode value=0 %s> $text{'core_default'}<br>\n",
	@v ? "" : "checked";
$rv .= sprintf "<input type=radio name=$_[0]_mode value=1 %s>\n",
	@v == 1 ? "checked" : "";
$rv .= sprintf "$text{'core_slimit'}<input name=$_[0]_soft1 size=5 value=\"%s\"><br>\n",
	@v == 1 ? $v[0] : "";
$rv .= sprintf "<input type=radio name=$_[0]_mode value=2 %s>\n",
	@v == 2 ? "checked" : "";
$rv .= sprintf "$text{'core_slimit'}<input name=$_[0]_soft2 size=5 value=\"%s\">\n",
	@v == 2 ? $v[0] : "";
$rv .= sprintf "$text{'core_hlimit'}<input name=$_[0]_hard2 size=5 value=\"%s\"><br>\n",
	@v == 2 ? $v[1] : "";
return (1, $_[1], $rv);
}

# parse_rlimit(name, desc)
sub parse_rlimit
{
if ($in{"$_[0]_mode"} == 0) { return ( [ ] ); }
elsif ($in{"$_[0]_mode"} == 1) {
	$in{"$_[0]_soft1"} =~ /^(\d+|max)$/ ||
		&error(&text('core_eslimit', $in{"$_[0]_soft1"}, $_[1]));
	return ( [ $in{"$_[0]_soft1"} ] );
	}
elsif ($in{"$_[0]_mode"} == 2) {
	$in{"$_[0]_soft2"} =~ /^(\d+|max)$/ ||
		&error(&text('core_eslimit', $in{"$_[0]_soft2"}, $_[1]));
	$in{"$_[0]_hard2"} =~ /^(\d+|max)$/ ||
		&error(&text('core_ehlimit', $in{"$_[0]_hard2"}, $_[1]));
	return ( [ $in{"$_[0]_soft2"}." ".$in{"$_[0]_hard2"} ] );
	}
}


#########################################################################
# Networking and address directives
sub edit_BindAddress_Listen_Port
{
local($bref, $lref, $pref, @blist, @plist, @slist, $inp);
$bref = $_[0]; $lref = $_[1]; $pref = $_[2];
if (@$lref) {
	# listen directives in use.. so BindAddress and Port are unused
	foreach $l (@$lref) {
		my @w = split(/\s+/, $l->{'value'});
		if ($w[0] =~ /^\[(\S+)\]:(\d+)$/) {
			# IPv6 address and port
			push(@blist, $1); push(@plist, $2);
			}
		elsif ($w[0] =~ /^\[(\S+)\]$/) {
			# IPv6 address only
			push(@blist, $1); push(@plist, undef);
			}
		elsif ($w[0] =~ /^(\S+):(\d+)$/) {
			# IPv4 address and port
			push(@blist, $1); push(@plist, $2);
			}
		elsif ($w[0] =~ /^(\d+)$/) {
			# Port only
			push(@blist, "*"); push(@plist, $1);
			}
		elsif ($w[0] =~ /^(\S+)$/) {
			# IPv4 address or hostname only
			push(@blist, $1); push(@plist, undef);
			}
		push(@slist, $w[1]);
		}
	}
else {
	# no listen directives... check for BindAddress
	if (@$bref) { push(@blist, $bref->[@$bref-1]->{'value'}); }
	else { push(@blist, "*"); }
	push(@plist, undef);
	push(@slist, undef);
	}
$port = @$pref ? $pref->[@$pref-1]->{'value'} : 80;
if ($_[3]->{'version'} < 2.0) {
	$inp = "<b>$text{'core_dport'}</b> ".
	       &ui_textbox("Port", $port, 6)."<br>\n";
	}
my @cols = ( $text{'core_address'}, $text{'core_port'} );
if ($_[3]->{'version'} >= 2.4) {
	# Apache supports a port protocol
	push(@cols, $text{'core_portname'});
	}
$inp .= &ui_columns_start(\@cols, "50%");
for($i=0; $i<@blist+1; $i++) {
	my @row;
	my $ba = $blist[$i] eq "*" ? 1 : $blist[$i] eq "" ? 2 : 0;
	push(@row, &ui_radio("BindAddress_def_$i", $ba,
			[ [ 2, $text{'core_none'} ],
			  [ 1, $text{'core_all'} ],
			  [ 0, &ui_textbox("BindAddress_$i",
				$ba == 0 ? $blist[$i] : "", 20) ] ]));
	if ($_[3]->{'version'} < 2.0) {
		push(@row, &opt_input($plist[$i], "Port_$i",
				      $text{'core_default'}, 5));
		}
	else {
		push(@row, &ui_textbox("Port_$i", $plist[$i], 5));
		}
	if ($_[3]->{'version'} >= 2.4) {
		push(@row, &ui_select("Name_$i", $slist[$i],
				      [ [ "", $text{'core_protoany'} ],
					[ "http", "HTTP" ],
					[ "https", "HTTPS" ] ]));
		}
	$inp .= &ui_columns_row(\@row);
	}
$inp .= &ui_columns_end();
return (2, $text{'core_listen'}, $inp);
}
sub save_BindAddress_Listen_Port
{
local(@blist, @plist, @slist, $bdef, $b, $p);

# build list of addresses and ports
for($i=0; defined($in{"Port_$i"}); $i++) {
	$bdef = $in{"BindAddress_def_$i"}; $b = $in{"BindAddress_$i"};
	$pdef = $in{"Port_${i}_def"}; $p = $in{"Port_$i"};
	if ($bdef == 2) { next; }

	if ($bdef) { push(@blist, "*"); }
	elsif ($b =~ /^\S+$/ &&
	       (&to_ipaddress($b) || &to_ip6address($b))) { push(@blist, $b); }
	else { &error(&text('core_eaddress', $b)); }

	if ($pdef) { push(@plist, undef); }
	elsif ($p =~ /^\d+$/) { push(@plist, $p); }
	else { &error(&text('core_eport', $p)); }

	push(@slist, $in{"Name_$i"});
	}
if (!@blist) { &error($text{'core_eoneaddr'}); }

# Return directives
if ($_[0]->{'version'} < 2.0) {
	# Older apaches have a port directive as well
	$in{'Port'} =~ /^\d+$/ || &error($text{'core_edefport'});
	if (@blist == 1 && !$plist[0]) {
		# Only one address, and the default port
		return ( $blist[0] eq "*" ? [ ] : [ $blist[0] ], [ ],
			 [ $in{'Port'} ] );
		}
	else {
		# More than one address, or a non-default port. Must use Listens
		for($i=0; $i<@blist; $i++) {
			if ($blist[$i] ne "*" && $plist[$i]) {
				push(@l, "$blist[$i]:$plist[$i]");
				}
			elsif ($blist[$i] ne "*") { push(@l, $blist[$i]); }
			elsif ($plist[$i]) { push(@l, "*:$plist[$i]"); }
			else { push(@l, $in{'Port'}); }
			}
		return ( [], \@l, [ $in{'Port'} ] );
		}
	}
else {
	# Apache 2.0 just uses Listen directives
	local %doneport;
	for($i=0; $i<@blist; $i++) {
		if (&check_ip6address($blist[$i])) {
			$blist[$i] = "[".$blist[$i]."]";
			}
		if ($blist[$i] ne "*" && $plist[$i]) {
			push(@l, "$blist[$i]:$plist[$i]");
			}
		elsif ($blist[$i] ne "*") { push(@l, $blist[$i]); }
		else { push(@l, "*:$plist[$i]"); }
		if ($doneport{$l[$#l]}++) {
			# Same listen given twice
			&error(&text('core_eduplisten', $l[$#l]));
			}
		if ($_[0]->{'version'} >= 2.4 && $slist[$i]) {
			$l[$#l] .= " ".$slist[$i];
			}
		}
	return ( [], \@l );
	}
}

sub edit_KeepAlive_MaxKeepAliveRequests
{
$kref = $_[0]; $mref = $_[1];
if ($_[2]->{'version'} >= 1.2) {
	# two separate directives for keep-alives
	$inp = sprintf
		"<input type=radio name=KeepAlive_def value=0 %s> $text{'core_none'}\n".
		"<input type=radio name=KeepAlive_def value=1 %s> $text{'core_default'}\n".
		"<input type=radio name=KeepAlive_def value=2 %s> ".
		"<input name=KeepAlive size=5 value=\"%s\">",
		$kref->{'value'} =~ /off/i ? "checked" : "",
		$kref->{'value'} !~ /off/i && !$mref ? "checked" : "",
		$mref ? "checked" : "",
		$mref ? $mref->{'value'} : "";
	}
else {
	# only one directive
	$inp = sprintf
		"<input type=radio name=KeepAlive_def value=0 %s> $text{'core_none'}\n".
		"<input type=radio name=KeepAlive_def value=1 %s> $text{'core_default'}\n".
		"<input type=radio name=KeepAlive_def value=2 %s> ".
		"<input name=KeepAlive size=5 value=\"%s\">",
		$kref->{'value'} eq "0" ? "checked" : "",
		$kref ? "" : "checked" ,
		$kref->{'value'} ? "checked" : "",
		$kref->{'value'} ? $kref->{'value'} : "";
	}
return (1, $text{'core_multi'}, $inp);
}
sub save_KeepAlive_MaxKeepAliveRequests
{
if ($_[0]->{'version'} >= 1.2) {
	# two separate directives
	if ($in{'KeepAlive_def'} == 0) { return ( [ "off" ], [ ] ); }
	elsif ($in{'KeepAlive_def'} == 1) { return ( [ "on" ], [ ] ); }
	elsif ($in{'KeepAlive'} !~ /^\d+$/) {
		&error(&text('core_ekeep', $in{'KeepAlive'}));
		}
	else { return ( [ "on" ], [ $in{'KeepAlive'} ] ); }
	}
else {
	# only one directive
	if ($in{'KeepAlive_def'} == 0) { return ( [ 0 ], [ ] ); }
	elsif ($in{'KeepAlive_def'} == 1) { return ( [ ], [ ] ); }
	elsif ($in{'KeepAlive'} !~ /^\d+$/) {
		&error(&text('core_ekeep', $in{'KeepAlive'}));
		}
	else { return ( [ $in{'KeepAlive'} ], [ ] ); }
	}
}

sub edit_KeepAliveTimeout
{
return (1,
	$text{'core_keeptout'},
	&opt_input($_[0]->{'value'}, "KeepAliveTimeout", $text{'core_default'}, 5));
}
sub save_KeepAliveTimeout
{
return &parse_opt("KeepAliveTimeout", '^\d+$',
		  $text{'core_ekeeptout'});
}

sub edit_ListenBacklog
{
return (1,
	$text{'core_lqueue'},
	&opt_input($_[0]->{'value'}, "ListenBacklog", $text{'core_default'}, 4));
}
sub save_ListenBacklog
{
return &parse_opt("ListenBacklog", '^\d+$',
		  $text{'core_elqueue'});
}

sub edit_SendBufferSize
{
return (1,
	$text{'core_bufsize'},
	&opt_input($_[0]->{'value'}, "SendBufferSize", $text{'core_osdefault'}, 4));
}
sub save_SendBufferSize
{
return &parse_opt("SendBufferSize", '^\d+$',
		  $text{'core_ebufsize'});
}

sub edit_ServerAdmin
{
return (1, $text{'core_admin'},
        &opt_input($_[0]->{'value'}, "ServerAdmin", $text{'core_noadmin'}, 25));
}
sub save_ServerAdmin
{
return &parse_opt("ServerAdmin");
}

sub edit_TimeOut
{
return (1,
	$text{'core_rtout'},
	&opt_input($_[0]->{'value'}, "TimeOut", $text{'core_default'}, 4));
}
sub save_TimeOut
{
return &parse_opt("TimeOut", '^\d+$',
		  $text{'core_ertout'});
}

sub edit_UseCanonicalName
{
return (1, $text{'core_bhostname'},
        &choice_input($_[0]->{'value'}, "UseCanonicalName",
	               "", "$text{'yes'},off", "$text{'no'},on", "$text{'core_default'},"));
}
sub save_UseCanonicalName
{
return &parse_choice("UseCanonicalName", "");
}

sub edit_HostNameLookups
{
if ($_[1]->{'version'} >= 1.3) {
	return (1, $text{'core_lookup'},
		&choice_input($_[0]->{'value'}, "HostNameLookups", "",
		       "$text{'no'},off", "$text{'yes'},on", "$text{'core_ltwice'},double", "$text{'core_default'},"));
	}
else {
	return (1, $text{'core_lookup'},
		&choice_input($_[0]->{'value'}, "HostNameLookups", "",
			      "$text{'yes'},on", "$text{'no'},off", "$text{'core_default'},"));
	}
}
sub save_HostNameLookups
{
return &parse_choice("HostNameLookups", "");
}

sub edit_IdentityCheck
{
return (1, $text{'core_useauth'},
	&choice_input($_[0]->{'value'}, "IdentityCheck", "",
		      "$text{'yes'},on", "$text{'no'},off", "$text{'core_default'},"));
}
sub save_IdentityCheck
{
return &parse_choice("IdentityCheck", "");
}

sub edit_ServerAlias
{
local($a, @al);
foreach $a (@{$_[0]}) { push(@al, split(/\s+/, $a->{'value'})); }
return (1, $text{'core_altnames'},
	sprintf "<textarea name=ServerAlias rows=3 cols=25>%s</textarea>\n",
		join("\n", @al) );
}
sub save_ServerAlias
{
local(@al);
@al = split(/\s+/, $in{'ServerAlias'});
if (@al) {
	local @spal;
	while(@al > 200) {
		push(@spal, join(" ", @al[0 .. 199]));
		@al = @al[200 .. $#al];
		}
	push(@spal, join(" ", @al)) if (@al);
	return ( \@spal );
	}
else {
	return ( [ ] );
	}
}

sub edit_ServerName
{
return (1, $text{'core_hostname'},
	&opt_input($_[0]->{'value'}, "ServerName", $text{'core_auto'}, 25));
}
sub save_ServerName
{
return &parse_opt("ServerName", '^\S+$', $text{'core_ehostname'});
}

sub edit_NameVirtualHost
{
local(@nv, $nv, $star);
foreach $nv (@{$_[0]}) {
	if ($nv->{'value'} eq "*" && $_[1]->{'version'} >= 1.312) { $star++; }
	elsif ($nv->{'value'} =~ /^\[(\S+)\]$/) { push(@nv, $1); }
	else { push(@nv, $nv->{'value'}); }
	}
if ($_[1]->{'version'} >= 1.312) {
	$starui = sprintf
	  "<input type=checkbox name=NameVirtualHost_star value=1 %s> %s<br>\n",
	  $star ? "checked" : "", $text{'core_virtaddr_star'};
	}
return (1, $text{'core_virtaddr'},
	$starui.
	"<textarea name=NameVirtualHost rows=3 cols=30>".
	join("\n", @nv)."</textarea>");
}
sub save_NameVirtualHost
{
local(@nv, $nv, $addr);
@nv = split(/\s+/, $in{'NameVirtualHost'});
@nv = ( "*", @nv ) if ($in{'NameVirtualHost_star'});
foreach $nv (@nv) {
	if ($nv =~ /^\[(\S+)\]:(\d+|\*)$/) { $addr = $1; }
	elsif ($nv =~ /^(\S+):(\d+|\*)$/) { $addr = $1; }
	else { $addr = $nv; }
	if (!&to_ipaddress($addr) &&
	    !&to_ip6address($addr) && $addr ne '*') {
		&error(&text('core_evirtaddr', $addr));
		}
	if ($nv =~ /^(\S+):(\d+|\*)$/ && &check_ip6address($1)) {
		$nv = "[$1]:$2";
		}
	elsif (&check_ip6address($nv)) {
		$nv = "[$nv]";
		}
	}
if (@nv) { return ( \@nv ); }
else { return ( [ ] ); }
}

sub edit_Protocols
{
my %p = map { $_, 1 } @{$_[0]->{'words'}};
my @popts = ( "h2", "h2c", "http/1.1" );
my @psel = map { &ui_checkbox("protocols", $_, $text{'core_protocols_'.$_} || $_, $p{$_}) } @popts;
return (1,
        $text{'core_protocols'},
	&ui_radio("protocols_def", %p ? 0 : 1,
		  [ [ 1, $text{'default'}.
		      " (".$text{'core_protocols_http/1.1'}.")<br>" ],
		    [ 0, $text{'core_protocols_sel'} ] ])." ".
	join(" ", @psel),
	);
}
sub save_Protocols
{
if ($in{'protocols_def'}) {
	return ( [ ] );
	}
else {
	my @prots = split(/\0/, $in{'protocols'});
	@prots || &error($text{'core_eprotocols'});
	@prots = sort @prots;
	return ( [ join(" ", @prots) ] );
	}
}

#########################################################################
# Document directives
sub edit_AccessFileName
{
return (1,
        $text{'core_optfile'},
        &opt_input($_[0]->{'value'}, "AccessFileName", $text{'core_default'}, 20));
}
sub save_AccessFileName
{
if ($_[0]->{'version'} < 1.3) {
	return &parse_opt("AccessFileName", '^(\S+)$',
	                  $text{'core_eoptfile'});
	}
else {
	return &parse_opt("AccessFileName", '\S',
			     $text{'core_enoopt'});
	}
}

@AllowOverride_v = ("AuthConfig", "FileInfo", "Indexes", "Limit", "Options");
@AllowOverride_d = ("$text{'core_auth'}", "$text{'core_mime'}",
                    "$text{'core_indexing'}", "$text{'core_hostacc'}",
                    "$text{'core_diropts'}");
sub edit_AllowOverride
{
local($rv, @ov, %over, $rv);
$rv = &choice_input($_[0] ? 0 : 1, "AllowOverride_def", 1,
		 "$text{'core_default'},1", "$text{'core_filesel'},0");
$rv .= "<table border><tr><td>\n";
if ($_[0]) { @ov = split(/\s+/, $_[0]->{'value'}); }
else { @ov = ("All"); }
foreach $ov (@ov) { $over{$ov}++; }
if ($over{'All'}) { foreach $ov (@AllowOverride_v) { $over{$ov}++; }	}
elsif ($over{'None'}) { %over = (); }

for($i=0; $i<@AllowOverride_v; $i++) {
	$rv .= sprintf "<input type=checkbox name=AllowOverride_%s %s> %s<br>\n",
	        $AllowOverride_v[$i],
	        $over{$AllowOverride_v[$i]} ? "checked" : "",
	        $AllowOverride_d[$i];
	}
$rv .= "</td></tr></table>\n";
return (1, $text{'core_overr'}, $rv);
}
sub save_AllowOverride
{
local(@ov, $ov);
if ($in{'AllowOverride_def'}) { return ( [ ] ); }
foreach $ov (@AllowOverride_v) {
	if ($in{"AllowOverride_$ov"}) { push(@ov, $ov); }
	}
if (!@ov) { return ( [ "None" ] ); }
elsif (@ov == @AllowOverride_v) { return ( [ "All" ] ); }
else { return ( [ join(' ', @ov) ] ); }
}

sub edit_ContentDigest
{
return (1,
	$text{'core_genmd5'},
	&choice_input($_[0]->{'value'}, "ContentDigest", "",
		      "$text{'yes'},on", "$text{'no'},off", "$text{'core_default'},"));
}
sub save_ContentDigest
{
return &parse_choice("ContentDigest", "");
}

sub edit_DocumentRoot
{
return (2, $text{'core_docroot'},
	&opt_input($_[0]->{'words'}->[0], "DocumentRoot", $text{'core_default'}, 40).
	&file_chooser_button("DocumentRoot", 1));
}
sub save_DocumentRoot
{
if (!$in{'DocumentRoot_def'}) {
	-d $in{'DocumentRoot'} ||
		&error(&text('core_enodoc', $in{'DocumentRoot'}));
	&allowed_doc_dir($in{'DocumentRoot'}) ||
		&error(&text('core_ecandoc', $in{'DocumentRoot'}));
	}
return &parse_opt("DocumentRoot");
}

sub edit_Options
{
local(@po, @o, $o, %opts, $opts, $po, @pon, $i);
@po = ("ExecCGI", "FollowSymLinks", "Includes", "IncludesNOEXEC",
       "Indexes", "MultiViews", "SymLinksIfOwnerMatch");
@pon = ("$text{'core_execcgi'}", "$text{'core_flink'}",
	"$text{'core_inclexe'}", "$text{'core_incl'}",
	"$text{'core_genind'}", "$text{'core_genmview'}",
	"$text{'core_flinkmatch'}");
$opts = &choice_input($_[0] ? 0 : 1, "Options_def", 1, "$text{'core_default'},1",
		      "$text{'core_optsel'},0")."<br>\n";
@o = split(/\s+/, $_[0]->{'value'});
foreach $o (split(/\s+/, $_[0]->{'value'})) {
	if ($o =~ /^\+(.*)$/) { $opts{$1} = 2; }
	elsif ($o =~ /^\-(.*)$/) { $opts{$1} = 3; }
	else { $opts{$o} = 1; }
	}
if ($opts{'All'}) {
	local($all); $all = $opts{'All'};
	undef(%opts);
	foreach $o (grep {!/MultiViews/} @po) {
		$opts{$o} = $all;
		}
	}
$opts .= "<table border>\n";
$opts .= "<tr $tb> <td><b>$text{'core_option'}</b></td> <td><b>$text{'core_setdir'}</b></td>\n";
$opts .= "<td><b>$text{'core_merge'}</b></td> </tr>\n";
for($i=0; $i<@po; $i++) {
	$po = $po[$i];
	$opts .= "<tr $cb> <td><b>$pon[$i]</b></td> <td>\n";
	$opts .= sprintf "<input type=radio name=$po value=1 %s> $text{'yes'}\n",
			$opts{$po}==1 ? "checked" : "";
	$opts .= sprintf "<input type=radio name=$po value=0 %s> $text{'no'}\n",
			$opts{$po}==0 ? "checked" : "";
	$opts .= "</td> <td>\n";
	$opts .= sprintf "<input type=radio name=$po value=2 %s> $text{'core_enable'}\n",
			$opts{$po}==2 ? "checked" : "";
	$opts .= sprintf "<input type=radio name=$po value=3 %s> $text{'core_disable'}\n",
			$opts{$po}==3 ? "checked" : "";
	$opts .= "</td> </tr>\n";
	}
$opts .= "</table>\n";
return (2, $text{'core_diropts'}, $opts);
}
sub save_Options
{
local(@po, $po, @rv);
if ($in{'Options_def'}) { return ( [ ] ); }
@po = ("ExecCGI", "FollowSymLinks", "Includes", "IncludesNOEXEC",
       "Indexes", "MultiViews", "SymLinksIfOwnerMatch");
my $abscount = 0;
my $pluscount = 0;
foreach $po (@po) {
	if ($in{$po} == 1) {
		push(@rv, $po);
		$abscount++;
		}
	elsif ($in{$po} == 2) {
		push(@rv, "+$po");
		$pluscount++;
		}
	elsif ($in{$po} == 3) {
		push(@rv, "-$po");
		$pluscount++;
		}
	}
$abscount && $pluscount && &error($text{'core_eoptionsboth'});
return @rv ? ( [ join(' ', @rv) ] ) : ( [ "None" ] );
}

sub edit_ServerPath
{
return (2,
	$text{'core_virtpath'},
	&opt_input($_[0]->{'value'}, "ServerPath", $text{'core_default'}, 40).
	&file_chooser_button("ServerPath", 1));
}
sub save_ServerPath
{
return &parse_opt("ServerPath", '^\/\S*$',
		  $text{'core_evirtpath'});
}

sub edit_ServerSignature
{
return (1, $text{'core_footer'},
	&select_input($_[0]->{'value'}, "ServerSignature", undef,
		      "$text{'core_sigemail'},Email", "$text{'core_signame'},On",
		      "$text{'core_signone'},Off", "$text{'core_default'},"));
}
sub save_ServerSignature
{
return &parse_select("ServerSignature", undef);
}

sub edit_FileETag
{
local (%et, $rv);
map { $et{lc($_)}++ } @{$_[0]->{'words'}} if ($_[0]);
$rv .= sprintf "<input type=radio name=FileETag_def value=1 %s> %s\n",
			$_[0] ? "" : "checked", $text{'default'};
$rv .= sprintf "<input type=radio name=FileETag_def value=0 %s> %s\n",
			$_[0] ? "checked" : "", $text{'core_fileetag_sel'};
foreach $e ('INode', 'MTime', 'Size') {
	$rv .= sprintf "<input type=checkbox name=FileETag value=%s %s> %s\n",
			$e, $et{lc($e)} || $et{'all'} ? "checked" : "",
			$text{'core_fileetag_'.lc($e)};
	}
return (2, $text{'core_fileetag'}, $rv);
}
sub save_FileETag
{
if ($in{'FileETag_def'}) {
	return ( [ ] );
	}
else {
	local @e = split(/\0/, $in{'FileETag'});
	return @e ? ( [ join(" ", @e) ] ) : ( [ "None" ] );
	}
}

#########################################################################
# MIME directives directives
sub edit_DefaultType
{
return (1,
	$text{'core_defmime'},
	&opt_input($_[0]->{'value'}, "DefaultType", $text{'core_default'}, 20));
}
sub save_DefaultType
{
return &parse_opt("DefaultType", '^(\S+)\/(\S+)$',
		  $text{'core_edefmime'});
}

sub edit_ForceType
{
return (1, $text{'mod_mime_defmime'},
	&opt_input($_[0]->{'value'}, "ForceType", $text{'mod_mime_real'}, 15));
}
sub save_ForceType
{
return &parse_opt("ForceType", '^\S+\/\S+$', $text{'mod_mime_etype'});
}

sub edit_SetOutputFilter
{
local @vals = split(/[\s;]+/, $_[0]->{'value'});
my $fi = &filters_input(\@vals, "SetOutputFilter");
return (2, $text{'core_outfilter'}, $fi);
}
sub save_SetOutputFilter
{
return &parse_filters("SetOutputFilter");
}

sub edit_SetInputFilter
{
local @vals = split(/[\s;]+/, $_[0]->{'value'});
my $fi = &filters_input(\@vals, "SetInputFilter");
return (2, $text{'core_infilter'}, $fi);
}
sub save_SetInputFilter
{
return &parse_filters("SetInputFilter");
}

sub edit_AddDefaultCharset
{
local $rv;
local $m = lc($_[0]->{'value'}) eq 'off' ? 2 :
	   $_[0]->{'value'} ? 0 : 1;
$rv .= sprintf "<input type=radio name=AddDefaultCharset_def value=1 %s> %s\n",
		$m == 1 ? "checked" : "", $text{'default'};
$rv .= sprintf "<input type=radio name=AddDefaultCharset_def value=2 %s> %s\n",
		$m == 2 ? 'checked' : "", $text{'core_none'};
$rv .= sprintf "<input type=radio name=AddDefaultCharset_def value=0 %s>\n",
		$m == 0 ? "checked" : "";
$rv .= sprintf "<input name=AddDefaultCharset size=12 value='%s'>\n",
		$m == 0 ? $_[0]->{'value'} : "";
return (1, $text{'core_defchar'}, $rv);
}
sub save_AddDefaultCharset
{
if ($in{'AddDefaultCharset_def'} == 1) {
	return ( [ ] );
	}
elsif ($in{'AddDefaultCharset_def'} == 2) {
	return ( [ "Off" ] );
	}
else {
	$in{'AddDefaultCharset'} =~ /^\S+$/ || &error($text{'core_edefchar'});
	return ( [ $in{'AddDefaultCharset'} ] );
	}
}

#########################################################################
# Access control directives
sub edit_AuthName
{
my $val = $_[1]->{'version'} >= 1.3 ? $_[0]->{'words'}->[0]
				    : $_[0]->{'value'};
return (1, $text{'core_realm'},
        &opt_input($val, "AuthName", $text{'core_default'}, 25));
}
sub save_AuthName
{
return $in{'AuthName_def'}	 ? ( [ ] ) :
       $_[0]->{'version'} >= 1.3 ? ( [ "\"$in{'AuthName'}\"" ] ) :
				   ( [ $in{'AuthName'} ] );
}

sub edit_AuthType
{
local($rv, $a);
$rv = "<select name=AuthType>\n";
foreach $a ("", "Basic", "Digest") {
	$rv .= sprintf "<option %s>$a</option>\n",
	        lc($_[0]->{'value'}) eq lc($a) ? "selected" : "";
	}
$rv .= "</select>";
return (1, $text{'core_authtype'}, $rv);
}
sub save_AuthType
{
if ($in{'AuthType'}) { return ( [ $in{'AuthType'} ] ); }
else { return ( [ ] ); }
}

sub edit_require
{
local($rv, $mode, $list);
local @w = @{$_[0]->{'words'}};
$mode = shift(@w);
$list = join(" ", map { $_ =~ /\s/ ? "\"$_\"" : $_ } @w);

# All users
$rv = sprintf
      "<input type=radio name=require_mode value=0 %s> $text{'default'}<br>\n",
      $mode ? "" : "checked";

# Only some users
$rv .= sprintf
      "<input type=radio name=require_mode value=1 %s> $text{'core_users'}:\n",
      $mode eq "user" ? "checked" : "";
$rv .= sprintf
      "<input name=require_user size=20 value=\"%s\"><br>\n",
      $mode eq "user" ? &html_escape($list) : "";

# Only members of groups
$rv .= sprintf
      "<input type=radio name=require_mode value=2 %s> $text{'core_groups'}:\n",
      $mode eq "group" ? "checked" : "";
$rv .= sprintf
      "<input name=require_group size=20 value=\"%s\"><br>\n",
      $mode eq "group" ? &html_escape($list) : "";

# All users
$rv .= sprintf
      "<input type=radio name=require_mode value=3 %s> $text{'core_allusers'}<br>\n",
      $mode eq "valid-user" ? "checked" : "";

if ($httpd_modules{'mod_authz_owner'} >= 2.2) {
	# File owner / group matches
	$rv .= sprintf
	      "<input type=radio name=require_mode value=4 %s> $text{'core_fileowner'}<br>\n",
	      $mode eq "file-owner" ? "checked" : "";
	$rv .= sprintf
	      "<input type=radio name=require_mode value=5 %s> $text{'core_filegroup'}<br>\n",
	      $mode eq "file-group" ? "checked" : "";

	}
return (1, $text{'core_authlog'}, $rv);
}
sub save_require
{
if ($in{'require_mode'} == 0) { return ( [ ] ); }
elsif ($in{'require_mode'} == 1) { return ( [ "user $in{'require_user'}" ] ); }
elsif ($in{'require_mode'} == 2) { return ( [ "group $in{'require_group'}" ] ); }
elsif ($in{'require_mode'} == 3) { return ( [ "valid-user" ] ); }
elsif ($in{'require_mode'} == 4) { return ( [ "file-owner" ] ); }
elsif ($in{'require_mode'} == 5) { return ( [ "file-group" ] ); }
else { return ( [ ] ); }	# huh?
}

sub edit_Satisfy
{
return (1, $text{'core_satisfy'},
	&choice_input_vert($_[0]->{'value'}, "Satisfy", "", "$text{'core_default'},",
			   "$text{'core_authall'},all","$text{'core_authany'},any"));
}
sub save_Satisfy
{
return &parse_choice("Satisfy", "");
}

#########################################################################
# Misc. directives
sub edit_CoreDumpDirectory
{
return (1, $text{'core_coredir'},
	 &opt_input($_[0]->{'words'}->[0], "CoreDumpDirectory", $text{'core_sroot'}, 20).
	 &file_chooser_button("CoreDumpDirectory", 1));
}
sub save_CoreDumpDirectory
{
return &parse_opt("CoreDumpDirectory", '^\S+$', $text{'core_ecore'});
}

sub edit_LockFile
{
return (1, $text{'core_lockfile'},
        &opt_input($_[0]->{'words'}->[0], "LockFile", $text{'core_default'}, 20).
        &file_chooser_button("LockFile", 0));
}
sub save_LockFile
{
return &parse_opt("LockFile", '^\S+', $text{'core_elock'});
}

sub edit_LimitRequestBody
{
return (1, $text{'core_maxbody'},
	&opt_input($_[0]->{'value'}, "LimitRequestBody", $text{'core_default'}, 8)
		.&ui_space(2).$text{'bytes'});
}
sub save_LimitRequestBody
{
return &parse_opt("LimitRequestBody", '^\d+$', $text{'core_ebody'});
}

sub edit_LimitXMLRequestBody
{
return (1, $text{'core_maxxml'},
	&opt_input($_[0]->{'value'}, "LimitXMLRequestBody",
		   $text{'core_default'}, 8).&ui_space(2).$text{'bytes'});
}
sub save_LimitXMLRequestBody
{
return &parse_opt("LimitXMLRequestBody", '^\d+$', $text{'core_exml'});
}



sub edit_LimitRequestFields
{
return (1, $text{'core_maxhead'},
	&opt_input($_[0]->{'value'}, "LimitRequestFields", $text{'core_default'}, 6));
}
sub save_LimitRequestFields
{
return &parse_opt("LimitRequestFields", '^\d+$', $text{'core_ehead'});
}

sub edit_LimitRequestFieldsize
{
return (1, $text{'core_maxshead'},
	&opt_input($_[0]->{'value'}, "LimitRequestFieldsize", $text{'core_default'}, 6));
}
sub save_LimitRequestFieldsize
{
return &parse_opt("LimitRequestFieldsize", '^\d+$', $text{'core_eshead'});
}

sub edit_LimitRequestLine
{
return (1, $text{'core_maxline'},
	&opt_input($_[0]->{'value'}, "LimitRequestLine", $text{'core_default'}, 6));
}
sub save_LimitRequestLine
{
return &parse_opt("LimitRequestLine", '^\d+$', $text{'core_eline'});
}

sub edit_PidFile
{
return (1, $text{'core_pid'},
        &opt_input($_[0]->{'words'}->[0], "PidFile", $text{'core_default'}, 20).
        &file_chooser_button("PidFile", 0));
}
sub save_PidFile
{
return &parse_opt("PidFile", '^\S+$', $text{'core_epid'});
}

sub edit_ScoreBoardFile
{
return (1, $text{'core_memsco'},
        &opt_input($_[0]->{'words'}->[0], "ScoreBoardFile", $text{'core_default'}, 20).
        &file_chooser_button("ScoreBoardFile", 0));
}
sub save_ScoreBoardFile
{
return &parse_opt("ScoreBoardFile", '^\S+$', $text{'core_escore'});
}

sub edit_ServerType
{
return (1, $text{'core_exec'},
        &choice_input($_[0]->{'value'}, "ServerType", "standalone",
                      "$text{'core_salone'},standalone", "$text{'core_inetd'},inetd"));
}
sub save_ServerType
{
return &parse_choice("ServerType", "standalone");
}

sub edit_ServerTokens
{
local $v = $_[0]->{'value'};
$v = "ProductOnly" if ($v eq "Prod");
$v = "Min" if ($v eq "Minimal");
return (1, $text{'core_header'},
	&select_input($v, "ServerTokens", "Full",
		      "$text{'core_verosmod'},Full",
		      "$text{'core_veros'},OS",
		      "$text{'core_ver'},Min",
		      "$text{'core_minor'},Minor",
		      $_[1]->{'version'} >= 1.313 ?
			("$text{'core_product'},ProductOnly") : (),
		      $_[1]->{'version'} >= 2.041 ?
			("$text{'core_major'},Major") : ()
			));
}
sub save_ServerTokens
{
return &parse_select("ServerTokens", "Full");
}

#########################################################################
# User/group directives
sub edit_Group
{
local($rv, @ginfo);
$rv = sprintf "<input type=radio name=Group value=0 %s>$text{'core_default'}&nbsp;\n",
       $_[0] ? "" : "checked";
$rv .= sprintf "<input type=radio name=Group value=1 %s>$text{'core_group'}\n",
        $_[0] && $_[0]->{'words'}->[0] !~ /^#/ ? "checked" : "";
$rv .= sprintf "<input name=Group_name size=8 value=\"%s\"> %s&nbsp;\n",
	$_[0]->{'words'}->[0] !~ /^#/ ? $_[0]->{'words'}->[0] : "",
	&group_chooser_button("Group_name", 0);
$rv .= sprintf "<input type=radio name=Group value=2 %s>$text{'core_gid'}\n",
        $_[0]->{'words'}->[0] =~ /^#/ ? "checked" : "";
$rv .= sprintf "<input name=Group_id size=6 value=\"%s\">\n",
	 $_[0]->{'words'}->[0] =~ /^#(.*)$/ ? $1 : "";
return (2, $text{'core_asgroup'}, $rv);
}
sub save_Group
{
if ($in{'Group'} == 0) { return ( [ ] ); }
elsif ($in{'Group'} == 1) { return ( [ $in{'Group_name'} ] ); }
elsif ($in{'Group_id'} !~ /^\-?\d+$/) {
	&error(&text('core_euid', $in{'Group_id'}));
	}
else { return ( [ "\"#$in{'Group_id'}\"" ] ); }
}

sub edit_User
{
local($rv, @uinfo);
$rv = sprintf "<input type=radio name=User value=0 %s>$text{'core_default'}&nbsp;\n",
       $_[0] ? "" : "checked";
$rv .= sprintf "<input type=radio name=User value=1 %s>$text{'core_user'}\n",
        $_[0] && $_[0]->{'words'}->[0] !~ /^#/ ? "checked" : "";
$rv .= sprintf "<input name=User_name size=8 value=\"%s\"> %s&nbsp;\n",
	$_[0]->{'words'}->[0] !~ /^#/ ? $_[0]->{'words'}->[0] : "",
	&user_chooser_button("User_name", 0);
$rv .= sprintf "<input type=radio name=User value=2 %s>$text{'core_uid'}\n",
        $_[0]->{'words'}->[0] =~ /^#/ ? "checked" : "";
$rv .= sprintf "<input name=User_id size=6 value=\"%s\">\n",
	 $_[0]->{'words'}->[0] =~ /^#(.*)$/ ? $1 : "";
return (2, $text{'core_asuser'}, $rv);
}
sub save_User
{
if ($in{'User'} == 0) { return ( [ ] ); }
elsif ($in{'User'} == 1) { return ( [ $in{'User_name'} ] ); }
elsif ($in{'User_id'} !~ /^\-?\d+$/) {
	&error(&text('core_egid', $in{'User_id'}));
	}
else { return ( [ "\"#$in{'User_id'}\"" ] ); }
}

#########################################################################
# Error handling directives
sub edit_ErrorDocument
{
local($rv, $len, $i);
$rv = "<table border width=100%>\n";
$rv .= "<tr $tb> <td><b>$text{'core_error'}</b></td> <td><b>$text{'core_resp'}</b></td> ".
       "<td><b>$text{'core_urlmsg'}</b></td> </tr>\n";
$len = @{$_[0]} + 1;
for($i=0; $i<$len; $i++) {
	$v = $_[0]->[$i]->{'value'};
	if ($v =~ /^(\d+)\s+((http|https|ftp|gopher):\S+)$/)
		{ $code = $1; $type = 0; $url = $2; }
	elsif ($v =~ /^(\d+)\s+(\/.*)$/) { $code = $1; $type = 0; $url = $2; }
	elsif ($v =~ /^(\d+)\s+"(.*)"$/) { $code = $1; $type = 1; $url = $2; }
	elsif ($v =~ /^(\d+)\s+"?(.*)$/) { $code = $1; $type = 1; $url = $2; }
	else { $code = ""; $type = 0; $url = ""; }
	$rv .= "<tr $cb>\n";
	$rv .= "<td><input name=ErrorDocument_code_$i size=3 value=$code></td>\n";
	$rv .= "<td><input type=radio name=ErrorDocument_type_$i value=0 ".
	       ($type==0 ? "checked" : "").">$text{'core_tourl'}\n";
	$rv .= "<input type=radio name=ErrorDocument_type_$i value=1 ".
	       ($type==1 ? "checked" : "").">$text{'core_mesg'}</td>\n";
	$rv .= "<td><input name=ErrorDocument_url_$i size=40 value=\"$url\"></td>\n";
	$rv .= "</tr>\n";
	}
$rv .= "</table>\n";
return (2, $text{'core_custom'}, $rv);
}
sub save_ErrorDocument
{
local($i, $code, $url, @rv);
for($i=0; defined($in{"ErrorDocument_code_$i"}); $i++) {
	$code = $in{"ErrorDocument_code_$i"}; $url = $in{"ErrorDocument_url_$i"};
	if ($code !~ /\S/ || $url !~ /\S/) { next; }
	$code =~ /^\d\d\d$/ || &error(&text('core_eerror', $code));
	if ($in{"ErrorDocument_type_$i"} == 0) {
		$url =~ /^\S+$/ || &error(&text('core_eurl', $url));
		push(@rv, "$code $url");
		}
	elsif ($_[0]->{'version'} >= 2.0) { push(@rv, "$code \"$url\""); }
	elsif ($_[0]->{'version'} >= 1.2) { push(@rv, "$code \"$url"); }
	else { push(@rv, "$code $url"); }
	}
return ( \@rv );
}

#########################################################################
# Logging directives
sub edit_ErrorLog
{
if ($_[1]->{'version'} < 1.3) {
	return (1, $text{'core_errfile'},
		&opt_input($_[0]->{'value'}, "ErrorLog", $text{'core_default'}, 20).
		&file_chooser_button("ErrorLog", 0));
	}
else {
	local $v = $_[0]->{'words'}->[0];
	local $t = !$v ? 3 :
		   $v eq 'syslog' ? 2 :
		   $v =~ /^\|/ ? 1 : 0;
	$rv = sprintf "<input type=radio name=ErrorLog_type value=3 %s>\n",
		$t == 3 ? "checked" : "";
	$rv .= "$text{'core_default'}";
	$rv .= sprintf "<input type=radio name=ErrorLog_type value=2 %s>\n",
		$t == 2 ? "checked" : "";
	$rv .= "$text{'core_syslog'}<br>\n";
	$rv .= sprintf "<input type=radio name=ErrorLog_type value=0 %s>\n",
		$t == 0 ? "checked" : "";
	$rv .= sprintf "$text{'core_filelog'}<input name=ErrorLog_file size=25 value='%s'>\n",
		$t == 0 ? $v : "";
	$rv .= sprintf "<input type=radio name=ErrorLog_type value=1 %s>\n",
		$t == 1 ? "checked" : "";
	$rv .= sprintf "$text{'core_proglog'}<input name=ErrorLog_prog size=25 value='%s'><br>\n",
		$t == 1 ? substr($v, 1) : "";
	return (2, $text{'core_logto'}, $rv);
	}
}
sub save_ErrorLog
{
if ($_[0]->{'version'} < 1.3) {
	$in{'ErrorLog_def'} || &allowed_auth_file($in{'ErrorLog'}) ||
		&error($text{'core_edirlog'});
	$in{'ErrorLog_def'} || &directory_exists($in{'ErrorLog'}) ||
		    &error($text{'core_eerrordir'});
	return &parse_opt("ErrorLog", '^\S+$', $text{'core_efilelog'});
	}
else {
	if ($in{'ErrorLog_type'} == 3) {
		return ( [ ] );
		}
	elsif ($in{'ErrorLog_type'} == 0) {
		$in{'ErrorLog_file'} =~ /\S/ ||
		    &error($text{'core_efilemiss'});
		&allowed_auth_file($in{'ErrorLog_file'}) ||
		    &error($text{'core_edirlog'});
		&directory_exists($in{'ErrorLog_file'}) ||
		    &error($text{'core_eerrordir'});
		return ( [ $in{'ErrorLog_file'} ] );
		}
	elsif ($in{'ErrorLog_type'} == 1) {
		$in{'ErrorLog_prog'} =~ /\S/ ||
		    &error($text{'core_eprogmiss'});
		$access{'pipe'} ||
		    &error($text{'core_eperm'});
		return ( [ "\"|$in{'ErrorLog_prog'}\"" ] );
		}
	else {
		return ( [ "syslog" ] );
		}
	}
}

sub edit_LogLevel
{
return (1, $text{'core_loglevel'},
	&select_input($_[0]->{'value'}, "LogLevel", "",
		      "$text{'core_log_emerg'} (emerg),emerg",
		      "$text{'core_log_alert'} (alert),alert",
		      "$text{'core_log_crit'} (crit),crit",
		      "$text{'core_log_error'} (error),error",
		      "$text{'core_log_warn'} (warn),warn",
		      "$text{'core_log_notice'} (notice),notice",
		      "$text{'core_log_info'} (info),info",
		      "$text{'core_log_debug'} (debug),debug"));
}
sub save_LogLevel
{
return &parse_select("LogLevel", "");
}

#########################################################################
# Module directives
# This isn't shown if the distro has a way of managing these, such as Debian's
# /etc/apache/mods-enabled
sub edit_ClearModuleList_AddModule
{
local($mods, @allmods, $d, %mods, $m, $i, $rv);
local $httpd = &find_httpd();
($ver, $mods) = &httpd_info($httpd);
@allmods = grep { !/^core$/ } @$mods;
local $conf = &get_config();
foreach $d (&find_directive_struct("LoadModule", $conf)) {
	# Add mod_ like modules
	if ($d->{'words'}->[1] =~ /(mod_\S+)\.(so|dll)/) {
		push(@allmods, $1);
		}
	# nodo50 v0.1 - Change 000002 - Bug fixed: Apache-ssl module detected as mod_ssl. Now Apache-ssl module included as mod_apachessl
	# nodo50 v0.1 - Change 000002 - Bug corregido: El modulo Apache-ssl se detecta como mod_ssl. Ahora Apache-ssl se incluye como mod_apachessl
	# Add apache-ssl libssl.so as mod_apachessl module
	elsif ($d->{'words'}->[1] =~ /libssl\.so/) {
		push(@allmods, "mod_apachessl");
		}
	# Add others lib* like as mod_ modules
	# nodo50 v0.1 - Change 000002 - End
	elsif ($d->{'words'}->[1] =~ /lib([^\/\s]+)\.(so|dll)/) {
		push(@allmods, "mod_$1");
		}
	}

if (@{$_[0]}) {
	# Only selected modules have been enabled
	foreach $d (@{$_[1]}) {
		local $modc = $d->{'value'};
		$modc =~ s/\.c$//;
		$mods{$modc} = "checked";
		}
	}
else { foreach $m (@allmods) { $mods{$m} = "checked"; } }
$rv = &choice_input(@{$_[0]} ? 1 : 0, "ClearModuleList", 1,
		    "$text{'core_allmod'},0", "$text{'core_selmod'},1")."<br>\n";
$rv .= "<table>\n";
foreach $m (@allmods) {
	if ($i%4 == 0) { $rv .= "<tr>\n"; }
	$rv .= "<td><input name=AddModule type=checkbox value=$m $mods{$m}> $m</td>\n";
	if ($i++%4 == 3) { $rv .= "</tr>\n"; }
	}
$rv .= "</table>\n";
return (2, $text{'core_actmod'}, $rv);
}
sub save_ClearModuleList_AddModule
{
if ($in{'ClearModuleList'}) {
	local @mods = split(/\0/, $in{'AddModule'});
	return ( [ "" ], [ map { $_.".c" } @mods ] );
	}
else { return ( [ ], [ ] ); }
}

1;


Anon7 - 2022
SCDN GOK