PNG  IHDRQgAMA a cHRMz&u0`:pQ<bKGDgmIDATxwUﹻ& ^CX(J I@ "% (** BX +*i"]j(IH{~R)[~>h{}gy)I$Ij .I$I$ʊy@}x.: $I$Ii}VZPC)I$IF ^0ʐJ$I$Q^}{"r=OzI$gRZeC.IOvH eKX $IMpxsk.쒷/&r[޳<v| .I~)@$updYRa$I |M.e JaֶpSYR6j>h%IRز if&uJ)M$I vLi=H;7UJ,],X$I1AҒJ$ XY XzI@GNҥRT)E@;]K*Mw;#5_wOn~\ DC&$(A5 RRFkvIR}l!RytRl;~^ǷJj اy뷦BZJr&ӥ8Pjw~vnv X^(I;4R=P[3]J,]ȏ~:3?[ a&e)`e*P[4]T=Cq6R[ ~ޤrXR Հg(t_HZ-Hg M$ãmL5R uk*`%C-E6/%[t X.{8P9Z.vkXŐKjgKZHg(aK9ڦmKjѺm_ \#$5,)-  61eJ,5m| r'= &ڡd%-]J on Xm|{ RҞe $eڧY XYrԮ-a7RK6h>n$5AVڴi*ֆK)mѦtmr1p| q:흺,)Oi*ֺK)ܬ֦K-5r3>0ԔHjJئEZj,%re~/z%jVMڸmrt)3]J,T K֦OvԒgii*bKiNO~%PW0=dii2tJ9Jݕ{7"I P9JKTbu,%r"6RKU}Ij2HKZXJ,妝 XYrP ެ24c%i^IK|.H,%rb:XRl1X4Pe/`x&P8Pj28Mzsx2r\zRPz4J}yP[g=L) .Q[6RjWgp FIH*-`IMRaK9TXcq*I y[jE>cw%gLRԕiFCj-ďa`#e~I j,%r,)?[gp FI˨mnWX#>mʔ XA DZf9,nKҲzIZXJ,L#kiPz4JZF,I,`61%2s $,VOϚ2/UFJfy7K> X+6 STXIeJILzMfKm LRaK9%|4p9LwJI!`NsiazĔ)%- XMq>pk$-$Q2x#N ؎-QR}ᶦHZډ)J,l#i@yn3LN`;nڔ XuX5pF)m|^0(>BHF9(cզEerJI rg7 4I@z0\JIi䵙RR0s;$s6eJ,`n 䂦0a)S)A 1eJ,堌#635RIgpNHuTH_SԕqVe ` &S)>p;S$魁eKIuX`I4춒o}`m$1":PI<[v9^\pTJjriRŭ P{#{R2,`)e-`mgj~1ϣLKam7&U\j/3mJ,`F;M'䱀 .KR#)yhTq;pcK9(q!w?uRR,n.yw*UXj#\]ɱ(qv2=RqfB#iJmmL<]Y͙#$5 uTU7ӦXR+q,`I}qL'`6Kͷ6r,]0S$- [RKR3oiRE|nӦXR.(i:LDLTJjY%o:)6rxzҒqTJjh㞦I.$YR.ʼnGZ\ֿf:%55 I˼!6dKxm4E"mG_ s? .e*?LRfK9%q#uh$)i3ULRfK9yxm܌bj84$i1U^@Wbm4uJ,ҪA>_Ij?1v32[gLRD96oTaR׿N7%L2 NT,`)7&ƝL*꽙yp_$M2#AS,`)7$rkTA29_Iye"|/0t)$n XT2`YJ;6Jx".e<`$) PI$5V4]29SRI>~=@j]lp2`K9Jaai^" Ԋ29ORI%:XV5]JmN9]H;1UC39NI%Xe78t)a;Oi Ҙ>Xt"~G>_mn:%|~ޅ_+]$o)@ǀ{hgN;IK6G&rp)T2i୦KJuv*T=TOSV>(~D>dm,I*Ɛ:R#ۙNI%D>G.n$o;+#RR!.eU˽TRI28t)1LWϚ>IJa3oFbu&:tJ*(F7y0ZR ^p'Ii L24x| XRI%ۄ>S1]Jy[zL$adB7.eh4%%누>WETf+3IR:I3Xה)3אOۦSRO'ٺ)S}"qOr[B7ϙ.edG)^ETR"RtRݜh0}LFVӦDB^k_JDj\=LS(Iv─aTeZ%eUAM-0;~˃@i|l @S4y72>sX-vA}ϛBI!ݎߨWl*)3{'Y|iSlEڻ(5KtSI$Uv02,~ԩ~x;P4ցCrO%tyn425:KMlD ^4JRxSهF_}شJTS6uj+ﷸk$eZO%G*^V2u3EMj3k%)okI]dT)URKDS 7~m@TJR~荪fT"֛L \sM -0T KfJz+nإKr L&j()[E&I ߴ>e FW_kJR|!O:5/2跌3T-'|zX ryp0JS ~^F>-2< `*%ZFP)bSn"L :)+pʷf(pO3TMW$~>@~ū:TAIsV1}S2<%ޟM?@iT ,Eūoz%i~g|`wS(]oȤ8)$ ntu`өe`6yPl IzMI{ʣzʨ )IZ2= ld:5+請M$-ї;U>_gsY$ÁN5WzWfIZ)-yuXIfp~S*IZdt;t>KūKR|$#LcԀ+2\;kJ`]YǔM1B)UbG"IRߊ<xܾӔJ0Z='Y嵤 Leveg)$znV-º^3Ւof#0Tfk^Zs[*I꯳3{)ˬW4Ւ4 OdpbZRS|*I 55#"&-IvT&/윚Ye:i$ 9{LkuRe[I~_\ؠ%>GL$iY8 9ܕ"S`kS.IlC;Ҏ4x&>u_0JLr<J2(^$5L s=MgV ~,Iju> 7r2)^=G$1:3G< `J3~&IR% 6Tx/rIj3O< ʔ&#f_yXJiގNSz; Tx(i8%#4 ~AS+IjerIUrIj362v885+IjAhK__5X%nV%Iͳ-y|7XV2v4fzo_68"S/I-qbf; LkF)KSM$ Ms>K WNV}^`-큧32ŒVؙGdu,^^m%6~Nn&͓3ŒVZMsRpfEW%IwdǀLm[7W&bIRL@Q|)* i ImsIMmKmyV`i$G+R 0tV'!V)֏28vU7͒vHꦼtxꗞT ;S}7Mf+fIRHNZUkUx5SAJㄌ9MqμAIRi|j5)o*^'<$TwI1hEU^c_j?Е$%d`z cyf,XO IJnTgA UXRD }{H}^S,P5V2\Xx`pZ|Yk:$e ~ @nWL.j+ϝYb퇪bZ BVu)u/IJ_ 1[p.p60bC >|X91P:N\!5qUB}5a5ja `ubcVxYt1N0Zzl4]7­gKj]?4ϻ *[bg$)+À*x쳀ogO$~,5 زUS9 lq3+5mgw@np1sso Ӻ=|N6 /g(Wv7U;zωM=wk,0uTg_`_P`uz?2yI!b`kĸSo+Qx%!\οe|އԁKS-s6pu_(ֿ$i++T8=eY; צP+phxWQv*|p1. ά. XRkIQYP,drZ | B%wP|S5`~́@i޾ E;Չaw{o'Q?%iL{u D?N1BD!owPHReFZ* k_-~{E9b-~P`fE{AܶBJAFO wx6Rox5 K5=WwehS8 (JClJ~ p+Fi;ŗo+:bD#g(C"wA^ r.F8L;dzdIHUX݆ϞXg )IFqem%I4dj&ppT{'{HOx( Rk6^C٫O.)3:s(۳(Z?~ٻ89zmT"PLtw䥈5&b<8GZ-Y&K?e8,`I6e(֍xb83 `rzXj)F=l($Ij 2*(F?h(/9ik:I`m#p3MgLaKjc/U#n5S# m(^)=y=đx8ŬI[U]~SцA4p$-F i(R,7Cx;X=cI>{Km\ o(Tv2vx2qiiDJN,Ҏ!1f 5quBj1!8 rDFd(!WQl,gSkL1Bxg''՞^ǘ;pQ P(c_ IRujg(Wz bs#P­rz> k c&nB=q+ؔXn#r5)co*Ũ+G?7< |PQӣ'G`uOd>%Mctz# Ԫڞ&7CaQ~N'-P.W`Oedp03C!IZcIAMPUۀ5J<\u~+{9(FbbyAeBhOSܳ1 bÈT#ŠyDžs,`5}DC-`̞%r&ڙa87QWWp6e7 Rϫ/oY ꇅ Nܶըtc!LA T7V4Jsū I-0Pxz7QNF_iZgúWkG83 0eWr9 X]㾮݁#Jˢ C}0=3ݱtBi]_ &{{[/o[~ \q鯜00٩|cD3=4B_b RYb$óBRsf&lLX#M*C_L܄:gx)WΘsGSbuL rF$9';\4Ɍq'n[%p.Q`u hNb`eCQyQ|l_C>Lb꟟3hSb #xNxSs^ 88|Mz)}:](vbۢamŖ࿥ 0)Q7@0=?^k(*J}3ibkFn HjB׻NO z x}7p 0tfDX.lwgȔhԾŲ }6g E |LkLZteu+=q\Iv0쮑)QٵpH8/2?Σo>Jvppho~f>%bMM}\//":PTc(v9v!gոQ )UfVG+! 35{=x\2+ki,y$~A1iC6#)vC5^>+gǵ@1Hy٪7u;p psϰu/S <aʸGu'tD1ԝI<pg|6j'p:tպhX{o(7v],*}6a_ wXRk,O]Lܳ~Vo45rp"N5k;m{rZbΦ${#)`(Ŵg,;j%6j.pyYT?}-kBDc3qA`NWQū20/^AZW%NQ MI.X#P#,^Ebc&?XR tAV|Y.1!؅⨉ccww>ivl(JT~ u`ٵDm q)+Ri x/x8cyFO!/*!/&,7<.N,YDŽ&ܑQF1Bz)FPʛ?5d 6`kQձ λc؎%582Y&nD_$Je4>a?! ͨ|ȎWZSsv8 j(I&yj Jb5m?HWp=g}G3#|I,5v珿] H~R3@B[☉9Ox~oMy=J;xUVoj bUsl_35t-(ՃɼRB7U!qc+x4H_Qo֮$[GO<4`&č\GOc[.[*Af%mG/ ňM/r W/Nw~B1U3J?P&Y )`ѓZ1p]^l“W#)lWZilUQu`-m|xĐ,_ƪ|9i:_{*(3Gѧ}UoD+>m_?VPۅ15&}2|/pIOʵ> GZ9cmíتmnz)yߐbD >e}:) r|@R5qVSA10C%E_'^8cR7O;6[eKePGϦX7jb}OTGO^jn*媓7nGMC t,k31Rb (vyܴʭ!iTh8~ZYZp(qsRL ?b}cŨʊGO^!rPJO15MJ[c&~Z`"ѓޔH1C&^|Ш|rʼ,AwĴ?b5)tLU)F| &g٣O]oqSUjy(x<Ϳ3 .FSkoYg2 \_#wj{u'rQ>o;%n|F*O_L"e9umDds?.fuuQbIWz |4\0 sb;OvxOSs; G%T4gFRurj(֍ڑb uԖKDu1MK{1^ q; C=6\8FR艇!%\YÔU| 88m)֓NcLve C6z;o&X x59:q61Z(T7>C?gcļxѐ Z oo-08jہ x,`' ҔOcRlf~`jj".Nv+sM_]Zk g( UOPyεx%pUh2(@il0ݽQXxppx-NS( WO+轾 nFߢ3M<;z)FBZjciu/QoF 7R¥ ZFLF~#ȣߨ^<쩡ݛкvџ))ME>ώx4m#!-m!L;vv#~Y[đKmx9.[,UFS CVkZ +ߟrY٧IZd/ioi$%͝ب_ֶX3ܫhNU ZZgk=]=bbJS[wjU()*I =ώ:}-蹞lUj:1}MWm=̛ _ ¾,8{__m{_PVK^n3esw5ӫh#$-q=A̟> ,^I}P^J$qY~Q[ Xq9{#&T.^GVj__RKpn,b=`żY@^՝;z{paVKkQXj/)y TIc&F;FBG7wg ZZDG!x r_tƢ!}i/V=M/#nB8 XxЫ ^@CR<{䤭YCN)eKOSƟa $&g[i3.C6xrOc8TI;o hH6P&L{@q6[ Gzp^71j(l`J}]e6X☉#͕ ׈$AB1Vjh㭦IRsqFBjwQ_7Xk>y"N=MB0 ,C #o6MRc0|$)ف"1!ixY<B9mx `,tA>)5ػQ?jQ?cn>YZe Tisvh# GMމȇp:ԴVuږ8ɼH]C.5C!UV;F`mbBk LTMvPʍϤj?ԯ/Qr1NB`9s"s TYsz &9S%U԰> {<ؿSMxB|H\3@!U| k']$U+> |HHMLޢ?V9iD!-@x TIî%6Z*9X@HMW#?nN ,oe6?tQwڱ.]-y':mW0#!J82qFjH -`ѓ&M0u Uγmxϵ^-_\])@0Rt.8/?ٰCY]x}=sD3ojަЫNuS%U}ԤwHH>ڗjܷ_3gN q7[q2la*ArǓԖ+p8/RGM ]jacd(JhWko6ڎbj]i5Bj3+3!\j1UZLsLTv8HHmup<>gKMJj0@H%,W΃7R) ">c, xixј^ aܖ>H[i.UIHc U1=yW\=S*GR~)AF=`&2h`DzT󑓶J+?W+}C%P:|0H܆}-<;OC[~o.$~i}~HQ TvXΈr=b}$vizL4:ȰT|4~*!oXQR6Lk+#t/g lԁߖ[Jڶ_N$k*". xsxX7jRVbAAʯKҎU3)zSNN _'s?f)6X!%ssAkʱ>qƷb hg %n ~p1REGMHH=BJiy[<5 ǁJҖgKR*倳e~HUy)Ag,K)`Vw6bRR:qL#\rclK/$sh*$ 6덤 KԖc 3Z9=Ɣ=o>X Ώ"1 )a`SJJ6k(<c e{%kϊP+SL'TcMJWRm ŏ"w)qc ef꒵i?b7b('"2r%~HUS1\<(`1Wx9=8HY9m:X18bgD1u ~|H;K-Uep,, C1 RV.MR5άh,tWO8WC$ XRVsQS]3GJ|12 [vM :k#~tH30Rf-HYݺ-`I9%lIDTm\ S{]9gOڒMNCV\G*2JRŨ;Rҏ^ڽ̱mq1Eu?To3I)y^#jJw^Ńj^vvlB_⋌P4x>0$c>K†Aļ9s_VjTt0l#m>E-,,x,-W)سo&96RE XR.6bXw+)GAEvL)͞K4$p=Ũi_ѱOjb HY/+@θH9޼]Nԥ%n{ &zjT? Ty) s^ULlb,PiTf^<À] 62R^V7)S!nllS6~͝V}-=%* ʻ>G DnK<y&>LPy7'r=Hj 9V`[c"*^8HpcO8bnU`4JȪAƋ#1_\ XϘHPRgik(~G~0DAA_2p|J묭a2\NCr]M_0 ^T%e#vD^%xy-n}-E\3aS%yN!r_{ )sAw ڼp1pEAk~v<:`'ӭ^5 ArXOI驻T (dk)_\ PuA*BY]yB"l\ey hH*tbK)3 IKZ򹞋XjN n *n>k]X_d!ryBH ]*R 0(#'7 %es9??ښFC,ՁQPjARJ\Ρw K#jahgw;2$l*) %Xq5!U᢯6Re] |0[__64ch&_}iL8KEgҎ7 M/\`|.p,~`a=BR?xܐrQ8K XR2M8f ?`sgWS%" Ԉ 7R%$ N}?QL1|-эټwIZ%pvL3Hk>,ImgW7{E xPHx73RA @RS CC !\ȟ5IXR^ZxHл$Q[ŝ40 (>+ _C >BRt<,TrT {O/H+˟Pl6 I B)/VC<6a2~(XwV4gnXR ϱ5ǀHٻ?tw똤Eyxp{#WK qG%5],(0ӈH HZ])ג=K1j&G(FbM@)%I` XRg ʔ KZG(vP,<`[ Kn^ SJRsAʠ5xՅF`0&RbV tx:EaUE/{fi2;.IAwW8/tTxAGOoN?G}l L(n`Zv?pB8K_gI+ܗ #i?ޙ.) p$utc ~DžfՈEo3l/)I-U?aԅ^jxArA ΧX}DmZ@QLےbTXGd.^|xKHR{|ΕW_h] IJ`[G9{).y) 0X YA1]qp?p_k+J*Y@HI>^?gt.06Rn ,` ?);p pSF9ZXLBJPWjgQ|&)7! HjQt<| ؅W5 x W HIzYoVMGP Hjn`+\(dNW)F+IrS[|/a`K|ͻ0Hj{R,Q=\ (F}\WR)AgSG`IsnAR=|8$}G(vC$)s FBJ?]_u XRvύ6z ŨG[36-T9HzpW̞ú Xg큽=7CufzI$)ki^qk-) 0H*N` QZkk]/tnnsI^Gu't=7$ Z;{8^jB% IItRQS7[ϭ3 $_OQJ`7!]W"W,)Iy W AJA;KWG`IY{8k$I$^%9.^(`N|LJ%@$I}ֽp=FB*xN=gI?Q{٥4B)mw $Igc~dZ@G9K X?7)aK%݅K$IZ-`IpC U6$I\0>!9k} Xa IIS0H$I H ?1R.Чj:4~Rw@p$IrA*u}WjWFPJ$I➓/6#! LӾ+ X36x8J |+L;v$Io4301R20M I$-E}@,pS^ޟR[/s¹'0H$IKyfŸfVOπFT*a$I>He~VY/3R/)>d$I>28`Cjw,n@FU*9ttf$I~<;=/4RD~@ X-ѕzἱI$: ԍR a@b X{+Qxuq$IЛzo /~3\8ڒ4BN7$IҀj V]n18H$IYFBj3̵̚ja pp $Is/3R Ӻ-Yj+L;.0ŔI$Av? #!5"aʄj}UKmɽH$IjCYs?h$IDl843.v}m7UiI=&=0Lg0$I4: embe` eQbm0u? $IT!Sƍ'-sv)s#C0:XB2a w I$zbww{."pPzO =Ɔ\[ o($Iaw]`E).Kvi:L*#gР7[$IyGPI=@R 4yR~̮´cg I$I/<tPͽ hDgo 94Z^k盇΄8I56^W$I^0̜N?4*H`237}g+hxoq)SJ@p|` $I%>-hO0eO>\ԣNߌZD6R=K ~n($I$y3D>o4b#px2$yڪtzW~a $I~?x'BwwpH$IZݑnC㧄Pc_9sO gwJ=l1:mKB>Ab<4Lp$Ib o1ZQ@85b̍ S'F,Fe,^I$IjEdù{l4 8Ys_s Z8.x m"+{~?q,Z D!I$ϻ'|XhB)=…']M>5 rgotԎ 獽PH$IjIPhh)n#cÔqA'ug5qwU&rF|1E%I$%]!'3AFD/;Ck_`9 v!ٴtPV;x`'*bQa w I$Ix5 FC3D_~A_#O݆DvV?<qw+I$I{=Z8".#RIYyjǪ=fDl9%M,a8$I$Ywi[7ݍFe$s1ՋBVA?`]#!oz4zjLJo8$I$%@3jAa4(o ;p,,dya=F9ً[LSPH$IJYЉ+3> 5"39aZ<ñh!{TpBGkj}Sp $IlvF.F$I z< '\K*qq.f<2Y!S"-\I$IYwčjF$ w9 \ߪB.1v!Ʊ?+r:^!I$BϹB H"B;L'G[ 4U#5>੐)|#o0aڱ$I>}k&1`U#V?YsV x>{t1[I~D&(I$I/{H0fw"q"y%4 IXyE~M3 8XψL}qE$I[> nD?~sf ]o΁ cT6"?'_Ἣ $I>~.f|'!N?⟩0G KkXZE]ޡ;/&?k OۘH$IRۀwXӨ<7@PnS04aӶp.:@\IWQJ6sS%I$e5ڑv`3:x';wq_vpgHyXZ 3gЂ7{{EuԹn±}$I$8t;b|591nءQ"P6O5i }iR̈́%Q̄p!I䮢]O{H$IRϻ9s֧ a=`- aB\X0"+5"C1Hb?߮3x3&gşggl_hZ^,`5?ߎvĸ%̀M!OZC2#0x LJ0 Gw$I$I}<{Eb+y;iI,`ܚF:5ܛA8-O-|8K7s|#Z8a&><a&/VtbtLʌI$I$I$I$I$I$IRjDD%tEXtdate:create2022-05-31T04:40:26+00:00!Î%tEXtdate:modify2022-05-31T04:40:26+00:00|{2IENDB`Mini Shell

HOME


Mini Shell 1.0
DIR:/proc/self/root/opt/cpanel/ea-ruby27/root/usr/share/ruby/ruby-2.7.8/rubygems/
Upload File :
Current File : //proc/self/root/opt/cpanel/ea-ruby27/root/usr/share/ruby/ruby-2.7.8/rubygems/server.rb
# frozen_string_literal: true
require 'webrick'
require 'zlib'
require 'erb'
require 'uri'

require 'rubygems'
require 'rubygems/rdoc'

##
# Gem::Server and allows users to serve gems for consumption by
# `gem --remote-install`.
#
# gem_server starts an HTTP server on the given port and serves the following:
# * "/" - Browsing of gem spec files for installed gems
# * "/specs.#{Gem.marshal_version}.gz" - specs name/version/platform index
# * "/latest_specs.#{Gem.marshal_version}.gz" - latest specs
#   name/version/platform index
# * "/quick/" - Individual gemspecs
# * "/gems" - Direct access to download the installable gems
# * "/rdoc?q=" - Search for installed rdoc documentation
#
# == Usage
#
#   gem_server = Gem::Server.new Gem.dir, 8089, false
#   gem_server.run
#
#--
# TODO Refactor into a real WEBrick servlet to remove code duplication.

class Gem::Server

  attr_reader :spec_dirs

  include ERB::Util
  include Gem::UserInteraction

  SEARCH = <<-ERB.freeze
      <form class="headerSearch" name="headerSearchForm" method="get" action="/rdoc">
        <div id="search" style="float:right">
          <label for="q">Filter/Search</label>
          <input id="q" type="text" style="width:10em" name="q">
          <button type="submit" style="display:none"></button>
        </div>
      </form>
  ERB

  DOC_TEMPLATE = <<-'ERB'.freeze
  <?xml version="1.0" encoding="iso-8859-1"?>
  <!DOCTYPE html
       PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
       "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

  <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  <head>
    <title>RubyGems Documentation Index</title>
    <link rel="stylesheet" href="gem-server-rdoc-style.css" type="text/css" media="screen" />
  </head>
  <body>
    <div id="fileHeader">
<%= SEARCH %>
      <h1>RubyGems Documentation Index</h1>
    </div>
    <!-- banner header -->

  <div id="bodyContent">
    <div id="contextContent">
      <div id="description">
        <h1>Summary</h1>
  <p>There are <%=values["gem_count"]%> gems installed:</p>
  <p>
  <%= values["specs"].map { |v| "<a href=\"##{u v["name"]}\">#{h v["name"]}</a>" }.join ', ' %>.
  <h1>Gems</h1>

  <dl>
  <% values["specs"].each do |spec| %>
    <dt>
    <% if spec["first_name_entry"] then %>
      <a name="<%=h spec["name"]%>"></a>
    <% end %>

    <b><%=h spec["name"]%> <%=h spec["version"]%></b>

    <% if spec["ri_installed"] || spec["rdoc_installed"] then %>
      <a href="<%=spec["doc_path"]%>">[rdoc]</a>
    <% else %>
      <span title="rdoc not installed">[rdoc]</span>
    <% end %>

    <% if spec["homepage"] then %>
      <a href="<%=uri_encode spec["homepage"]%>" title="<%=h spec["homepage"]%>">[www]</a>
    <% else %>
      <span title="no homepage available">[www]</span>
    <% end %>

    <% if spec["has_deps"] then %>
     - depends on
      <%= spec["dependencies"].map { |v| "<a href=\"##{u v["name"]}\">#{h v["name"]}</a>" }.join ', ' %>.
    <% end %>
    </dt>
    <dd>
    <%=spec["summary"]%>
    <% if spec["executables"] then %>
      <br/>

      <% if spec["only_one_executable"] then %>
          Executable is
      <% else %>
          Executables are
      <%end%>

      <%= spec["executables"].map { |v| "<span class=\"context-item-name\">#{h v["executable"]}</span>"}.join ', ' %>.

    <%end%>
    <br/>
    <br/>
    </dd>
  <% end %>
  </dl>

      </div>
     </div>
    </div>
  <div id="validator-badges">
    <p><small><a href="http://validator.w3.org/check/referer">[Validate]</a></small></p>
  </div>
  </body>
  </html>
  ERB

  # CSS is copy & paste from rdoc-style.css, RDoc V1.0.1 - 20041108
  RDOC_CSS = <<-CSS.freeze
body {
    font-family: Verdana,Arial,Helvetica,sans-serif;
    font-size:   90%;
    margin: 0;
    margin-left: 40px;
    padding: 0;
    background: white;
}

h1,h2,h3,h4 { margin: 0; color: #efefef; background: transparent; }
h1 { font-size: 150%; }
h2,h3,h4 { margin-top: 1em; }

a { background: #eef; color: #039; text-decoration: none; }
a:hover { background: #039; color: #eef; }

/* Override the base stylesheets Anchor inside a table cell */
td > a {
  background: transparent;
  color: #039;
  text-decoration: none;
}

/* and inside a section title */
.section-title > a {
  background: transparent;
  color: #eee;
  text-decoration: none;
}

/* === Structural elements =================================== */

div#index {
    margin: 0;
    margin-left: -40px;
    padding: 0;
    font-size: 90%;
}


div#index a {
    margin-left: 0.7em;
}

div#index .section-bar {
   margin-left: 0px;
   padding-left: 0.7em;
   background: #ccc;
   font-size: small;
}


div#classHeader, div#fileHeader {
    width: auto;
    color: white;
    padding: 0.5em 1.5em 0.5em 1.5em;
    margin: 0;
    margin-left: -40px;
    border-bottom: 3px solid #006;
}

div#classHeader a, div#fileHeader a {
    background: inherit;
    color: white;
}

div#classHeader td, div#fileHeader td {
    background: inherit;
    color: white;
}


div#fileHeader {
    background: #057;
}

div#classHeader {
    background: #048;
}


.class-name-in-header {
  font-size:  180%;
  font-weight: bold;
}


div#bodyContent {
    padding: 0 1.5em 0 1.5em;
}

div#description {
    padding: 0.5em 1.5em;
    background: #efefef;
    border: 1px dotted #999;
}

div#description h1,h2,h3,h4,h5,h6 {
    color: #125;;
    background: transparent;
}

div#validator-badges {
    text-align: center;
}
div#validator-badges img { border: 0; }

div#copyright {
    color: #333;
    background: #efefef;
    font: 0.75em sans-serif;
    margin-top: 5em;
    margin-bottom: 0;
    padding: 0.5em 2em;
}


/* === Classes =================================== */

table.header-table {
    color: white;
    font-size: small;
}

.type-note {
    font-size: small;
    color: #DEDEDE;
}

.xxsection-bar {
    background: #eee;
    color: #333;
    padding: 3px;
}

.section-bar {
   color: #333;
   border-bottom: 1px solid #999;
    margin-left: -20px;
}


.section-title {
    background: #79a;
    color: #eee;
    padding: 3px;
    margin-top: 2em;
    margin-left: -30px;
    border: 1px solid #999;
}

.top-aligned-row {  vertical-align: top }
.bottom-aligned-row { vertical-align: bottom }

/* --- Context section classes ----------------------- */

.context-row { }
.context-item-name { font-family: monospace; font-weight: bold; color: black; }
.context-item-value { font-size: small; color: #448; }
.context-item-desc { color: #333; padding-left: 2em; }

/* --- Method classes -------------------------- */
.method-detail {
    background: #efefef;
    padding: 0;
    margin-top: 0.5em;
    margin-bottom: 1em;
    border: 1px dotted #ccc;
}
.method-heading {
  color: black;
  background: #ccc;
  border-bottom: 1px solid #666;
  padding: 0.2em 0.5em 0 0.5em;
}
.method-signature { color: black; background: inherit; }
.method-name { font-weight: bold; }
.method-args { font-style: italic; }
.method-description { padding: 0 0.5em 0 0.5em; }

/* --- Source code sections -------------------- */

a.source-toggle { font-size: 90%; }
div.method-source-code {
    background: #262626;
    color: #ffdead;
    margin: 1em;
    padding: 0.5em;
    border: 1px dashed #999;
    overflow: hidden;
}

div.method-source-code pre { color: #ffdead; overflow: hidden; }

/* --- Ruby keyword styles --------------------- */

.standalone-code { background: #221111; color: #ffdead; overflow: hidden; }

.ruby-constant  { color: #7fffd4; background: transparent; }
.ruby-keyword { color: #00ffff; background: transparent; }
.ruby-ivar    { color: #eedd82; background: transparent; }
.ruby-operator  { color: #00ffee; background: transparent; }
.ruby-identifier { color: #ffdead; background: transparent; }
.ruby-node    { color: #ffa07a; background: transparent; }
.ruby-comment { color: #b22222; font-weight: bold; background: transparent; }
.ruby-regexp  { color: #ffa07a; background: transparent; }
.ruby-value   { color: #7fffd4; background: transparent; }
  CSS

  RDOC_NO_DOCUMENTATION = <<-'ERB'.freeze
<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
          "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  <head>
    <title>Found documentation</title>
    <link rel="stylesheet" href="gem-server-rdoc-style.css" type="text/css" media="screen" />
  </head>
  <body>
    <div id="fileHeader">
<%= SEARCH %>
      <h1>No documentation found</h1>
    </div>

    <div id="bodyContent">
      <div id="contextContent">
        <div id="description">
          <p>No gems matched <%= h query.inspect %></p>

          <p>
            Back to <a href="/">complete gem index</a>
          </p>

        </div>
      </div>
    </div>
    <div id="validator-badges">
      <p><small><a href="http://validator.w3.org/check/referer">[Validate]</a></small></p>
    </div>
  </body>
</html>
  ERB

  RDOC_SEARCH_TEMPLATE = <<-'ERB'.freeze
<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
          "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  <head>
    <title>Found documentation</title>
    <link rel="stylesheet" href="gem-server-rdoc-style.css" type="text/css" media="screen" />
  </head>
  <body>
    <div id="fileHeader">
<%= SEARCH %>
      <h1>Found documentation</h1>
    </div>
    <!-- banner header -->

    <div id="bodyContent">
      <div id="contextContent">
        <div id="description">
          <h1>Summary</h1>
          <p><%=doc_items.length%> documentation topics found.</p>
          <h1>Topics</h1>

          <dl>
          <% doc_items.each do |doc_item| %>
            <dt>
              <b><%=doc_item[:name]%></b>
              <a href="<%=u doc_item[:url]%>">[rdoc]</a>
            </dt>
            <dd>
              <%=h doc_item[:summary]%>
              <br/>
              <br/>
            </dd>
          <% end %>
          </dl>

          <p>
            Back to <a href="/">complete gem index</a>
          </p>

        </div>
      </div>
    </div>
    <div id="validator-badges">
      <p><small><a href="http://validator.w3.org/check/referer">[Validate]</a></small></p>
    </div>
  </body>
</html>
  ERB

  def self.run(options)
    new(options[:gemdir], options[:port], options[:daemon],
        options[:launch], options[:addresses]).run
  end

  def initialize(gem_dirs, port, daemon, launch = nil, addresses = nil)
    Gem::RDoc.load_rdoc
    Socket.do_not_reverse_lookup = true

    @gem_dirs  = Array gem_dirs
    @port      = port
    @daemon    = daemon
    @launch    = launch
    @addresses = addresses

    logger  = WEBrick::Log.new nil, WEBrick::BasicLog::FATAL
    @server = WEBrick::HTTPServer.new :DoNotListen => true, :Logger => logger

    @spec_dirs = @gem_dirs.map { |gem_dir| File.join gem_dir, 'specifications' }
    @spec_dirs.reject! { |spec_dir| !File.directory? spec_dir }

    reset_gems

    @have_rdoc_4_plus = nil
  end

  def add_date(res)
    res['date'] = @spec_dirs.map do |spec_dir|
      File.stat(spec_dir).mtime
    end.max
  end

  def uri_encode(str)
    str.gsub(URI::UNSAFE) do |match|
      match.each_byte.map { |c| sprintf('%%%02X', c.ord) }.join
    end
  end

  def doc_root(gem_name)
    if have_rdoc_4_plus?
      "/doc_root/#{u gem_name}/"
    else
      "/doc_root/#{u gem_name}/rdoc/index.html"
    end
  end

  def have_rdoc_4_plus?
    @have_rdoc_4_plus ||=
      Gem::Requirement.new('>= 4.0.0.preview2').satisfied_by? Gem::RDoc.rdoc_version
  end

  def latest_specs(req, res)
    reset_gems

    res['content-type'] = 'application/x-gzip'

    add_date res

    latest_specs = Gem::Specification.latest_specs

    specs = latest_specs.sort.map do |spec|
      platform = spec.original_platform || Gem::Platform::RUBY
      [spec.name, spec.version, platform]
    end

    specs = Marshal.dump specs

    if req.path =~ /\.gz$/
      specs = Gem::Util.gzip specs
      res['content-type'] = 'application/x-gzip'
    else
      res['content-type'] = 'application/octet-stream'
    end

    if req.request_method == 'HEAD'
      res['content-length'] = specs.length
    else
      res.body << specs
    end
  end

  ##
  # Creates server sockets based on the addresses option.  If no addresses
  # were given a server socket for all interfaces is created.

  def listen(addresses = @addresses)
    addresses = [nil] unless addresses

    listeners = 0

    addresses.each do |address|
      begin
        @server.listen address, @port
        @server.listeners[listeners..-1].each do |listener|
          host, port = listener.addr.values_at 2, 1
          host = "[#{host}]" if host =~ /:/ # we don't reverse lookup
          say "Server started at http://#{host}:#{port}"
        end

        listeners = @server.listeners.length
      rescue SystemCallError
        next
      end
    end

    if @server.listeners.empty?
      say "Unable to start a server."
      say "Check for running servers or your --bind and --port arguments"
      terminate_interaction 1
    end
  end

  def prerelease_specs(req, res)
    reset_gems

    res['content-type'] = 'application/x-gzip'

    add_date res

    specs = Gem::Specification.select do |spec|
      spec.version.prerelease?
    end.sort.map do |spec|
      platform = spec.original_platform || Gem::Platform::RUBY
      [spec.name, spec.version, platform]
    end

    specs = Marshal.dump specs

    if req.path =~ /\.gz$/
      specs = Gem::Util.gzip specs
      res['content-type'] = 'application/x-gzip'
    else
      res['content-type'] = 'application/octet-stream'
    end

    if req.request_method == 'HEAD'
      res['content-length'] = specs.length
    else
      res.body << specs
    end
  end

  def quick(req, res)
    reset_gems

    res['content-type'] = 'text/plain'
    add_date res

    case req.request_uri.path
    when %r|^/quick/(Marshal.#{Regexp.escape Gem.marshal_version}/)?(.*?)\.gemspec\.rz$| then
      marshal_format, full_name = $1, $2
      specs = Gem::Specification.find_all_by_full_name(full_name)

      selector = full_name.inspect

      if specs.empty?
        res.status = 404
        res.body = "No gems found matching #{selector}"
      elsif specs.length > 1
        res.status = 500
        res.body = "Multiple gems found matching #{selector}"
      elsif marshal_format
        res['content-type'] = 'application/x-deflate'
        res.body << Gem.deflate(Marshal.dump(specs.first))
      end
    else
      raise WEBrick::HTTPStatus::NotFound, "`#{req.path}' not found."
    end
  end

  def root(req, res)
    reset_gems

    add_date res

    raise WEBrick::HTTPStatus::NotFound, "`#{req.path}' not found." unless
      req.path == '/'

    specs = []
    total_file_count = 0

    Gem::Specification.each do |spec|
      total_file_count += spec.files.size
      deps = spec.dependencies.map do |dep|
        {
          "name"    => dep.name,
          "type"    => dep.type,
          "version" => dep.requirement.to_s,
        }
      end

      deps = deps.sort_by { |dep| [dep["name"].downcase, dep["version"]] }
      deps.last["is_last"] = true unless deps.empty?

      # executables
      executables = spec.executables.sort.collect { |exec| {"executable" => exec} }
      executables = nil if executables.empty?
      executables.last["is_last"] = true if executables

      # Pre-process spec homepage for safety reasons
      begin
        homepage_uri = URI.parse(spec.homepage)
        if [URI::HTTP, URI::HTTPS].member? homepage_uri.class
          homepage_uri = spec.homepage
        else
          homepage_uri = "."
        end
      rescue URI::InvalidURIError
        homepage_uri = "."
      end

      specs << {
        "authors"             => spec.authors.sort.join(", "),
        "date"                => spec.date.to_s,
        "dependencies"        => deps,
        "doc_path"            => doc_root(spec.full_name),
        "executables"         => executables,
        "only_one_executable" => (executables && executables.size == 1),
        "full_name"           => spec.full_name,
        "has_deps"            => !deps.empty?,
        "homepage"            => homepage_uri,
        "name"                => spec.name,
        "rdoc_installed"      => Gem::RDoc.new(spec).rdoc_installed?,
        "ri_installed"        => Gem::RDoc.new(spec).ri_installed?,
        "summary"             => spec.summary,
        "version"             => spec.version.to_s,
      }
    end

    specs << {
      "authors" => "Chad Fowler, Rich Kilmer, Jim Weirich, Eric Hodel and others",
      "dependencies" => [],
      "doc_path" => doc_root("rubygems-#{Gem::VERSION}"),
      "executables" => [{"executable" => 'gem', "is_last" => true}],
      "only_one_executable" => true,
      "full_name" => "rubygems-#{Gem::VERSION}",
      "has_deps" => false,
      "homepage" => "https://guides.rubygems.org/",
      "name" => 'rubygems',
      "ri_installed" => true,
      "summary" => "RubyGems itself",
      "version" => Gem::VERSION,
    }

    specs = specs.sort_by { |spec| [spec["name"].downcase, spec["version"]] }
    specs.last["is_last"] = true

    # tag all specs with first_name_entry
    last_spec = nil
    specs.each do |spec|
      is_first = last_spec.nil? || (last_spec["name"].downcase != spec["name"].downcase)
      spec["first_name_entry"] = is_first
      last_spec = spec
    end

    # create page from template
    template = ERB.new(DOC_TEMPLATE)
    res['content-type'] = 'text/html'

    values = { "gem_count" => specs.size.to_s, "specs" => specs,
               "total_file_count" => total_file_count.to_s }

    # suppress 1.9.3dev warning about unused variable
    values = values

    result = template.result binding
    res.body = result
  end

  ##
  # Can be used for quick navigation to the rdoc documentation.  You can then
  # define a search shortcut for your browser.  E.g. in Firefox connect
  # 'shortcut:rdoc' to http://localhost:8808/rdoc?q=%s template. Then you can
  # directly open the ActionPack documentation by typing 'rdoc actionp'. If
  # there are multiple hits for the search term, they are presented as a list
  # with links.
  #
  # Search algorithm aims for an intuitive search:
  # 1. first try to find the gems and documentation folders which name
  #    starts with the search term
  # 2. search for entries, that *contain* the search term
  # 3. show all the gems
  #
  # If there is only one search hit, user is immediately redirected to the
  # documentation for the particular gem, otherwise a list with results is
  # shown.
  #
  # === Additional trick - install documentation for Ruby core
  #
  # Note: please adjust paths accordingly use for example 'locate yaml.rb' and
  # 'gem environment' to identify directories, that are specific for your
  # local installation
  #
  # 1. install Ruby sources
  #      cd /usr/src
  #      sudo apt-get source ruby
  #
  # 2. generate documentation
  #      rdoc -o /usr/lib/ruby/gems/1.8/doc/core/rdoc \
  #        /usr/lib/ruby/1.8 ruby1.8-1.8.7.72
  #
  # By typing 'rdoc core' you can now access the core documentation

  def rdoc(req, res)
    query = req.query['q']
    show_rdoc_for_pattern("#{query}*", res) && return
    show_rdoc_for_pattern("*#{query}*", res) && return

    template = ERB.new RDOC_NO_DOCUMENTATION

    res['content-type'] = 'text/html'
    res.body = template.result binding
  end

  ##
  # Updates the server to use the latest installed gems.

  def reset_gems # :nodoc:
    Gem::Specification.dirs = @gem_dirs
  end

  ##
  # Returns true and prepares http response, if rdoc for the requested gem
  # name pattern was found.
  #
  # The search is based on the file system content, not on the gems metadata.
  # This allows additional documentation folders like 'core' for the Ruby core
  # documentation - just put it underneath the main doc folder.

  def show_rdoc_for_pattern(pattern, res)
    found_gems = Dir.glob("{#{@gem_dirs.join ','}}/doc/#{pattern}").select do |path|
      File.exist? File.join(path, 'rdoc/index.html')
    end
    case found_gems.length
    when 0
      return false
    when 1
      new_path = File.basename(found_gems[0])
      res.status = 302
      res['Location'] = doc_root new_path
      return true
    else
      doc_items = []
      found_gems.each do |file_name|
        base_name = File.basename(file_name)
        doc_items << {
          :name    => base_name,
          :url     => doc_root(new_path),
          :summary => ''
        }
      end

      template = ERB.new(RDOC_SEARCH_TEMPLATE)
      res['content-type'] = 'text/html'
      result = template.result binding
      res.body = result
      return true
    end
  end

  def run
    listen

    WEBrick::Daemon.start if @daemon

    @server.mount_proc "/specs.#{Gem.marshal_version}", method(:specs)
    @server.mount_proc "/specs.#{Gem.marshal_version}.gz", method(:specs)

    @server.mount_proc "/latest_specs.#{Gem.marshal_version}",
                       method(:latest_specs)
    @server.mount_proc "/latest_specs.#{Gem.marshal_version}.gz",
                       method(:latest_specs)

    @server.mount_proc "/prerelease_specs.#{Gem.marshal_version}",
                       method(:prerelease_specs)
    @server.mount_proc "/prerelease_specs.#{Gem.marshal_version}.gz",
                       method(:prerelease_specs)

    @server.mount_proc "/quick/", method(:quick)

    @server.mount_proc("/gem-server-rdoc-style.css") do |req, res|
      res['content-type'] = 'text/css'
      add_date res
      res.body << RDOC_CSS
    end

    @server.mount_proc "/", method(:root)

    @server.mount_proc "/rdoc", method(:rdoc)

    file_handlers = {
      '/gems' => '/cache/',
    }

    if have_rdoc_4_plus?
      @server.mount '/doc_root', RDoc::Servlet, '/doc_root'
    else
      file_handlers['/doc_root'] = '/doc/'
    end

    @gem_dirs.each do |gem_dir|
      file_handlers.each do |mount_point, mount_dir|
        @server.mount(mount_point, WEBrick::HTTPServlet::FileHandler,
                      File.join(gem_dir, mount_dir), true)
      end
    end

    trap("INT") { @server.shutdown; exit! }
    trap("TERM") { @server.shutdown; exit! }

    launch if @launch

    @server.start
  end

  def specs(req, res)
    reset_gems

    add_date res

    specs = Gem::Specification.sort_by(&:sort_obj).map do |spec|
      platform = spec.original_platform || Gem::Platform::RUBY
      [spec.name, spec.version, platform]
    end

    specs = Marshal.dump specs

    if req.path =~ /\.gz$/
      specs = Gem::Util.gzip specs
      res['content-type'] = 'application/x-gzip'
    else
      res['content-type'] = 'application/octet-stream'
    end

    if req.request_method == 'HEAD'
      res['content-length'] = specs.length
    else
      res.body << specs
    end
  end

  def launch
    listeners = @server.listeners.map{|l| l.addr[2] }

    # TODO: 0.0.0.0 == any, not localhost.
    host = listeners.any?{|l| l == '0.0.0.0'} ? 'localhost' : listeners.first

    say "Launching browser to http://#{host}:#{@port}"

    system("#{@launch} http://#{host}:#{@port}")
  end

end